/** \details Initialize ldb_context to samdb, creates one for all emsmdbp contexts \param lp_ctx pointer to the loadparm context */ static struct ldb_context *samdb_init(struct loadparm_context *lp_ctx) { TALLOC_CTX *mem_ctx; struct tevent_context *ev; const char *samdb_url; if (samdb_ctx) return samdb_ctx; mem_ctx = talloc_autofree_context(); ev = tevent_context_init(mem_ctx); if (!ev) { OC_PANIC(false, ("Fail to initialize tevent_context\n")); return NULL; } tevent_loop_allow_nesting(ev); /* Retrieve samdb url (local or external) */ samdb_url = lpcfg_parm_string(lp_ctx, NULL, "dcerpc_mapiproxy", "samdb_url"); if (!samdb_url) { samdb_ctx = samdb_connect(mem_ctx, ev, lp_ctx, system_session(lp_ctx), 0); } else { samdb_ctx = samdb_connect_url(mem_ctx, ev, lp_ctx, system_session(lp_ctx), LDB_FLG_RECONNECT, samdb_url); } return samdb_ctx; }
/** \details Initialize the EMSABP context and open connections to Samba databases. \param lp_ctx pointer to the loadparm context \param tdb_ctx pointer to the EMSABP TDB context \return Allocated emsabp_context on success, otherwise NULL */ _PUBLIC_ struct emsabp_context *emsabp_init(struct loadparm_context *lp_ctx, TDB_CONTEXT *tdb_ctx) { TALLOC_CTX *mem_ctx; struct emsabp_context *emsabp_ctx; struct tevent_context *ev; const char *samdb_url; /* Sanity checks */ if (!lp_ctx) return NULL; mem_ctx = talloc_named(NULL, 0, "emsabp_init"); emsabp_ctx = talloc_zero(mem_ctx, struct emsabp_context); if (!emsabp_ctx) { talloc_free(mem_ctx); return NULL; } emsabp_ctx->mem_ctx = mem_ctx; ev = tevent_context_init(mem_ctx); if (!ev) { talloc_free(mem_ctx); return NULL; } tevent_loop_allow_nesting(ev); /* Save a pointer to the loadparm context */ emsabp_ctx->lp_ctx = lp_ctx; /* Retrieve samdb url (local or external) */ samdb_url = lpcfg_parm_string(lp_ctx, NULL, "dcerpc_mapiproxy", "samdb_url"); /* return an opaque context pointer on samDB database */ if (!samdb_url) { emsabp_ctx->samdb_ctx = samdb_connect(mem_ctx, ev, lp_ctx, system_session(lp_ctx), 0); } else { emsabp_ctx->samdb_ctx = samdb_connect_url(mem_ctx, ev, lp_ctx, system_session(lp_ctx), 0, samdb_url); } if (!emsabp_ctx->samdb_ctx) { talloc_free(mem_ctx); DEBUG(0, ("[%s:%d]: Connection to \"sam.ldb\" failed\n", __FUNCTION__, __LINE__)); return NULL; } /* Reference the global TDB context to the current emsabp context */ emsabp_ctx->tdb_ctx = tdb_ctx; /* Initialize a temporary (on-memory) TDB database to store * temporary MId used within EMSABP */ emsabp_ctx->ttdb_ctx = emsabp_tdb_init_tmp(emsabp_ctx->mem_ctx); if (!emsabp_ctx->ttdb_ctx) { smb_panic("unable to create on-memory TDB database"); } return emsabp_ctx; }
/** connect to the schannel ldb */ struct ldb_context *schannel_db_connect(TALLOC_CTX *mem_ctx) { char *path; struct ldb_context *ldb; BOOL existed; const char *init_ldif = "dn: @ATTRIBUTES\n" \ "computerName: CASE_INSENSITIVE\n" \ "flatname: CASE_INSENSITIVE\n"; path = smbd_tmp_path(mem_ctx, "schannel.ldb"); if (!path) { return NULL; } existed = file_exist(path); ldb = ldb_wrap_connect(mem_ctx, path, system_session(mem_ctx), NULL, LDB_FLG_NOSYNC, NULL); talloc_free(path); if (!ldb) { return NULL; } if (!existed) { gendb_add_ldif(ldb, init_ldif); } return ldb; }
static NTSTATUS sldb_init(TALLOC_CTX *mem_ctx, const struct share_ops *ops, struct tevent_context *ev_ctx, struct loadparm_context *lp_ctx, struct share_context **ctx) { struct ldb_context *sdb; *ctx = talloc(mem_ctx, struct share_context); if (!*ctx) { DEBUG(0, ("ERROR: Out of memory!\n")); return NT_STATUS_NO_MEMORY; } sdb = ldb_wrap_connect(*ctx, ev_ctx, lp_ctx, private_path(*ctx, lp_ctx, "share.ldb"), system_session(lp_ctx), NULL, 0); if (!sdb) { talloc_free(*ctx); return NT_STATUS_UNSUCCESSFUL; } (*ctx)->ops = ops; (*ctx)->priv_data = (void *)sdb; return NT_STATUS_OK; }
int net_samsync_ldb(struct net_context *ctx, int argc, const char **argv) { NTSTATUS status; struct libnet_context *libnetctx; struct libnet_samsync_ldb r; libnetctx = libnet_context_init(ctx->event_ctx, ctx->lp_ctx); if (!libnetctx) { return -1; } libnetctx->cred = ctx->credentials; r.out.error_string = NULL; r.in.machine_account = NULL; r.in.binding_string = NULL; /* Needed to override the ACLs on ldb */ r.in.session_info = system_session(libnetctx, ctx->lp_ctx); status = libnet_samsync_ldb(libnetctx, libnetctx, &r); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("libnet_samsync_ldb returned %s: %s\n", nt_errstr(status), r.out.error_string)); return -1; } talloc_free(libnetctx); return 0; }
/* pre-open the sam ldb to ensure the schema has been loaded. This saves a lot of time in child processes */ static void prime_samdb_schema(struct tevent_context *event_ctx) { TALLOC_CTX *samdb_context; samdb_context = talloc_new(event_ctx); samdb_connect(samdb_context, event_ctx, cmdline_lp_ctx, system_session(samdb_context, cmdline_lp_ctx)); talloc_free(samdb_context); }
static isc_result_t dlz_bind9_writeable_zone_hook(dns_view_t *view, const char *zone_name) { struct torture_context *tctx = talloc_get_type((void *)view, struct torture_context); struct ldb_context *samdb = samdb_connect_url(tctx, NULL, tctx->lp_ctx, system_session(tctx->lp_ctx), 0, lpcfg_private_path(tctx, tctx->lp_ctx, "dns/sam.ldb")); struct ldb_message *msg; int ret; const char *attrs[] = { NULL }; if (!samdb) { torture_fail(tctx, "Failed to connect to samdb"); return ISC_R_FAILURE; } ret = dsdb_search_one(samdb, tctx, &msg, NULL, LDB_SCOPE_SUBTREE, attrs, DSDB_SEARCH_SEARCH_ALL_PARTITIONS, "(&(objectClass=dnsZone)(name=%s))", zone_name); if (ret != LDB_SUCCESS) { torture_fail(tctx, talloc_asprintf(tctx, "Failed to search for %s: %s", zone_name, ldb_errstring(samdb))); return ISC_R_FAILURE; } talloc_free(msg); return ISC_R_SUCCESS; }
static struct ldb_context *wins_config_db_connect(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx, struct loadparm_context *lp_ctx) { return ldb_wrap_connect(mem_ctx, ev_ctx, lp_ctx, private_path(mem_ctx, lp_ctx, lp_wins_config_url(lp_ctx)), system_session(mem_ctx, lp_ctx), NULL, 0, NULL); }
/* startup the nbtd task */ static void nbtd_task_init(struct task_server *task) { struct nbtd_server *nbtsrv; NTSTATUS status; struct interface *ifaces; load_interface_list(task, task->lp_ctx, &ifaces); if (iface_list_count(ifaces) == 0) { task_server_terminate(task, "nbtd: no network interfaces configured", false); return; } if (lpcfg_disable_netbios(task->lp_ctx)) { task_server_terminate(task, "nbtd: 'disable netbios = yes' set in smb.conf, shutting down nbt server", false); return; } task_server_set_title(task, "task[nbtd]"); nbtsrv = talloc(task, struct nbtd_server); if (nbtsrv == NULL) { task_server_terminate(task, "nbtd: out of memory", true); return; } nbtsrv->task = task; nbtsrv->interfaces = NULL; nbtsrv->bcast_interface = NULL; nbtsrv->wins_interface = NULL; /* start listening on the configured network interfaces */ status = nbtd_startup_interfaces(nbtsrv, task->lp_ctx, ifaces); if (!NT_STATUS_IS_OK(status)) { task_server_terminate(task, "nbtd failed to setup interfaces", true); return; } nbtsrv->sam_ctx = samdb_connect(nbtsrv, task->event_ctx, task->lp_ctx, system_session(task->lp_ctx), 0); if (nbtsrv->sam_ctx == NULL) { task_server_terminate(task, "nbtd failed to open samdb", true); return; } /* start the WINS server, if appropriate */ status = nbtd_winsserver_init(nbtsrv); if (!NT_STATUS_IS_OK(status)) { task_server_terminate(task, "nbtd failed to start WINS server", true); return; } nbtd_register_irpc(nbtsrv); /* start the process of registering our names on all interfaces */ nbtd_register_names(nbtsrv); irpc_add_name(task->msg_ctx, "nbt_server"); }
/* establish system creds */ static WERROR kccsrv_init_creds(struct kccsrv_service *service) { service->system_session_info = system_session(service->task->lp_ctx); if (!service->system_session_info) { return WERR_NOMEM; } return WERR_OK; }
static WERROR dreplsrv_init_creds(struct dreplsrv_service *service) { service->system_session_info = system_session(service->task->lp_ctx); if (service->system_session_info == NULL) { return WERR_NOMEM; } return WERR_OK; }
/* startup the cldapd task */ static void cldapd_task_init(struct task_server *task) { struct cldapd_server *cldapd; NTSTATUS status; struct interface *ifaces; load_interface_list(task, task->lp_ctx, &ifaces); if (iface_list_count(ifaces) == 0) { task_server_terminate(task, "cldapd: no network interfaces configured", false); return; } switch (lpcfg_server_role(task->lp_ctx)) { case ROLE_STANDALONE: task_server_terminate(task, "cldap_server: no CLDAP server required in standalone configuration", false); return; case ROLE_DOMAIN_MEMBER: task_server_terminate(task, "cldap_server: no CLDAP server required in member server configuration", false); return; case ROLE_ACTIVE_DIRECTORY_DC: /* Yes, we want an CLDAP server */ break; } task_server_set_title(task, "task[cldapd]"); cldapd = talloc(task, struct cldapd_server); if (cldapd == NULL) { task_server_terminate(task, "cldapd: out of memory", true); return; } cldapd->task = task; cldapd->samctx = samdb_connect(cldapd, task->event_ctx, task->lp_ctx, system_session(task->lp_ctx), NULL, 0); if (cldapd->samctx == NULL) { task_server_terminate(task, "cldapd failed to open samdb", true); return; } /* start listening on the configured network interfaces */ status = cldapd_startup_interfaces(cldapd, task->lp_ctx, ifaces); if (!NT_STATUS_IS_OK(status)) { task_server_terminate(task, "cldapd failed to setup interfaces", true); return; } irpc_add_name(task->msg_ctx, "cldap_server"); }
/* pre-open the key databases. This saves a lot of time in child processes */ static void prime_ldb_databases(struct tevent_context *event_ctx) { TALLOC_CTX *db_context; db_context = talloc_new(event_ctx); samdb_connect(db_context, event_ctx, cmdline_lp_ctx, system_session(cmdline_lp_ctx), 0); privilege_connect(db_context, cmdline_lp_ctx); /* we deliberately leave these open, which allows them to be * re-used in ldb_wrap_connect() */ }
static void ldapsrv_accept_priv(struct stream_connection *c) { struct ldapsrv_service *ldapsrv_service = talloc_get_type_abort( c->private_data, struct ldapsrv_service); struct auth_session_info *session_info; session_info = system_session(ldapsrv_service->task->lp_ctx); if (!session_info) { stream_terminate_connection(c, "failed to setup system " "session info"); return; } ldapsrv_accept(c, session_info); }
static PyObject *py_system_session(PyObject *module, PyObject *args) { PyObject *py_lp_ctx = Py_None; struct loadparm_context *lp_ctx = NULL; struct auth_session_info *session; if (!PyArg_ParseTuple(args, "|O", &py_lp_ctx)) return NULL; lp_ctx = lp_from_py_object(py_lp_ctx); if (lp_ctx == NULL) return NULL; session = system_session(lp_ctx); return PyAuthSession_FromSession(session); }
/* setup the privilege mask for this security token based on our local SAM */ NTSTATUS samdb_privilege_setup(struct tevent_context *ev_ctx, struct loadparm_context *lp_ctx, struct security_token *token) { void *samctx; TALLOC_CTX *mem_ctx; int i; NTSTATUS status; /* Shortcuts to prevent recursion and avoid lookups */ if (token->user_sid == NULL) { token->privilege_mask = 0; return NT_STATUS_OK; } if (security_token_is_system(token)) { token->privilege_mask = ~0; return NT_STATUS_OK; } if (security_token_is_anonymous(token)) { token->privilege_mask = 0; return NT_STATUS_OK; } mem_ctx = talloc_new(token); samctx = samdb_connect(mem_ctx, ev_ctx, lp_ctx, system_session(mem_ctx, lp_ctx)); if (samctx == NULL) { talloc_free(mem_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } token->privilege_mask = 0; for (i=0;i<token->num_sids;i++) { status = samdb_privilege_setup_sid(samctx, mem_ctx, token, token->sids[i]); if (!NT_STATUS_IS_OK(status)) { talloc_free(mem_ctx); return status; } } talloc_free(mem_ctx); return NT_STATUS_OK; }
/* Used in the gensec_gssapi and gensec_krb5 server-side code, where the PAC isn't available */ NTSTATUS authsam_get_server_info_principal(TALLOC_CTX *mem_ctx, struct auth_context *auth_context, const char *principal, struct auth_serversupplied_info **server_info) { NTSTATUS nt_status; DATA_BLOB user_sess_key = data_blob(NULL, 0); DATA_BLOB lm_sess_key = data_blob(NULL, 0); struct ldb_message *msg; struct ldb_context *sam_ctx; struct ldb_dn *domain_dn; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); if (!tmp_ctx) { return NT_STATUS_NO_MEMORY; } sam_ctx = samdb_connect(tmp_ctx, auth_context->event_ctx, auth_context->lp_ctx, system_session(tmp_ctx, auth_context->lp_ctx)); if (sam_ctx == NULL) { talloc_free(tmp_ctx); return NT_STATUS_INVALID_SYSTEM_SERVICE; } nt_status = sam_get_results_principal(sam_ctx, tmp_ctx, principal, user_attrs, &domain_dn, &msg); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } nt_status = authsam_make_server_info(tmp_ctx, sam_ctx, lp_netbios_name(auth_context->lp_ctx), lp_workgroup(auth_context->lp_ctx), domain_dn, msg, user_sess_key, lm_sess_key, server_info); if (NT_STATUS_IS_OK(nt_status)) { talloc_steal(mem_ctx, *server_info); } talloc_free(tmp_ctx); return nt_status; }
/* A user password change Return true if there is a valid error packet (or sucess) formed in the error_blob */ static bool kpasswdd_change_password(struct kdc_server *kdc, TALLOC_CTX *mem_ctx, struct auth_session_info *session_info, const DATA_BLOB *password, DATA_BLOB *reply) { NTSTATUS status; enum samPwdChangeReason reject_reason; struct samr_DomInfo1 *dominfo; struct ldb_context *samdb; samdb = samdb_connect(mem_ctx, kdc->task->event_ctx, kdc->task->lp_ctx, system_session(kdc->task->lp_ctx)); if (!samdb) { return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_HARDERROR, "Failed to open samdb", reply); } DEBUG(3, ("Changing password of %s\\%s (%s)\n", session_info->server_info->domain_name, session_info->server_info->account_name, dom_sid_string(mem_ctx, session_info->security_token->user_sid))); /* User password change */ status = samdb_set_password_sid(samdb, mem_ctx, session_info->security_token->user_sid, password, NULL, NULL, true, /* this is a user password change */ &reject_reason, &dominfo); return kpasswd_make_pwchange_reply(kdc, mem_ctx, status, reject_reason, dominfo, reply); }
/* samr_ChangePasswordUser */ NTSTATUS dcesrv_samr_ChangePasswordUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_ChangePasswordUser *r) { struct dcesrv_handle *h; struct samr_account_state *a_state; struct ldb_context *sam_ctx; struct ldb_message **res; int ret; struct samr_Password new_lmPwdHash, new_ntPwdHash, checkHash; struct samr_Password *lm_pwd, *nt_pwd; NTSTATUS status = NT_STATUS_OK; const char * const attrs[] = { "dBCSPwd", "unicodePwd" , NULL }; DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER); a_state = h->data; /* basic sanity checking on parameters. Do this before any database ops */ if (!r->in.lm_present || !r->in.nt_present || !r->in.old_lm_crypted || !r->in.new_lm_crypted || !r->in.old_nt_crypted || !r->in.new_nt_crypted) { /* we should really handle a change with lm not present */ return NT_STATUS_INVALID_PARAMETER_MIX; } /* Connect to a SAMDB with system privileges for fetching the old pw * hashes. */ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(dce_call->conn->dce_ctx->lp_ctx), 0); if (sam_ctx == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } /* fetch the old hashes */ ret = gendb_search_dn(sam_ctx, mem_ctx, a_state->account_dn, &res, attrs); if (ret != 1) { return NT_STATUS_WRONG_PASSWORD; } status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, res[0], &lm_pwd, &nt_pwd); if (!NT_STATUS_IS_OK(status) || !nt_pwd) { return NT_STATUS_WRONG_PASSWORD; } /* decrypt and check the new lm hash */ if (lm_pwd) { D_P16(lm_pwd->hash, r->in.new_lm_crypted->hash, new_lmPwdHash.hash); D_P16(new_lmPwdHash.hash, r->in.old_lm_crypted->hash, checkHash.hash); if (memcmp(checkHash.hash, lm_pwd, 16) != 0) { return NT_STATUS_WRONG_PASSWORD; } } /* decrypt and check the new nt hash */ D_P16(nt_pwd->hash, r->in.new_nt_crypted->hash, new_ntPwdHash.hash); D_P16(new_ntPwdHash.hash, r->in.old_nt_crypted->hash, checkHash.hash); if (memcmp(checkHash.hash, nt_pwd, 16) != 0) { return NT_STATUS_WRONG_PASSWORD; } /* The NT Cross is not required by Win2k3 R2, but if present check the nt cross hash */ if (r->in.cross1_present && r->in.nt_cross && lm_pwd) { D_P16(lm_pwd->hash, r->in.nt_cross->hash, checkHash.hash); if (memcmp(checkHash.hash, new_ntPwdHash.hash, 16) != 0) { return NT_STATUS_WRONG_PASSWORD; } } /* The LM Cross is not required by Win2k3 R2, but if present check the lm cross hash */ if (r->in.cross2_present && r->in.lm_cross && lm_pwd) { D_P16(nt_pwd->hash, r->in.lm_cross->hash, checkHash.hash); if (memcmp(checkHash.hash, new_lmPwdHash.hash, 16) != 0) { return NT_STATUS_WRONG_PASSWORD; } } /* Start a SAM with user privileges for the password change */ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info, 0); if (sam_ctx == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } /* Start transaction */ ret = ldb_transaction_start(sam_ctx); if (ret != LDB_SUCCESS) { DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx))); return NT_STATUS_TRANSACTION_ABORTED; } /* Performs the password modification. We pass the old hashes read out * from the database since they were already checked against the user- * provided ones. */ status = samdb_set_password(sam_ctx, mem_ctx, a_state->account_dn, a_state->domain_state->domain_dn, NULL, &new_lmPwdHash, &new_ntPwdHash, lm_pwd, nt_pwd, /* this is a user password change */ NULL, NULL); if (!NT_STATUS_IS_OK(status)) { ldb_transaction_cancel(sam_ctx); return status; } /* And this confirms it in a transaction commit */ ret = ldb_transaction_commit(sam_ctx); if (ret != LDB_SUCCESS) { DEBUG(1,("Failed to commit transaction to change password on %s: %s\n", ldb_dn_get_linearized(a_state->account_dn), ldb_errstring(sam_ctx))); return NT_STATUS_TRANSACTION_ABORTED; } return NT_STATUS_OK; }
/* connect to the SPOOLSS database return a ldb_context pointer on success, or NULL on failure */ static struct ldb_context *sptr_db_connect(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx, struct loadparm_context *lp_ctx) { return ldb_wrap_connect(mem_ctx, ev_ctx, lp_ctx, "spoolss.ldb", system_session(lp_ctx), NULL, 0); }
/* samr_ChangePasswordUser3 */ NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_ChangePasswordUser3 *r) { NTSTATUS status; DATA_BLOB new_password; struct ldb_context *sam_ctx = NULL; struct ldb_dn *user_dn; int ret; struct ldb_message **res, *mod; const char * const attrs[] = { "unicodePwd", "dBCSPwd", NULL }; struct samr_Password *nt_pwd, *lm_pwd; DATA_BLOB nt_pwd_blob; struct samr_DomInfo1 *dominfo = NULL; struct samr_ChangeReject *reject = NULL; enum samr_RejectReason reason = SAMR_REJECT_OTHER; uint8_t new_nt_hash[16], new_lm_hash[16]; struct samr_Password nt_verifier, lm_verifier; *r->out.dominfo = NULL; *r->out.reject = NULL; if (r->in.nt_password == NULL || r->in.nt_verifier == NULL) { return NT_STATUS_INVALID_PARAMETER; } /* To change a password we need to open as system */ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx)); if (sam_ctx == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } ret = ldb_transaction_start(sam_ctx); if (ret) { talloc_free(sam_ctx); DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx))); return NT_STATUS_TRANSACTION_ABORTED; } /* we need the users dn and the domain dn (derived from the user SID). We also need the current lm and nt password hashes in order to decrypt the incoming passwords */ ret = gendb_search(sam_ctx, mem_ctx, NULL, &res, attrs, "(&(sAMAccountName=%s)(objectclass=user))", r->in.account->string); if (ret != 1) { /* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */ status = NT_STATUS_WRONG_PASSWORD; goto failed; } user_dn = res[0]->dn; status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, res[0], &lm_pwd, &nt_pwd); if (!NT_STATUS_IS_OK(status) ) { goto failed; } if (!nt_pwd) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } /* decrypt the password we have been given */ nt_pwd_blob = data_blob(nt_pwd->hash, sizeof(nt_pwd->hash)); arcfour_crypt_blob(r->in.nt_password->data, 516, &nt_pwd_blob); data_blob_free(&nt_pwd_blob); if (!extract_pw_from_buffer(mem_ctx, r->in.nt_password->data, &new_password)) { ldb_transaction_cancel(sam_ctx); DEBUG(3,("samr: failed to decode password buffer\n")); return NT_STATUS_WRONG_PASSWORD; } if (r->in.nt_verifier == NULL) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } /* check NT verifier */ mdfour(new_nt_hash, new_password.data, new_password.length); E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash); if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } /* check LM verifier (really not needed as we just checked the * much stronger NT hash, but the RPC-SAMR test checks for * this) */ if (lm_pwd && r->in.lm_verifier != NULL) { char *new_pass; if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx), CH_UTF16, CH_UNIX, (const char *)new_password.data, new_password.length, (void **)&new_pass, NULL, false)) { E_deshash(new_pass, new_lm_hash); E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash); if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } } } mod = ldb_msg_new(mem_ctx); if (mod == NULL) { status = NT_STATUS_NO_MEMORY; goto failed; } mod->dn = ldb_dn_copy(mod, user_dn); if (!mod->dn) { status = NT_STATUS_NO_MEMORY; goto failed; } /* set the password on the user DN specified. This may fail * due to password policies */ status = samdb_set_password(sam_ctx, mem_ctx, user_dn, NULL, mod, &new_password, NULL, NULL, true, /* this is a user password change */ &reason, &dominfo); if (!NT_STATUS_IS_OK(status)) { goto failed; } /* The above call only setup the modifications, this actually * makes the write to the database. */ ret = samdb_replace(sam_ctx, mem_ctx, mod); if (ret != 0) { DEBUG(2,("samdb_replace failed to change password for %s: %s\n", ldb_dn_get_linearized(user_dn), ldb_errstring(sam_ctx))); status = NT_STATUS_UNSUCCESSFUL; goto failed; } /* And this confirms it in a transaction commit */ ret = ldb_transaction_commit(sam_ctx); if (ret != 0) { DEBUG(1,("Failed to commit transaction to change password on %s: %s\n", ldb_dn_get_linearized(user_dn), ldb_errstring(sam_ctx))); status = NT_STATUS_TRANSACTION_ABORTED; goto failed; } return NT_STATUS_OK; failed: ldb_transaction_cancel(sam_ctx); talloc_free(sam_ctx); reject = talloc(mem_ctx, struct samr_ChangeReject); *r->out.dominfo = dominfo; *r->out.reject = reject; if (reject == NULL) { return status; } ZERO_STRUCTP(reject); reject->reason = reason; return status; }
/* samr_ChangePasswordUser */ NTSTATUS dcesrv_samr_ChangePasswordUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_ChangePasswordUser *r) { struct dcesrv_handle *h; struct samr_account_state *a_state; struct ldb_context *sam_ctx; struct ldb_message **res, *msg; int ret; struct samr_Password new_lmPwdHash, new_ntPwdHash, checkHash; struct samr_Password *lm_pwd, *nt_pwd; NTSTATUS status = NT_STATUS_OK; const char * const attrs[] = { "dBCSPwd", "unicodePwd" , NULL }; DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER); a_state = h->data; /* basic sanity checking on parameters. Do this before any database ops */ if (!r->in.lm_present || !r->in.nt_present || !r->in.old_lm_crypted || !r->in.new_lm_crypted || !r->in.old_nt_crypted || !r->in.new_nt_crypted) { /* we should really handle a change with lm not present */ return NT_STATUS_INVALID_PARAMETER_MIX; } /* To change a password we need to open as system */ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx)); if (sam_ctx == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } ret = ldb_transaction_start(sam_ctx); if (ret) { DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx))); return NT_STATUS_TRANSACTION_ABORTED; } /* fetch the old hashes */ ret = gendb_search_dn(sam_ctx, mem_ctx, a_state->account_dn, &res, attrs); if (ret != 1) { ldb_transaction_cancel(sam_ctx); return NT_STATUS_WRONG_PASSWORD; } msg = res[0]; status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, msg, &lm_pwd, &nt_pwd); if (!NT_STATUS_IS_OK(status) || !lm_pwd || !nt_pwd) { ldb_transaction_cancel(sam_ctx); return NT_STATUS_WRONG_PASSWORD; } /* decrypt and check the new lm hash */ D_P16(lm_pwd->hash, r->in.new_lm_crypted->hash, new_lmPwdHash.hash); D_P16(new_lmPwdHash.hash, r->in.old_lm_crypted->hash, checkHash.hash); if (memcmp(checkHash.hash, lm_pwd, 16) != 0) { ldb_transaction_cancel(sam_ctx); return NT_STATUS_WRONG_PASSWORD; } /* decrypt and check the new nt hash */ D_P16(nt_pwd->hash, r->in.new_nt_crypted->hash, new_ntPwdHash.hash); D_P16(new_ntPwdHash.hash, r->in.old_nt_crypted->hash, checkHash.hash); if (memcmp(checkHash.hash, nt_pwd, 16) != 0) { ldb_transaction_cancel(sam_ctx); return NT_STATUS_WRONG_PASSWORD; } /* The NT Cross is not required by Win2k3 R2, but if present check the nt cross hash */ if (r->in.cross1_present && r->in.nt_cross) { D_P16(lm_pwd->hash, r->in.nt_cross->hash, checkHash.hash); if (memcmp(checkHash.hash, new_ntPwdHash.hash, 16) != 0) { ldb_transaction_cancel(sam_ctx); return NT_STATUS_WRONG_PASSWORD; } } /* The LM Cross is not required by Win2k3 R2, but if present check the lm cross hash */ if (r->in.cross2_present && r->in.lm_cross) { D_P16(nt_pwd->hash, r->in.lm_cross->hash, checkHash.hash); if (memcmp(checkHash.hash, new_lmPwdHash.hash, 16) != 0) { ldb_transaction_cancel(sam_ctx); return NT_STATUS_WRONG_PASSWORD; } } msg = ldb_msg_new(mem_ctx); if (msg == NULL) { ldb_transaction_cancel(sam_ctx); return NT_STATUS_NO_MEMORY; } msg->dn = ldb_dn_copy(msg, a_state->account_dn); if (!msg->dn) { ldb_transaction_cancel(sam_ctx); return NT_STATUS_NO_MEMORY; } /* setup password modify mods on the user DN specified. This may fail * due to password policies. */ status = samdb_set_password(sam_ctx, mem_ctx, a_state->account_dn, a_state->domain_state->domain_dn, msg, NULL, &new_lmPwdHash, &new_ntPwdHash, true, /* this is a user password change */ NULL, NULL); if (!NT_STATUS_IS_OK(status)) { ldb_transaction_cancel(sam_ctx); return status; } /* The above call only setup the modifications, this actually * makes the write to the database. */ ret = samdb_replace(sam_ctx, mem_ctx, msg); if (ret != 0) { DEBUG(2,("Failed to modify record to change password on %s: %s\n", ldb_dn_get_linearized(a_state->account_dn), ldb_errstring(sam_ctx))); ldb_transaction_cancel(sam_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } /* And this confirms it in a transaction commit */ ret = ldb_transaction_commit(sam_ctx); if (ret != 0) { DEBUG(1,("Failed to commit transaction to change password on %s: %s\n", ldb_dn_get_linearized(a_state->account_dn), ldb_errstring(sam_ctx))); return NT_STATUS_TRANSACTION_ABORTED; } return NT_STATUS_OK; }
NTSTATUS crack_name_to_nt4_name(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx, struct loadparm_context *lp_ctx, enum drsuapi_DsNameFormat format_offered, const char *name, const char **nt4_domain, const char **nt4_account) { WERROR werr; struct drsuapi_DsNameInfo1 info1; struct ldb_context *ldb; char *p; /* Handle anonymous bind */ if (!name || !*name) { *nt4_domain = ""; *nt4_account = ""; return NT_STATUS_OK; } ldb = samdb_connect(mem_ctx, ev_ctx, lp_ctx, system_session(lp_ctx), 0); if (ldb == NULL) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } werr = DsCrackNameOneName(ldb, mem_ctx, 0, format_offered, DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT, name, &info1); if (!W_ERROR_IS_OK(werr)) { return werror_to_ntstatus(werr); } switch (info1.status) { case DRSUAPI_DS_NAME_STATUS_OK: break; case DRSUAPI_DS_NAME_STATUS_NOT_FOUND: case DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY: case DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE: return NT_STATUS_NO_SUCH_USER; case DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR: default: return NT_STATUS_UNSUCCESSFUL; } *nt4_domain = talloc_strdup(mem_ctx, info1.result_name); if (*nt4_domain == NULL) { return NT_STATUS_NO_MEMORY; } p = strchr(*nt4_domain, '\\'); if (!p) { return NT_STATUS_INVALID_PARAMETER; } p[0] = '\0'; *nt4_account = talloc_strdup(mem_ctx, &p[1]); if (*nt4_account == NULL) { return NT_STATUS_NO_MEMORY; } return NT_STATUS_OK; }
/** \details Initialize the EMSMDBP context and open connections to Samba databases. \param lp_ctx pointer to the loadparm_context \param username account name for current session \param ldb_ctx pointer to the openchange dispatcher ldb database \return Allocated emsmdbp_context pointer on success, otherwise NULL */ _PUBLIC_ struct emsmdbp_context *emsmdbp_init(struct loadparm_context *lp_ctx, const char *username, void *ldb_ctx) { TALLOC_CTX *mem_ctx; struct emsmdbp_context *emsmdbp_ctx; struct tevent_context *ev; enum mapistore_error ret; /* Sanity Checks */ if (!lp_ctx) return NULL; mem_ctx = talloc_named(NULL, 0, "emsmdbp_init"); emsmdbp_ctx = talloc_zero(mem_ctx, struct emsmdbp_context); if (!emsmdbp_ctx) { talloc_free(mem_ctx); return NULL; } emsmdbp_ctx->mem_ctx = mem_ctx; ev = tevent_context_init(mem_ctx); if (!ev) { talloc_free(mem_ctx); return NULL; } tevent_loop_allow_nesting(ev); /* Save a pointer to the loadparm context */ emsmdbp_ctx->lp_ctx = lp_ctx; /* return an opaque context pointer on samDB database */ emsmdbp_ctx->samdb_ctx = samdb_connect(mem_ctx, ev, lp_ctx, system_session(lp_ctx), 0); if (!emsmdbp_ctx->samdb_ctx) { talloc_free(mem_ctx); DEBUG(0, ("[%s:%d]: Connection to \"sam.ldb\" failed\n", __FUNCTION__, __LINE__)); return NULL; } /* Reference global OpenChange dispatcher database pointer within current context */ emsmdbp_ctx->oc_ctx = ldb_ctx; /* Initialize the mapistore context */ emsmdbp_ctx->mstore_ctx = mapistore_init(mem_ctx, lp_ctx, NULL); if (!emsmdbp_ctx->mstore_ctx) { DEBUG(0, ("[%s:%d]: MAPISTORE initialization failed\n", __FUNCTION__, __LINE__)); talloc_free(mem_ctx); return NULL; } ret = mapistore_set_connection_info(emsmdbp_ctx->mstore_ctx, emsmdbp_ctx->samdb_ctx, emsmdbp_ctx->oc_ctx, username); if (ret != MAPISTORE_SUCCESS) { DEBUG(0, ("[%s:%d]: MAPISTORE connection info initialization failed\n", __FUNCTION__, __LINE__)); talloc_free(mem_ctx); return NULL; } talloc_set_destructor((void *)emsmdbp_ctx->mstore_ctx, (int (*)(void *))emsmdbp_mapi_store_destructor); /* Initialize MAPI handles context */ emsmdbp_ctx->handles_ctx = mapi_handles_init(mem_ctx); if (!emsmdbp_ctx->handles_ctx) { DEBUG(0, ("[%s:%d]: MAPI handles context initialization failed\n", __FUNCTION__, __LINE__)); talloc_free(mem_ctx); return NULL; } talloc_set_destructor((void *)emsmdbp_ctx->handles_ctx, (int (*)(void *))emsmdbp_mapi_handles_destructor); return emsmdbp_ctx; }
/* samr_OemChangePasswordUser2 */ NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_OemChangePasswordUser2 *r) { NTSTATUS status; DATA_BLOB new_password, new_unicode_password; char *new_pass; struct samr_CryptPassword *pwbuf = r->in.password; struct ldb_context *sam_ctx; struct ldb_dn *user_dn; int ret; struct ldb_message **res; const char * const attrs[] = { "objectSid", "dBCSPwd", NULL }; struct samr_Password *lm_pwd; DATA_BLOB lm_pwd_blob; uint8_t new_lm_hash[16]; struct samr_Password lm_verifier; size_t unicode_pw_len; if (pwbuf == NULL) { return NT_STATUS_INVALID_PARAMETER; } if (r->in.hash == NULL) { return NT_STATUS_INVALID_PARAMETER; } /* this call can only work with lanman auth */ if (!lpcfg_lanman_auth(dce_call->conn->dce_ctx->lp_ctx)) { return NT_STATUS_WRONG_PASSWORD; } /* Connect to a SAMDB with system privileges for fetching the old pw * hashes. */ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(dce_call->conn->dce_ctx->lp_ctx), 0); if (sam_ctx == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } /* we need the users dn and the domain dn (derived from the user SID). We also need the current lm password hash in order to decrypt the incoming password */ ret = gendb_search(sam_ctx, mem_ctx, NULL, &res, attrs, "(&(sAMAccountName=%s)(objectclass=user))", r->in.account->string); if (ret != 1) { /* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */ return NT_STATUS_WRONG_PASSWORD; } user_dn = res[0]->dn; status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, res[0], &lm_pwd, NULL); if (!NT_STATUS_IS_OK(status) || !lm_pwd) { return NT_STATUS_WRONG_PASSWORD; } /* decrypt the password we have been given */ lm_pwd_blob = data_blob(lm_pwd->hash, sizeof(lm_pwd->hash)); arcfour_crypt_blob(pwbuf->data, 516, &lm_pwd_blob); data_blob_free(&lm_pwd_blob); if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) { DEBUG(3,("samr: failed to decode password buffer\n")); return NT_STATUS_WRONG_PASSWORD; } if (!convert_string_talloc_convenience(mem_ctx, lpcfg_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx), CH_DOS, CH_UNIX, (const char *)new_password.data, new_password.length, (void **)&new_pass, NULL, false)) { DEBUG(3,("samr: failed to convert incoming password buffer to unix charset\n")); return NT_STATUS_WRONG_PASSWORD; } if (!convert_string_talloc_convenience(mem_ctx, lpcfg_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx), CH_DOS, CH_UTF16, (const char *)new_password.data, new_password.length, (void **)&new_unicode_password.data, &unicode_pw_len, false)) { DEBUG(3,("samr: failed to convert incoming password buffer to UTF16 charset\n")); return NT_STATUS_WRONG_PASSWORD; } new_unicode_password.length = unicode_pw_len; E_deshash(new_pass, new_lm_hash); E_old_pw_hash(new_lm_hash, lm_pwd->hash, lm_verifier.hash); if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) { return NT_STATUS_WRONG_PASSWORD; } /* Connect to a SAMDB with user privileges for the password change */ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info, 0); if (sam_ctx == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } /* Start transaction */ ret = ldb_transaction_start(sam_ctx); if (ret != LDB_SUCCESS) { DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx))); return NT_STATUS_TRANSACTION_ABORTED; } /* Performs the password modification. We pass the old hashes read out * from the database since they were already checked against the user- * provided ones. */ status = samdb_set_password(sam_ctx, mem_ctx, user_dn, NULL, &new_unicode_password, NULL, NULL, lm_pwd, NULL, /* this is a user password change */ NULL, NULL); if (!NT_STATUS_IS_OK(status)) { ldb_transaction_cancel(sam_ctx); return status; } /* And this confirms it in a transaction commit */ ret = ldb_transaction_commit(sam_ctx); if (ret != LDB_SUCCESS) { DEBUG(1,("Failed to commit transaction to change password on %s: %s\n", ldb_dn_get_linearized(user_dn), ldb_errstring(sam_ctx))); return NT_STATUS_TRANSACTION_ABORTED; } return NT_STATUS_OK; }
bool torture_gpo_system_access_policies(struct torture_context *tctx) { TALLOC_CTX *ctx = talloc_new(tctx); int ret, vers = 0, i; const char *sysvol_path = NULL, *gpo_dir = NULL; const char *gpo_file = NULL, *gpt_file = NULL; struct ldb_context *samdb = NULL; struct ldb_result *result; const char *attrs[] = { "minPwdAge", "maxPwdAge", "minPwdLength", "pwdProperties", NULL }; FILE *fp = NULL; const char **gpo_update_cmd; char **gpo_unapply_cmd; int minpwdcases[] = { 0, 1, 998 }; int maxpwdcases[] = { 0, 1, 999 }; int pwdlencases[] = { 0, 1, 14 }; int pwdpropcases[] = { 0, 1, 1 }; struct ldb_message *old_message = NULL; const char **itr; int gpo_update_len = 0; sysvol_path = lpcfg_path(lpcfg_service(tctx->lp_ctx, "sysvol"), lpcfg_default_service(tctx->lp_ctx), tctx); torture_assert(tctx, sysvol_path, "Failed to fetch the sysvol path"); /* Ensure the sysvol path exists */ gpo_dir = talloc_asprintf(ctx, "%s/%s", sysvol_path, GPODIR); mkdir_p(gpo_dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); gpo_file = talloc_asprintf(ctx, "%s/%s", gpo_dir, GPOFILE); /* Get the gpo update command */ gpo_update_cmd = lpcfg_gpo_update_command(tctx->lp_ctx); torture_assert(tctx, gpo_update_cmd && gpo_update_cmd[0], "Failed to fetch the gpo update command"); /* Open and read the samba db and store the initial password settings */ samdb = samdb_connect(ctx, tctx->ev, tctx->lp_ctx, system_session(tctx->lp_ctx), NULL, 0); torture_assert(tctx, samdb, "Failed to connect to the samdb"); ret = ldb_search(samdb, ctx, &result, ldb_get_default_basedn(samdb), LDB_SCOPE_BASE, attrs, NULL); torture_assert(tctx, ret == LDB_SUCCESS && result->count == 1, "Searching the samdb failed"); old_message = result->msgs[0]; for (i = 0; i < 3; i++) { /* Write out the sysvol */ if ( (fp = fopen(gpo_file, "w")) ) { fputs(talloc_asprintf(ctx, GPTTMPL, minpwdcases[i], maxpwdcases[i], pwdlencases[i], pwdpropcases[i]), fp); fclose(fp); } /* Update the version in the GPT.INI */ gpt_file = talloc_asprintf(ctx, "%s/%s", sysvol_path, GPTINI); if ( (fp = fopen(gpt_file, "r")) ) { char line[256]; while (fgets(line, 256, fp)) { if (strncasecmp(line, "Version=", 8) == 0) { vers = atoi(line+8); break; } } fclose(fp); } if ( (fp = fopen(gpt_file, "w")) ) { char *data = talloc_asprintf(ctx, "[General]\nVersion=%d\n", ++vers); fputs(data, fp); fclose(fp); } /* Run the gpo update command */ ret = exec_wait(discard_const_p(char *, gpo_update_cmd)); torture_assert(tctx, ret == 0, "Failed to execute the gpo update command"); ret = ldb_search(samdb, ctx, &result, ldb_get_default_basedn(samdb), LDB_SCOPE_BASE, attrs, NULL); torture_assert(tctx, ret == LDB_SUCCESS && result->count == 1, "Searching the samdb failed"); /* minPwdAge */ torture_assert_int_equal(tctx, unix2nttime( ldb_msg_find_attr_as_string( result->msgs[0], attrs[0], "")), minpwdcases[i], "The minPwdAge was not applied"); /* maxPwdAge */ torture_assert_int_equal(tctx, unix2nttime( ldb_msg_find_attr_as_string( result->msgs[0], attrs[1], "")), maxpwdcases[i], "The maxPwdAge was not applied"); /* minPwdLength */ torture_assert_int_equal(tctx, ldb_msg_find_attr_as_int( result->msgs[0], attrs[2], -1), pwdlencases[i], "The minPwdLength was not applied"); /* pwdProperties */ torture_assert_int_equal(tctx, ldb_msg_find_attr_as_int( result->msgs[0], attrs[3], -1), pwdpropcases[i], "The pwdProperties were not applied"); } /* Unapply the settings and verify they are removed */ for (itr = gpo_update_cmd; *itr != NULL; itr++) { gpo_update_len++; } gpo_unapply_cmd = talloc_array(ctx, char*, gpo_update_len+2); for (i = 0; i < gpo_update_len; i++) { gpo_unapply_cmd[i] = talloc_strdup(gpo_unapply_cmd, gpo_update_cmd[i]); } gpo_unapply_cmd[i] = talloc_asprintf(gpo_unapply_cmd, "--unapply"); gpo_unapply_cmd[i+1] = NULL; ret = exec_wait(gpo_unapply_cmd); torture_assert(tctx, ret == 0, "Failed to execute the gpo unapply command"); ret = ldb_search(samdb, ctx, &result, ldb_get_default_basedn(samdb), LDB_SCOPE_BASE, attrs, NULL); torture_assert(tctx, ret == LDB_SUCCESS && result->count == 1, "Searching the samdb failed"); /* minPwdAge */ torture_assert_int_equal(tctx, unix2nttime(ldb_msg_find_attr_as_string( result->msgs[0], attrs[0], "")), unix2nttime(ldb_msg_find_attr_as_string(old_message, attrs[0], "") ), "The minPwdAge was not unapplied"); /* maxPwdAge */ torture_assert_int_equal(tctx, unix2nttime(ldb_msg_find_attr_as_string( result->msgs[0], attrs[1], "")), unix2nttime(ldb_msg_find_attr_as_string(old_message, attrs[1], "") ), "The maxPwdAge was not unapplied"); /* minPwdLength */ torture_assert_int_equal(tctx, ldb_msg_find_attr_as_int( result->msgs[0], attrs[2], -1), ldb_msg_find_attr_as_int( old_message, attrs[2], -2), "The minPwdLength was not unapplied"); /* pwdProperties */ torture_assert_int_equal(tctx, ldb_msg_find_attr_as_int( result->msgs[0], attrs[3], -1), ldb_msg_find_attr_as_int( old_message, attrs[3], -2), "The pwdProperties were not unapplied"); talloc_free(ctx); return true; }
/* samr_ChangePasswordUser3 */ NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_ChangePasswordUser3 *r) { NTSTATUS status; DATA_BLOB new_password; struct ldb_context *sam_ctx = NULL; struct ldb_dn *user_dn; int ret; struct ldb_message **res; const char * const attrs[] = { "unicodePwd", "dBCSPwd", NULL }; struct samr_Password *nt_pwd, *lm_pwd; DATA_BLOB nt_pwd_blob; struct samr_DomInfo1 *dominfo = NULL; struct userPwdChangeFailureInformation *reject = NULL; enum samPwdChangeReason reason = SAM_PWD_CHANGE_NO_ERROR; uint8_t new_nt_hash[16], new_lm_hash[16]; struct samr_Password nt_verifier, lm_verifier; *r->out.dominfo = NULL; *r->out.reject = NULL; if (r->in.nt_password == NULL || r->in.nt_verifier == NULL) { return NT_STATUS_INVALID_PARAMETER; } /* Connect to a SAMDB with system privileges for fetching the old pw * hashes. */ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(dce_call->conn->dce_ctx->lp_ctx), 0); if (sam_ctx == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } /* we need the users dn and the domain dn (derived from the user SID). We also need the current lm and nt password hashes in order to decrypt the incoming passwords */ ret = gendb_search(sam_ctx, mem_ctx, NULL, &res, attrs, "(&(sAMAccountName=%s)(objectclass=user))", r->in.account->string); if (ret != 1) { /* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */ status = NT_STATUS_WRONG_PASSWORD; goto failed; } user_dn = res[0]->dn; status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, res[0], &lm_pwd, &nt_pwd); if (!NT_STATUS_IS_OK(status) ) { goto failed; } if (!nt_pwd) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } /* decrypt the password we have been given */ nt_pwd_blob = data_blob(nt_pwd->hash, sizeof(nt_pwd->hash)); arcfour_crypt_blob(r->in.nt_password->data, 516, &nt_pwd_blob); data_blob_free(&nt_pwd_blob); if (!extract_pw_from_buffer(mem_ctx, r->in.nt_password->data, &new_password)) { DEBUG(3,("samr: failed to decode password buffer\n")); status = NT_STATUS_WRONG_PASSWORD; goto failed; } if (r->in.nt_verifier == NULL) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } /* check NT verifier */ mdfour(new_nt_hash, new_password.data, new_password.length); E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash); if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } /* check LM verifier (really not needed as we just checked the * much stronger NT hash, but the RPC-SAMR test checks for * this) */ if (lm_pwd && r->in.lm_verifier != NULL) { char *new_pass; if (!convert_string_talloc_convenience(mem_ctx, lpcfg_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx), CH_UTF16, CH_UNIX, (const char *)new_password.data, new_password.length, (void **)&new_pass, NULL, false)) { E_deshash(new_pass, new_lm_hash); E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash); if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } } } /* Connect to a SAMDB with user privileges for the password change */ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info, 0); if (sam_ctx == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } ret = ldb_transaction_start(sam_ctx); if (ret != LDB_SUCCESS) { DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx))); return NT_STATUS_TRANSACTION_ABORTED; } /* Performs the password modification. We pass the old hashes read out * from the database since they were already checked against the user- * provided ones. */ status = samdb_set_password(sam_ctx, mem_ctx, user_dn, NULL, &new_password, NULL, NULL, lm_pwd, nt_pwd, /* this is a user password change */ &reason, &dominfo); if (!NT_STATUS_IS_OK(status)) { ldb_transaction_cancel(sam_ctx); goto failed; } /* And this confirms it in a transaction commit */ ret = ldb_transaction_commit(sam_ctx); if (ret != LDB_SUCCESS) { DEBUG(1,("Failed to commit transaction to change password on %s: %s\n", ldb_dn_get_linearized(user_dn), ldb_errstring(sam_ctx))); status = NT_STATUS_TRANSACTION_ABORTED; goto failed; } return NT_STATUS_OK; failed: reject = talloc_zero(mem_ctx, struct userPwdChangeFailureInformation); if (reject != NULL) { reject->extendedFailureReason = reason; *r->out.reject = reject; } *r->out.dominfo = dominfo; return status; }
/* drsuapi_DsBind */ static WERROR dcesrv_drsuapi_DsBind(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct drsuapi_DsBind *r) { struct drsuapi_bind_state *b_state; struct dcesrv_handle *handle; struct drsuapi_DsBindInfoCtr *bind_info; struct GUID site_guid; struct ldb_result *site_res; struct ldb_dn *server_site_dn; static const char *site_attrs[] = { "objectGUID", NULL }; struct ldb_result *ntds_res; struct ldb_dn *ntds_dn; static const char *ntds_attrs[] = { "ms-DS-ReplicationEpoch", NULL }; uint32_t pid; uint32_t repl_epoch; int ret; struct auth_session_info *auth_info; WERROR werr; r->out.bind_info = NULL; ZERO_STRUCTP(r->out.bind_handle); b_state = talloc_zero(mem_ctx, struct drsuapi_bind_state); W_ERROR_HAVE_NO_MEMORY(b_state); /* if this is a DC connecting, give them system level access */ werr = drs_security_level_check(dce_call, NULL); if (W_ERROR_IS_OK(werr)) { DEBUG(3,(__location__ ": doing DsBind with system_session\n")); auth_info = system_session(dce_call->conn->dce_ctx->lp_ctx); } else { auth_info = dce_call->conn->auth_state.session_info; } /* * connect to the samdb */ b_state->sam_ctx = samdb_connect(b_state, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, auth_info); if (!b_state->sam_ctx) { return WERR_FOOBAR; } /* * find out the guid of our own site */ server_site_dn = samdb_server_site_dn(b_state->sam_ctx, mem_ctx); W_ERROR_HAVE_NO_MEMORY(server_site_dn); ret = ldb_search(b_state->sam_ctx, mem_ctx, &site_res, server_site_dn, LDB_SCOPE_BASE, site_attrs, "(objectClass=*)"); if (ret != LDB_SUCCESS) { return WERR_DS_DRA_INTERNAL_ERROR; } if (site_res->count != 1) { return WERR_DS_DRA_INTERNAL_ERROR; } site_guid = samdb_result_guid(site_res->msgs[0], "objectGUID"); /* * lookup the local servers Replication Epoch */ ntds_dn = samdb_ntds_settings_dn(b_state->sam_ctx); W_ERROR_HAVE_NO_MEMORY(ntds_dn); ret = ldb_search(b_state->sam_ctx, mem_ctx, &ntds_res, ntds_dn, LDB_SCOPE_BASE, ntds_attrs, "(objectClass=*)"); if (ret != LDB_SUCCESS) { return WERR_DS_DRA_INTERNAL_ERROR; } if (ntds_res->count != 1) { return WERR_DS_DRA_INTERNAL_ERROR; } repl_epoch = samdb_result_uint(ntds_res->msgs[0], "ms-DS-ReplicationEpoch", 0); /* * The "process identifier" of the client. * According to the WSPP docs, sectin 5.35, this is * for informational and debugging purposes only. * The assignment is implementation specific. */ pid = 0; /* * store the clients bind_guid */ if (r->in.bind_guid) { b_state->remote_bind_guid = *r->in.bind_guid; } /* * store the clients bind_info */ if (r->in.bind_info) { switch (r->in.bind_info->length) { case 24: { struct drsuapi_DsBindInfo24 *info24; info24 = &r->in.bind_info->info.info24; b_state->remote_info28.supported_extensions = info24->supported_extensions; b_state->remote_info28.site_guid = info24->site_guid; b_state->remote_info28.pid = info24->pid; b_state->remote_info28.repl_epoch = 0; break; } case 28: b_state->remote_info28 = r->in.bind_info->info.info28; break; } } /* * fill in our local bind info 28 */ b_state->local_info28.supported_extensions = 0; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_BASE; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2; #if 0 /* we don't support MSZIP compression (only decompression) */ b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS; #endif b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_00100000; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7; b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT; #if 0 /* we don't support XPRESS compression yet */ b_state->local_info28.supported_extensions |= DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS; #endif b_state->local_info28.site_guid = site_guid; b_state->local_info28.pid = pid; b_state->local_info28.repl_epoch = repl_epoch; /* * allocate the return bind_info */ bind_info = talloc(mem_ctx, struct drsuapi_DsBindInfoCtr); W_ERROR_HAVE_NO_MEMORY(bind_info); bind_info->length = 28; bind_info->info.info28 = b_state->local_info28; /* * allocate a bind handle */ handle = dcesrv_handle_new(dce_call->context, DRSUAPI_BIND_HANDLE); W_ERROR_HAVE_NO_MEMORY(handle); handle->data = talloc_steal(handle, b_state); /* * prepare reply */ r->out.bind_info = bind_info; *r->out.bind_handle = handle->wire_handle; return WERR_OK; }
/* startup the kdc task */ static void kdc_task_init(struct task_server *task) { struct kdc_server *kdc; krb5_kdc_configuration *kdc_config = NULL; NTSTATUS status; krb5_error_code ret; struct interface *ifaces; int ldb_ret; switch (lpcfg_server_role(task->lp_ctx)) { case ROLE_STANDALONE: task_server_terminate(task, "kdc: no KDC required in standalone configuration", false); return; case ROLE_DOMAIN_MEMBER: task_server_terminate(task, "kdc: no KDC required in member server configuration", false); return; case ROLE_DOMAIN_PDC: case ROLE_DOMAIN_BDC: task_server_terminate(task, "Cannot start KDC as a 'classic Samba' DC", true); return; case ROLE_ACTIVE_DIRECTORY_DC: /* Yes, we want a KDC */ break; } load_interface_list(task, task->lp_ctx, &ifaces); if (iface_list_count(ifaces) == 0) { task_server_terminate(task, "kdc: no network interfaces configured", false); return; } task_server_set_title(task, "task[kdc]"); kdc = talloc_zero(task, struct kdc_server); if (kdc == NULL) { task_server_terminate(task, "kdc: out of memory", true); return; } kdc->task = task; /* get a samdb connection */ kdc->samdb = samdb_connect(kdc, kdc->task->event_ctx, kdc->task->lp_ctx, system_session(kdc->task->lp_ctx), NULL, 0); if (!kdc->samdb) { DEBUG(1,("kdc_task_init: unable to connect to samdb\n")); task_server_terminate(task, "kdc: krb5_init_context samdb connect failed", true); return; } ldb_ret = samdb_rodc(kdc->samdb, &kdc->am_rodc); if (ldb_ret != LDB_SUCCESS) { DEBUG(1, ("kdc_task_init: Cannot determine if we are an RODC: %s\n", ldb_errstring(kdc->samdb))); task_server_terminate(task, "kdc: krb5_init_context samdb RODC connect failed", true); return; } kdc->proxy_timeout = lpcfg_parm_int(kdc->task->lp_ctx, NULL, "kdc", "proxy timeout", 5); initialize_krb5_error_table(); ret = smb_krb5_init_context(kdc, task->lp_ctx, &kdc->smb_krb5_context); if (ret) { DEBUG(1,("kdc_task_init: krb5_init_context failed (%s)\n", error_message(ret))); task_server_terminate(task, "kdc: krb5_init_context failed", true); return; } krb5_add_et_list(kdc->smb_krb5_context->krb5_context, initialize_hdb_error_table_r); ret = krb5_kdc_get_config(kdc->smb_krb5_context->krb5_context, &kdc_config); if(ret) { task_server_terminate(task, "kdc: failed to get KDC configuration", true); return; } kdc_config->logf = (krb5_log_facility *)kdc->smb_krb5_context->pvt_log_data; kdc_config->db = talloc(kdc, struct HDB *); if (!kdc_config->db) { task_server_terminate(task, "kdc: out of memory", true); return; } kdc_config->num_db = 1; /* * This restores the behavior before * commit 255e3e18e00f717d99f3bc57c8a8895ff624f3c3 * s4:heimdal: import lorikeet-heimdal-201107150856 * (commit 48936803fae4a2fb362c79365d31f420c917b85b) * * as_use_strongest_session_key,preauth_use_strongest_session_key * and tgs_use_strongest_session_key are input to the * _kdc_find_etype() function. The old bahavior is in * the use_strongest_session_key=FALSE code path. * (The only remaining difference in _kdc_find_etype() * is the is_preauth parameter.) * * The old behavior in the _kdc_get_preferred_key() * function is use_strongest_server_key=TRUE. */ kdc_config->as_use_strongest_session_key = false; kdc_config->preauth_use_strongest_session_key = false; kdc_config->tgs_use_strongest_session_key = false; kdc_config->use_strongest_server_key = true; kdc_config->autodetect_referrals = false; /* Register hdb-samba4 hooks for use as a keytab */ kdc->base_ctx = talloc_zero(kdc, struct samba_kdc_base_context); if (!kdc->base_ctx) { task_server_terminate(task, "kdc: out of memory", true); return; } kdc->base_ctx->ev_ctx = task->event_ctx; kdc->base_ctx->lp_ctx = task->lp_ctx; kdc->base_ctx->msg_ctx = task->msg_ctx; status = hdb_samba4_create_kdc(kdc->base_ctx, kdc->smb_krb5_context->krb5_context, &kdc_config->db[0]); if (!NT_STATUS_IS_OK(status)) { task_server_terminate(task, "kdc: hdb_samba4_create_kdc (setup KDC database) failed", true); return; } ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context, PLUGIN_TYPE_DATA, "hdb", &hdb_samba4_interface); if(ret) { task_server_terminate(task, "kdc: failed to register hdb plugin", true); return; } ret = krb5_kt_register(kdc->smb_krb5_context->krb5_context, &hdb_kt_ops); if(ret) { task_server_terminate(task, "kdc: failed to register keytab plugin", true); return; } kdc->keytab_name = talloc_asprintf(kdc, "HDB:samba4&%p", kdc->base_ctx); if (kdc->keytab_name == NULL) { task_server_terminate(task, "kdc: Failed to set keytab name", true); return; } /* Register WinDC hooks */ ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context, PLUGIN_TYPE_DATA, "windc", &windc_plugin_table); if(ret) { task_server_terminate(task, "kdc: failed to register windc plugin", true); return; } ret = krb5_kdc_windc_init(kdc->smb_krb5_context->krb5_context); if(ret) { task_server_terminate(task, "kdc: failed to init windc plugin", true); return; } ret = krb5_kdc_pkinit_config(kdc->smb_krb5_context->krb5_context, kdc_config); if(ret) { task_server_terminate(task, "kdc: failed to init kdc pkinit subsystem", true); return; } kdc->private_data = kdc_config; /* start listening on the configured network interfaces */ status = kdc_startup_interfaces(kdc, task->lp_ctx, ifaces, task->model_ops); if (!NT_STATUS_IS_OK(status)) { task_server_terminate(task, "kdc failed to setup interfaces", true); return; } status = IRPC_REGISTER(task->msg_ctx, irpc, KDC_CHECK_GENERIC_KERBEROS, kdc_check_generic_kerberos, kdc); if (!NT_STATUS_IS_OK(status)) { task_server_terminate(task, "kdc failed to setup monitoring", true); return; } irpc_add_name(task->msg_ctx, "kdc_server"); }
/* add a socket address to the list of events, one event per port */ static NTSTATUS add_socket(struct tevent_context *event_context, struct loadparm_context *lp_ctx, const struct model_ops *model_ops, const char *address, struct ldapsrv_service *ldap_service) { uint16_t port = 389; NTSTATUS status; struct ldb_context *ldb; status = stream_setup_socket(event_context, lp_ctx, model_ops, &ldap_stream_nonpriv_ops, "ipv4", address, &port, lp_socket_options(lp_ctx), ldap_service); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("ldapsrv failed to bind to %s:%u - %s\n", address, port, nt_errstr(status))); } if (tls_support(ldap_service->tls_params)) { /* add ldaps server */ port = 636; status = stream_setup_socket(event_context, lp_ctx, model_ops, &ldap_stream_nonpriv_ops, "ipv4", address, &port, lp_socket_options(lp_ctx), ldap_service); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("ldapsrv failed to bind to %s:%u - %s\n", address, port, nt_errstr(status))); } } /* Load LDAP database, but only to read our settings */ ldb = samdb_connect(ldap_service, ldap_service->task->event_ctx, lp_ctx, system_session(ldap_service, lp_ctx)); if (!ldb) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } if (samdb_is_gc(ldb)) { port = 3268; status = stream_setup_socket(event_context, lp_ctx, model_ops, &ldap_stream_nonpriv_ops, "ipv4", address, &port, lp_socket_options(lp_ctx), ldap_service); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("ldapsrv failed to bind to %s:%u - %s\n", address, port, nt_errstr(status))); } } /* And once we are bound, free the tempoary ldb, it will * connect again on each incoming LDAP connection */ talloc_free(ldb); return status; }