summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2011-10-04 12:42:11 +0200
committerStefan Metzmacher <metze@samba.org>2011-10-08 01:43:38 +0200
commitcc17ac9bba0de5ea8f057cf7683aa914ff4e5702 (patch)
tree8b80474f29554c6554c23be55f84d74c086087b8
parentf697956dcba801e4209b375f6ebda3168e2a210d (diff)
downloadsamba-cc17ac9bba0de5ea8f057cf7683aa914ff4e5702.tar.gz
samba-cc17ac9bba0de5ea8f057cf7683aa914ff4e5702.tar.bz2
samba-cc17ac9bba0de5ea8f057cf7683aa914ff4e5702.zip
s4:smb_server: implement dfs referral handing on top of dfs_server_ad_get_referrals()
metze
-rw-r--r--source4/smb_server/smb/trans2.c865
-rw-r--r--source4/smb_server/smb/wscript_build1
2 files changed, 54 insertions, 812 deletions
diff --git a/source4/smb_server/smb/trans2.c b/source4/smb_server/smb/trans2.c
index 1bc5c12b0a..89402bac82 100644
--- a/source4/smb_server/smb/trans2.c
+++ b/source4/smb_server/smb/trans2.c
@@ -33,6 +33,7 @@
#include "auth/session.h"
#include "param/param.h"
#include "lib/tsocket/tsocket.h"
+#include "dfs_server/dfs_server_ad.h"
#define MAX_DFS_RESPONSE 56*1024 /* 56 Kb */
@@ -63,13 +64,7 @@ struct trans_op {
NTSTATUS (*send_fn)(struct trans_op *);
void *op_info;
};
-/* A DC set is a group of DC, they might have been grouped together
- because they belong to the same site, or to site with same cost ...
-*/
-struct dc_set {
- const char **names;
- uint32_t count;
-};
+
#define CHECK_MIN_BLOB_SIZE(blob, size) do { \
if ((blob)->length < (size)) { \
return NT_STATUS_INFO_LENGTH_MISMATCH; \
@@ -858,456 +853,69 @@ static NTSTATUS trans2_findfirst_send(struct trans_op *op)
return NT_STATUS_OK;
}
-
-/*
- fill a referral type structure
- */
-static NTSTATUS fill_normal_dfs_referraltype(struct dfs_referral_type *ref,
- uint16_t version,
- const char *dfs_path,
- const char *server_path, int isfirstoffset)
-{
- ZERO_STRUCTP(ref);
- switch (version) {
- case 4:
- version = 3;
-# if 0
- /* For the moment there is a bug with XP that don't seems to appriciate much
- * level4 so we return just level 3 for everyone
- */
- ref->referral.v4.server_type = DFS_SERVER_NON_ROOT;
- /* "normal" referral seems to always include the GUID */
- ref->referral.v4.size = 34;
-
- if (isfirstoffset) {
- ref->referral.v4.entry_flags = DFS_HEADER_FLAG_TARGET_BCK;
- }
- ref->referral.v4.ttl = 900; /* As w2k8r2 */
- ref->referral.v4.referrals.r1.DFS_path = talloc_strdup(ref, dfs_path);
- ref->referral.v4.referrals.r1.DFS_alt_path = talloc_strdup(ref, dfs_path);
- ref->referral.v4.referrals.r1.netw_address = talloc_strdup(ref, server_path);
- return NT_STATUS_OK;
-#endif
- case 3:
- ref->version = version;
- ref->referral.v3.server_type = DFS_SERVER_NON_ROOT;
- /* "normal" referral seems to always include the GUID */
- ref->referral.v3.size = 34;
-
- ref->referral.v3.entry_flags = 0;
- ref->referral.v3.ttl = 600; /* As w2k3 */
- ref->referral.v3.referrals.r1.DFS_path = talloc_strdup(ref, dfs_path);
- ref->referral.v3.referrals.r1.DFS_alt_path = talloc_strdup(ref, dfs_path);
- ref->referral.v3.referrals.r1.netw_address = talloc_strdup(ref, server_path);
- return NT_STATUS_OK;
- }
- return NT_STATUS_INVALID_LEVEL;
-}
-
-/*
- fill a domain refererral
- */
-static NTSTATUS fill_domain_dfs_referraltype(struct dfs_referral_type *ref,
- uint16_t version,
- const char *domain,
- const char **names,
- uint16_t numnames)
-{
- switch (version) {
- case 3:
- ZERO_STRUCTP(ref);
- DEBUG(8, ("Called fill_domain_dfs_referraltype\n"));
- ref->version = version;
- ref->referral.v3.server_type = DFS_SERVER_NON_ROOT;
- /* It's hard coded ... don't think it's a good way but the sizeof return not the
- * correct values
- *
- * We have 18 if the GUID is not included 34 otherwise
- */
- if (numnames == 0) {
- /* Windows return without the guid when returning domain list
- */
- ref->referral.v3.size = 18;
- } else {
- ref->referral.v3.size = 34;
- }
- ref->referral.v3.entry_flags = DFS_FLAG_REFERRAL_DOMAIN_RESP;
- ref->referral.v3.ttl = 600; /* As w2k3 */
- ref->referral.v3.referrals.r2.special_name = domain;
- ref->referral.v3.referrals.r2.nb_expanded_names = numnames;
- /* Put the final terminator */
- if (names) {
- const char **names2 = talloc_array(ref, const char *, numnames+1);
- NT_STATUS_HAVE_NO_MEMORY(names2);
- int i;
- for (i = 0; i<numnames; i++) {
- names2[i] = talloc_asprintf(names2, "\\%s", names[i]);
- NT_STATUS_HAVE_NO_MEMORY(names2[i]);
- }
- names2[numnames] = NULL;
- ref->referral.v3.referrals.r2.expanded_names = names2;
- }
- return NT_STATUS_OK;
- }
- return NT_STATUS_INVALID_LEVEL;
-}
-
/*
- get the DCs list within a site
- */
-static NTSTATUS get_dcs_insite(TALLOC_CTX *ctx, struct ldb_context *ldb,
- struct ldb_dn *sitedn, struct dc_set *list,
- bool dofqdn)
-{
- static const char *attrs[] = { "serverReference", NULL };
- static const char *attrs2[] = { "dNSHostName", "sAMAccountName", NULL };
- struct ldb_result *r;
- unsigned int i;
- int ret;
- const char **dc_list;
-
- ret = ldb_search(ldb, ctx, &r, sitedn, LDB_SCOPE_SUBTREE, attrs,
- "(&(objectClass=server)(serverReference=*))");
- if (ret != LDB_SUCCESS) {
- DEBUG(2,(__location__ ": Failed to get list of servers - %s\n",
- ldb_errstring(ldb)));
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- if (r->count == 0) {
- /* none in this site */
- talloc_free(r);
- return NT_STATUS_OK;
- }
-
- /*
- * need to search for all server object to know the size of the array.
- * Search all the object of class server in this site
- */
- dc_list = talloc_array(r, const char *, r->count);
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(dc_list, r);
-
- /* TODO put some random here in the order */
- list->names = talloc_realloc(list, list->names, const char *, list->count + r->count);
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(list->names, r);
-
- for (i = 0; i<r->count; i++) {
- struct ldb_dn *dn;
- struct ldb_result *r2;
-
- dn = ldb_msg_find_attr_as_dn(ldb, ctx, r->msgs[i], "serverReference");
- if (!dn) {
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- ret = ldb_search(ldb, r, &r2, dn, LDB_SCOPE_BASE, attrs2, "(objectClass=computer)");
- if (ret != LDB_SUCCESS) {
- DEBUG(2,(__location__ ": Search for computer on %s failed - %s\n",
- ldb_dn_get_linearized(dn), ldb_errstring(ldb)));
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- if (dofqdn) {
- const char *dns = ldb_msg_find_attr_as_string(r2->msgs[0], "dNSHostName", NULL);
- if (dns == NULL) {
- DEBUG(2,(__location__ ": dNSHostName missing on %s\n",
- ldb_dn_get_linearized(dn)));
- talloc_free(r);
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- list->names[list->count] = talloc_strdup(list->names, dns);
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(list->names[list->count], r);
- } else {
- char *tmp;
- const char *acct = ldb_msg_find_attr_as_string(r2->msgs[0], "sAMAccountName", NULL);
- if (acct == NULL) {
- DEBUG(2,(__location__ ": sAMAccountName missing on %s\n",
- ldb_dn_get_linearized(dn)));
- talloc_free(r);
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- tmp = talloc_strdup(list->names, acct);
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(tmp, r);
-
- /* Netbios name is also the sAMAccountName for
- computer but without the final $ */
- tmp[strlen(tmp) - 1] = '\0';
- list->names[list->count] = tmp;
- }
- list->count++;
- talloc_free(r2);
- }
-
- talloc_free(r);
- return NT_STATUS_OK;
-}
-
-
-/*
- get all DCs
- */
-static NTSTATUS get_dcs(TALLOC_CTX *ctx, struct ldb_context *ldb,
- const char *searched_site, bool need_fqdn,
- struct dc_set ***pset_list, uint32_t flags)
+ trans2 getdfsreferral implementation
+*/
+static NTSTATUS trans2_getdfsreferral(struct smbsrv_request *req,
+ struct trans_op *op)
{
- /*
- * Flags will be used later to indicate things like least-expensive
- * or same-site options
- */
- const char *attrs_none[] = { NULL };
- const char *attrs3[] = { "name", NULL };
- struct ldb_dn *configdn, *sitedn, *dn, *sitescontainerdn;
- struct ldb_result *r;
- struct dc_set **set_list = NULL;
- uint32_t i;
- int ret;
- uint32_t current_pos = 0;
+ enum ndr_err_code ndr_err;
+ struct smb_trans2 *trans = op->trans;
+ struct ldb_context *ldb;
+ struct loadparm_context *lp_ctx;
NTSTATUS status;
- TALLOC_CTX *subctx = talloc_new(ctx);
-
- *pset_list = set_list = NULL;
-
- subctx = talloc_new(ctx);
- NT_STATUS_HAVE_NO_MEMORY(subctx);
-
- configdn = ldb_get_config_basedn(ldb);
+ struct dfs_GetDFSReferral *r;
+ DATA_BLOB outblob = data_blob_null;
+ uint16_t nb_referrals = 0;
- /* Let's search for the Site container */
- ret = ldb_search(ldb, subctx, &r, configdn, LDB_SCOPE_SUBTREE, attrs_none,
- "(objectClass=sitesContainer)");
- if (ret != LDB_SUCCESS) {
- DEBUG(2,(__location__ ": Failed to find sitesContainer within %s - %s\n",
- ldb_dn_get_linearized(configdn), ldb_errstring(ldb)));
- talloc_free(subctx);
- return NT_STATUS_INTERNAL_ERROR;
- }
- if (r->count > 1) {
- DEBUG(2,(__location__ ": Expected 1 sitesContainer - found %u within %s\n",
- r->count, ldb_dn_get_linearized(configdn)));
- talloc_free(subctx);
- return NT_STATUS_INTERNAL_ERROR;
+ lp_ctx = req->tcon->ntvfs->lp_ctx;
+ if (!lpcfg_host_msdfs(lp_ctx)) {
+ return NT_STATUS_NOT_IMPLEMENTED;
}
- sitescontainerdn = talloc_steal(subctx, r->msgs[0]->dn);
- talloc_free(r);
+ r = talloc_zero(req, struct dfs_GetDFSReferral);
+ NT_STATUS_HAVE_NO_MEMORY(r);
- /*
- * TODO: Here we should have a more subtle handling
- * for the case "same-site"
- */
- ret = ldb_search(ldb, subctx, &r, sitescontainerdn, LDB_SCOPE_SUBTREE,
- attrs_none, "(objectClass=server)");
- if (ret != LDB_SUCCESS) {
- DEBUG(2,(__location__ ": Failed to find servers within %s - %s\n",
- ldb_dn_get_linearized(sitescontainerdn), ldb_errstring(ldb)));
- talloc_free(subctx);
+ ldb = samdb_connect(r, req->tcon->ntvfs->event_ctx, lp_ctx, system_session(lp_ctx), 0);
+ if (ldb == NULL) {
+ DEBUG(2,(__location__ ": Failed to open samdb\n"));
+ talloc_free(r);
return NT_STATUS_INTERNAL_ERROR;
}
- talloc_free(r);
-
- if (searched_site != NULL && searched_site[0] != '\0') {
- ret = ldb_search(ldb, subctx, &r, configdn, LDB_SCOPE_SUBTREE,
- attrs_none, "(&(name=%s)(objectClass=site))", searched_site);
- if (ret != LDB_SUCCESS) {
- talloc_free(subctx);
- return NT_STATUS_FOOBAR;
- } else if (r->count != 1) {
- talloc_free(subctx);
- return NT_STATUS_FOOBAR;
- }
- /* All of this was to get the DN of the searched_site */
- sitedn = r->msgs[0]->dn;
-
- set_list = talloc_realloc(subctx, set_list, struct dc_set *, current_pos+1);
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list, subctx);
-
- set_list[current_pos] = talloc(set_list, struct dc_set);
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list[current_pos], subctx);
-
- set_list[current_pos]->names = NULL;
- set_list[current_pos]->count = 0;
- status = get_dcs_insite(subctx, ldb, sitedn,
- set_list[current_pos], need_fqdn);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(2,(__location__ ": Failed to get DC from site %s - %s\n",
- ldb_dn_get_linearized(sitedn), nt_errstr(status)));
- talloc_free(subctx);
- return status;
- }
+ ndr_err = ndr_pull_struct_blob(&trans->in.params, r,
+ &r->in.req,
+ (ndr_pull_flags_fn_t)ndr_pull_dfs_GetDFSReferral_in);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ DEBUG(2,(__location__ ": Failed to parse GetDFSReferral_in - %s\n",
+ nt_errstr(status)));
talloc_free(r);
- current_pos++;
- }
-
- /* Let's find all the sites */
- ret = ldb_search(ldb, subctx, &r, configdn, LDB_SCOPE_SUBTREE, attrs3, "(objectClass=site)");
- if (ret != LDB_SUCCESS) {
- DEBUG(2,(__location__ ": Failed to find any site containers in %s\n",
- ldb_dn_get_linearized(configdn)));
- talloc_free(subctx);
- return NT_STATUS_INTERNAL_DB_CORRUPTION;
- }
-
- /*
- * TODO:
- * We should randomize the order in the main site,
- * it's mostly needed for sysvol/netlogon referral.
- * Depending of flag we either randomize order of the
- * not "in the same site DCs"
- * or we randomize by group of site that have the same cost
- * In the long run we want to manipulate an array of site_set
- * All the site in one set have the same cost (if least-expansive options is selected)
- * and we will put all the dc related to 1 site set into 1 DCs set.
- * Within a site set, site order has to be randomized
- *
- * But for the moment we just return the list of sites
- */
- if (r->count) {
- /*
- * We will realloc + 2 because we will need one additional place
- * for element at current_pos + 1 for the NULL element
- */
- set_list = talloc_realloc(subctx, set_list, struct dc_set *,
- current_pos+2);
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list, subctx);
-
- set_list[current_pos] = talloc(ctx, struct dc_set);
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(set_list[current_pos], subctx);
-
- set_list[current_pos]->names = NULL;
- set_list[current_pos]->count = 0;
-
- set_list[current_pos+1] = NULL;
- }
-
- for (i=0; i<r->count; i++) {
- const char *site_name = ldb_msg_find_attr_as_string(r->msgs[i], "name", NULL);
- if (site_name == NULL) {
- DEBUG(2,(__location__ ": Failed to find name attribute in %s\n",
- ldb_dn_get_linearized(r->msgs[i]->dn)));
- talloc_free(subctx);
- return NT_STATUS_INTERNAL_DB_CORRUPTION;
- }
-
- if (searched_site == NULL ||
- strcmp(searched_site, site_name) != 0) {
- DEBUG(2,(__location__ ": Site: %s %s\n",
- searched_site, site_name));
-
- /*
- * Do all the site but the one of the client
- * (because it has already been done ...)
- */
- dn = r->msgs[i]->dn;
-
- status = get_dcs_insite(subctx, ldb, dn,
- set_list[current_pos],
- need_fqdn);
- if (!NT_STATUS_IS_OK(status)) {
- talloc_free(subctx);
- return status;
- }
- }
- }
- current_pos++;
- set_list[current_pos] = NULL;
-
- *pset_list = talloc_move(ctx, &set_list);
- talloc_free(subctx);
- return NT_STATUS_OK;
-}
-
-static NTSTATUS dodomain_referral(TALLOC_CTX *ctx,
- const struct dfs_GetDFSReferral_in *dfsreq,
- struct ldb_context *ldb,
- struct smb_trans2 *trans,
- struct loadparm_context *lp_ctx)
-{
- /*
- * TODO for the moment we just return the local domain
- */
- DATA_BLOB outblob;
- enum ndr_err_code ndr_err;
- NTSTATUS status;
- const char *dns_domain = lpcfg_dnsdomain(lp_ctx);
- const char *netbios_domain = lpcfg_workgroup(lp_ctx);
- struct dfs_referral_resp resp;
- struct dfs_referral_type *tab;
- struct dfs_referral_type *referral;
- const char *referral_str;
- /* In the future this needs to be fetched from the ldb */
- uint32_t found_domain = 2;
- uint32_t current_pos = 0;
- TALLOC_CTX *context;
-
- if (lpcfg_server_role(lp_ctx) != ROLE_DOMAIN_CONTROLLER) {
- DEBUG(10 ,("Received a domain referral request on a non DC\n"));
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- if (dfsreq->max_referral_level < 3) {
- DEBUG(2,("invalid max_referral_level %u\n",
- dfsreq->max_referral_level));
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- context = talloc_new(ctx);
- NT_STATUS_HAVE_NO_MEMORY(context);
-
- resp.path_consumed = 0;
- resp.header_flags = 0; /* Do like w2k3 */
- resp.nb_referrals = found_domain; /* the fqdn one + the NT domain */
-
- tab = talloc_array(context, struct dfs_referral_type, found_domain);
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(tab, context);
-
- referral = talloc(tab, struct dfs_referral_type);
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral, context);
- referral_str = talloc_asprintf(referral, "\\%s", netbios_domain);
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str, context);
- status = fill_domain_dfs_referraltype(referral, 3,
- referral_str,
- NULL, 0);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(2,(__location__ ":Unable to fill domain referral structure\n"));
- talloc_free(context);
- return NT_STATUS_UNSUCCESSFUL;
+ return status;
}
- tab[current_pos] = *referral;
- current_pos++;
+ DEBUG(8, ("Requested DFS name: %s length: %u\n",
+ r->in.req.servername,
+ (unsigned int)strlen_m(r->in.req.servername)*2));
- referral = talloc(tab, struct dfs_referral_type);
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral, context);
- referral_str = talloc_asprintf(referral, "\\%s", dns_domain);
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str, context);
- status = fill_domain_dfs_referraltype(referral, 3,
- referral_str,
- NULL, 0);
+ status = dfs_server_ad_get_referrals(lp_ctx, ldb,
+ req->smb_conn->connection->remote_address, r);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(2,(__location__ ":Unable to fill domain referral structure\n"));
- talloc_free(context);
- return NT_STATUS_UNSUCCESSFUL;
+ talloc_free(r);
+ return status;
}
- tab[current_pos] = *referral;
- current_pos++;
- /*
- * Put here the code from filling the array for trusted domain
- */
- resp.referral_entries = tab;
-
- ndr_err = ndr_push_struct_blob(&outblob, context,
- &resp,
+ ndr_err = ndr_push_struct_blob(&outblob, trans,
+ r->out.resp,
(ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
DEBUG(2,(__location__ ":NDR marchalling of domain deferral response failed\n"));
- talloc_free(context);
+ talloc_free(r);
return NT_STATUS_INTERNAL_ERROR;
}
+ nb_referrals = r->out.resp->nb_referrals;
+
if (outblob.length > trans->in.max_data) {
bool ok = false;
@@ -1317,43 +925,42 @@ static NTSTATUS dodomain_referral(TALLOC_CTX *ctx,
if (trans->in.max_data != MAX_DFS_RESPONSE) {
/* As specified in MS-DFSC.pdf 3.3.5.2 */
- talloc_free(context);
+ talloc_free(r);
return STATUS_BUFFER_OVERFLOW;
}
/*
* The answer is too big, so let's remove some answers
*/
- while (!ok && resp.nb_referrals > 2) {
+ while (!ok && r->out.resp->nb_referrals > 2) {
data_blob_free(&outblob);
/*
- * Let's scrap the first referral (for now)
+ * Let's scrap the last referral (for now)
*/
- resp.nb_referrals -= 1;
- resp.referral_entries += 1;
+ r->out.resp->nb_referrals -= 1;
- ndr_err = ndr_push_struct_blob(&outblob, context,
- &resp,
+ ndr_err = ndr_push_struct_blob(&outblob, trans,
+ r->out.resp,
(ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- talloc_free(context);
+ talloc_free(r);
return NT_STATUS_INTERNAL_ERROR;
}
if (outblob.length <= MAX_DFS_RESPONSE) {
DEBUG(10,("DFS: managed to reduce the size of referral initial"
"number of referral %d, actual count: %d",
- found_domain, resp.nb_referrals));
+ nb_referrals, r->out.resp->nb_referrals));
ok = true;
break;
}
}
- if (!ok && resp.nb_referrals == 2) {
+ if (!ok && r->out.resp->nb_referrals <= 2) {
DEBUG(8, (__location__ "; Not able to fit the domain and realm in DFS a "
" 56K buffer, something must be broken"));
- talloc_free(context);
+ talloc_free(r);
return NT_STATUS_INTERNAL_ERROR;
}
}
@@ -1361,377 +968,11 @@ static NTSTATUS dodomain_referral(TALLOC_CTX *ctx,
TRANS2_CHECK(trans2_setup_reply(trans, 0, outblob.length, 0));
trans->out.data = outblob;
- talloc_steal(ctx, outblob.data);
- talloc_free(context);
- return NT_STATUS_OK;
-}
-
-/*
- * Handle the logic for dfs referral request like \\domain
- * or \\domain\sysvol or \\fqdn or \\fqdn\netlogon
- */
-static NTSTATUS dodc_or_sysvol_referral(TALLOC_CTX *ctx,
- const struct dfs_GetDFSReferral_in dfsreq,
- const char* requesteddomain,
- const char* requestedshare,
- const char* requestedname,
- struct ldb_context *ldb,
- struct smb_trans2 *trans,
- struct smbsrv_request *req,
- struct loadparm_context *lp_ctx)
-{
- /*
- * It's not a "standard" DFS referral but a referral to get the DC list
- * or sysvol/netlogon
- * Let's check that it's for one of our domain ...
- */
- DATA_BLOB outblob;
- NTSTATUS status;
- unsigned int num_domain = 1;
- enum ndr_err_code ndr_err;
- const char *realm = lpcfg_realm(lp_ctx);
- const char *domain = lpcfg_workgroup(lp_ctx);
- const char *site_name = NULL; /* Name of the site where the client is */
- bool found = false;
- bool need_fqdn = false;
- bool dc_referral = true;
- unsigned int i;
- struct dc_set **set;
- char const **domain_list;
- struct tsocket_address *remote_address;
- char *client_addr = NULL;
- TALLOC_CTX *context;
-
- if (lpcfg_server_role(lp_ctx) != ROLE_DOMAIN_CONTROLLER) {
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- if (dfsreq.max_referral_level < 3) {
- DEBUG(2,("invalid max_referral_level %u\n",
- dfsreq.max_referral_level));
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- context = talloc_new(ctx);
- NT_STATUS_HAVE_NO_MEMORY(context);
-
- DEBUG(10, ("in this we have request for %s and share %s requested is %s\n",
- requesteddomain,
- requestedshare,
- requestedname));
-
- if (requestedshare) {
- DEBUG(10, ("Have a non DC domain referal\n"));
- dc_referral = false;
- }
-
- /*
- * We will fetch the trusted domain list soon with something like this:
- *
- * "(&(|(flatname=%s)(cn=%s)(trustPartner=%s)(flatname=%s)(cn=%s)
- * (trustPartner=%s))(objectclass=trustedDomain))"
- *
- * Allocate for num_domain + 1 so that the last element will be NULL)
- */
- domain_list = talloc_array(context, const char*, num_domain+1);
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(domain_list, context);
-
- domain_list[0] = realm;
- domain_list[1] = domain;
- for (i=0; i<=num_domain; i++) {
- if (strncasecmp(domain_list[i], requesteddomain, strlen(domain_list[i])) == 0) {
- found = true;
- break;
- }
- }
-
- if (!found) {
- /* The requested domain is not one that we support */
- DEBUG(3,("Requested referral for domain %s, but we don't handle it",
- requesteddomain));
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- if (strchr(requestedname,'.')) {
- need_fqdn = 1;
- }
-
- remote_address = req->smb_conn->connection->remote_address;
- if (tsocket_address_is_inet(remote_address, "ip")) {
- client_addr = tsocket_address_inet_addr_string(remote_address, context);
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(client_addr, context);
- }
- site_name = samdb_client_site_name(ldb, context, client_addr, NULL);
- status = get_dcs(context, ldb, site_name, need_fqdn, &set, 0);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(3,("Unable to get list of DCs\n"));
- talloc_free(context);
- return status;
- }
-
- if (dc_referral) {
- const char **dc_list = NULL;
- uint32_t num_dcs = 0;
- struct dfs_referral_type *referral;
- const char *referral_str;
- struct dfs_referral_resp resp;
-
- for(i=0; set[i]; i++) {
- uint32_t j;
-
- dc_list = talloc_realloc(context, dc_list, const char*,
- num_dcs + set[i]->count + 1);
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(dc_list, context);
-
- for(j=0; j<set[i]->count; j++) {
- dc_list[num_dcs + j] = talloc_steal(context, set[i]->names[j]);
- }
- num_dcs = num_dcs + set[i]->count;
- TALLOC_FREE(set[i]);
- dc_list[num_dcs] = NULL;
- }
-
- resp.path_consumed = 0;
- resp.header_flags = 0; /* Do like w2k3 and like in 3.3.5.3 of MS-DFSC*/
-
- /*
- * The NumberOfReferrals field MUST be set to 1,
- * independent of the number of DC names
- * returned. (as stated in 3.3.5.3 of MS-DFSC)
- */
- resp.nb_referrals = 1;
-
- /* Put here the code from filling the array for trusted domain */
- referral = talloc(context, struct dfs_referral_type);
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral, context);
-
- if (requestedname[0] == '\\') {
- referral_str = talloc_asprintf(referral, "%s",
- requestedname);
- } else {
- referral_str = talloc_asprintf(referral, "\\%s",
- requestedname);
- }
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str, context);
-
- status = fill_domain_dfs_referraltype(referral, 3,
- referral_str,
- dc_list, num_dcs);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(2,(__location__ ":Unable to fill domain referral structure\n"));
- talloc_free(context);
- return NT_STATUS_UNSUCCESSFUL;
- }
- resp.referral_entries = referral;
-
- ndr_err = ndr_push_struct_blob(&outblob, context,
- &resp,
- (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- DEBUG(2,(__location__ ":NDR marshalling of dfs referral response failed\n"));
- talloc_free(context);
- return NT_STATUS_INTERNAL_ERROR;
- }
- } else {
- unsigned int nb_entries = 0;
- unsigned int current = 0;
- struct dfs_referral_type *tab;
- struct dfs_referral_resp resp;
-
- for(i=0; set[i]; i++) {
- nb_entries = nb_entries + set[i]->count;
- }
-
- resp.path_consumed = 2*strlen(requestedname); /* The length is expected in bytes */
- resp.header_flags = DFS_HEADER_FLAG_STORAGE_SVR; /* Do like w2k3 and like in 3.3.5.3 of MS-DFSC*/
-
- /*
- * The NumberOfReferrals field MUST be set to 1,
- * independent of the number of DC names
- * returned. (as stated in 3.3.5.3 of MS-DFSC)
- */
- resp.nb_referrals = nb_entries;
-
- tab = talloc_array(context, struct dfs_referral_type, nb_entries);
- NT_STATUS_HAVE_NO_MEMORY(tab);
-
- for(i=0; set[i]; i++) {
- uint32_t j;
-
- for(j=0; j< set[i]->count; j++) {
- struct dfs_referral_type *referral;
- const char *referral_str;
-
- referral = talloc(tab, struct dfs_referral_type);
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral, context);
-
- referral_str = talloc_asprintf(referral, "\\%s\\%s",
- set[i]->names[j], requestedshare);
- DEBUG(8, ("Doing a dfs referral for %s with this value %s requested %s\n", set[i]->names[j], referral_str, requestedname));
- NT_STATUS_HAVE_NO_MEMORY_AND_FREE(referral_str, context);
-
- status = fill_normal_dfs_referraltype(referral,
- dfsreq.max_referral_level,
- requestedname, referral_str, j==0);
-
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(2, (__location__ ": Unable to fill a normal dfs referral object"));
- talloc_free(context);
- return NT_STATUS_UNSUCCESSFUL;
- }
- tab[current] = *referral;
- current++;
- }
- }
- resp.referral_entries = tab;
-
- ndr_err = ndr_push_struct_blob(&outblob, context,
- &resp,
- (ndr_push_flags_fn_t)ndr_push_dfs_referral_resp);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- DEBUG(2,(__location__ ":NDR marchalling of domain deferral response failed\n"));
- talloc_free(context);
- return NT_STATUS_INTERNAL_ERROR;
- }
- }
-
- TRANS2_CHECK(trans2_setup_reply(trans, 0, outblob.length, 0));
-
- /*
- * TODO If the size is too big we should remove
- * some DC from the answer or return STATUS_BUFFER_OVERFLOW
- */
- trans->out.data = outblob;
- talloc_steal(ctx, outblob.data);
- talloc_free(context);
+ talloc_free(r);
return NT_STATUS_OK;
}
/*
- trans2 getdfsreferral implementation
-*/
-static NTSTATUS trans2_getdfsreferral(struct smbsrv_request *req,
- struct trans_op *op)
-{
- enum ndr_err_code ndr_err;
- struct smb_trans2 *trans = op->trans;
- struct dfs_GetDFSReferral_in dfsreq;
- TALLOC_CTX *context;
- struct ldb_context *ldb;
- struct loadparm_context *lp_ctx;
- const char *realm, *nbname, *requestedname;
- char *fqdn, *share, *domain, *tmp;
- NTSTATUS status;
-
- lp_ctx = req->tcon->ntvfs->lp_ctx;
- if (!lpcfg_host_msdfs(lp_ctx)) {
- return NT_STATUS_NOT_IMPLEMENTED;
- }
-
- context = talloc_new(req);
- NT_STATUS_HAVE_NO_MEMORY(context);
-
- ldb = samdb_connect(context, req->tcon->ntvfs->event_ctx, lp_ctx, system_session(lp_ctx), 0);
- if (ldb == NULL) {
- DEBUG(2,(__location__ ": Failed to open samdb\n"));
- talloc_free(context);
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- ndr_err = ndr_pull_struct_blob(&trans->in.params, op,
- &dfsreq,
- (ndr_pull_flags_fn_t)ndr_pull_dfs_GetDFSReferral_in);
- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
- status = ndr_map_error2ntstatus(ndr_err);
- DEBUG(2,(__location__ ": Failed to parse GetDFSReferral_in - %s\n",
- nt_errstr(status)));
- talloc_free(context);
- return status;
- }
-
- DEBUG(8, ("Requested DFS name: %s length: %u\n",
- dfsreq.servername, (unsigned int)strlen(dfsreq.servername)));
-
- /*
- * If the servername is "" then we are in a case of domain dfs
- * and the client just searches for the list of local domain
- * it is attached and also trusted ones.
- */
- requestedname = dfsreq.servername;
- if (requestedname == NULL || requestedname[0] == '\0') {
- return dodomain_referral(op, &dfsreq, ldb, trans, lp_ctx);
- }
-
- realm = lpcfg_realm(lp_ctx);
- nbname = lpcfg_netbios_name(lp_ctx);
- fqdn = talloc_asprintf(context, "%s.%s", nbname, realm);
-
- if ((strncasecmp(requestedname+1, nbname, strlen(nbname)) == 0) ||
- (strncasecmp(requestedname+1, fqdn, strlen(fqdn)) == 0) ) {
- /*
- * the referral request starts with \NETBIOSNAME or \fqdn
- * it's a standalone referral we do not do it
- * (TODO correct this)
- * If a DFS link that is a complete prefix of the DFS referral
- * request path is identified, the server MUST return a DFS link
- * referral response; otherwise, if it has a match for the DFS root,
- * it MUST return a root referral response.
- */
- DEBUG(3, ("Received a standalone request for %s, we do not support standalone referral yet",requestedname));
- talloc_free(context);
- return NT_STATUS_NOT_FOUND;
- }
- talloc_free(fqdn);
-
- domain = talloc_strdup(context, requestedname);
- while(*domain && *domain == '\\') {
- domain++;
- }
-
- tmp = strchr(domain,'\\'); /* To get second \ if any */
- share = NULL;
- if (tmp) {
- /*
- * We are finishing properly the domain string
- * and the share one will start after the \
- */
- tmp[0] = '\\';
- tmp++;
- share = talloc_strdup(context, tmp);
- }
- /*
- * Here we have filtered the thing the requested name don't contain our DNS name.
- * So if the share == NULL or if share in ("sysvol", "netlogon")
- * then we proceed. In the first case it will be a dc refereal in the second it will
- * be just a sysvol/netlogon referral.
- */
- if (share == NULL ||
- strcasecmp(share, "sysvol") == 0 ||
- strcasecmp(share, "netlogon") == 0) {
- status = dodc_or_sysvol_referral(op, dfsreq, domain, share, requestedname,
- ldb, trans, req, lp_ctx);
- talloc_free(context);
- return status;
- }
-
- tmp = strchr(share, '\\');
- if (tmp &&
- (strncasecmp(share, "sysvol", 6) == 0 ||
- strncasecmp(share, "netlogon", 8) == 0)) {
- /*
- * We have more than two \ so it something like
- * \domain\sysvol\foobar
- */
- talloc_free(context);
- return NT_STATUS_NOT_FOUND;
- }
-
- talloc_free(context);
- /* By default until all the case are handled*/
- return NT_STATUS_NOT_FOUND;
-}
-
-/*
trans2 findfirst implementation
*/
static NTSTATUS trans2_findfirst(struct smbsrv_request *req, struct trans_op *op)
diff --git a/source4/smb_server/smb/wscript_build b/source4/smb_server/smb/wscript_build
index 4004bac2d3..5c717a3601 100644
--- a/source4/smb_server/smb/wscript_build
+++ b/source4/smb_server/smb/wscript_build
@@ -3,6 +3,7 @@
bld.SAMBA_SUBSYSTEM('SMB_PROTOCOL',
source='receive.c negprot.c nttrans.c reply.c request.c search.c service.c sesssetup.c srvtime.c trans2.c signing.c',
autoproto='smb_proto.h',
+ deps='dfs_server_ad',
public_deps='ntvfs LIBPACKET samba-credentials samba_server_gensec'
)