static void ridalloc_get_ridset_values(struct ldb_message *msg, struct ridalloc_ridset_values *v) { v->alloc_pool = ldb_msg_find_attr_as_uint64(msg, "rIDAllocationPool", UINT64_MAX); v->prev_pool = ldb_msg_find_attr_as_uint64(msg, "rIDPreviousAllocationPool", UINT64_MAX); v->next_rid = ldb_msg_find_attr_as_uint(msg, "rIDNextRID", UINT32_MAX); v->used_pool = ldb_msg_find_attr_as_uint(msg, "rIDUsedPool", UINT32_MAX); }
/* port functions */ static WERROR sptr_EnumPorts(struct ntptr_context *ntptr, TALLOC_CTX *mem_ctx, struct spoolss_EnumPorts *r) { struct ldb_context *sptr_db = talloc_get_type(ntptr->private_data, struct ldb_context); struct ldb_message **msgs; int count; int i; union spoolss_PortInfo *info; count = sptr_db_search(sptr_db, mem_ctx, NULL, &msgs, NULL, "(&(objectclass=port))"); if (count == 0) return WERR_OK; if (count < 0) return WERR_GENERAL_FAILURE; info = talloc_array(mem_ctx, union spoolss_PortInfo, count); W_ERROR_HAVE_NO_MEMORY(info); switch (r->in.level) { case 1: for (i = 0; i < count; i++) { info[i].info1.port_name = ldb_msg_find_attr_as_string(msgs[i], "port-name", ""); W_ERROR_HAVE_NO_MEMORY(info[i].info1.port_name); } break; case 2: for (i=0; i < count; i++) { info[i].info2.port_name = ldb_msg_find_attr_as_string(msgs[i], "port-name", ""); W_ERROR_HAVE_NO_MEMORY(info[i].info2.port_name); info[i].info2.monitor_name = ldb_msg_find_attr_as_string(msgs[i], "monitor-name", ""); W_ERROR_HAVE_NO_MEMORY(info[i].info2.monitor_name); info[i].info2.description = ldb_msg_find_attr_as_string(msgs[i], "description", ""); W_ERROR_HAVE_NO_MEMORY(info[i].info2.description); info[i].info2.port_type = ldb_msg_find_attr_as_uint(msgs[i], "port-type", SPOOLSS_PORT_TYPE_WRITE); info[i].info2.reserved = ldb_msg_find_attr_as_uint(msgs[i], "reserved", 0); } break; default: return WERR_UNKNOWN_LEVEL; } *r->out.info = info; *r->out.count = count; return WERR_OK; }
/** \details return the next unmapped property ID \param ldb_ctx pointer to the namedprops ldb context \return 0 on error, the next mapped id otherwise */ _PUBLIC_ uint16_t mapistore_namedprops_next_unused_id(struct ldb_context *ldb_ctx) { uint16_t highest_id = 0, current_id; TALLOC_CTX *mem_ctx; struct ldb_result *res = NULL; const char * const attrs[] = { "mappedId", NULL }; int ret; unsigned int i; mem_ctx = talloc_named(NULL, 0, "mapistore_namedprops_get_mapped_propID"); ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), LDB_SCOPE_SUBTREE, attrs, "(cn=*)"); MAPISTORE_RETVAL_IF(ret != LDB_SUCCESS, 0, mem_ctx); for (i = 0; i < res->count; i++) { current_id = ldb_msg_find_attr_as_uint(res->msgs[i], "mappedId", 0); if (current_id > 0 && highest_id < current_id) { highest_id = current_id; } } talloc_free(mem_ctx); DEBUG(5, ("next_mapped_id: %d\n", (highest_id + 1))); return (highest_id + 1); }
static NTSTATUS unbecomeDC_ldap_computer_object(struct libnet_UnbecomeDC_state *s) { int ret; struct ldb_result *r; struct ldb_dn *basedn; static const char *attrs[] = { "distinguishedName", "userAccountControl", NULL }; basedn = ldb_dn_new(s, s->ldap.ldb, s->domain.dn_str); NT_STATUS_HAVE_NO_MEMORY(basedn); ret = ldb_search(s->ldap.ldb, s, &r, basedn, LDB_SCOPE_SUBTREE, attrs, "(&(|(objectClass=user)(objectClass=computer))(sAMAccountName=%s$))", s->dest_dsa.netbios_name); talloc_free(basedn); if (ret != LDB_SUCCESS) { return NT_STATUS_LDAP(ret); } else if (r->count != 1) { talloc_free(r); return NT_STATUS_INVALID_NETWORK_RESPONSE; } s->dest_dsa.computer_dn_str = ldb_msg_find_attr_as_string(r->msgs[0], "distinguishedName", NULL); if (!s->dest_dsa.computer_dn_str) return NT_STATUS_INVALID_NETWORK_RESPONSE; talloc_steal(s, s->dest_dsa.computer_dn_str); s->dest_dsa.user_account_control = ldb_msg_find_attr_as_uint(r->msgs[0], "userAccountControl", 0); talloc_free(r); return NT_STATUS_OK; }
static void generate_sambaPrimaryGroupSID(struct ldb_module *module, const char *local_attr, const struct ldb_message *local, struct ldb_message *remote_mp, struct ldb_message *remote_fb) { const struct ldb_val *sidval; char *sidstring; struct dom_sid *sid; NTSTATUS status; /* We need the domain, so we get it from the objectSid that we hope is here... */ sidval = ldb_msg_find_ldb_val(local, "objectSid"); if (!sidval) return; /* Sorry, no SID today.. */ sid = talloc(remote_mp, struct dom_sid); if (sid == NULL) { return; } status = ndr_pull_struct_blob(sidval, sid, sid, (ndr_pull_flags_fn_t)ndr_pull_dom_sid); if (!NT_STATUS_IS_OK(status)) { talloc_free(sid); return; } if (!ldb_msg_find_ldb_val(local, "primaryGroupID")) return; /* Sorry, no SID today.. */ sid->num_auths--; sidstring = dom_sid_string(remote_mp, sid); talloc_free(sid); ldb_msg_add_fmt(remote_mp, "sambaPrimaryGroupSID", "%s-%d", sidstring, ldb_msg_find_attr_as_uint(local, "primaryGroupID", 0)); talloc_free(sidstring); }
/* construct msDS-User-Account-Control-Computed attr */ static int construct_msds_user_account_control_computed(struct ldb_module *module, struct ldb_message *msg, enum ldb_scope scope, struct ldb_request *parent) { uint32_t userAccountControl; uint32_t msDS_User_Account_Control_Computed = 0; struct ldb_context *ldb = ldb_module_get_ctx(module); NTTIME now; struct ldb_dn *nc_root; int ret; ret = dsdb_find_nc_root(ldb, msg, msg->dn, &nc_root); if (ret != 0) { ldb_asprintf_errstring(ldb, "Failed to find NC root of DN: %s: %s", ldb_dn_get_linearized(msg->dn), ldb_errstring(ldb_module_get_ctx(module))); return ret; } if (ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) != 0) { /* Only calculate this on our default NC */ return 0; } /* Test account expire time */ unix_to_nt_time(&now, time(NULL)); userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0); if (!(userAccountControl & _UF_TRUST_ACCOUNTS)) { int64_t lockoutTime = ldb_msg_find_attr_as_int64(msg, "lockoutTime", 0); if (lockoutTime != 0) { int64_t lockoutDuration = samdb_search_int64(ldb, msg, 0, nc_root, "lockoutDuration", NULL); if (lockoutDuration >= 0) { msDS_User_Account_Control_Computed |= UF_LOCKOUT; } else if (lockoutTime - lockoutDuration >= now) { msDS_User_Account_Control_Computed |= UF_LOCKOUT; } } } if (!(userAccountControl & _UF_NO_EXPIRY_ACCOUNTS)) { NTTIME must_change_time = get_msds_user_password_expiry_time_computed(module, msg, nc_root); /* check for expired password */ if (must_change_time < now) { msDS_User_Account_Control_Computed |= UF_PASSWORD_EXPIRED; } } return samdb_msg_add_int64(ldb, msg->elements, msg, "msDS-User-Account-Control-Computed", msDS_User_Account_Control_Computed); }
bool ads_pull_uint32(ADS_STRUCT *ads, LDAPMessage *res, const char *field, uint32_t *ret) { if (ldb_msg_find_element(res->msgs[0], field) == NULL) { return false; } *ret = ldb_msg_find_attr_as_uint(res->msgs[0], field, 0); return true; }
bool samba_princ_needs_pac(struct hdb_entry_ex *princ) { struct samba_kdc_entry *p = talloc_get_type(princ->ctx, struct samba_kdc_entry); uint32_t userAccountControl; /* The service account may be set not to want the PAC */ userAccountControl = ldb_msg_find_attr_as_uint(p->msg, "userAccountControl", 0); if (userAccountControl & UF_NO_AUTH_DATA_REQUIRED) { return false; } return true; }
/* Printer Form functions */ static WERROR sptr_GetPrinterForm(struct ntptr_GenericHandle *printer, TALLOC_CTX *mem_ctx, struct spoolss_GetForm *r) { struct ldb_context *sptr_db = talloc_get_type(printer->ntptr->private_data, struct ldb_context); struct ldb_message **msgs; struct ldb_dn *base_dn; int count; union spoolss_FormInfo *info; /* TODO: do checks access here * if (!(printer->access_mask & desired_access)) { * return WERR_FOOBAR; * } */ base_dn = ldb_dn_new_fmt(mem_ctx, sptr_db, "CN=Forms,CN=%s,CN=Printers", printer->object_name); W_ERROR_HAVE_NO_MEMORY(base_dn); count = sptr_db_search(sptr_db, mem_ctx, base_dn, &msgs, NULL, "(&(form-name=%s)(objectClass=form))", r->in.form_name); if (count == 0) return WERR_FOOBAR; if (count > 1) return WERR_FOOBAR; if (count < 0) return WERR_GENERAL_FAILURE; info = talloc(mem_ctx, union spoolss_FormInfo); W_ERROR_HAVE_NO_MEMORY(info); switch (r->in.level) { case 1: info->info1.flags = ldb_msg_find_attr_as_uint(msgs[0], "flags", SPOOLSS_FORM_BUILTIN); info->info1.form_name = ldb_msg_find_attr_as_string(msgs[0], "form-name", NULL); W_ERROR_HAVE_NO_MEMORY(info->info1.form_name); info->info1.size.width = ldb_msg_find_attr_as_uint(msgs[0], "size-width", 0); info->info1.size.height = ldb_msg_find_attr_as_uint(msgs[0], "size-height", 0); info->info1.area.left = ldb_msg_find_attr_as_uint(msgs[0], "area-left", 0); info->info1.area.top = ldb_msg_find_attr_as_uint(msgs[0], "area-top", 0); info->info1.area.right = ldb_msg_find_attr_as_uint(msgs[0], "area-right", 0); info->info1.area.bottom = ldb_msg_find_attr_as_uint(msgs[0], "area-bottom", 0); break; default: return WERR_UNKNOWN_LEVEL; } r->out.info = info; return WERR_OK; }
/* PrintServer Form functions */ static WERROR sptr_EnumPrintServerForms(struct ntptr_GenericHandle *server, TALLOC_CTX *mem_ctx, struct spoolss_EnumForms *r) { struct ldb_context *sptr_db = talloc_get_type(server->ntptr->private_data, struct ldb_context); struct ldb_message **msgs; int count; int i; union spoolss_FormInfo *info; count = sptr_db_search(sptr_db, mem_ctx, ldb_dn_new(mem_ctx, sptr_db, "CN=Forms,CN=PrintServer"), &msgs, NULL, "(&(objectClass=form))"); if (count == 0) return WERR_OK; if (count < 0) return WERR_GENERAL_FAILURE; info = talloc_array(mem_ctx, union spoolss_FormInfo, count); W_ERROR_HAVE_NO_MEMORY(info); switch (r->in.level) { case 1: for (i=0; i < count; i++) { info[i].info1.flags = ldb_msg_find_attr_as_uint(msgs[i], "flags", SPOOLSS_FORM_BUILTIN); info[i].info1.form_name = ldb_msg_find_attr_as_string(msgs[i], "form-name", NULL); W_ERROR_HAVE_NO_MEMORY(info[i].info1.form_name); info[i].info1.size.width = ldb_msg_find_attr_as_uint(msgs[i], "size-width", 0); info[i].info1.size.height = ldb_msg_find_attr_as_uint(msgs[i], "size-height", 0); info[i].info1.area.left = ldb_msg_find_attr_as_uint(msgs[i], "area-left", 0); info[i].info1.area.top = ldb_msg_find_attr_as_uint(msgs[i], "area-top", 0); info[i].info1.area.right = ldb_msg_find_attr_as_uint(msgs[i], "area-right", 0); info[i].info1.area.bottom = ldb_msg_find_attr_as_uint(msgs[i], "area-bottom", 0); } break; default: return WERR_UNKNOWN_LEVEL; } *r->out.info = info; *r->out.count = count; return WERR_OK; }
static WERROR sptr_DeletePrintServerForm(struct ntptr_GenericHandle *server, TALLOC_CTX *mem_ctx, struct spoolss_DeleteForm *r) { struct ldb_context *sptr_db = talloc_get_type(server->ntptr->private_data, struct ldb_context); struct ldb_message **msgs; const char * const attrs[] = { "flags", NULL}; int count, ret; enum spoolss_FormFlags flags; /* TODO: do checks access here * if (!(server->access_mask & desired_access)) { * return WERR_FOOBAR; * } */ if (!r->in.form_name) { return WERR_FOOBAR; } count = sptr_db_search(sptr_db, mem_ctx, ldb_dn_new(mem_ctx, sptr_db, "CN=Forms,CN=PrintServer"), &msgs, attrs, "(&(form-name=%s)(objectclass=form))", r->in.form_name); if (count == 0) return WERR_FOOBAR; if (count > 1) return WERR_FOOBAR; if (count < 0) return WERR_GENERAL_FAILURE; flags = ldb_msg_find_attr_as_uint(msgs[0], "flags", SPOOLSS_FORM_BUILTIN); if (flags != SPOOLSS_FORM_USER) { return WERR_FOOBAR; } ret = ldb_delete(sptr_db, msgs[0]->dn); if (ret != 0) { return WERR_FOOBAR; } return WERR_OK; }
/** \details return the mapped property ID matching the nameid structure passed in parameter. \param ldb_ctx pointer to the namedprops ldb context \param nameid the MAPINAMEID structure to lookup \param propID pointer to the property ID the function returns \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE_ERROR */ _PUBLIC_ enum mapistore_error mapistore_namedprops_get_mapped_id(struct ldb_context *ldb_ctx, struct MAPINAMEID nameid, uint16_t *propID) { TALLOC_CTX *mem_ctx; struct ldb_result *res = NULL; const char * const attrs[] = { "*", NULL }; int ret; char *filter = NULL; char *guid; /* Sanity checks */ MAPISTORE_RETVAL_IF(!ldb_ctx, MAPISTORE_ERROR, NULL); MAPISTORE_RETVAL_IF(!propID, MAPISTORE_ERROR, NULL); *propID = 0; mem_ctx = talloc_named(NULL, 0, "mapistore_namedprops_get_mapped_propID"); guid = GUID_string(mem_ctx, (const struct GUID *)&nameid.lpguid); switch (nameid.ulKind) { case MNID_ID: filter = talloc_asprintf(mem_ctx, "(&(objectClass=MNID_ID)(oleguid=%s)(cn=0x%.4x))", guid, nameid.kind.lid); break; case MNID_STRING: filter = talloc_asprintf(mem_ctx, "(&(objectClass=MNID_STRING)(oleguid=%s)(cn=%s))", guid, nameid.kind.lpwstr.Name); break; } talloc_free(guid); ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), LDB_SCOPE_SUBTREE, attrs, "%s", filter); MAPISTORE_RETVAL_IF((ret != LDB_SUCCESS || !res->count), MAPISTORE_ERROR, mem_ctx); *propID = ldb_msg_find_attr_as_uint(res->msgs[0], "mappedId", 0); MAPISTORE_RETVAL_IF(!*propID, MAPISTORE_ERROR, mem_ctx); talloc_free(mem_ctx); return MAPISTORE_SUCCESS; }
static WERROR sptr_SetPrintServerForm(struct ntptr_GenericHandle *server, TALLOC_CTX *mem_ctx, struct spoolss_SetForm *r) { struct ldb_context *sptr_db = talloc_get_type(server->ntptr->private_data, struct ldb_context); struct ldb_message *msg,**msgs; const char * const attrs[] = { "flags", NULL}; int count, ret; enum spoolss_FormFlags flags; /* TODO: do checks access here * if (!(server->access_mask & desired_access)) { * return WERR_FOOBAR; * } */ switch (r->in.level) { case 1: if (!r->in.info.info1) { return WERR_FOOBAR; } count = sptr_db_search(sptr_db, mem_ctx, ldb_dn_new(mem_ctx, sptr_db, "CN=Forms,CN=PrintServer"), &msgs, attrs, "(&(form-name=%s)(objectClass=form))", r->in.info.info1->form_name); if (count == 0) return WERR_FOOBAR; if (count > 1) return WERR_FOOBAR; if (count < 0) return WERR_GENERAL_FAILURE; flags = ldb_msg_find_attr_as_uint(msgs[0], "flags", SPOOLSS_FORM_BUILTIN); if (flags != SPOOLSS_FORM_USER) { return WERR_FOOBAR; } msg = ldb_msg_new(mem_ctx); W_ERROR_HAVE_NO_MEMORY(msg); /* add core elements to the ldb_message for the user */ msg->dn = msgs[0]->dn; SET_UINT(sptr_db, msg, "flags", r->in.info.info1->flags); SET_STRING(sptr_db, msg, "form-name", r->in.info.info1->form_name); SET_UINT(sptr_db, msg, "size-width", r->in.info.info1->size.width); SET_UINT(sptr_db, msg, "size-height", r->in.info.info1->size.height); SET_UINT(sptr_db, msg, "area-left", r->in.info.info1->area.left); SET_UINT(sptr_db, msg, "area-top", r->in.info.info1->area.top); SET_UINT(sptr_db, msg, "area-right", r->in.info.info1->area.right); SET_UINT(sptr_db, msg, "area-bottom", r->in.info.info1->area.bottom); break; default: return WERR_UNKNOWN_LEVEL; } ret = dsdb_replace(sptr_db, msg, 0); if (ret != 0) { return WERR_FOOBAR; } return WERR_OK; }
/* calculate msDS-UserPasswordExpiryTimeComputed */ static NTTIME get_msds_user_password_expiry_time_computed(struct ldb_module *module, struct ldb_message *msg, struct ldb_dn *domain_dn) { int64_t pwdLastSet, maxPwdAge; uint32_t userAccountControl; NTTIME ret; userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0); if (userAccountControl & _UF_NO_EXPIRY_ACCOUNTS) { return 0x7FFFFFFFFFFFFFFFULL; } pwdLastSet = ldb_msg_find_attr_as_int64(msg, "pwdLastSet", 0); if (pwdLastSet == 0) { return 0; } if (pwdLastSet <= -1) { /* * This can't really happen... */ return 0x7FFFFFFFFFFFFFFFULL; } if (pwdLastSet >= 0x7FFFFFFFFFFFFFFFULL) { /* * Somethings wrong with the clock... */ return 0x7FFFFFFFFFFFFFFFULL; } /* * Note that maxPwdAge is a stored as negative value. * * Possible values are in the range of: * * maxPwdAge: -864000000001 * to * maxPwdAge: -9223372036854775808 (-0x8000000000000000ULL) * */ maxPwdAge = samdb_search_int64(ldb_module_get_ctx(module), msg, 0, domain_dn, "maxPwdAge", NULL); if (maxPwdAge >= -864000000000) { /* * This is not really possible... */ return 0x7FFFFFFFFFFFFFFFULL; } if (maxPwdAge == -0x8000000000000000ULL) { return 0x7FFFFFFFFFFFFFFFULL; } /* * Note we already catched maxPwdAge == -0x8000000000000000ULL * and pwdLastSet >= 0x7FFFFFFFFFFFFFFFULL above. * * Remember maxPwdAge is a negative number, * so it results in the following. * * 0x7FFFFFFFFFFFFFFEULL + 0x7FFFFFFFFFFFFFFFULL * = * 0xFFFFFFFFFFFFFFFFULL */ ret = pwdLastSet - maxPwdAge; if (ret >= 0x7FFFFFFFFFFFFFFFULL) { return 0x7FFFFFFFFFFFFFFFULL; } return ret; }
/* * complete a domain join, when joining to a AD domain: * 1.) connect and bind to the DRSUAPI pipe * 2.) do a DsCrackNames() to find the machine account dn * 3.) connect to LDAP * 4.) do an ldap search to find the "msDS-KeyVersionNumber" of the machine account * 5.) set the servicePrincipalName's of the machine account via LDAP, (maybe we should use DsWriteAccountSpn()...) * 6.) do a DsCrackNames() to find the domain dn * 7.) find out Site specific stuff, look at libnet_JoinSite() for details */ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_JoinDomain *r) { NTSTATUS status; TALLOC_CTX *tmp_ctx; const char *realm = r->out.realm; struct dcerpc_binding *samr_binding = r->out.samr_binding; struct dcerpc_pipe *drsuapi_pipe; struct dcerpc_binding *drsuapi_binding; struct drsuapi_DsBind r_drsuapi_bind; struct drsuapi_DsCrackNames r_crack_names; struct drsuapi_DsNameString names[1]; struct policy_handle drsuapi_bind_handle; struct GUID drsuapi_bind_guid; struct ldb_context *remote_ldb; struct ldb_dn *account_dn; const char *account_dn_str; const char *remote_ldb_url; struct ldb_result *res; struct ldb_message *msg; int ret, rtn; unsigned int kvno; const char * const attrs[] = { "msDS-KeyVersionNumber", "servicePrincipalName", "dNSHostName", NULL, }; r->out.error_string = NULL; /* We need to convert between a samAccountName and domain to a * DN in the directory. The correct way to do this is with * DRSUAPI CrackNames */ /* Fiddle with the bindings, so get to DRSUAPI on * NCACN_IP_TCP, sealed */ tmp_ctx = talloc_named(r, 0, "libnet_JoinADSDomain temp context"); if (!tmp_ctx) { r->out.error_string = NULL; return NT_STATUS_NO_MEMORY; } drsuapi_binding = talloc(tmp_ctx, struct dcerpc_binding); if (!drsuapi_binding) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } *drsuapi_binding = *samr_binding; /* DRSUAPI is only available on IP_TCP, and locally on NCALRPC */ if (drsuapi_binding->transport != NCALRPC) { drsuapi_binding->transport = NCACN_IP_TCP; } drsuapi_binding->endpoint = NULL; drsuapi_binding->flags |= DCERPC_SEAL; status = dcerpc_pipe_connect_b(tmp_ctx, &drsuapi_pipe, drsuapi_binding, &dcerpc_table_drsuapi, ctx->cred, ctx->event_ctx); if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(r, "Connection to DRSUAPI pipe of PDC of domain '%s' failed: %s", r->in.domain_name, nt_errstr(status)); talloc_free(tmp_ctx); return status; } /* get a DRSUAPI pipe handle */ GUID_from_string(DRSUAPI_DS_BIND_GUID, &drsuapi_bind_guid); r_drsuapi_bind.in.bind_guid = &drsuapi_bind_guid; r_drsuapi_bind.in.bind_info = NULL; r_drsuapi_bind.out.bind_handle = &drsuapi_bind_handle; status = dcerpc_drsuapi_DsBind(drsuapi_pipe, tmp_ctx, &r_drsuapi_bind); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { r->out.error_string = talloc_asprintf(r, "dcerpc_drsuapi_DsBind failed - %s", dcerpc_errstr(tmp_ctx, drsuapi_pipe->last_fault_code)); talloc_free(tmp_ctx); return status; } else { r->out.error_string = talloc_asprintf(r, "dcerpc_drsuapi_DsBind failed - %s", nt_errstr(status)); talloc_free(tmp_ctx); return status; } } else if (!W_ERROR_IS_OK(r_drsuapi_bind.out.result)) { r->out.error_string = talloc_asprintf(r, "DsBind failed - %s", win_errstr(r_drsuapi_bind.out.result)); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } /* Actually 'crack' the names */ ZERO_STRUCT(r_crack_names); r_crack_names.in.bind_handle = &drsuapi_bind_handle; r_crack_names.in.level = 1; r_crack_names.in.req.req1.unknown1 = 0x000004e4; r_crack_names.in.req.req1.unknown2 = 0x00000407; r_crack_names.in.req.req1.count = 1; r_crack_names.in.req.req1.names = names; r_crack_names.in.req.req1.format_flags = DRSUAPI_DS_NAME_FLAG_NO_FLAGS; r_crack_names.in.req.req1.format_offered= DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY; r_crack_names.in.req.req1.format_desired= DRSUAPI_DS_NAME_FORMAT_FQDN_1779; names[0].str = dom_sid_string(tmp_ctx, r->out.account_sid); if (!names[0].str) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } status = dcerpc_drsuapi_DsCrackNames(drsuapi_pipe, tmp_ctx, &r_crack_names); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { r->out.error_string = talloc_asprintf(r, "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s", names[0].str, dcerpc_errstr(tmp_ctx, drsuapi_pipe->last_fault_code)); talloc_free(tmp_ctx); return status; } else { r->out.error_string = talloc_asprintf(r, "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s", names[0].str, nt_errstr(status)); talloc_free(tmp_ctx); return status; } } else if (!W_ERROR_IS_OK(r_crack_names.out.result)) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed - %s", win_errstr(r_crack_names.out.result)); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } else if (r_crack_names.out.level != 1 || !r_crack_names.out.ctr.ctr1 || r_crack_names.out.ctr.ctr1->count != 1) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed"); talloc_free(tmp_ctx); return NT_STATUS_INVALID_PARAMETER; } else if (r_crack_names.out.ctr.ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed: %d", r_crack_names.out.ctr.ctr1->array[0].status); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } else if (r_crack_names.out.ctr.ctr1->array[0].result_name == NULL) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed: no result name"); talloc_free(tmp_ctx); return NT_STATUS_INVALID_PARAMETER; } /* Store the DN of our machine account. */ account_dn_str = r_crack_names.out.ctr.ctr1->array[0].result_name; account_dn = ldb_dn_new(tmp_ctx, remote_ldb, account_dn_str); if (! ldb_dn_validate(account_dn)) { r->out.error_string = talloc_asprintf(r, "Invalid account dn: %s", account_dn_str); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } /* Now we know the user's DN, open with LDAP, read and modify a few things */ remote_ldb_url = talloc_asprintf(tmp_ctx, "ldap://%s", drsuapi_binding->target_hostname); if (!remote_ldb_url) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } remote_ldb = ldb_wrap_connect(tmp_ctx, remote_ldb_url, NULL, ctx->cred, 0, NULL); if (!remote_ldb) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } /* search for the user's record */ ret = ldb_search(remote_ldb, account_dn, LDB_SCOPE_BASE, NULL, attrs, &res); if (ret != LDB_SUCCESS) { r->out.error_string = talloc_asprintf(r, "ldb_search for %s failed - %s", account_dn_str, ldb_errstring(remote_ldb)); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } talloc_steal(tmp_ctx, res); if (res->count != 1) { r->out.error_string = talloc_asprintf(r, "ldb_search for %s failed - found %d entries", account_dn_str, res->count); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } /* If we have a kvno recorded in AD, we need it locally as well */ kvno = ldb_msg_find_attr_as_uint(res->msgs[0], "msDS-KeyVersionNumber", 0); /* Prepare a new message, for the modify */ msg = ldb_msg_new(tmp_ctx); if (!msg) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } msg->dn = res->msgs[0]->dn; { int i; const char *service_principal_name[6]; const char *dns_host_name = strlower_talloc(tmp_ctx, talloc_asprintf(tmp_ctx, "%s.%s", r->in.netbios_name, realm)); if (!dns_host_name) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } service_principal_name[0] = talloc_asprintf(tmp_ctx, "host/%s", dns_host_name); service_principal_name[1] = talloc_asprintf(tmp_ctx, "host/%s", strlower_talloc(tmp_ctx, r->in.netbios_name)); service_principal_name[2] = talloc_asprintf(tmp_ctx, "host/%s/%s", dns_host_name, realm); service_principal_name[3] = talloc_asprintf(tmp_ctx, "host/%s/%s", strlower_talloc(tmp_ctx, r->in.netbios_name), realm); service_principal_name[4] = talloc_asprintf(tmp_ctx, "host/%s/%s", dns_host_name, r->out.domain_name); service_principal_name[5] = talloc_asprintf(tmp_ctx, "host/%s/%s", strlower_talloc(tmp_ctx, r->in.netbios_name), r->out.domain_name); for (i=0; i < ARRAY_SIZE(service_principal_name); i++) { if (!service_principal_name[i]) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } rtn = samdb_msg_add_string(remote_ldb, tmp_ctx, msg, "servicePrincipalName", service_principal_name[i]); if (rtn == -1) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } } rtn = samdb_msg_add_string(remote_ldb, tmp_ctx, msg, "dNSHostName", dns_host_name); if (rtn == -1) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } rtn = samdb_replace(remote_ldb, tmp_ctx, msg); if (rtn != 0) { r->out.error_string = talloc_asprintf(r, "Failed to replace entries on %s", ldb_dn_get_linearized(msg->dn)); talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } } /* DsCrackNames to find out the DN of the domain. */ r_crack_names.in.req.req1.format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT; r_crack_names.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779; names[0].str = talloc_asprintf(tmp_ctx, "%s\\", r->out.domain_name); if (!names[0].str) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } status = dcerpc_drsuapi_DsCrackNames(drsuapi_pipe, tmp_ctx, &r_crack_names); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { r->out.error_string = talloc_asprintf(r, "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s", r->in.domain_name, dcerpc_errstr(tmp_ctx, drsuapi_pipe->last_fault_code)); talloc_free(tmp_ctx); return status; } else { r->out.error_string = talloc_asprintf(r, "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s", r->in.domain_name, nt_errstr(status)); talloc_free(tmp_ctx); return status; } } else if (!W_ERROR_IS_OK(r_crack_names.out.result)) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed - %s", win_errstr(r_crack_names.out.result)); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } else if (r_crack_names.out.level != 1 || !r_crack_names.out.ctr.ctr1 || r_crack_names.out.ctr.ctr1->count != 1 || !r_crack_names.out.ctr.ctr1->array[0].result_name || r_crack_names.out.ctr.ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed"); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } /* Store the account DN. */ r->out.account_dn_str = account_dn_str; talloc_steal(r, account_dn_str); /* Store the domain DN. */ r->out.domain_dn_str = r_crack_names.out.ctr.ctr1->array[0].result_name; talloc_steal(r, r_crack_names.out.ctr.ctr1->array[0].result_name); r->out.kvno = kvno; if (r->in.acct_type == ACB_SVRTRUST) { status = libnet_JoinSite(remote_ldb, r); } talloc_free(tmp_ctx); return status; }
/* lookup a SID for 1 name */ static NTSTATUS dcesrv_lsa_lookup_name(struct tevent_context *ev_ctx, struct loadparm_context *lp_ctx, struct lsa_policy_state *state, TALLOC_CTX *mem_ctx, const char *name, const char **authority_name, struct dom_sid **sid, enum lsa_SidType *rtype, uint32_t *rid) { int ret, i; uint32_t atype; struct ldb_message **res; const char * const attrs[] = { "objectSid", "sAMAccountType", NULL}; const char *p; const char *domain; const char *username; struct ldb_dn *domain_dn; struct dom_sid *domain_sid; NTSTATUS status; p = strchr_m(name, '\\'); if (p != NULL) { domain = talloc_strndup(mem_ctx, name, p-name); if (!domain) { return NT_STATUS_NO_MEMORY; } username = p + 1; } else if (strchr_m(name, '@')) { status = crack_name_to_nt4_name(mem_ctx, ev_ctx, lp_ctx, DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL, name, &domain, &username); if (!NT_STATUS_IS_OK(status)) { DEBUG(3, ("Failed to crack name %s into an NT4 name: %s\n", name, nt_errstr(status))); return status; } } else { domain = NULL; username = name; } if (!domain) { /* Look up table of well known names */ status = lookup_well_known_names(mem_ctx, NULL, username, authority_name, sid, rtype); if (NT_STATUS_IS_OK(status)) { dom_sid_split_rid(NULL, *sid, NULL, rid); return NT_STATUS_OK; } if (username == NULL) { *authority_name = NAME_BUILTIN; *sid = dom_sid_parse_talloc(mem_ctx, SID_BUILTIN); if (*sid == NULL) { return NT_STATUS_NO_MEMORY; } *rtype = SID_NAME_DOMAIN; *rid = 0xFFFFFFFF; return NT_STATUS_OK; } if (strcasecmp_m(username, NAME_NT_AUTHORITY) == 0) { *authority_name = NAME_NT_AUTHORITY; *sid = dom_sid_parse_talloc(mem_ctx, SID_NT_AUTHORITY); if (*sid == NULL) { return NT_STATUS_NO_MEMORY; } *rtype = SID_NAME_DOMAIN; dom_sid_split_rid(NULL, *sid, NULL, rid); return NT_STATUS_OK; } if (strcasecmp_m(username, NAME_BUILTIN) == 0) { *authority_name = NAME_BUILTIN; *sid = dom_sid_parse_talloc(mem_ctx, SID_BUILTIN); if (*sid == NULL) { return NT_STATUS_NO_MEMORY; } *rtype = SID_NAME_DOMAIN; *rid = 0xFFFFFFFF; return NT_STATUS_OK; } if (strcasecmp_m(username, state->domain_dns) == 0) { *authority_name = talloc_strdup(mem_ctx, state->domain_name); if (*authority_name == NULL) { return NT_STATUS_NO_MEMORY; } *sid = dom_sid_dup(mem_ctx, state->domain_sid); if (*sid == NULL) { return NT_STATUS_NO_MEMORY; } *rtype = SID_NAME_DOMAIN; *rid = 0xFFFFFFFF; return NT_STATUS_OK; } if (strcasecmp_m(username, state->domain_name) == 0) { *authority_name = talloc_strdup(mem_ctx, state->domain_name); if (*authority_name == NULL) { return NT_STATUS_NO_MEMORY; } *sid = dom_sid_dup(mem_ctx, state->domain_sid); if (*sid == NULL) { return NT_STATUS_NO_MEMORY; } *rtype = SID_NAME_DOMAIN; *rid = 0xFFFFFFFF; return NT_STATUS_OK; } /* Perhaps this is a well known user? */ name = talloc_asprintf(mem_ctx, "%s\\%s", NAME_NT_AUTHORITY, username); if (!name) { return NT_STATUS_NO_MEMORY; } status = dcesrv_lsa_lookup_name(ev_ctx, lp_ctx, state, mem_ctx, name, authority_name, sid, rtype, rid); if (NT_STATUS_IS_OK(status)) { return status; } /* Perhaps this is a BUILTIN user? */ name = talloc_asprintf(mem_ctx, "%s\\%s", NAME_BUILTIN, username); if (!name) { return NT_STATUS_NO_MEMORY; } status = dcesrv_lsa_lookup_name(ev_ctx, lp_ctx, state, mem_ctx, name, authority_name, sid, rtype, rid); if (NT_STATUS_IS_OK(status)) { return status; } /* OK, I give up - perhaps we need to assume the user is in our domain? */ name = talloc_asprintf(mem_ctx, "%s\\%s", state->domain_name, username); if (!name) { return NT_STATUS_NO_MEMORY; } status = dcesrv_lsa_lookup_name(ev_ctx, lp_ctx, state, mem_ctx, name, authority_name, sid, rtype, rid); if (NT_STATUS_IS_OK(status)) { return status; } return STATUS_SOME_UNMAPPED; } else if (strcasecmp_m(domain, NAME_NT_AUTHORITY) == 0) { if (!*username) { *authority_name = NAME_NT_AUTHORITY; *sid = dom_sid_parse_talloc(mem_ctx, SID_NT_AUTHORITY); if (*sid == NULL) { return NT_STATUS_NO_MEMORY; } *rtype = SID_NAME_DOMAIN; dom_sid_split_rid(NULL, *sid, NULL, rid); return NT_STATUS_OK; } /* Look up table of well known names */ status = lookup_well_known_names(mem_ctx, domain, username, authority_name, sid, rtype); if (NT_STATUS_IS_OK(status)) { dom_sid_split_rid(NULL, *sid, NULL, rid); } return status; } else if (strcasecmp_m(domain, NAME_BUILTIN) == 0) { *authority_name = NAME_BUILTIN; domain_dn = state->builtin_dn; } else if (strcasecmp_m(domain, state->domain_dns) == 0) { *authority_name = talloc_strdup(mem_ctx, state->domain_name); if (*authority_name == NULL) { return NT_STATUS_NO_MEMORY; } domain_dn = state->domain_dn; } else if (strcasecmp_m(domain, state->domain_name) == 0) { *authority_name = talloc_strdup(mem_ctx, state->domain_name); if (*authority_name == NULL) { return NT_STATUS_NO_MEMORY; } domain_dn = state->domain_dn; } else { /* Not local, need to ask winbind in future */ return STATUS_SOME_UNMAPPED; } ret = gendb_search_dn(state->sam_ldb, mem_ctx, domain_dn, &res, attrs); if (ret != 1) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } domain_sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid"); if (domain_sid == NULL) { return NT_STATUS_INVALID_SID; } if (!*username) { *sid = domain_sid; *rtype = SID_NAME_DOMAIN; *rid = 0xFFFFFFFF; return NT_STATUS_OK; } ret = gendb_search(state->sam_ldb, mem_ctx, domain_dn, &res, attrs, "(&(sAMAccountName=%s)(objectSid=*))", ldb_binary_encode_string(mem_ctx, username)); if (ret < 0) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } for (i=0; i < ret; i++) { *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid"); if (*sid == NULL) { return NT_STATUS_INVALID_SID; } /* Check that this is in the domain */ if (!dom_sid_in_domain(domain_sid, *sid)) { continue; } atype = ldb_msg_find_attr_as_uint(res[i], "sAMAccountType", 0); *rtype = ds_atype_map(atype); if (*rtype == SID_NAME_UNKNOWN) { return STATUS_SOME_UNMAPPED; } dom_sid_split_rid(NULL, *sid, NULL, rid); return NT_STATUS_OK; } /* need to check for an allocated sid */ return NT_STATUS_INVALID_SID; }
/* lookup a name for 1 SID */ static NTSTATUS dcesrv_lsa_lookup_sid(struct lsa_policy_state *state, TALLOC_CTX *mem_ctx, struct dom_sid *sid, const char *sid_str, const char **authority_name, const char **name, enum lsa_SidType *rtype) { NTSTATUS status; int ret; uint32_t atype; struct ldb_message **res; struct ldb_dn *domain_dn; const char * const attrs[] = { "sAMAccountName", "sAMAccountType", "cn", NULL}; status = lookup_well_known_sids(mem_ctx, sid_str, authority_name, name, rtype); if (NT_STATUS_IS_OK(status)) { return status; } if (dom_sid_equal(state->domain_sid, sid)) { *authority_name = talloc_strdup(mem_ctx, state->domain_name); if (*authority_name == NULL) { return NT_STATUS_NO_MEMORY; } *name = NULL; *rtype = SID_NAME_DOMAIN; return NT_STATUS_OK; } if (dom_sid_in_domain(state->domain_sid, sid)) { *authority_name = talloc_strdup(mem_ctx, state->domain_name); if (*authority_name == NULL) { return NT_STATUS_NO_MEMORY; } domain_dn = state->domain_dn; } else if (dom_sid_in_domain(state->builtin_sid, sid)) { *authority_name = NAME_BUILTIN; domain_dn = state->builtin_dn; } else { /* Not well known, our domain or built in */ /* In future, we must look at SID histories, and at trusted domains via winbind */ return NT_STATUS_NOT_FOUND; } /* need to re-add a check for an allocated sid */ ret = gendb_search(state->sam_ldb, mem_ctx, domain_dn, &res, attrs, "objectSid=%s", ldap_encode_ndr_dom_sid(mem_ctx, sid)); if ((ret < 0) || (ret > 1)) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } if (ret == 0) { return NT_STATUS_NOT_FOUND; } *name = ldb_msg_find_attr_as_string(res[0], "sAMAccountName", NULL); if (!*name) { *name = ldb_msg_find_attr_as_string(res[0], "cn", NULL); if (!*name) { *name = talloc_strdup(mem_ctx, sid_str); NT_STATUS_HAVE_NO_MEMORY(*name); } } atype = ldb_msg_find_attr_as_uint(res[0], "sAMAccountType", 0); *rtype = ds_atype_map(atype); return NT_STATUS_OK; }
/* see if we are on the last pool we have */ static int drepl_ridalloc_pool_exhausted(struct ldb_context *ldb, bool *exhausted, uint64_t *_alloc_pool) { struct ldb_dn *server_dn, *machine_dn, *rid_set_dn; TALLOC_CTX *tmp_ctx = talloc_new(ldb); uint64_t alloc_pool; uint64_t prev_pool; uint32_t prev_pool_lo, prev_pool_hi; uint32_t next_rid; static const char * const attrs[] = { "rIDAllocationPool", "rIDPreviousAllocationPool", "rIDNextRid", NULL }; int ret; struct ldb_result *res; *exhausted = false; *_alloc_pool = UINT64_MAX; server_dn = ldb_dn_get_parent(tmp_ctx, samdb_ntds_settings_dn(ldb)); if (!server_dn) { talloc_free(tmp_ctx); return ldb_operr(ldb); } ret = samdb_reference_dn(ldb, tmp_ctx, server_dn, "serverReference", &machine_dn); if (ret != LDB_SUCCESS) { DEBUG(0,(__location__ ": Failed to find serverReference in %s - %s\n", ldb_dn_get_linearized(server_dn), ldb_errstring(ldb))); talloc_free(tmp_ctx); return ret; } ret = samdb_reference_dn(ldb, tmp_ctx, machine_dn, "rIDSetReferences", &rid_set_dn); if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) { *exhausted = true; *_alloc_pool = 0; talloc_free(tmp_ctx); return LDB_SUCCESS; } if (ret != LDB_SUCCESS) { DEBUG(0,(__location__ ": Failed to find rIDSetReferences in %s - %s\n", ldb_dn_get_linearized(machine_dn), ldb_errstring(ldb))); talloc_free(tmp_ctx); return ret; } ret = ldb_search(ldb, tmp_ctx, &res, rid_set_dn, LDB_SCOPE_BASE, attrs, NULL); if (ret != LDB_SUCCESS) { DEBUG(0,(__location__ ": Failed to load RID Set attrs from %s - %s\n", ldb_dn_get_linearized(rid_set_dn), ldb_errstring(ldb))); talloc_free(tmp_ctx); return ret; } alloc_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDAllocationPool", 0); prev_pool = ldb_msg_find_attr_as_uint64(res->msgs[0], "rIDPreviousAllocationPool", 0); prev_pool_lo = prev_pool & 0xFFFFFFFF; prev_pool_hi = prev_pool >> 32; next_rid = ldb_msg_find_attr_as_uint(res->msgs[0], "rIDNextRid", 0); if (alloc_pool != prev_pool) { talloc_free(tmp_ctx); return LDB_SUCCESS; } if (next_rid < (prev_pool_hi + prev_pool_lo)/2) { talloc_free(tmp_ctx); return LDB_SUCCESS; } *exhausted = true; *_alloc_pool = alloc_pool; talloc_free(tmp_ctx); return LDB_SUCCESS; }
/* construct the token groups for SAM objects from a message */ static int construct_token_groups(struct ldb_module *module, struct ldb_message *msg, enum ldb_scope scope, struct ldb_request *parent) { struct ldb_context *ldb = ldb_module_get_ctx(module);; TALLOC_CTX *tmp_ctx = talloc_new(msg); unsigned int i; int ret; const char *filter; NTSTATUS status; struct dom_sid *primary_group_sid; const char *primary_group_string; const char *primary_group_dn; DATA_BLOB primary_group_blob; struct dom_sid *account_sid; const char *account_sid_string; const char *account_sid_dn; DATA_BLOB account_sid_blob; struct dom_sid *groupSIDs = NULL; unsigned int num_groupSIDs = 0; struct dom_sid *domain_sid; if (scope != LDB_SCOPE_BASE) { ldb_set_errstring(ldb, "Cannot provide tokenGroups attribute, this is not a BASE search"); return LDB_ERR_OPERATIONS_ERROR; } /* If it's not a user, it won't have a primaryGroupID */ if (ldb_msg_find_element(msg, "primaryGroupID") == NULL) { talloc_free(tmp_ctx); return LDB_SUCCESS; } /* Ensure it has an objectSID too */ account_sid = samdb_result_dom_sid(tmp_ctx, msg, "objectSid"); if (account_sid == NULL) { talloc_free(tmp_ctx); return LDB_SUCCESS; } status = dom_sid_split_rid(tmp_ctx, account_sid, &domain_sid, NULL); if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { talloc_free(tmp_ctx); return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; } else if (!NT_STATUS_IS_OK(status)) { talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } primary_group_sid = dom_sid_add_rid(tmp_ctx, domain_sid, ldb_msg_find_attr_as_uint(msg, "primaryGroupID", ~0)); if (!primary_group_sid) { talloc_free(tmp_ctx); return ldb_oom(ldb); } /* only return security groups */ filter = talloc_asprintf(tmp_ctx, "(&(objectClass=group)(groupType:1.2.840.113556.1.4.803:=%u))", GROUP_TYPE_SECURITY_ENABLED); if (!filter) { talloc_free(tmp_ctx); return ldb_oom(ldb); } primary_group_string = dom_sid_string(tmp_ctx, primary_group_sid); if (!primary_group_string) { talloc_free(tmp_ctx); return ldb_oom(ldb); } primary_group_dn = talloc_asprintf(tmp_ctx, "<SID=%s>", primary_group_string); if (!primary_group_dn) { talloc_free(tmp_ctx); return ldb_oom(ldb); } primary_group_blob = data_blob_string_const(primary_group_dn); account_sid_string = dom_sid_string(tmp_ctx, account_sid); if (!account_sid_string) { talloc_free(tmp_ctx); return ldb_oom(ldb); } account_sid_dn = talloc_asprintf(tmp_ctx, "<SID=%s>", account_sid_string); if (!account_sid_dn) { talloc_free(tmp_ctx); return ldb_oom(ldb); } account_sid_blob = data_blob_string_const(account_sid_dn); status = dsdb_expand_nested_groups(ldb, &account_sid_blob, true, /* We don't want to add the object's SID itself, it's not returend in this attribute */ filter, tmp_ctx, &groupSIDs, &num_groupSIDs); if (!NT_STATUS_IS_OK(status)) { ldb_asprintf_errstring(ldb, "Failed to construct tokenGroups: expanding groups of SID %s failed: %s", account_sid_string, nt_errstr(status)); talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } /* Expands the primary group - this function takes in * memberOf-like values, so we fake one up with the * <SID=S-...> format of DN and then let it expand * them, as long as they meet the filter - so only * domain groups, not builtin groups */ status = dsdb_expand_nested_groups(ldb, &primary_group_blob, false, filter, tmp_ctx, &groupSIDs, &num_groupSIDs); if (!NT_STATUS_IS_OK(status)) { ldb_asprintf_errstring(ldb, "Failed to construct tokenGroups: expanding groups of SID %s failed: %s", account_sid_string, nt_errstr(status)); talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } for (i=0; i < num_groupSIDs; i++) { ret = samdb_msg_add_dom_sid(ldb, msg, msg, "tokenGroups", &groupSIDs[i]); if (ret) { talloc_free(tmp_ctx); return ret; } } return LDB_SUCCESS; }
static void reg_ldb_unpack_value(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char **name, uint32_t *type, DATA_BLOB *data) { const struct ldb_val *val; uint32_t value_type; if (name != NULL) { *name = talloc_strdup(mem_ctx, ldb_msg_find_attr_as_string(msg, "value", "")); } value_type = ldb_msg_find_attr_as_uint(msg, "type", 0); *type = value_type; val = ldb_msg_find_ldb_val(msg, "data"); switch (value_type) { case REG_SZ: case REG_EXPAND_SZ: if (val != NULL) { /* The data should be provided as UTF16 string */ convert_string_talloc(mem_ctx, CH_UTF8, CH_UTF16, val->data, val->length, (void **)&data->data, &data->length); } else { data->data = NULL; data->length = 0; } break; case REG_DWORD: case REG_DWORD_BIG_ENDIAN: if (val != NULL) { /* The data is a plain DWORD */ uint32_t tmp = strtoul((char *)val->data, NULL, 0); data->data = talloc_size(mem_ctx, sizeof(uint32_t)); if (data->data != NULL) { SIVAL(data->data, 0, tmp); } data->length = sizeof(uint32_t); } else { data->data = NULL; data->length = 0; } break; case REG_QWORD: if (val != NULL) { /* The data is a plain QWORD */ uint64_t tmp = strtoull((char *)val->data, NULL, 0); data->data = talloc_size(mem_ctx, sizeof(uint64_t)); if (data->data != NULL) { SBVAL(data->data, 0, tmp); } data->length = sizeof(uint64_t); } else { data->data = NULL; data->length = 0; } break; case REG_BINARY: default: if (val != NULL) { data->data = talloc_memdup(mem_ctx, val->data, val->length); data->length = val->length; } else { data->data = NULL; data->length = 0; } break; } }
/* * complete a domain join, when joining to a AD domain: * 1.) connect and bind to the DRSUAPI pipe * 2.) do a DsCrackNames() to find the machine account dn * 3.) connect to LDAP * 4.) do an ldap search to find the "msDS-KeyVersionNumber" of the machine account * 5.) set the servicePrincipalName's of the machine account via LDAP, (maybe we should use DsWriteAccountSpn()...) * 6.) do a DsCrackNames() to find the domain dn * 7.) find out Site specific stuff, look at libnet_JoinSite() for details */ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_JoinDomain *r) { NTSTATUS status; TALLOC_CTX *tmp_ctx; const char *realm = r->out.realm; struct dcerpc_binding *samr_binding = r->out.samr_binding; struct dcerpc_pipe *drsuapi_pipe; struct dcerpc_binding *drsuapi_binding; struct drsuapi_DsBind r_drsuapi_bind; struct drsuapi_DsCrackNames r_crack_names; struct drsuapi_DsNameString names[1]; struct policy_handle drsuapi_bind_handle; struct GUID drsuapi_bind_guid; struct ldb_context *remote_ldb; struct ldb_dn *account_dn; const char *account_dn_str; const char *remote_ldb_url; struct ldb_result *res; struct ldb_message *msg; int ret, rtn; const char * const attrs[] = { "msDS-KeyVersionNumber", "servicePrincipalName", "dNSHostName", "objectGUID", NULL, }; r->out.error_string = NULL; /* We need to convert between a samAccountName and domain to a * DN in the directory. The correct way to do this is with * DRSUAPI CrackNames */ /* Fiddle with the bindings, so get to DRSUAPI on * NCACN_IP_TCP, sealed */ tmp_ctx = talloc_named(r, 0, "libnet_JoinADSDomain temp context"); if (!tmp_ctx) { r->out.error_string = NULL; return NT_STATUS_NO_MEMORY; } drsuapi_binding = talloc_zero(tmp_ctx, struct dcerpc_binding); if (!drsuapi_binding) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } *drsuapi_binding = *samr_binding; /* DRSUAPI is only available on IP_TCP, and locally on NCALRPC */ if (drsuapi_binding->transport != NCALRPC) { drsuapi_binding->transport = NCACN_IP_TCP; } drsuapi_binding->endpoint = NULL; drsuapi_binding->flags |= DCERPC_SEAL; status = dcerpc_pipe_connect_b(tmp_ctx, &drsuapi_pipe, drsuapi_binding, &ndr_table_drsuapi, ctx->cred, ctx->event_ctx, ctx->lp_ctx); if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(r, "Connection to DRSUAPI pipe of PDC of domain '%s' failed: %s", r->out.domain_name, nt_errstr(status)); talloc_free(tmp_ctx); return status; } /* get a DRSUAPI pipe handle */ GUID_from_string(DRSUAPI_DS_BIND_GUID, &drsuapi_bind_guid); r_drsuapi_bind.in.bind_guid = &drsuapi_bind_guid; r_drsuapi_bind.in.bind_info = NULL; r_drsuapi_bind.out.bind_handle = &drsuapi_bind_handle; status = dcerpc_drsuapi_DsBind_r(drsuapi_pipe->binding_handle, tmp_ctx, &r_drsuapi_bind); if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(r, "dcerpc_drsuapi_DsBind failed - %s", nt_errstr(status)); talloc_free(tmp_ctx); return status; } else if (!W_ERROR_IS_OK(r_drsuapi_bind.out.result)) { r->out.error_string = talloc_asprintf(r, "DsBind failed - %s", win_errstr(r_drsuapi_bind.out.result)); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } /* Actually 'crack' the names */ ZERO_STRUCT(r_crack_names); r_crack_names.in.bind_handle = &drsuapi_bind_handle; r_crack_names.in.level = 1; r_crack_names.in.req = talloc(r, union drsuapi_DsNameRequest); if (!r_crack_names.in.req) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } r_crack_names.in.req->req1.codepage = 1252; /* western european */ r_crack_names.in.req->req1.language = 0x00000407; /* german */ r_crack_names.in.req->req1.count = 1; r_crack_names.in.req->req1.names = names; r_crack_names.in.req->req1.format_flags = DRSUAPI_DS_NAME_FLAG_NO_FLAGS; r_crack_names.in.req->req1.format_offered = DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY; r_crack_names.in.req->req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779; names[0].str = dom_sid_string(tmp_ctx, r->out.account_sid); if (!names[0].str) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } r_crack_names.out.ctr = talloc(r, union drsuapi_DsNameCtr); r_crack_names.out.level_out = talloc(r, uint32_t); if (!r_crack_names.out.ctr || !r_crack_names.out.level_out) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } status = dcerpc_drsuapi_DsCrackNames_r(drsuapi_pipe->binding_handle, tmp_ctx, &r_crack_names); if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(r, "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s", names[0].str, nt_errstr(status)); talloc_free(tmp_ctx); return status; } else if (!W_ERROR_IS_OK(r_crack_names.out.result)) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed - %s", win_errstr(r_crack_names.out.result)); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } else if (*r_crack_names.out.level_out != 1 || !r_crack_names.out.ctr->ctr1 || r_crack_names.out.ctr->ctr1->count != 1) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed"); talloc_free(tmp_ctx); return NT_STATUS_INVALID_PARAMETER; } else if (r_crack_names.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed: %d", r_crack_names.out.ctr->ctr1->array[0].status); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } else if (r_crack_names.out.ctr->ctr1->array[0].result_name == NULL) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed: no result name"); talloc_free(tmp_ctx); return NT_STATUS_INVALID_PARAMETER; } /* Store the DN of our machine account. */ account_dn_str = r_crack_names.out.ctr->ctr1->array[0].result_name; /* Now we know the user's DN, open with LDAP, read and modify a few things */ remote_ldb_url = talloc_asprintf(tmp_ctx, "ldap://%s", drsuapi_binding->target_hostname); if (!remote_ldb_url) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } remote_ldb = ldb_wrap_connect(tmp_ctx, ctx->event_ctx, ctx->lp_ctx, remote_ldb_url, NULL, ctx->cred, 0); if (!remote_ldb) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } account_dn = ldb_dn_new(tmp_ctx, remote_ldb, account_dn_str); if (account_dn == NULL) { r->out.error_string = talloc_asprintf(r, "Invalid account dn: %s", account_dn_str); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } /* search for the user's record */ ret = ldb_search(remote_ldb, tmp_ctx, &res, account_dn, LDB_SCOPE_BASE, attrs, NULL); if (ret != LDB_SUCCESS) { r->out.error_string = talloc_asprintf(r, "ldb_search for %s failed - %s", account_dn_str, ldb_errstring(remote_ldb)); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } if (res->count != 1) { r->out.error_string = talloc_asprintf(r, "ldb_search for %s failed - found %d entries", account_dn_str, res->count); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } /* Prepare a new message, for the modify */ msg = ldb_msg_new(tmp_ctx); if (!msg) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } msg->dn = res->msgs[0]->dn; { unsigned int i; const char *service_principal_name[2]; const char *dns_host_name = strlower_talloc(msg, talloc_asprintf(msg, "%s.%s", r->in.netbios_name, realm)); if (!dns_host_name) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } service_principal_name[0] = talloc_asprintf(msg, "HOST/%s", dns_host_name); service_principal_name[1] = talloc_asprintf(msg, "HOST/%s", r->in.netbios_name); for (i=0; i < ARRAY_SIZE(service_principal_name); i++) { if (!service_principal_name[i]) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } rtn = ldb_msg_add_string(msg, "servicePrincipalName", service_principal_name[i]); if (rtn != LDB_SUCCESS) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } } rtn = ldb_msg_add_string(msg, "dNSHostName", dns_host_name); if (rtn != LDB_SUCCESS) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } rtn = dsdb_replace(remote_ldb, msg, 0); if (rtn != LDB_SUCCESS) { r->out.error_string = talloc_asprintf(r, "Failed to replace entries on %s", ldb_dn_get_linearized(msg->dn)); talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } } msg = ldb_msg_new(tmp_ctx); if (!msg) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } msg->dn = res->msgs[0]->dn; rtn = samdb_msg_add_uint(remote_ldb, msg, msg, "msDS-SupportedEncryptionTypes", ENC_ALL_TYPES); if (rtn != LDB_SUCCESS) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } rtn = dsdb_replace(remote_ldb, msg, 0); /* The remote server may not support this attribute, if it * isn't a modern schema */ if (rtn != LDB_SUCCESS && rtn != LDB_ERR_NO_SUCH_ATTRIBUTE) { r->out.error_string = talloc_asprintf(r, "Failed to replace msDS-SupportedEncryptionTypes on %s", ldb_dn_get_linearized(msg->dn)); talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } /* DsCrackNames to find out the DN of the domain. */ r_crack_names.in.req->req1.format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT; r_crack_names.in.req->req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779; names[0].str = talloc_asprintf(tmp_ctx, "%s\\", r->out.domain_name); if (!names[0].str) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } status = dcerpc_drsuapi_DsCrackNames_r(drsuapi_pipe->binding_handle, tmp_ctx, &r_crack_names); if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(r, "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s", r->in.domain_name, nt_errstr(status)); talloc_free(tmp_ctx); return status; } else if (!W_ERROR_IS_OK(r_crack_names.out.result)) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed - %s", win_errstr(r_crack_names.out.result)); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } else if (*r_crack_names.out.level_out != 1 || !r_crack_names.out.ctr->ctr1 || r_crack_names.out.ctr->ctr1->count != 1 || !r_crack_names.out.ctr->ctr1->array[0].result_name || r_crack_names.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed"); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } /* Store the account DN. */ r->out.account_dn_str = account_dn_str; talloc_steal(r, account_dn_str); /* Store the domain DN. */ r->out.domain_dn_str = r_crack_names.out.ctr->ctr1->array[0].result_name; talloc_steal(r, r_crack_names.out.ctr->ctr1->array[0].result_name); /* Store the KVNO of the account, critical for some kerberos * operations */ r->out.kvno = ldb_msg_find_attr_as_uint(res->msgs[0], "msDS-KeyVersionNumber", 0); /* Store the account GUID. */ r->out.account_guid = samdb_result_guid(res->msgs[0], "objectGUID"); if (r->in.acct_type == ACB_SVRTRUST) { status = libnet_JoinSite(ctx, remote_ldb, r); } talloc_free(tmp_ctx); return status; }
/* load our replication partners */ NTSTATUS wreplsrv_load_partners(struct wreplsrv_service *service) { struct wreplsrv_partner *partner; struct ldb_result *res = NULL; int ret; TALLOC_CTX *tmp_ctx; int i; uint64_t new_seqnumber; new_seqnumber = wins_config_db_get_seqnumber(service->config.ldb); /* if it's not the first run and nothing changed we're done */ if (service->config.seqnumber != 0 && service->config.seqnumber == new_seqnumber) { return NT_STATUS_OK; } tmp_ctx = talloc_new(service); NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); service->config.seqnumber = new_seqnumber; /* find the record in the WINS database */ ret = ldb_search(service->config.ldb, tmp_ctx, &res, ldb_dn_new(tmp_ctx, service->config.ldb, "CN=PARTNERS"), LDB_SCOPE_SUBTREE, NULL, "(objectClass=wreplPartner)"); if (ret != LDB_SUCCESS) goto failed; /* first disable all existing partners */ for (partner=service->partners; partner; partner = partner->next) { partner->type = WINSREPL_PARTNER_NONE; } for (i=0; i < res->count; i++) { const char *address; address = ldb_msg_find_attr_as_string(res->msgs[i], "address", NULL); if (!address) { goto failed; } partner = wreplsrv_find_partner(service, address); if (partner) { if (partner->name != partner->address) { talloc_free(discard_const(partner->name)); } partner->name = NULL; talloc_free(discard_const(partner->our_address)); partner->our_address = NULL; /* force rescheduling of pulling */ partner->pull.next_run = timeval_zero(); } else { partner = talloc_zero(service, struct wreplsrv_partner); if (partner == NULL) goto failed; partner->service = service; partner->address = address; talloc_steal(partner, partner->address); DLIST_ADD_END(service->partners, partner, struct wreplsrv_partner *); } partner->name = ldb_msg_find_attr_as_string(res->msgs[i], "name", partner->address); talloc_steal(partner, partner->name); partner->our_address = ldb_msg_find_attr_as_string(res->msgs[i], "ourAddress", NULL); talloc_steal(partner, partner->our_address); partner->type = ldb_msg_find_attr_as_uint(res->msgs[i], "type", WINSREPL_PARTNER_BOTH); partner->pull.interval = ldb_msg_find_attr_as_uint(res->msgs[i], "pullInterval", WINSREPL_DEFAULT_PULL_INTERVAL); partner->pull.retry_interval = ldb_msg_find_attr_as_uint(res->msgs[i], "pullRetryInterval", WINSREPL_DEFAULT_PULL_RETRY_INTERVAL); partner->push.change_count = ldb_msg_find_attr_as_uint(res->msgs[i], "pushChangeCount", WINSREPL_DEFAULT_PUSH_CHANGE_COUNT); partner->push.use_inform = ldb_msg_find_attr_as_uint(res->msgs[i], "pushUseInform", true); DEBUG(3,("wreplsrv_load_partners: found partner: %s type: 0x%X\n", partner->address, partner->type)); } DEBUG(2,("wreplsrv_load_partners: %u partners found: wins_config_db seqnumber %llu\n", res->count, (unsigned long long)service->config.seqnumber)); talloc_free(tmp_ctx); return NT_STATUS_OK; failed: talloc_free(tmp_ctx); return NT_STATUS_FOOBAR; }
/* Printer functions */ static WERROR sptr_EnumPrinters(struct ntptr_context *ntptr, TALLOC_CTX *mem_ctx, struct spoolss_EnumPrinters *r) { struct ldb_context *sptr_db = talloc_get_type(ntptr->private_data, struct ldb_context); struct ldb_message **msgs; int count; int i; union spoolss_PrinterInfo *info; count = sptr_db_search(sptr_db, mem_ctx, NULL, &msgs, NULL, "(&(objectclass=printer))"); if (count == 0) return WERR_OK; if (count < 0) return WERR_GENERAL_FAILURE; info = talloc_array(mem_ctx, union spoolss_PrinterInfo, count); W_ERROR_HAVE_NO_MEMORY(info); switch(r->in.level) { case 1: for (i = 0; i < count; i++) { info[i].info1.flags = ldb_msg_find_attr_as_uint(msgs[i], "flags", 0); info[i].info1.name = ldb_msg_find_attr_as_string(msgs[i], "name", ""); W_ERROR_HAVE_NO_MEMORY(info[i].info1.name); info[i].info1.description = ldb_msg_find_attr_as_string(msgs[i], "description", ""); W_ERROR_HAVE_NO_MEMORY(info[i].info1.description); info[i].info1.comment = ldb_msg_find_attr_as_string(msgs[i], "comment", NULL); } break; case 2: for (i = 0; i < count; i++) { info[i].info2.servername = ldb_msg_find_attr_as_string(msgs[i], "servername", ""); W_ERROR_HAVE_NO_MEMORY(info[i].info2.servername); info[i].info2.printername = ldb_msg_find_attr_as_string(msgs[i], "printername", ""); W_ERROR_HAVE_NO_MEMORY(info[i].info2.printername); info[i].info2.sharename = ldb_msg_find_attr_as_string(msgs[i], "sharename", ""); W_ERROR_HAVE_NO_MEMORY(info[i].info2.sharename); info[i].info2.portname = ldb_msg_find_attr_as_string(msgs[i], "portname", ""); W_ERROR_HAVE_NO_MEMORY(info[i].info2.portname); info[i].info2.drivername = ldb_msg_find_attr_as_string(msgs[i], "drivername", ""); W_ERROR_HAVE_NO_MEMORY(info[i].info2.drivername); info[i].info2.comment = ldb_msg_find_attr_as_string(msgs[i], "comment", NULL); info[i].info2.location = ldb_msg_find_attr_as_string(msgs[i], "location", NULL); info[i].info2.devmode = NULL; info[i].info2.sepfile = ldb_msg_find_attr_as_string(msgs[i], "sepfile", NULL); info[i].info2.printprocessor = ldb_msg_find_attr_as_string(msgs[i], "printprocessor", ""); W_ERROR_HAVE_NO_MEMORY(info[i].info2.printprocessor); info[i].info2.datatype = ldb_msg_find_attr_as_string(msgs[i], "datatype", ""); W_ERROR_HAVE_NO_MEMORY(info[i].info2.datatype); info[i].info2.parameters = ldb_msg_find_attr_as_string(msgs[i], "parameters", NULL); info[i].info2.secdesc = NULL; info[i].info2.attributes = ldb_msg_find_attr_as_uint(msgs[i], "attributes", 0); info[i].info2.priority = ldb_msg_find_attr_as_uint(msgs[i], "priority", 0); info[i].info2.defaultpriority = ldb_msg_find_attr_as_uint(msgs[i], "defaultpriority", 0); info[i].info2.starttime = ldb_msg_find_attr_as_uint(msgs[i], "starttime", 0); info[i].info2.untiltime = ldb_msg_find_attr_as_uint(msgs[i], "untiltime", 0); info[i].info2.status = ldb_msg_find_attr_as_uint(msgs[i], "status", 0); info[i].info2.cjobs = ldb_msg_find_attr_as_uint(msgs[i], "cjobs", 0); info[i].info2.averageppm = ldb_msg_find_attr_as_uint(msgs[i], "averageppm", 0); } break; case 4: for (i = 0; i < count; i++) { info[i].info4.printername = ldb_msg_find_attr_as_string(msgs[i], "printername", ""); W_ERROR_HAVE_NO_MEMORY(info[i].info2.printername); info[i].info4.servername = ldb_msg_find_attr_as_string(msgs[i], "servername", ""); W_ERROR_HAVE_NO_MEMORY(info[i].info2.servername); info[i].info4.attributes = ldb_msg_find_attr_as_uint(msgs[i], "attributes", 0); } break; case 5: for (i = 0; i < count; i++) { info[i].info5.printername = ldb_msg_find_attr_as_string(msgs[i], "name", ""); W_ERROR_HAVE_NO_MEMORY(info[i].info5.printername); info[i].info5.portname = ldb_msg_find_attr_as_string(msgs[i], "port", ""); W_ERROR_HAVE_NO_MEMORY(info[i].info5.portname); info[i].info5.attributes = ldb_msg_find_attr_as_uint(msgs[i], "attributes", 0); info[i].info5.device_not_selected_timeout = ldb_msg_find_attr_as_uint(msgs[i], "device_not_selected_timeout", 0); info[i].info5.transmission_retry_timeout = ldb_msg_find_attr_as_uint(msgs[i], "transmission_retry_timeout", 0); } break; default: return WERR_UNKNOWN_LEVEL; } *r->out.info = info; *r->out.count = count; return WERR_OK; }
/* add_record: add instancetype attribute */ static int instancetype_add(struct ldb_module *module, struct ldb_request *req) { struct ldb_context *ldb = ldb_module_get_ctx(module); struct ldb_request *down_req; struct ldb_message *msg; struct ldb_message_element *el; uint32_t instanceType; int ret; /* do not manipulate our control entries */ if (ldb_dn_is_special(req->op.add.message->dn)) { return ldb_next_request(module, req); } ldb_debug(ldb, LDB_DEBUG_TRACE, "instancetype_add\n"); el = ldb_msg_find_element(req->op.add.message, "instanceType"); if (el != NULL) { if (el->num_values != 1) { ldb_set_errstring(ldb, "instancetype: the 'instanceType' attribute is single-valued!"); return LDB_ERR_UNWILLING_TO_PERFORM; } instanceType = ldb_msg_find_attr_as_uint(req->op.add.message, "instanceType", 0); if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) { /* * If we have no NC add operation (no TYPE_IS_NC_HEAD) * then "instanceType" can only be "0" or "TYPE_WRITE". */ if ((instanceType != 0) && ((instanceType & INSTANCE_TYPE_WRITE) == 0)) { ldb_set_errstring(ldb, "instancetype: if TYPE_IS_NC_HEAD wasn't set, then only TYPE_WRITE or 0 are allowed!"); return LDB_ERR_UNWILLING_TO_PERFORM; } } else { /* * If we have a NC add operation then we need also the * "TYPE_WRITE" flag in order to succeed, * unless this NC is not instantiated */ if (!(instanceType & INSTANCE_TYPE_UNINSTANT) && !(instanceType & INSTANCE_TYPE_WRITE)) { ldb_set_errstring(ldb, "instancetype: if TYPE_IS_NC_HEAD was set, then also TYPE_WRITE is requested!"); return LDB_ERR_UNWILLING_TO_PERFORM; } } /* we did only tests, so proceed with the original request */ return ldb_next_request(module, req); } /* we have to copy the message as the caller might have it as a const */ msg = ldb_msg_copy_shallow(req, req->op.add.message); if (msg == NULL) { return ldb_oom(ldb); } /* * TODO: calculate correct instance type */ instanceType = INSTANCE_TYPE_WRITE; ret = samdb_msg_add_uint(ldb, msg, msg, "instanceType", instanceType); if (ret != LDB_SUCCESS) { return ret; } ret = ldb_build_add_req(&down_req, ldb, req, msg, req->controls, req, dsdb_next_callback, req); LDB_REQ_SET_LOCATION(down_req); if (ret != LDB_SUCCESS) { return ret; } /* go on with the call chain */ return ldb_next_request(module, down_req); }
/* construct the parent GUID for an entry from a message */ static int construct_parent_guid(struct ldb_module *module, struct ldb_message *msg, enum ldb_scope scope, struct ldb_request *parent) { struct ldb_result *res, *parent_res; const struct ldb_val *parent_guid; const char *attrs[] = { "instanceType", NULL }; const char *attrs2[] = { "objectGUID", NULL }; uint32_t instanceType; int ret; struct ldb_dn *parent_dn; struct ldb_val v; /* determine if the object is NC by instance type */ ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs, DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_RECYCLED, parent); if (ret != LDB_SUCCESS) { return ret; } instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", 0); talloc_free(res); if (instanceType & INSTANCE_TYPE_IS_NC_HEAD) { DEBUG(4,(__location__ ": Object %s is NC\n", ldb_dn_get_linearized(msg->dn))); return LDB_SUCCESS; } parent_dn = ldb_dn_get_parent(msg, msg->dn); if (parent_dn == NULL) { DEBUG(4,(__location__ ": Failed to find parent for dn %s\n", ldb_dn_get_linearized(msg->dn))); return LDB_SUCCESS; } ret = dsdb_module_search_dn(module, msg, &parent_res, parent_dn, attrs2, DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_RECYCLED, parent); talloc_free(parent_dn); /* not NC, so the object should have a parent*/ if (ret == LDB_ERR_NO_SUCH_OBJECT) { return ldb_error(ldb_module_get_ctx(module), LDB_ERR_OPERATIONS_ERROR, talloc_asprintf(msg, "Parent dn for %s does not exist", ldb_dn_get_linearized(msg->dn))); } else if (ret != LDB_SUCCESS) { return ret; } parent_guid = ldb_msg_find_ldb_val(parent_res->msgs[0], "objectGUID"); if (!parent_guid) { talloc_free(parent_res); return LDB_SUCCESS; } v = data_blob_dup_talloc(parent_res, *parent_guid); if (!v.data) { talloc_free(parent_res); return ldb_oom(ldb_module_get_ctx(module)); } ret = ldb_msg_add_steal_value(msg, "parentGUID", &v); talloc_free(parent_res); return ret; }
_PUBLIC_ NTSTATUS authsam_make_user_info_dc(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx, const char *netbios_name, const char *domain_name, struct ldb_dn *domain_dn, struct ldb_message *msg, DATA_BLOB user_sess_key, DATA_BLOB lm_sess_key, struct auth_user_info_dc **_user_info_dc) { NTSTATUS status; struct auth_user_info_dc *user_info_dc; struct auth_user_info *info; const char *str, *filter; /* SIDs for the account and his primary group */ struct dom_sid *account_sid; const char *primary_group_string; const char *primary_group_dn; DATA_BLOB primary_group_blob; /* SID structures for the expanded group memberships */ struct dom_sid *sids = NULL; unsigned int num_sids = 0, i; struct dom_sid *domain_sid; TALLOC_CTX *tmp_ctx; struct ldb_message_element *el; user_info_dc = talloc(mem_ctx, struct auth_user_info_dc); NT_STATUS_HAVE_NO_MEMORY(user_info_dc); tmp_ctx = talloc_new(user_info_dc); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(user_info_dc, user_info_dc); sids = talloc_array(user_info_dc, struct dom_sid, 2); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sids, user_info_dc); num_sids = 2; account_sid = samdb_result_dom_sid(user_info_dc, msg, "objectSid"); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(account_sid, user_info_dc); status = dom_sid_split_rid(tmp_ctx, account_sid, &domain_sid, NULL); if (!NT_STATUS_IS_OK(status)) { talloc_free(user_info_dc); return status; } sids[PRIMARY_USER_SID_INDEX] = *account_sid; sids[PRIMARY_GROUP_SID_INDEX] = *domain_sid; sid_append_rid(&sids[PRIMARY_GROUP_SID_INDEX], ldb_msg_find_attr_as_uint(msg, "primaryGroupID", ~0)); /* Filter out builtin groups from this token. We will search * for builtin groups later, and not include them in the PAC * on SamLogon validation info */ filter = talloc_asprintf(tmp_ctx, "(&(objectClass=group)(!(groupType:1.2.840.113556.1.4.803:=%u))(groupType:1.2.840.113556.1.4.803:=%u))", GROUP_TYPE_BUILTIN_LOCAL_GROUP, GROUP_TYPE_SECURITY_ENABLED); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(filter, user_info_dc); primary_group_string = dom_sid_string(tmp_ctx, &sids[PRIMARY_GROUP_SID_INDEX]); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(primary_group_string, user_info_dc); primary_group_dn = talloc_asprintf(tmp_ctx, "<SID=%s>", primary_group_string); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(primary_group_dn, user_info_dc); primary_group_blob = data_blob_string_const(primary_group_dn); /* Expands the primary group - this function takes in * memberOf-like values, so we fake one up with the * <SID=S-...> format of DN and then let it expand * them, as long as they meet the filter - so only * domain groups, not builtin groups * * The primary group is still treated specially, so we set the * 'only childs' flag to true */ status = dsdb_expand_nested_groups(sam_ctx, &primary_group_blob, true, filter, user_info_dc, &sids, &num_sids); if (!NT_STATUS_IS_OK(status)) { talloc_free(user_info_dc); return status; } /* Expands the additional groups */ el = ldb_msg_find_element(msg, "memberOf"); for (i = 0; el && i < el->num_values; i++) { /* This function takes in memberOf values and expands * them, as long as they meet the filter - so only * domain groups, not builtin groups */ status = dsdb_expand_nested_groups(sam_ctx, &el->values[i], false, filter, user_info_dc, &sids, &num_sids); if (!NT_STATUS_IS_OK(status)) { talloc_free(user_info_dc); return status; } } user_info_dc->sids = sids; user_info_dc->num_sids = num_sids; user_info_dc->info = info = talloc_zero(user_info_dc, struct auth_user_info); NT_STATUS_HAVE_NO_MEMORY(user_info_dc->info); info->account_name = talloc_steal(info, ldb_msg_find_attr_as_string(msg, "sAMAccountName", NULL)); info->domain_name = talloc_strdup(info, domain_name); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(info->domain_name, user_info_dc); str = ldb_msg_find_attr_as_string(msg, "displayName", ""); info->full_name = talloc_strdup(info, str); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(info->full_name, user_info_dc); str = ldb_msg_find_attr_as_string(msg, "scriptPath", ""); info->logon_script = talloc_strdup(info, str); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(info->logon_script, user_info_dc); str = ldb_msg_find_attr_as_string(msg, "profilePath", ""); info->profile_path = talloc_strdup(info, str); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(info->profile_path, user_info_dc); str = ldb_msg_find_attr_as_string(msg, "homeDirectory", ""); info->home_directory = talloc_strdup(info, str); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(info->home_directory, user_info_dc); str = ldb_msg_find_attr_as_string(msg, "homeDrive", ""); info->home_drive = talloc_strdup(info, str); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(info->home_drive, user_info_dc); info->logon_server = talloc_strdup(info, netbios_name); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(info->logon_server, user_info_dc); info->last_logon = samdb_result_nttime(msg, "lastLogon", 0); info->last_logoff = samdb_result_last_logoff(msg); info->acct_expiry = samdb_result_account_expires(msg); info->last_password_change = samdb_result_nttime(msg, "pwdLastSet", 0); info->allow_password_change = samdb_result_allow_password_change(sam_ctx, mem_ctx, domain_dn, msg, "pwdLastSet"); info->force_password_change = samdb_result_force_password_change(sam_ctx, mem_ctx, domain_dn, msg); info->logon_count = ldb_msg_find_attr_as_uint(msg, "logonCount", 0); info->bad_password_count = ldb_msg_find_attr_as_uint(msg, "badPwdCount", 0); info->acct_flags = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, domain_dn); user_info_dc->user_session_key = data_blob_talloc(user_info_dc, user_sess_key.data, user_sess_key.length); if (user_sess_key.data) { NT_STATUS_HAVE_NO_MEMORY_AND_FREE(user_info_dc->user_session_key.data, user_info_dc); } user_info_dc->lm_session_key = data_blob_talloc(user_info_dc, lm_sess_key.data, lm_sess_key.length); if (lm_sess_key.data) { NT_STATUS_HAVE_NO_MEMORY_AND_FREE(user_info_dc->lm_session_key.data, user_info_dc); } if (info->acct_flags & ACB_SVRTRUST) { /* the SID_NT_ENTERPRISE_DCS SID gets added into the PAC */ user_info_dc->sids = talloc_realloc(user_info_dc, user_info_dc->sids, struct dom_sid, user_info_dc->num_sids+1); NT_STATUS_HAVE_NO_MEMORY_AND_FREE(user_info_dc->sids, user_info_dc); user_info_dc->sids[user_info_dc->num_sids] = global_sid_Enterprise_DCs; user_info_dc->num_sids++; }
NTSTATUS dsdb_lookup_rids(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct dom_sid *domain_sid, unsigned int num_rids, uint32_t *rids, const char **names, enum lsa_SidType *lsa_attrs) { const char *attrs[] = { "sAMAccountType", "sAMAccountName", NULL }; unsigned int i, num_mapped; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); num_mapped = 0; for (i=0; i<num_rids; i++) { struct ldb_message *msg; struct ldb_dn *dn; uint32_t attr; int rc; lsa_attrs[i] = SID_NAME_UNKNOWN; dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<SID=%s>", dom_sid_string(tmp_ctx, dom_sid_add_rid(tmp_ctx, domain_sid, rids[i]))); if (dn == NULL) { talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } rc = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE, attrs, 0, "samAccountName=*"); if (rc == LDB_ERR_NO_SUCH_OBJECT) { continue; } else if (rc != LDB_SUCCESS) { talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } names[i] = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL); if (names[i] == NULL) { DEBUG(10, ("no samAccountName\n")); continue; } talloc_steal(names, names[i]); attr = ldb_msg_find_attr_as_uint(msg, "samAccountType", 0); lsa_attrs[i] = ds_atype_map(attr); if (lsa_attrs[i] == SID_NAME_UNKNOWN) { continue; } num_mapped += 1; } talloc_free(tmp_ctx); if (num_mapped == 0) { return NT_STATUS_NONE_MAPPED; } if (num_mapped < num_rids) { return STATUS_SOME_UNMAPPED; } return NT_STATUS_OK; }
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); if (state->sam_ldb == 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 = samdb_root_dn(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 = lp_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; }