bool torture_ldap_sort(struct torture_context *torture) { struct ldb_context *ldb; bool ret = false; const char *host = torture_setting_string(torture, "host", NULL); char *url; int i; codepoint_t j; struct ldb_message_element *elem; struct ldb_message *msg; struct ldb_server_sort_control **control; struct ldb_request *req; struct ldb_result *ctx; struct ldb_val *prev = NULL; const char *prev_txt = NULL; int prev_len = 0; struct ldb_val *cur = NULL; const char *cur_txt = NULL; int cur_len = 0; struct ldb_dn *dn; /* TALLOC_CTX* ctx;*/ url = talloc_asprintf(torture, "ldap://%s/", host); ldb = ldb_wrap_connect(torture, torture->ev, torture->lp_ctx, url, NULL, popt_get_cmdline_credentials(), 0); torture_assert(torture, ldb, "Failed to make LDB connection to target"); ctx = talloc_zero(ldb, struct ldb_result); control = talloc_array(ctx, struct ldb_server_sort_control *, 2); control[0] = talloc(control, struct ldb_server_sort_control); control[0]->attributeName = talloc_strdup(control, "cn"); control[0]->orderingRule = NULL; control[0]->reverse = 0; control[1] = NULL; dn = ldb_get_default_basedn(ldb); ldb_dn_add_child_fmt(dn, "cn=users"); ret = ldb_build_search_req(&req, ldb, ctx, dn, LDB_SCOPE_SUBTREE, "(objectClass=*)", NULL, NULL, ctx, ldb_search_default_callback, NULL); torture_assert(torture, ret == LDB_SUCCESS, "Failed to build search request"); ret = ldb_request_add_control(req, LDB_CONTROL_SERVER_SORT_OID, true, control); torture_assert(torture, ret == LDB_SUCCESS, "Failed to add control to search request"); ret = ldb_request(ldb, req); torture_assert(torture, ret == LDB_SUCCESS, ldb_errstring(ldb)); ret = ldb_wait(req->handle, LDB_WAIT_ALL); torture_assert(torture, ret == LDB_SUCCESS, ldb_errstring(ldb)); ret = true; if (ctx->count > 1) { for (i=0;i<ctx->count;i++) { msg = ctx->msgs[i]; elem = ldb_msg_find_element(msg,"cn"); torture_assert_not_null(torture, elem, "msg lacks CN"); cur = elem->values; torture_comment(torture, "cn: %s\n",cur->data); if (prev != NULL) { /* Do only the ascii case right now ... */ cur_txt = (const char *) cur->data; cur_len = cur->length; prev_txt = (const char *) prev->data; prev_len = prev->length; /* Remove leading whitespace as the sort function do so ... */ while ( cur_txt[0] == cur_txt[1] ) { cur_txt++; cur_len--;} while ( prev_txt[0] == prev_txt[1] ) { prev_txt++; prev_len--;} while( *(cur_txt) && *(prev_txt) && cur_len && prev_len ) { j = toupper_m(*(prev_txt))-toupper_m(*(cur_txt)); if ( j > 0 ) { /* Just check that is not due to trailling white space in prev_txt * That is to say *cur_txt = 0 and prev_txt = 20 */ /* Remove trailling whitespace */ while ( *prev_txt == ' ' ) { prev_txt++; prev_len--;} while ( *cur_txt == ' ' ) { cur_txt++; cur_len--;} /* Now that potential whitespace are removed if we are at the end * of the cur_txt then it means that in fact strings were identical */ torture_assert(torture, *cur_txt && *prev_txt, "Data wrongly sorted"); break; } else { if ( j == 0 ) { if ( *(cur_txt) == ' ') { while ( cur_txt[0] == cur_txt[1] ) { cur_txt++; cur_len--;} while ( prev_txt[0] == prev_txt[1] ) { prev_txt++; prev_len--;} } cur_txt++; prev_txt++; prev_len--; cur_len--; } else { break; } } } if ( ret != 1 ) { break; } } prev = cur; } } return ret; }
static WERROR DsCrackNameOneFilter(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct smb_krb5_context *smb_krb5_context, uint32_t format_flags, enum drsuapi_DsNameFormat format_offered, enum drsuapi_DsNameFormat format_desired, struct ldb_dn *name_dn, const char *name, const char *domain_filter, const char *result_filter, struct drsuapi_DsNameInfo1 *info1, int scope, struct ldb_dn *search_dn) { int ldb_ret; struct ldb_result *domain_res = NULL; const char * const *domain_attrs; const char * const *result_attrs; struct ldb_message **result_res = NULL; struct ldb_message *result = NULL; int i; char *p; struct ldb_dn *partitions_basedn = samdb_partitions_dn(sam_ctx, mem_ctx); const char * const _domain_attrs_1779[] = { "ncName", "dnsRoot", NULL}; const char * const _result_attrs_null[] = { NULL }; const char * const _domain_attrs_canonical[] = { "ncName", "dnsRoot", NULL}; const char * const _result_attrs_canonical[] = { "canonicalName", NULL }; const char * const _domain_attrs_nt4[] = { "ncName", "dnsRoot", "nETBIOSName", NULL}; const char * const _result_attrs_nt4[] = { "sAMAccountName", "objectSid", "objectClass", NULL}; const char * const _domain_attrs_guid[] = { "ncName", "dnsRoot", NULL}; const char * const _result_attrs_guid[] = { "objectGUID", NULL}; const char * const _domain_attrs_display[] = { "ncName", "dnsRoot", NULL}; const char * const _result_attrs_display[] = { "displayName", "samAccountName", NULL}; const char * const _domain_attrs_none[] = { "ncName", "dnsRoot" , NULL}; const char * const _result_attrs_none[] = { NULL}; /* here we need to set the attrs lists for domain and result lookups */ switch (format_desired) { case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX: domain_attrs = _domain_attrs_1779; result_attrs = _result_attrs_null; break; case DRSUAPI_DS_NAME_FORMAT_CANONICAL: domain_attrs = _domain_attrs_canonical; result_attrs = _result_attrs_canonical; break; case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: domain_attrs = _domain_attrs_nt4; result_attrs = _result_attrs_nt4; break; case DRSUAPI_DS_NAME_FORMAT_GUID: domain_attrs = _domain_attrs_guid; result_attrs = _result_attrs_guid; break; case DRSUAPI_DS_NAME_FORMAT_DISPLAY: domain_attrs = _domain_attrs_display; result_attrs = _result_attrs_display; break; default: domain_attrs = _domain_attrs_none; result_attrs = _result_attrs_none; break; } if (domain_filter) { /* if we have a domain_filter look it up and set the result_basedn and the dns_domain_name */ ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res, partitions_basedn, LDB_SCOPE_ONELEVEL, domain_attrs, "%s", domain_filter); if (ldb_ret != LDB_SUCCESS) { DEBUG(2, ("DsCrackNameOneFilter domain ref search failed: %s\n", ldb_errstring(sam_ctx))); info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR; return WERR_OK; } switch (domain_res->count) { case 1: break; case 0: info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; return WERR_OK; default: info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE; return WERR_OK; } info1->dns_domain_name = ldb_msg_find_attr_as_string(domain_res->msgs[0], "dnsRoot", NULL); W_ERROR_HAVE_NO_MEMORY(info1->dns_domain_name); info1->status = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY; } else { info1->dns_domain_name = NULL; info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR; } if (result_filter) { int ret; struct ldb_result *res; uint32_t dsdb_flags = 0; struct ldb_dn *real_search_dn = NULL; info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; /* * From 4.1.4.2.11 of MS-DRSR * if DS_NAME_FLAG_GCVERIFY in flags then * rt := select all O from all * where attrValue in GetAttrVals(O, att, false) * else * rt := select all O from subtree DefaultNC() * where attrValue in GetAttrVals(O, att, false) * endif * return rt */ if (format_flags & DRSUAPI_DS_NAME_FLAG_GCVERIFY || format_offered == DRSUAPI_DS_NAME_FORMAT_GUID) { dsdb_flags = DSDB_SEARCH_SEARCH_ALL_PARTITIONS; } else if (domain_res) { if (!search_dn) { struct ldb_dn *tmp_dn = samdb_result_dn(sam_ctx, mem_ctx, domain_res->msgs[0], "ncName", NULL); real_search_dn = tmp_dn; } else { real_search_dn = search_dn; } } else { real_search_dn = ldb_get_default_basedn(sam_ctx); } if (format_desired == DRSUAPI_DS_NAME_FORMAT_GUID){ dsdb_flags |= DSDB_SEARCH_SHOW_RECYCLED; } /* search with the 'phantom root' flag */ ret = dsdb_search(sam_ctx, mem_ctx, &res, real_search_dn, scope, result_attrs, dsdb_flags, "%s", result_filter); if (ret != LDB_SUCCESS) { DEBUG(2, ("DsCrackNameOneFilter search from '%s' with flags 0x%08x failed: %s\n", ldb_dn_get_linearized(real_search_dn), dsdb_flags, ldb_errstring(sam_ctx))); info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR; return WERR_OK; } ldb_ret = res->count; result_res = res->msgs; } else if (format_offered == DRSUAPI_DS_NAME_FORMAT_FQDN_1779) { ldb_ret = gendb_search_dn(sam_ctx, mem_ctx, name_dn, &result_res, result_attrs); } else if (domain_res) { name_dn = samdb_result_dn(sam_ctx, mem_ctx, domain_res->msgs[0], "ncName", NULL); ldb_ret = gendb_search_dn(sam_ctx, mem_ctx, name_dn, &result_res, result_attrs); } else { /* Can't happen */ DEBUG(0, ("LOGIC ERROR: DsCrackNameOneFilter domain ref search not available: This can't happen...\n")); info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR; return WERR_OK; } switch (ldb_ret) { case 1: result = result_res[0]; break; case 0: switch (format_offered) { case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: return DsCrackNameSPNAlias(sam_ctx, mem_ctx, smb_krb5_context, format_flags, format_offered, format_desired, name, info1); case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL: return DsCrackNameUPN(sam_ctx, mem_ctx, smb_krb5_context, format_flags, format_offered, format_desired, name, info1); default: break; } info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; return WERR_OK; case -1: DEBUG(2, ("DsCrackNameOneFilter result search failed: %s\n", ldb_errstring(sam_ctx))); info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR; return WERR_OK; default: switch (format_offered) { case DRSUAPI_DS_NAME_FORMAT_CANONICAL: case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX: { const char *canonical_name = NULL; /* Not required, but we get warnings... */ /* We may need to manually filter further */ for (i = 0; i < ldb_ret; i++) { switch (format_offered) { case DRSUAPI_DS_NAME_FORMAT_CANONICAL: canonical_name = ldb_dn_canonical_string(mem_ctx, result_res[i]->dn); break; case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX: canonical_name = ldb_dn_canonical_ex_string(mem_ctx, result_res[i]->dn); break; default: break; } if (strcasecmp_m(canonical_name, name) == 0) { result = result_res[i]; break; } } if (!result) { info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; return WERR_OK; } } /* FALL TROUGH */ default: info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE; return WERR_OK; } } info1->dns_domain_name = ldb_dn_canonical_string(mem_ctx, result->dn); W_ERROR_HAVE_NO_MEMORY(info1->dns_domain_name); p = strchr(info1->dns_domain_name, '/'); if (p) { p[0] = '\0'; } /* here we can use result and domain_res[0] */ switch (format_desired) { case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: { info1->result_name = ldb_dn_alloc_linearized(mem_ctx, result->dn); W_ERROR_HAVE_NO_MEMORY(info1->result_name); info1->status = DRSUAPI_DS_NAME_STATUS_OK; return WERR_OK; } case DRSUAPI_DS_NAME_FORMAT_CANONICAL: { info1->result_name = ldb_msg_find_attr_as_string(result, "canonicalName", NULL); info1->status = DRSUAPI_DS_NAME_STATUS_OK; return WERR_OK; } case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX: { /* Not in the virtual ldb attribute */ return DsCrackNameOneSyntactical(mem_ctx, DRSUAPI_DS_NAME_FORMAT_FQDN_1779, DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX, result->dn, name, info1); } case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: { const struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, result, "objectSid"); const char *_acc = "", *_dom = ""; if (sid == NULL) { info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING; return WERR_OK; } if (samdb_find_attribute(sam_ctx, result, "objectClass", "domain")) { /* This can also find a DomainDNSZones entry, * but it won't have the SID we just * checked. */ ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res, partitions_basedn, LDB_SCOPE_ONELEVEL, domain_attrs, "(ncName=%s)", ldb_dn_get_linearized(result->dn)); if (ldb_ret != LDB_SUCCESS) { DEBUG(2, ("DsCrackNameOneFilter domain ref search failed: %s\n", ldb_errstring(sam_ctx))); info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR; return WERR_OK; } switch (domain_res->count) { case 1: break; case 0: info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; return WERR_OK; default: info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE; return WERR_OK; } _dom = ldb_msg_find_attr_as_string(domain_res->msgs[0], "nETBIOSName", NULL); W_ERROR_HAVE_NO_MEMORY(_dom); } else { _acc = ldb_msg_find_attr_as_string(result, "sAMAccountName", NULL); if (!_acc) { info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING; return WERR_OK; } if (dom_sid_in_domain(dom_sid_parse_talloc(mem_ctx, SID_BUILTIN), sid)) { _dom = "BUILTIN"; } else { const char *attrs[] = { NULL }; struct ldb_result *domain_res2; struct dom_sid *dom_sid = dom_sid_dup(mem_ctx, sid); if (!dom_sid) { return WERR_OK; } dom_sid->num_auths--; ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res, NULL, LDB_SCOPE_BASE, attrs, "(&(objectSid=%s)(objectClass=domain))", ldap_encode_ndr_dom_sid(mem_ctx, dom_sid)); if (ldb_ret != LDB_SUCCESS) { DEBUG(2, ("DsCrackNameOneFilter domain search failed: %s\n", ldb_errstring(sam_ctx))); info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR; return WERR_OK; } switch (domain_res->count) { case 1: break; case 0: info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; return WERR_OK; default: info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE; return WERR_OK; } ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res2, partitions_basedn, LDB_SCOPE_ONELEVEL, domain_attrs, "(ncName=%s)", ldb_dn_get_linearized(domain_res->msgs[0]->dn)); if (ldb_ret != LDB_SUCCESS) { DEBUG(2, ("DsCrackNameOneFilter domain ref search failed: %s\n", ldb_errstring(sam_ctx))); info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR; return WERR_OK; } switch (domain_res2->count) { case 1: break; case 0: info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; return WERR_OK; default: info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE; return WERR_OK; } _dom = ldb_msg_find_attr_as_string(domain_res2->msgs[0], "nETBIOSName", NULL); W_ERROR_HAVE_NO_MEMORY(_dom); } } info1->result_name = talloc_asprintf(mem_ctx, "%s\\%s", _dom, _acc); W_ERROR_HAVE_NO_MEMORY(info1->result_name); info1->status = DRSUAPI_DS_NAME_STATUS_OK; return WERR_OK; } case DRSUAPI_DS_NAME_FORMAT_GUID: { struct GUID guid; guid = samdb_result_guid(result, "objectGUID"); info1->result_name = GUID_string2(mem_ctx, &guid); W_ERROR_HAVE_NO_MEMORY(info1->result_name); info1->status = DRSUAPI_DS_NAME_STATUS_OK; return WERR_OK; } case DRSUAPI_DS_NAME_FORMAT_DISPLAY: { info1->result_name = ldb_msg_find_attr_as_string(result, "displayName", NULL); if (!info1->result_name) { info1->result_name = ldb_msg_find_attr_as_string(result, "sAMAccountName", NULL); } if (!info1->result_name) { info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; } else { info1->status = DRSUAPI_DS_NAME_STATUS_OK; } return WERR_OK; } case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: { info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE; return WERR_OK; } case DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN: case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY: { info1->dns_domain_name = NULL; info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR; return WERR_OK; } default: info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING; return WERR_OK; } }
_PUBLIC_ enum MAPISTATUS openchangedb_table_get_property(TALLOC_CTX *mem_ctx, void *table_object, struct ldb_context *ldb_ctx, enum MAPITAGS proptag, uint32_t pos, bool live_filtered, void **data) { struct openchangedb_table *table; char *ldb_filter = NULL; struct ldb_result *res = NULL, *live_res = NULL; const char * const attrs[] = { "*", NULL }; const char *PidTagAttr = NULL, *childIdAttr; uint64_t *row_fmid; int ret; /* Sanity checks */ OPENCHANGE_RETVAL_IF(!table_object, MAPI_E_NOT_INITIALIZED, NULL); OPENCHANGE_RETVAL_IF(!ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL); OPENCHANGE_RETVAL_IF(!data, MAPI_E_NOT_INITIALIZED, NULL); table = (struct openchangedb_table *)table_object; /* Fetch results */ if (!table->res) { /* Build ldb filter */ if (live_filtered) { ldb_filter = openchangedb_table_build_filter(NULL, table, 0, NULL); DEBUG(0, ("(live-filtered) ldb_filter = %s\n", ldb_filter)); } else { ldb_filter = openchangedb_table_build_filter(NULL, table, 0, table->restrictions); DEBUG(0, ("(pre-filtered) ldb_filter = %s\n", ldb_filter)); } OPENCHANGE_RETVAL_IF(!ldb_filter, MAPI_E_TOO_COMPLEX, NULL); ret = ldb_search(ldb_ctx, (TALLOC_CTX *)table_object, &table->res, ldb_get_default_basedn(ldb_ctx), LDB_SCOPE_SUBTREE, attrs, ldb_filter, NULL); talloc_free(ldb_filter); OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_INVALID_OBJECT, NULL); } res = table->res; /* Ensure position is within search results range */ OPENCHANGE_RETVAL_IF(pos >= res->count, MAPI_E_INVALID_OBJECT, NULL); /* If live filtering, make sure the specified row match the restrictions */ if (live_filtered) { TALLOC_CTX *local_mem_ctx; switch (table->table_type) { case 0x3 /* EMSMDBP_TABLE_FAI_TYPE */: case 0x2 /* EMSMDBP_TABLE_MESSAGE_TYPE */: childIdAttr = "PidTagMessageId"; break; case 0x1 /* EMSMDBP_TABLE_FOLDER_TYPE */: childIdAttr = "PidTagFolderId"; break; default: DEBUG(0, ("unsupported table type for openchangedb: %d\n", table->table_type)); abort(); } row_fmid = openchangedb_get_property_data(mem_ctx, res, pos, PR_MID, childIdAttr); if (!row_fmid || !*row_fmid) { DEBUG(0, ("ldb object must have a '%s' field\n", childIdAttr)); abort(); } local_mem_ctx = talloc_zero(NULL, TALLOC_CTX); ldb_filter = openchangedb_table_build_filter(local_mem_ctx, table, *row_fmid, table->restrictions); OPENCHANGE_RETVAL_IF(!ldb_filter, MAPI_E_TOO_COMPLEX, NULL); DEBUG(0, (" row ldb_filter = %s\n", ldb_filter)); ret = ldb_search(ldb_ctx, local_mem_ctx, &live_res, ldb_get_default_basedn(ldb_ctx), LDB_SCOPE_SUBTREE, attrs, ldb_filter, NULL); OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS || live_res->count == 0, MAPI_E_INVALID_OBJECT, local_mem_ctx); talloc_free(local_mem_ctx); } /* hacks for some attributes specific to tables */ if (proptag == PR_INST_ID) { if (table->table_type == 1) { proptag = PR_FID; } else { proptag = PR_MID; } } else if (proptag == PR_INSTANCE_NUM) { *data = talloc_zero(mem_ctx, uint32_t); return MAPI_E_SUCCESS; } /* Convert proptag into PidTag attribute */ if ((table->table_type != 0x1) && proptag == PR_FID) { proptag = PR_PARENT_FID; } PidTagAttr = openchangedb_property_get_attribute(proptag); OPENCHANGE_RETVAL_IF(!PidTagAttr, MAPI_E_NOT_FOUND, NULL); /* Ensure the element exists */ OPENCHANGE_RETVAL_IF(!ldb_msg_find_element(res->msgs[pos], PidTagAttr), MAPI_E_NOT_FOUND, NULL); /* Check if this is a "special property" */ *data = openchangedb_get_special_property(mem_ctx, ldb_ctx, res, proptag, PidTagAttr); OPENCHANGE_RETVAL_IF(*data != NULL, MAPI_E_SUCCESS, NULL); /* Check if this is NOT a "special property" */ *data = openchangedb_get_property_data(mem_ctx, res, pos, proptag, PidTagAttr); OPENCHANGE_RETVAL_IF(*data != NULL, MAPI_E_SUCCESS, NULL); return MAPI_E_NOT_FOUND; }
/* perform a zone transfer */ _PUBLIC_ isc_result_t dlz_allnodes(const char *zone, void *dbdata, dns_sdlzallnodes_t *allnodes) { struct dlz_bind9_data *state = talloc_get_type_abort(dbdata, struct dlz_bind9_data); const char *attrs[] = { "dnsRecord", NULL }; int ret = LDB_SUCCESS, i, j; struct ldb_dn *dn; struct ldb_result *res; TALLOC_CTX *tmp_ctx = talloc_new(state); for (i=0; zone_prefixes[i]; i++) { dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(state->samdb)); if (dn == NULL) { talloc_free(tmp_ctx); return ISC_R_NOMEMORY; } if (!ldb_dn_add_child_fmt(dn, "DC=%s,%s", zone, zone_prefixes[i])) { talloc_free(tmp_ctx); return ISC_R_NOMEMORY; } ret = ldb_search(state->samdb, tmp_ctx, &res, dn, LDB_SCOPE_SUBTREE, attrs, "objectClass=dnsNode"); if (ret == LDB_SUCCESS) { break; } } if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ISC_R_NOTFOUND; } for (i=0; i<res->count; i++) { struct ldb_message_element *el; TALLOC_CTX *el_ctx = talloc_new(tmp_ctx); const char *rdn, *name; const struct ldb_val *v; el = ldb_msg_find_element(res->msgs[i], "dnsRecord"); if (el == NULL || el->num_values == 0) { state->log(ISC_LOG_INFO, "failed to find dnsRecord for %s", ldb_dn_get_linearized(dn)); talloc_free(el_ctx); continue; } v = ldb_dn_get_rdn_val(res->msgs[i]->dn); if (v == NULL) { state->log(ISC_LOG_INFO, "failed to find RDN for %s", ldb_dn_get_linearized(dn)); talloc_free(el_ctx); continue; } rdn = talloc_strndup(el_ctx, (char *)v->data, v->length); if (rdn == NULL) { talloc_free(tmp_ctx); return ISC_R_NOMEMORY; } if (strcmp(rdn, "@") == 0) { name = zone; } else { name = talloc_asprintf(el_ctx, "%s.%s", rdn, zone); } if (name == NULL) { talloc_free(tmp_ctx); return ISC_R_NOMEMORY; } for (j=0; j<el->num_values; j++) { struct dnsp_DnssrvRpcRecord rec; enum ndr_err_code ndr_err; isc_result_t result; ndr_err = ndr_pull_struct_blob(&el->values[j], el_ctx, &rec, (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s", ldb_dn_get_linearized(dn)); continue; } result = b9_putnamedrr(state, allnodes, name, &rec); if (result != ISC_R_SUCCESS) { continue; } } } talloc_free(tmp_ctx); return ISC_R_SUCCESS; }
/* A user password change Return true if there is a valid error packet (or success) formed in the error_blob */ NTSTATUS samdb_kpasswd_change_password(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct tevent_context *event_ctx, struct ldb_context *samdb, struct auth_session_info *session_info, const DATA_BLOB *password, enum samPwdChangeReason *reject_reason, struct samr_DomInfo1 **dominfo, const char **error_string, NTSTATUS *result) { struct samr_Password *oldLmHash, *oldNtHash; const char * const attrs[] = { "dBCSPwd", "unicodePwd", NULL }; struct ldb_message *msg; NTSTATUS status; int ret; /* Fetch the old hashes to get the old password in order to perform * the password change operation. Naturally it would be much better to * have a password hash from an authentication around but this doesn't * seem to be the case here. */ ret = dsdb_search_one(samdb, mem_ctx, &msg, ldb_get_default_basedn(samdb), LDB_SCOPE_SUBTREE, attrs, DSDB_SEARCH_NO_GLOBAL_CATALOG, "(&(objectClass=user)(sAMAccountName=%s))", session_info->info->account_name); if (ret != LDB_SUCCESS) { *error_string = "No such user when changing password"; return NT_STATUS_NO_SUCH_USER; } /* * No need to check for password lockout here, the KDC will * have done that when issuing the ticket, which is not based * on the user's password */ status = samdb_result_passwords_no_lockout(mem_ctx, lp_ctx, msg, &oldLmHash, &oldNtHash); if (!NT_STATUS_IS_OK(status)) { *error_string = "Not permitted to change password"; return NT_STATUS_ACCESS_DENIED; } /* Start a SAM with user privileges for the password change */ samdb = samdb_connect(mem_ctx, event_ctx, lp_ctx, session_info, 0); if (!samdb) { *error_string = "Failed to open samdb"; return NT_STATUS_ACCESS_DENIED; } DEBUG(3, ("Changing password of %s\\%s (%s)\n", session_info->info->domain_name, session_info->info->account_name, dom_sid_string(mem_ctx, &session_info->security_token->sids[PRIMARY_USER_SID_INDEX]))); /* Performs the password change */ status = samdb_set_password_sid(samdb, mem_ctx, &session_info->security_token->sids[PRIMARY_USER_SID_INDEX], NULL, password, NULL, NULL, oldLmHash, oldNtHash, /* this is a user password change */ reject_reason, dominfo); if (!NT_STATUS_IS_OK(status)) { *error_string = nt_errstr(status); } *result = status; return NT_STATUS_OK; }
static NTSTATUS authsam_check_password_internals(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, const struct auth_usersupplied_info *user_info, struct auth_serversupplied_info **server_info) { NTSTATUS nt_status; const char *account_name = user_info->mapped.account_name; struct ldb_message *msg; struct ldb_context *sam_ctx; struct ldb_dn *domain_dn; DATA_BLOB user_sess_key, lm_sess_key; TALLOC_CTX *tmp_ctx; if (!account_name || !*account_name) { /* 'not for me' */ return NT_STATUS_NOT_IMPLEMENTED; } tmp_ctx = talloc_new(mem_ctx); if (!tmp_ctx) { return NT_STATUS_NO_MEMORY; } sam_ctx = samdb_connect(tmp_ctx, ctx->auth_ctx->event_ctx, ctx->auth_ctx->lp_ctx, system_session(mem_ctx, ctx->auth_ctx->lp_ctx)); if (sam_ctx == NULL) { talloc_free(tmp_ctx); return NT_STATUS_INVALID_SYSTEM_SERVICE; } domain_dn = ldb_get_default_basedn(sam_ctx); if (domain_dn == NULL) { talloc_free(tmp_ctx); return NT_STATUS_NO_SUCH_DOMAIN; } nt_status = authsam_search_account(tmp_ctx, sam_ctx, account_name, domain_dn, &msg); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(tmp_ctx); return nt_status; } nt_status = authsam_authenticate(ctx->auth_ctx, tmp_ctx, sam_ctx, domain_dn, msg, user_info, &user_sess_key, &lm_sess_key); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(tmp_ctx); return nt_status; } nt_status = authsam_make_server_info(tmp_ctx, sam_ctx, lp_netbios_name(ctx->auth_ctx->lp_ctx), lp_sam_name(ctx->auth_ctx->lp_ctx), domain_dn, msg, user_sess_key, lm_sess_key, server_info); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(tmp_ctx); return nt_status; } talloc_steal(mem_ctx, *server_info); talloc_free(tmp_ctx); return NT_STATUS_OK; }
/* lookup one record */ static isc_result_t dlz_lookup_types(struct dlz_bind9_data *state, const char *zone, const char *name, dns_sdlzlookup_t *lookup, const char **types) { TALLOC_CTX *tmp_ctx = talloc_new(state); const char *attrs[] = { "dnsRecord", NULL }; int ret = LDB_SUCCESS, i; struct ldb_result *res; struct ldb_message_element *el; struct ldb_dn *dn; for (i=0; zone_prefixes[i]; i++) { dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(state->samdb)); if (dn == NULL) { talloc_free(tmp_ctx); return ISC_R_NOMEMORY; } if (!ldb_dn_add_child_fmt(dn, "DC=%s,DC=%s,%s", name, zone, zone_prefixes[i])) { talloc_free(tmp_ctx); return ISC_R_NOMEMORY; } ret = ldb_search(state->samdb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, "objectClass=dnsNode"); if (ret == LDB_SUCCESS) { break; } } if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ISC_R_NOTFOUND; } el = ldb_msg_find_element(res->msgs[0], "dnsRecord"); if (el == NULL || el->num_values == 0) { talloc_free(tmp_ctx); return ISC_R_NOTFOUND; } for (i=0; i<el->num_values; i++) { struct dnsp_DnssrvRpcRecord rec; enum ndr_err_code ndr_err; isc_result_t result; ndr_err = ndr_pull_struct_blob(&el->values[i], tmp_ctx, &rec, (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { state->log(ISC_LOG_ERROR, "samba_dlz: failed to parse dnsRecord for %s", ldb_dn_get_linearized(dn)); talloc_free(tmp_ctx); return ISC_R_FAILURE; } result = b9_putrr(state, lookup, &rec, types); if (result != ISC_R_SUCCESS) { talloc_free(tmp_ctx); return result; } } talloc_free(tmp_ctx); return ISC_R_SUCCESS; }
/** \details Resolve a recipient and build the associated RecipientRow structure \param mem_ctx pointer to the memory context \param emsmdbp_ctx pointer to the EMSMDBP context \param recipient pointer to the recipient string \param properties array of properties to lookup for a recipient \param row the RecipientRow to fill in \note This is a very preliminary implementation with a lot of pseudo-hardcoded things. Lot of work is required to make this function generic and to cover all different cases \return Allocated RecipientRow on success, otherwise NULL */ _PUBLIC_ enum MAPISTATUS emsmdbp_resolve_recipient(TALLOC_CTX *mem_ctx, struct emsmdbp_context *emsmdbp_ctx, char *recipient, struct mapi_SPropTagArray *properties, struct RecipientRow *row) { enum MAPISTATUS retval; struct ldb_result *res = NULL; const char * const recipient_attrs[] = { "*", NULL }; int ret; uint32_t i; uint32_t property = 0; void *data; char *str; char *username; char *legacyExchangeDN; uint32_t org_length; uint32_t l; /* Sanity checks */ OPENCHANGE_RETVAL_IF(!mem_ctx, MAPI_E_NOT_INITIALIZED, NULL); OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL); OPENCHANGE_RETVAL_IF(!emsmdbp_ctx->samdb_ctx, MAPI_E_NOT_INITIALIZED, NULL); OPENCHANGE_RETVAL_IF(!properties, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!recipient, MAPI_E_INVALID_PARAMETER, NULL); OPENCHANGE_RETVAL_IF(!row, MAPI_E_INVALID_PARAMETER, NULL); ret = ldb_search(emsmdbp_ctx->samdb_ctx, emsmdbp_ctx, &res, ldb_get_default_basedn(emsmdbp_ctx->samdb_ctx), LDB_SCOPE_SUBTREE, recipient_attrs, "(&(objectClass=user)(sAMAccountName=*%s*)(!(objectClass=computer)))", ldb_binary_encode_string(mem_ctx, recipient)); /* If the search failed, build an external recipient: very basic for the moment */ if (ret != LDB_SUCCESS || !res->count) { failure: row->RecipientFlags = 0x07db; row->EmailAddress.lpszW = talloc_strdup(mem_ctx, recipient); row->DisplayName.lpszW = talloc_strdup(mem_ctx, recipient); row->SimpleDisplayName.lpszW = talloc_strdup(mem_ctx, recipient); row->prop_count = properties->cValues; row->layout = 0x1; row->prop_values.length = 0; for (i = 0; i < properties->cValues; i++) { switch (properties->aulPropTag[i]) { case PidTagSmtpAddress: property = properties->aulPropTag[i]; data = (void *) recipient; break; default: retval = MAPI_E_NOT_FOUND; property = (properties->aulPropTag[i] & 0xFFFF0000) + PT_ERROR; data = (void *)&retval; break; } libmapiserver_push_property(mem_ctx, property, (const void *)data, &row->prop_values, row->layout, 0, 0); } return MAPI_E_SUCCESS; } /* Otherwise build a RecipientRow for resolved username */ username = (char *) ldb_msg_find_attr_as_string(res->msgs[0], "mailNickname", NULL); legacyExchangeDN = (char *) ldb_msg_find_attr_as_string(res->msgs[0], "legacyExchangeDN", NULL); if (!username || !legacyExchangeDN) { DEBUG(0, ("record found but mailNickname or legacyExchangeDN is missing for %s\n", recipient)); goto failure; } org_length = strlen(legacyExchangeDN) - strlen(username); /* Check if we need a flagged blob */ row->layout = 0; for (i = 0; i < properties->cValues; i++) { switch (properties->aulPropTag[i]) { case PR_DISPLAY_TYPE: case PR_OBJECT_TYPE: case PidTagAddressBookDisplayNamePrintable: case PidTagSmtpAddress: break; default: row->layout = 1; break; } } row->RecipientFlags = 0x06d1; row->AddressPrefixUsed.prefix_size = org_length; row->DisplayType.display_type = SINGLE_RECIPIENT; row->X500DN.recipient_x500name = talloc_strdup(mem_ctx, username); row->DisplayName.lpszW = talloc_strdup(mem_ctx, username); row->SimpleDisplayName.lpszW = talloc_strdup(mem_ctx, username); row->prop_count = properties->cValues; row->prop_values.length = 0; /* Add this very small set of properties */ for (i = 0; i < properties->cValues; i++) { switch (properties->aulPropTag[i]) { case PR_DISPLAY_TYPE: property = properties->aulPropTag[i]; l = 0x0; data = (void *)&l; break; case PR_OBJECT_TYPE: property = properties->aulPropTag[i]; l = MAPI_MAILUSER; data = (void *)&l; break; case PidTagAddressBookDisplayNamePrintable: property = properties->aulPropTag[i]; str = (char *) ldb_msg_find_attr_as_string(res->msgs[0], "mailNickname", NULL); data = (void *) str; break; case PidTagSmtpAddress: property = properties->aulPropTag[i]; str = (char *) ldb_msg_find_attr_as_string(res->msgs[0], "legacyExchangeDN", NULL); data = (void *) str; break; default: retval = MAPI_E_NOT_FOUND; property = (properties->aulPropTag[i] & 0xFFFF0000) + PT_ERROR; data = (void *)&retval; break; } libmapiserver_push_property(mem_ctx, property, (const void *)data, &row->prop_values, row->layout, 0, 0); } return MAPI_E_SUCCESS; }
/* configure a writeable zone */ _PUBLIC_ isc_result_t dlz_configure(dns_view_t *view, void *dbdata) { struct dlz_bind9_data *state = talloc_get_type_abort(dbdata, struct dlz_bind9_data); TALLOC_CTX *tmp_ctx; struct ldb_dn *dn; int i; state->log(ISC_LOG_INFO, "samba_dlz: starting configure"); if (state->writeable_zone == NULL) { state->log(ISC_LOG_INFO, "samba_dlz: no writeable_zone method available"); return ISC_R_FAILURE; } tmp_ctx = talloc_new(state); for (i=0; zone_prefixes[i]; i++) { const char *attrs[] = { "name", NULL }; int j, ret; struct ldb_result *res; dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(state->samdb)); if (dn == NULL) { talloc_free(tmp_ctx); return ISC_R_NOMEMORY; } if (!ldb_dn_add_child_fmt(dn, "%s", zone_prefixes[i])) { talloc_free(tmp_ctx); return ISC_R_NOMEMORY; } ret = ldb_search(state->samdb, tmp_ctx, &res, dn, LDB_SCOPE_SUBTREE, attrs, "objectClass=dnsZone"); if (ret != LDB_SUCCESS) { continue; } for (j=0; j<res->count; j++) { isc_result_t result; const char *zone = ldb_msg_find_attr_as_string(res->msgs[j], "name", NULL); struct ldb_dn *zone_dn; if (zone == NULL) { continue; } zone_dn = ldb_dn_copy(tmp_ctx, dn); if (zone_dn == NULL) { talloc_free(tmp_ctx); return ISC_R_NOMEMORY; } if (!b9_has_soa(state, zone_dn, zone)) { continue; } result = state->writeable_zone(view, zone); if (result != ISC_R_SUCCESS) { state->log(ISC_LOG_ERROR, "samba_dlz: Failed to configure zone '%s'", zone); talloc_free(tmp_ctx); return result; } state->log(ISC_LOG_INFO, "samba_dlz: configured writeable zone '%s'", zone); } } talloc_free(tmp_ctx); return ISC_R_SUCCESS; }
NTSTATUS dcesrv_lsa_get_policy_state(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, uint32_t access_desired, struct lsa_policy_state **_state) { struct auth_session_info *session_info = dce_call->conn->auth_state.session_info; enum security_user_level security_level; struct lsa_policy_state *state; struct ldb_result *dom_res; const char *dom_attrs[] = { "objectSid", "objectGUID", "nTMixedDomain", "fSMORoleOwner", NULL }; char *p; int ret; state = talloc_zero(mem_ctx, struct lsa_policy_state); if (!state) { return NT_STATUS_NO_MEMORY; } /* make sure the sam database is accessible */ state->sam_ldb = samdb_connect(state, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info, dce_call->conn->remote_address, 0); if (state->sam_ldb == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } /* and the privilege database */ state->pdb = privilege_connect(state, dce_call->conn->dce_ctx->lp_ctx); if (state->pdb == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } /* work out the domain_dn - useful for so many calls its worth fetching here */ state->domain_dn = ldb_get_default_basedn(state->sam_ldb); if (!state->domain_dn) { return NT_STATUS_NO_MEMORY; } /* work out the forest root_dn - useful for so many calls its worth fetching here */ state->forest_dn = ldb_get_root_basedn(state->sam_ldb); if (!state->forest_dn) { return NT_STATUS_NO_MEMORY; } ret = ldb_search(state->sam_ldb, mem_ctx, &dom_res, state->domain_dn, LDB_SCOPE_BASE, dom_attrs, NULL); if (ret != LDB_SUCCESS) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } if (dom_res->count != 1) { return NT_STATUS_NO_SUCH_DOMAIN; } state->domain_sid = samdb_result_dom_sid(state, dom_res->msgs[0], "objectSid"); if (!state->domain_sid) { return NT_STATUS_NO_SUCH_DOMAIN; } state->domain_guid = samdb_result_guid(dom_res->msgs[0], "objectGUID"); state->mixed_domain = ldb_msg_find_attr_as_uint(dom_res->msgs[0], "nTMixedDomain", 0); talloc_free(dom_res); state->domain_name = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx); state->domain_dns = ldb_dn_canonical_string(state, state->domain_dn); if (!state->domain_dns) { return NT_STATUS_NO_SUCH_DOMAIN; } p = strchr(state->domain_dns, '/'); if (p) { *p = '\0'; } state->forest_dns = ldb_dn_canonical_string(state, state->forest_dn); if (!state->forest_dns) { return NT_STATUS_NO_SUCH_DOMAIN; } p = strchr(state->forest_dns, '/'); if (p) { *p = '\0'; } /* work out the builtin_dn - useful for so many calls its worth fetching here */ state->builtin_dn = samdb_search_dn(state->sam_ldb, state, state->domain_dn, "(objectClass=builtinDomain)"); if (!state->builtin_dn) { return NT_STATUS_NO_SUCH_DOMAIN; } /* work out the system_dn - useful for so many calls its worth fetching here */ state->system_dn = samdb_search_dn(state->sam_ldb, state, state->domain_dn, "(&(objectClass=container)(cn=System))"); if (!state->system_dn) { return NT_STATUS_NO_SUCH_DOMAIN; } state->builtin_sid = dom_sid_parse_talloc(state, SID_BUILTIN); if (!state->builtin_sid) { return NT_STATUS_NO_SUCH_DOMAIN; } state->nt_authority_sid = dom_sid_parse_talloc(state, SID_NT_AUTHORITY); if (!state->nt_authority_sid) { return NT_STATUS_NO_SUCH_DOMAIN; } state->creator_owner_domain_sid = dom_sid_parse_talloc(state, SID_CREATOR_OWNER_DOMAIN); if (!state->creator_owner_domain_sid) { return NT_STATUS_NO_SUCH_DOMAIN; } state->world_domain_sid = dom_sid_parse_talloc(state, SID_WORLD_DOMAIN); if (!state->world_domain_sid) { return NT_STATUS_NO_SUCH_DOMAIN; } state->sd = sddl_decode(state, DCESRV_LSA_POLICY_SD_SDDL, state->domain_sid); if (state->sd == NULL) { return NT_STATUS_NO_MEMORY; } state->sd->dacl->revision = SECURITY_ACL_REVISION_NT4; se_map_generic(&access_desired, &dcesrv_lsa_policy_mapping); security_acl_map_generic(state->sd->dacl, &dcesrv_lsa_policy_mapping); security_level = security_session_user_level(session_info, NULL); if (security_level >= SECURITY_SYSTEM) { /* * The security descriptor doesn't allow system, * but we want to allow system via ncalrpc as root. */ state->access_mask = access_desired; if (state->access_mask & SEC_FLAG_MAXIMUM_ALLOWED) { state->access_mask &= ~SEC_FLAG_MAXIMUM_ALLOWED; state->access_mask |= LSA_POLICY_ALL_ACCESS; } } else { NTSTATUS status; status = se_access_check(state->sd, session_info->security_token, access_desired, &state->access_mask); if (!NT_STATUS_IS_OK(status)) { DEBUG(2,("%s: access desired[0x%08X] rejected[0x%08X] - %s\n", __func__, (unsigned)access_desired, (unsigned)state->access_mask, nt_errstr(status))); return status; } } DEBUG(10,("%s: access desired[0x%08X] granted[0x%08X] - success.\n", __func__, (unsigned)access_desired, (unsigned)state->access_mask)); *_state = state; return NT_STATUS_OK; }
NTSTATUS dcesrv_lsa_get_policy_state(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct lsa_policy_state **_state) { struct lsa_policy_state *state; struct ldb_result *dom_res; const char *dom_attrs[] = { "objectSid", "objectGUID", "nTMixedDomain", "fSMORoleOwner", NULL }; char *p; int ret; state = talloc(mem_ctx, struct lsa_policy_state); if (!state) { return NT_STATUS_NO_MEMORY; } /* make sure the sam database is accessible */ state->sam_ldb = samdb_connect(state, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info, 0); if (state->sam_ldb == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } /* and the privilege database */ state->pdb = privilege_connect(state, dce_call->conn->dce_ctx->lp_ctx); if (state->pdb == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } /* work out the domain_dn - useful for so many calls its worth fetching here */ state->domain_dn = ldb_get_default_basedn(state->sam_ldb); if (!state->domain_dn) { return NT_STATUS_NO_MEMORY; } /* work out the forest root_dn - useful for so many calls its worth fetching here */ state->forest_dn = ldb_get_root_basedn(state->sam_ldb); if (!state->forest_dn) { return NT_STATUS_NO_MEMORY; } ret = ldb_search(state->sam_ldb, mem_ctx, &dom_res, state->domain_dn, LDB_SCOPE_BASE, dom_attrs, NULL); if (ret != LDB_SUCCESS) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } if (dom_res->count != 1) { return NT_STATUS_NO_SUCH_DOMAIN; } state->domain_sid = samdb_result_dom_sid(state, dom_res->msgs[0], "objectSid"); if (!state->domain_sid) { return NT_STATUS_NO_SUCH_DOMAIN; } state->domain_guid = samdb_result_guid(dom_res->msgs[0], "objectGUID"); state->mixed_domain = ldb_msg_find_attr_as_uint(dom_res->msgs[0], "nTMixedDomain", 0); talloc_free(dom_res); state->domain_name = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx); state->domain_dns = ldb_dn_canonical_string(state, state->domain_dn); if (!state->domain_dns) { return NT_STATUS_NO_SUCH_DOMAIN; } p = strchr(state->domain_dns, '/'); if (p) { *p = '\0'; } state->forest_dns = ldb_dn_canonical_string(state, state->forest_dn); if (!state->forest_dns) { return NT_STATUS_NO_SUCH_DOMAIN; } p = strchr(state->forest_dns, '/'); if (p) { *p = '\0'; } /* work out the builtin_dn - useful for so many calls its worth fetching here */ state->builtin_dn = samdb_search_dn(state->sam_ldb, state, state->domain_dn, "(objectClass=builtinDomain)"); if (!state->builtin_dn) { return NT_STATUS_NO_SUCH_DOMAIN; } /* work out the system_dn - useful for so many calls its worth fetching here */ state->system_dn = samdb_search_dn(state->sam_ldb, state, state->domain_dn, "(&(objectClass=container)(cn=System))"); if (!state->system_dn) { return NT_STATUS_NO_SUCH_DOMAIN; } state->builtin_sid = dom_sid_parse_talloc(state, SID_BUILTIN); if (!state->builtin_sid) { return NT_STATUS_NO_SUCH_DOMAIN; } state->nt_authority_sid = dom_sid_parse_talloc(state, SID_NT_AUTHORITY); if (!state->nt_authority_sid) { return NT_STATUS_NO_SUCH_DOMAIN; } state->creator_owner_domain_sid = dom_sid_parse_talloc(state, SID_CREATOR_OWNER_DOMAIN); if (!state->creator_owner_domain_sid) { return NT_STATUS_NO_SUCH_DOMAIN; } state->world_domain_sid = dom_sid_parse_talloc(state, SID_WORLD_DOMAIN); if (!state->world_domain_sid) { return NT_STATUS_NO_SUCH_DOMAIN; } *_state = state; return NT_STATUS_OK; }
/* Add a user, SAMR style, including the correct transaction * semantics. Used by the SAMR server and by pdb_samba4 */ NTSTATUS dsdb_add_user(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *account_name, uint32_t acct_flags, struct dom_sid **sid, struct ldb_dn **dn) { const char *name; struct ldb_message *msg; int ret; const char *container, *obj_class=NULL; char *cn_name; size_t cn_name_len; const char *attrs[] = { "objectSid", "userAccountControl", NULL }; uint32_t user_account_control; struct ldb_dn *account_dn; struct dom_sid *account_sid; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); /* * Start a transaction, so we can query and do a subsequent atomic * modify */ ret = ldb_transaction_start(ldb); if (ret != LDB_SUCCESS) { DEBUG(0,("Failed to start a transaction for user creation: %s\n", ldb_errstring(ldb))); talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } /* check if the user already exists */ name = samdb_search_string(ldb, tmp_ctx, NULL, "sAMAccountName", "(&(sAMAccountName=%s)(objectclass=user))", ldb_binary_encode_string(tmp_ctx, account_name)); if (name != NULL) { ldb_transaction_cancel(ldb); talloc_free(tmp_ctx); return NT_STATUS_USER_EXISTS; } cn_name = talloc_strdup(tmp_ctx, account_name); if (!cn_name) { ldb_transaction_cancel(ldb); talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } cn_name_len = strlen(cn_name); if (cn_name_len < 1) { ldb_transaction_cancel(ldb); talloc_free(tmp_ctx); return NT_STATUS_INVALID_PARAMETER; } msg = ldb_msg_new(tmp_ctx); if (msg == NULL) { ldb_transaction_cancel(ldb); talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } /* This must be one of these values *only* */ if (acct_flags == ACB_NORMAL) { container = "CN=Users"; obj_class = "user"; } else if (acct_flags == ACB_WSTRUST) { if (cn_name[cn_name_len - 1] != '$') { ldb_transaction_cancel(ldb); return NT_STATUS_FOOBAR; } cn_name[cn_name_len - 1] = '\0'; container = "CN=Computers"; obj_class = "computer"; } else if (acct_flags == ACB_SVRTRUST) { if (cn_name[cn_name_len - 1] != '$') { ldb_transaction_cancel(ldb); return NT_STATUS_FOOBAR; } cn_name[cn_name_len - 1] = '\0'; container = "OU=Domain Controllers"; obj_class = "computer"; } else { ldb_transaction_cancel(ldb); talloc_free(tmp_ctx); return NT_STATUS_INVALID_PARAMETER; } /* add core elements to the ldb_message for the user */ msg->dn = ldb_dn_copy(msg, ldb_get_default_basedn(ldb)); if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s,%s", cn_name, container)) { ldb_transaction_cancel(ldb); talloc_free(tmp_ctx); return NT_STATUS_FOOBAR; } ldb_msg_add_string(msg, "sAMAccountName", account_name); ldb_msg_add_string(msg, "objectClass", obj_class); /* create the user */ ret = ldb_add(ldb, msg); switch (ret) { case LDB_SUCCESS: break; case LDB_ERR_ENTRY_ALREADY_EXISTS: ldb_transaction_cancel(ldb); DEBUG(0,("Failed to create user record %s: %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(ldb))); talloc_free(tmp_ctx); return NT_STATUS_USER_EXISTS; case LDB_ERR_UNWILLING_TO_PERFORM: case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS: ldb_transaction_cancel(ldb); DEBUG(0,("Failed to create user record %s: %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(ldb))); talloc_free(tmp_ctx); return NT_STATUS_ACCESS_DENIED; default: ldb_transaction_cancel(ldb); DEBUG(0,("Failed to create user record %s: %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(ldb))); talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } account_dn = msg->dn; /* retrieve the sid and account control bits for the user just created */ ret = dsdb_search_one(ldb, tmp_ctx, &msg, account_dn, LDB_SCOPE_BASE, attrs, 0, NULL); if (ret != LDB_SUCCESS) { ldb_transaction_cancel(ldb); DEBUG(0,("Can't locate the account we just created %s: %s\n", ldb_dn_get_linearized(account_dn), ldb_errstring(ldb))); talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } account_sid = samdb_result_dom_sid(tmp_ctx, msg, "objectSid"); if (account_sid == NULL) { ldb_transaction_cancel(ldb); DEBUG(0,("Apparently we failed to get the objectSid of the just created account record %s\n", ldb_dn_get_linearized(msg->dn))); talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } /* Change the account control to be the correct account type. * The default is for a workstation account */ user_account_control = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0); user_account_control = (user_account_control & ~(UF_NORMAL_ACCOUNT | UF_INTERDOMAIN_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT | UF_SERVER_TRUST_ACCOUNT)); user_account_control |= ds_acb2uf(acct_flags); talloc_free(msg); msg = ldb_msg_new(tmp_ctx); if (msg == NULL) { ldb_transaction_cancel(ldb); talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } msg->dn = account_dn; if (samdb_msg_add_uint(ldb, tmp_ctx, msg, "userAccountControl", user_account_control) != LDB_SUCCESS) { ldb_transaction_cancel(ldb); talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } /* modify the samdb record */ ret = dsdb_replace(ldb, msg, 0); if (ret != LDB_SUCCESS) { DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(ldb))); ldb_transaction_cancel(ldb); talloc_free(tmp_ctx); /* we really need samdb.c to return NTSTATUS */ return NT_STATUS_UNSUCCESSFUL; } ret = ldb_transaction_commit(ldb); if (ret != LDB_SUCCESS) { DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(ldb))); talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } *dn = talloc_steal(mem_ctx, account_dn); *sid = talloc_steal(mem_ctx, account_sid); talloc_free(tmp_ctx); return NT_STATUS_OK; }
NTSTATUS dsdb_add_domain_alias(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *alias_name, struct dom_sid **sid, struct ldb_dn **dn) { const char *name; struct ldb_message *msg; struct dom_sid *alias_sid; int ret; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); if (ldb_transaction_start(ldb) != LDB_SUCCESS) { DEBUG(0, ("Failed to start transaction in dsdb_add_domain_alias(): %s\n", ldb_errstring(ldb))); return NT_STATUS_INTERNAL_ERROR; } /* Check if alias already exists */ name = samdb_search_string(ldb, tmp_ctx, NULL, "sAMAccountName", "(sAMAccountName=%s)(objectclass=group))", ldb_binary_encode_string(mem_ctx, alias_name)); if (name != NULL) { talloc_free(tmp_ctx); ldb_transaction_cancel(ldb); return NT_STATUS_ALIAS_EXISTS; } msg = ldb_msg_new(tmp_ctx); if (msg == NULL) { talloc_free(tmp_ctx); ldb_transaction_cancel(ldb); return NT_STATUS_NO_MEMORY; } /* add core elements to the ldb_message for the alias */ msg->dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(ldb)); ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", alias_name); if (!msg->dn) { talloc_free(tmp_ctx); ldb_transaction_cancel(ldb); return NT_STATUS_NO_MEMORY; } ldb_msg_add_string(msg, "sAMAccountName", alias_name); ldb_msg_add_string(msg, "objectClass", "group"); samdb_msg_add_int(ldb, mem_ctx, msg, "groupType", GTYPE_SECURITY_DOMAIN_LOCAL_GROUP); /* create the alias */ ret = ldb_add(ldb, msg); switch (ret) { case LDB_SUCCESS: break; case LDB_ERR_ENTRY_ALREADY_EXISTS: talloc_free(tmp_ctx); ldb_transaction_cancel(ldb); return NT_STATUS_ALIAS_EXISTS; case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS: talloc_free(tmp_ctx); ldb_transaction_cancel(ldb); return NT_STATUS_ACCESS_DENIED; default: DEBUG(0,("Failed to create alias record %s: %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(ldb))); talloc_free(tmp_ctx); ldb_transaction_cancel(ldb); return NT_STATUS_INTERNAL_DB_CORRUPTION; } /* retrieve the sid for the alias just created */ alias_sid = samdb_search_dom_sid(ldb, tmp_ctx, msg->dn, "objectSid", NULL); if (ldb_transaction_commit(ldb) != LDB_SUCCESS) { DEBUG(0, ("Failed to commit transaction in dsdb_add_domain_alias(): %s\n", ldb_errstring(ldb))); return NT_STATUS_INTERNAL_ERROR; } *dn = talloc_steal(mem_ctx, msg->dn); *sid = talloc_steal(mem_ctx, alias_sid); talloc_free(tmp_ctx); return NT_STATUS_OK; }
/* called by samr_CreateDomainGroup and pdb_samba4 */ NTSTATUS dsdb_add_domain_group(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *groupname, struct dom_sid **sid, struct ldb_dn **dn) { const char *name; struct ldb_message *msg; struct dom_sid *group_sid; int ret; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); /* check if the group already exists */ name = samdb_search_string(ldb, tmp_ctx, NULL, "sAMAccountName", "(&(sAMAccountName=%s)(objectclass=group))", ldb_binary_encode_string(tmp_ctx, groupname)); if (name != NULL) { return NT_STATUS_GROUP_EXISTS; } msg = ldb_msg_new(tmp_ctx); if (msg == NULL) { return NT_STATUS_NO_MEMORY; } /* add core elements to the ldb_message for the user */ msg->dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(ldb)); ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", groupname); if (!msg->dn) { talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } ldb_msg_add_string(msg, "sAMAccountName", groupname); ldb_msg_add_string(msg, "objectClass", "group"); /* create the group */ ret = ldb_add(ldb, msg); switch (ret) { case LDB_SUCCESS: break; case LDB_ERR_ENTRY_ALREADY_EXISTS: DEBUG(0,("Failed to create group record %s: %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(ldb))); talloc_free(tmp_ctx); return NT_STATUS_GROUP_EXISTS; case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS: DEBUG(0,("Failed to create group record %s: %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(ldb))); talloc_free(tmp_ctx); return NT_STATUS_ACCESS_DENIED; default: DEBUG(0,("Failed to create group record %s: %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(ldb))); talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } /* retrieve the sid for the group just created */ group_sid = samdb_search_dom_sid(ldb, tmp_ctx, msg->dn, "objectSid", NULL); if (group_sid == NULL) { return NT_STATUS_UNSUCCESSFUL; } *dn = talloc_steal(mem_ctx, msg->dn); *sid = talloc_steal(mem_ctx, group_sid); talloc_free(tmp_ctx); return NT_STATUS_OK; }
/* fill in the cldap netlogon union for a given version */ NTSTATUS fill_netlogon_samlogon_response(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, const char *domain, const char *netbios_domain, struct dom_sid *domain_sid, const char *domain_guid, const char *user, uint32_t acct_control, const char *src_address, uint32_t version, struct loadparm_context *lp_ctx, struct netlogon_samlogon_response *netlogon, bool fill_on_blank_request) { const char *dom_attrs[] = {"objectGUID", NULL}; const char *none_attrs[] = {NULL}; struct ldb_result *dom_res = NULL; int ret; const char **services = lpcfg_server_services(lp_ctx); uint32_t server_type; const char *pdc_name; struct GUID domain_uuid; const char *dns_domain; const char *forest_domain; const char *pdc_dns_name; const char *flatname; const char *server_site; const char *client_site; const char *pdc_ip; struct ldb_dn *domain_dn = NULL; struct interface *ifaces; bool user_known = false, am_rodc = false; uint32_t uac = 0; NTSTATUS status; /* the domain parameter could have an optional trailing "." */ if (domain && domain[strlen(domain)-1] == '.') { domain = talloc_strndup(mem_ctx, domain, strlen(domain)-1); NT_STATUS_HAVE_NO_MEMORY(domain); } /* Lookup using long or short domainname */ if (domain && (strcasecmp_m(domain, lpcfg_dnsdomain(lp_ctx)) == 0)) { domain_dn = ldb_get_default_basedn(sam_ctx); } if (netbios_domain && (strcasecmp_m(netbios_domain, lpcfg_sam_name(lp_ctx)) == 0)) { domain_dn = ldb_get_default_basedn(sam_ctx); } if (domain_dn) { const char *domain_identifier = domain != NULL ? domain : netbios_domain; ret = ldb_search(sam_ctx, mem_ctx, &dom_res, domain_dn, LDB_SCOPE_BASE, dom_attrs, "objectClass=domain"); if (ret != LDB_SUCCESS) { DEBUG(2,("Error finding domain '%s'/'%s' in sam: %s\n", domain_identifier, ldb_dn_get_linearized(domain_dn), ldb_errstring(sam_ctx))); return NT_STATUS_NO_SUCH_DOMAIN; } if (dom_res->count != 1) { DEBUG(2,("Error finding domain '%s'/'%s' in sam\n", domain_identifier, ldb_dn_get_linearized(domain_dn))); return NT_STATUS_NO_SUCH_DOMAIN; } } /* Lookup using GUID or SID */ if ((dom_res == NULL) && (domain_guid || domain_sid)) { if (domain_guid) { struct GUID binary_guid; struct ldb_val guid_val; /* By this means, we ensure we don't have funny stuff in the GUID */ status = GUID_from_string(domain_guid, &binary_guid); if (!NT_STATUS_IS_OK(status)) { return status; } /* And this gets the result into the binary format we want anyway */ status = GUID_to_ndr_blob(&binary_guid, mem_ctx, &guid_val); if (!NT_STATUS_IS_OK(status)) { return status; } ret = ldb_search(sam_ctx, mem_ctx, &dom_res, NULL, LDB_SCOPE_SUBTREE, dom_attrs, "(&(objectCategory=DomainDNS)(objectGUID=%s))", ldb_binary_encode(mem_ctx, guid_val)); } else { /* domain_sid case */ ret = ldb_search(sam_ctx, mem_ctx, &dom_res, NULL, LDB_SCOPE_SUBTREE, dom_attrs, "(&(objectCategory=DomainDNS)(objectSid=%s))", dom_sid_string(mem_ctx, domain_sid)); } if (ret != LDB_SUCCESS) { DEBUG(2,("Unable to find a correct reference to GUID '%s' or SID '%s' in sam: %s\n", domain_guid, dom_sid_string(mem_ctx, domain_sid), ldb_errstring(sam_ctx))); return NT_STATUS_NO_SUCH_DOMAIN; } else if (dom_res->count == 1) { /* Ok, now just check it is our domain */ if (ldb_dn_compare(ldb_get_default_basedn(sam_ctx), dom_res->msgs[0]->dn) != 0) { DEBUG(2,("The GUID '%s' or SID '%s' doesn't identify our domain\n", domain_guid, dom_sid_string(mem_ctx, domain_sid))); return NT_STATUS_NO_SUCH_DOMAIN; } } else { DEBUG(2,("Unable to find a correct reference to GUID '%s' or SID '%s' in sam\n", domain_guid, dom_sid_string(mem_ctx, domain_sid))); return NT_STATUS_NO_SUCH_DOMAIN; } } if (dom_res == NULL && fill_on_blank_request) { /* blank inputs gives our domain - tested against w2k8r2. Without this ADUC on Win7 won't start */ domain_dn = ldb_get_default_basedn(sam_ctx); ret = ldb_search(sam_ctx, mem_ctx, &dom_res, domain_dn, LDB_SCOPE_BASE, dom_attrs, "objectClass=domain"); if (ret != LDB_SUCCESS) { DEBUG(2,("Error finding domain '%s'/'%s' in sam: %s\n", lpcfg_dnsdomain(lp_ctx), ldb_dn_get_linearized(domain_dn), ldb_errstring(sam_ctx))); return NT_STATUS_NO_SUCH_DOMAIN; } } if (dom_res == NULL) { DEBUG(2,(__location__ ": Unable to get domain information with no inputs\n")); return NT_STATUS_NO_SUCH_DOMAIN; } /* work around different inputs for not-specified users */ if (!user) { user = ""; } /* Enquire about any valid username with just a CLDAP packet - * if kerberos didn't also do this, the security folks would * scream... */ if (user[0]) { /* Only allow some bits to be enquired: [MS-ATDS] 7.3.3.2 */ if (acct_control == (uint32_t)-1) { acct_control = 0; } /* * ACB_AUTOLOCK/UF_LOCKOUT seems to be a special * hack for SEC_CHAN_DNS_DOMAIN. * * It's used together with user = "******" */ if (acct_control != ACB_AUTOLOCK) { acct_control &= (ACB_TEMPDUP | ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); } uac = ds_acb2uf(acct_control); } if (uac == UF_LOCKOUT) { struct ldb_message *tdo_msg = NULL; /* * ACB_AUTOLOCK/UF_LOCKOUT seems to be a special * hack for SEC_CHAN_DNS_DOMAIN. * * It's used together with user = "******" */ status = dsdb_trust_search_tdo_by_type(sam_ctx, SEC_CHAN_DNS_DOMAIN, user, none_attrs, mem_ctx, &tdo_msg); if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { user_known = false; } else if (NT_STATUS_IS_OK(status)) { TALLOC_FREE(tdo_msg); user_known = true; } else { DEBUG(2,("Unable to find reference to TDO '%s' - %s\n", user, nt_errstr(status))); return status; } } else if (user[0]) { struct ldb_result *user_res = NULL; /* We must exclude disabled accounts, but otherwise do the bitwise match the client asked for */ ret = ldb_search(sam_ctx, mem_ctx, &user_res, dom_res->msgs[0]->dn, LDB_SCOPE_SUBTREE, none_attrs, "(&(objectClass=user)(samAccountName=%s)" "(!(userAccountControl:" LDB_OID_COMPARATOR_AND ":=%u))" "(userAccountControl:" LDB_OID_COMPARATOR_OR ":=%u))", ldb_binary_encode_string(mem_ctx, user), UF_ACCOUNTDISABLE, uac); if (ret != LDB_SUCCESS) { DEBUG(2,("Unable to find reference to user '%s' with ACB 0x%8x under %s: %s\n", user, acct_control, ldb_dn_get_linearized(dom_res->msgs[0]->dn), ldb_errstring(sam_ctx))); return NT_STATUS_NO_SUCH_USER; } else if (user_res->count == 1) { user_known = true; } else { user_known = false; } TALLOC_FREE(user_res); } else { user_known = true; } server_type = DS_SERVER_DS; if (samdb_is_pdc(sam_ctx)) { server_type |= DS_SERVER_PDC; } if (samdb_is_gc(sam_ctx)) { server_type |= DS_SERVER_GC; } if (str_list_check(services, "ldap")) { server_type |= DS_SERVER_LDAP; } if (str_list_check(services, "kdc")) { server_type |= DS_SERVER_KDC; } if (str_list_check(services, "ntp_signd")) { server_type |= DS_SERVER_TIMESERV | DS_SERVER_GOOD_TIMESERV; } if (samdb_rodc(sam_ctx, &am_rodc) == LDB_SUCCESS && !am_rodc) { server_type |= DS_SERVER_WRITABLE; } if (dsdb_functional_level(sam_ctx) >= DS_DOMAIN_FUNCTION_2008) { if (server_type & DS_SERVER_WRITABLE) { server_type |= DS_SERVER_FULL_SECRET_DOMAIN_6; } else { server_type |= DS_SERVER_SELECT_SECRET_DOMAIN_6; } } if (version & (NETLOGON_NT_VERSION_5EX|NETLOGON_NT_VERSION_5EX_WITH_IP)) { pdc_name = lpcfg_netbios_name(lp_ctx); } else { pdc_name = talloc_asprintf(mem_ctx, "\\\\%s", lpcfg_netbios_name(lp_ctx)); NT_STATUS_HAVE_NO_MEMORY(pdc_name); } domain_uuid = samdb_result_guid(dom_res->msgs[0], "objectGUID"); dns_domain = lpcfg_dnsdomain(lp_ctx); forest_domain = samdb_forest_name(sam_ctx, mem_ctx); NT_STATUS_HAVE_NO_MEMORY(forest_domain); pdc_dns_name = talloc_asprintf(mem_ctx, "%s.%s", strlower_talloc(mem_ctx, lpcfg_netbios_name(lp_ctx)), dns_domain); NT_STATUS_HAVE_NO_MEMORY(pdc_dns_name); flatname = lpcfg_workgroup(lp_ctx); server_site = samdb_server_site_name(sam_ctx, mem_ctx); NT_STATUS_HAVE_NO_MEMORY(server_site); client_site = samdb_client_site_name(sam_ctx, mem_ctx, src_address, NULL); NT_STATUS_HAVE_NO_MEMORY(client_site); if (strcasecmp(server_site, client_site) == 0) { server_type |= DS_SERVER_CLOSEST; } load_interface_list(mem_ctx, lp_ctx, &ifaces); if (src_address) { pdc_ip = iface_list_best_ip(ifaces, src_address); } else { pdc_ip = iface_list_first_v4(ifaces); } if (pdc_ip == NULL || !is_ipaddress_v4(pdc_ip)) { /* this matches windows behaviour */ pdc_ip = "127.0.0.1"; } ZERO_STRUCTP(netlogon); /* check if either of these bits is present */ if (version & (NETLOGON_NT_VERSION_5EX|NETLOGON_NT_VERSION_5EX_WITH_IP)) { uint32_t extra_flags = 0; netlogon->ntver = NETLOGON_NT_VERSION_5EX; /* could check if the user exists */ if (user_known) { netlogon->data.nt5_ex.command = LOGON_SAM_LOGON_RESPONSE_EX; } else { netlogon->data.nt5_ex.command = LOGON_SAM_LOGON_USER_UNKNOWN_EX; } netlogon->data.nt5_ex.pdc_name = pdc_name; netlogon->data.nt5_ex.user_name = user; netlogon->data.nt5_ex.domain_name = flatname; netlogon->data.nt5_ex.domain_uuid = domain_uuid; netlogon->data.nt5_ex.forest = forest_domain; netlogon->data.nt5_ex.dns_domain = dns_domain; netlogon->data.nt5_ex.pdc_dns_name = pdc_dns_name; netlogon->data.nt5_ex.server_site = server_site; netlogon->data.nt5_ex.client_site = client_site; if (version & NETLOGON_NT_VERSION_5EX_WITH_IP) { /* note that this is always a IPV4 address */ extra_flags = NETLOGON_NT_VERSION_5EX_WITH_IP; netlogon->data.nt5_ex.sockaddr.sockaddr_family = 2; netlogon->data.nt5_ex.sockaddr.pdc_ip = pdc_ip; netlogon->data.nt5_ex.sockaddr.remaining = data_blob_talloc_zero(mem_ctx, 8); } netlogon->data.nt5_ex.server_type = server_type; netlogon->data.nt5_ex.nt_version = NETLOGON_NT_VERSION_1|NETLOGON_NT_VERSION_5EX|extra_flags; netlogon->data.nt5_ex.lmnt_token = 0xFFFF; netlogon->data.nt5_ex.lm20_token = 0xFFFF; } else if (version & NETLOGON_NT_VERSION_5) { netlogon->ntver = NETLOGON_NT_VERSION_5; /* could check if the user exists */ if (user_known) { netlogon->data.nt5.command = LOGON_SAM_LOGON_RESPONSE; } else { netlogon->data.nt5.command = LOGON_SAM_LOGON_USER_UNKNOWN; } netlogon->data.nt5.pdc_name = pdc_name; netlogon->data.nt5.user_name = user; netlogon->data.nt5.domain_name = flatname; netlogon->data.nt5.domain_uuid = domain_uuid; netlogon->data.nt5.forest = forest_domain; netlogon->data.nt5.dns_domain = dns_domain; netlogon->data.nt5.pdc_dns_name = pdc_dns_name; netlogon->data.nt5.pdc_ip = pdc_ip; netlogon->data.nt5.server_type = server_type; netlogon->data.nt5.nt_version = NETLOGON_NT_VERSION_1|NETLOGON_NT_VERSION_5; netlogon->data.nt5.lmnt_token = 0xFFFF; netlogon->data.nt5.lm20_token = 0xFFFF; } else /* (version & NETLOGON_NT_VERSION_1) and all other cases */ { netlogon->ntver = NETLOGON_NT_VERSION_1; /* could check if the user exists */ if (user_known) { netlogon->data.nt4.command = LOGON_SAM_LOGON_RESPONSE; } else { netlogon->data.nt4.command = LOGON_SAM_LOGON_USER_UNKNOWN; } netlogon->data.nt4.pdc_name = pdc_name; netlogon->data.nt4.user_name = user; netlogon->data.nt4.domain_name = flatname; netlogon->data.nt4.nt_version = NETLOGON_NT_VERSION_1; netlogon->data.nt4.lmnt_token = 0xFFFF; netlogon->data.nt4.lm20_token = 0xFFFF; } return NT_STATUS_OK; }
/* called to initialise the driver */ _PUBLIC_ isc_result_t dlz_create(const char *dlzname, unsigned int argc, char *argv[], void **dbdata, ...) { struct dlz_bind9_data *state; const char *helper_name; va_list ap; isc_result_t result; struct ldb_dn *dn; NTSTATUS nt_status; state = talloc_zero(NULL, struct dlz_bind9_data); if (state == NULL) { return ISC_R_NOMEMORY; } talloc_set_destructor(state, dlz_state_debug_unregister); /* fill in the helper functions */ va_start(ap, dbdata); while ((helper_name = va_arg(ap, const char *)) != NULL) { b9_add_helper(state, helper_name, va_arg(ap, void*)); } va_end(ap); /* Do not install samba signal handlers */ fault_setup_disable(); /* Start logging (to the bind9 logs) */ debug_set_callback(state, b9_debug); state->ev_ctx = s4_event_context_init(state); if (state->ev_ctx == NULL) { result = ISC_R_NOMEMORY; goto failed; } result = parse_options(state, argc, argv, &state->options); if (result != ISC_R_SUCCESS) { goto failed; } state->lp = loadparm_init_global(true); if (state->lp == NULL) { result = ISC_R_NOMEMORY; goto failed; } if (state->options.debug) { lpcfg_do_global_parameter(state->lp, "log level", state->options.debug); } else { lpcfg_do_global_parameter(state->lp, "log level", "0"); } if (smb_krb5_init_context(state, state->ev_ctx, state->lp, &state->smb_krb5_ctx) != 0) { result = ISC_R_NOMEMORY; goto failed; } nt_status = gensec_init(); if (!NT_STATUS_IS_OK(nt_status)) { result = ISC_R_NOMEMORY; goto failed; } state->auth_context = talloc_zero(state, struct auth4_context); if (state->auth_context == NULL) { result = ISC_R_NOMEMORY; goto failed; } if (state->options.url == NULL) { state->options.url = lpcfg_private_path(state, state->lp, "dns/sam.ldb"); if (state->options.url == NULL) { result = ISC_R_NOMEMORY; goto failed; } } state->samdb = samdb_connect_url(state, state->ev_ctx, state->lp, system_session(state->lp), 0, state->options.url); if (state->samdb == NULL) { state->log(ISC_LOG_ERROR, "samba_dlz: Failed to connect to %s", state->options.url); result = ISC_R_FAILURE; goto failed; } dn = ldb_get_default_basedn(state->samdb); if (dn == NULL) { state->log(ISC_LOG_ERROR, "samba_dlz: Unable to get basedn for %s - %s", state->options.url, ldb_errstring(state->samdb)); result = ISC_R_FAILURE; goto failed; } state->log(ISC_LOG_INFO, "samba_dlz: started for DN %s", ldb_dn_get_linearized(dn)); state->auth_context->event_ctx = state->ev_ctx; state->auth_context->lp_ctx = state->lp; state->auth_context->sam_ctx = state->samdb; state->auth_context->generate_session_info_pac = b9_generate_session_info_pac; *dbdata = state; return ISC_R_SUCCESS; failed: talloc_free(state); return result; }
static krb5_error_code hdb_samba4_auth_status(krb5_context context, HDB *db, hdb_entry_ex *entry, struct sockaddr *from_addr, const char *original_client_name, const char *auth_type, int hdb_auth_status) { struct samba_kdc_db_context *kdc_db_ctx = talloc_get_type_abort(db->hdb_db, struct samba_kdc_db_context); struct ldb_dn *domain_dn = ldb_get_default_basedn(kdc_db_ctx->samdb); /* * Forcing this via the NTLM auth structure is not ideal, but * it is the most practical option right now, and ensures the * logs are consistent, even if some elements are always NULL. */ struct auth_usersupplied_info ui = { .mapped_state = true, .was_mapped = true, .client = { .account_name = original_client_name, .domain_name = NULL, }, .service_description = "Kerberos KDC", .auth_description = "ENC-TS Pre-authentication", .password_type = auth_type }; size_t sa_socklen = 0; switch (from_addr->sa_family) { case AF_INET: sa_socklen = sizeof(struct sockaddr_in); break; #ifdef HAVE_IPV6 case AF_INET6: sa_socklen = sizeof(struct sockaddr_in6); break; #endif } switch (hdb_auth_status) { case HDB_AUTHZ_SUCCESS: { struct samba_kdc_entry *p = talloc_get_type(entry->ctx, struct samba_kdc_entry); /* * TODO: We could log the AS-REQ authorization success here as * well. However before we do that, we need to pass * in the PAC here or re-calculate it. */ authsam_logon_success_accounting(kdc_db_ctx->samdb, p->msg, domain_dn, true); break; } case HDB_AUTH_INVALID_SIGNATURE: break; case HDB_AUTH_CORRECT_PASSWORD: case HDB_AUTH_WRONG_PASSWORD: { TALLOC_CTX *frame = talloc_stackframe(); struct samba_kdc_entry *p = talloc_get_type(entry->ctx, struct samba_kdc_entry); struct dom_sid *sid = samdb_result_dom_sid(frame, p->msg, "objectSid"); const char *account_name = ldb_msg_find_attr_as_string(p->msg, "sAMAccountName", NULL); const char *domain_name = lpcfg_sam_name(p->kdc_db_ctx->lp_ctx); struct tsocket_address *remote_host; NTSTATUS status; int ret; if (hdb_auth_status == HDB_AUTH_WRONG_PASSWORD) { authsam_update_bad_pwd_count(kdc_db_ctx->samdb, p->msg, domain_dn); status = NT_STATUS_WRONG_PASSWORD; } else { status = NT_STATUS_OK; } ret = tsocket_address_bsd_from_sockaddr(frame, from_addr, sa_socklen, &remote_host); if (ret != 0) { ui.remote_host = NULL; } else { ui.remote_host = remote_host; } ui.mapped.account_name = account_name; ui.mapped.domain_name = domain_name; log_authentication_event(kdc_db_ctx->msg_ctx, kdc_db_ctx->lp_ctx, &ui, status, domain_name, account_name, NULL, sid); TALLOC_FREE(frame); break; } case HDB_AUTH_CLIENT_UNKNOWN: { struct tsocket_address *remote_host; int ret; TALLOC_CTX *frame = talloc_stackframe(); ret = tsocket_address_bsd_from_sockaddr(frame, from_addr, sa_socklen, &remote_host); if (ret != 0) { ui.remote_host = NULL; } else { ui.remote_host = remote_host; } log_authentication_event(kdc_db_ctx->msg_ctx, kdc_db_ctx->lp_ctx, &ui, NT_STATUS_NO_SUCH_USER, NULL, NULL, NULL, NULL); TALLOC_FREE(frame); break; } } return 0; }
static NTSTATUS authsam_check_password_internals(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, const struct auth_usersupplied_info *user_info, struct auth_user_info_dc **user_info_dc, bool *authoritative) { NTSTATUS nt_status; const char *account_name = user_info->mapped.account_name; struct ldb_message *msg; struct ldb_dn *domain_dn; DATA_BLOB user_sess_key, lm_sess_key; TALLOC_CTX *tmp_ctx; const char *p = NULL; if (ctx->auth_ctx->sam_ctx == NULL) { DEBUG(0, ("No SAM available, cannot log in users\n")); return NT_STATUS_INVALID_SYSTEM_SERVICE; } if (!account_name || !*account_name) { /* 'not for me' */ return NT_STATUS_NOT_IMPLEMENTED; } tmp_ctx = talloc_new(mem_ctx); if (!tmp_ctx) { return NT_STATUS_NO_MEMORY; } domain_dn = ldb_get_default_basedn(ctx->auth_ctx->sam_ctx); if (domain_dn == NULL) { talloc_free(tmp_ctx); return NT_STATUS_NO_SUCH_DOMAIN; } p = strchr_m(account_name, '@'); if (p != NULL) { const char *nt4_domain = NULL; const char *nt4_account = NULL; bool is_my_domain = false; nt_status = crack_name_to_nt4_name(mem_ctx, ctx->auth_ctx->sam_ctx, /* * DRSUAPI_DS_NAME_FORMAT_UPN_FOR_LOGON ? */ DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL, account_name, &nt4_domain, &nt4_account); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(tmp_ctx); return NT_STATUS_NO_SUCH_USER; } is_my_domain = lpcfg_is_mydomain(ctx->auth_ctx->lp_ctx, nt4_domain); if (!is_my_domain) { /* * This is a user within our forest, * but in a different domain, * we're not authoritative */ talloc_free(tmp_ctx); return NT_STATUS_NOT_IMPLEMENTED; } /* * Let's use the NT4 account name for the lookup. */ account_name = nt4_account; } nt_status = authsam_search_account(tmp_ctx, ctx->auth_ctx->sam_ctx, account_name, domain_dn, &msg); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(tmp_ctx); return nt_status; } nt_status = authsam_authenticate(ctx->auth_ctx, tmp_ctx, ctx->auth_ctx->sam_ctx, domain_dn, msg, user_info, &user_sess_key, &lm_sess_key, authoritative); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(tmp_ctx); return nt_status; } nt_status = authsam_make_user_info_dc(tmp_ctx, ctx->auth_ctx->sam_ctx, lpcfg_netbios_name(ctx->auth_ctx->lp_ctx), lpcfg_sam_name(ctx->auth_ctx->lp_ctx), lpcfg_sam_dnsname(ctx->auth_ctx->lp_ctx), domain_dn, msg, user_sess_key, lm_sess_key, user_info_dc); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(tmp_ctx); return nt_status; } talloc_steal(mem_ctx, *user_info_dc); talloc_free(tmp_ctx); return NT_STATUS_OK; }