From acda755f54f7458d1ff5e41bbf3a4ec6af4dadc0 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 20 May 2004 13:29:38 +0000 Subject: r793: - don't make templates members of any class that would make them show up in searches like "objectclass=user" - auto-add the computer objectclass for computer accounts on create - added two types of password change call in samr server - reset last_fault_code before each dcerpc call (This used to be commit c1a65f83f6a4c51e60efd204dab89c20cda65d2b) --- source4/librpc/rpc/dcerpc.c | 3 + source4/provision.ldif | 7 +- source4/rpc_server/samr/dcesrv_samr.c | 260 +++++++++++++++++++++++++++++----- source4/rpc_server/samr/samdb.c | 27 ++++ 4 files changed, 263 insertions(+), 34 deletions(-) diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c index 8987cead92..21340e4f63 100644 --- a/source4/librpc/rpc/dcerpc.c +++ b/source4/librpc/rpc/dcerpc.c @@ -467,6 +467,9 @@ NTSTATUS dcerpc_request(struct dcerpc_pipe *p, DATA_BLOB blob, payload; uint32 remaining, chunk_size; + /* allow the application to tell when a fault has happened */ + p->last_fault_code = 0; + init_dcerpc_hdr(p, &pkt); remaining = stub_data_in->length; diff --git a/source4/provision.ldif b/source4/provision.ldif index 35027fe7f8..075cd758ba 100644 --- a/source4/provision.ldif +++ b/source4/provision.ldif @@ -754,6 +754,11 @@ systemFlags: 0x8c000000 objectCategory: CN=Container,CN=Schema,CN=Configuration,${BASEDN} isCriticalSystemObject: TRUE +### +# note! the template users must not match normal searches. Be careful +# with what classes you put them in +### + dn: CN=TemplateUser,CN=Templates,${BASEDN} objectClass: top objectClass: person @@ -778,7 +783,6 @@ sAMAccountType: 0x30000000 dn: CN=TemplateMemberServer,CN=Templates,${BASEDN} objectClass: top -objectClass: computer objectClass: Template objectClass: userTemplate cn: TemplateMemberServer @@ -799,7 +803,6 @@ sAMAccountType: 0x30000001 dn: CN=TemplateDomainController,CN=Templates,${BASEDN} objectClass: top -objectClass: computer objectClass: Template objectClass: userTemplate cn: TemplateDomainController diff --git a/source4/rpc_server/samr/dcesrv_samr.c b/source4/rpc_server/samr/dcesrv_samr.c index e980c25b80..30856c6ce9 100644 --- a/source4/rpc_server/samr/dcesrv_samr.c +++ b/source4/rpc_server/samr/dcesrv_samr.c @@ -603,7 +603,7 @@ static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX struct dcesrv_handle *u_handle; int ret; NTSTATUS status; - const char *container; + const char *container, *additional_class=NULL; ZERO_STRUCTP(r->out.acct_handle); *r->out.access_granted = 0; @@ -651,6 +651,7 @@ static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX } container = "Computers"; + additional_class = "computer"; } else if (r->in.acct_flags == ACB_SVRTRUST) { /* pull in all the template attributes */ @@ -662,6 +663,7 @@ static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX } container = "DomainControllers"; + additional_class = "computer"; } else if (r->in.acct_flags == ACB_DOMTRUST) { /* pull in all the template attributes */ @@ -673,6 +675,7 @@ static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX } container = "ForeignDomains"; /* FIXME: Is this correct?*/ + additional_class = "computer"; } else { return NT_STATUS_INVALID_PARAMETER; @@ -700,6 +703,9 @@ static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "cn", username); samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "sAMAccountName", username); samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectClass", "user"); + if (additional_class) { + samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectClass", additional_class); + } samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectSid", sidstr); samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenCreated", now); samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenChanged", now); @@ -1829,12 +1835,232 @@ static NTSTATUS samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX samr_ChangePasswordUser */ static NTSTATUS samr_ChangePasswordUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct samr_ChangePasswordUser *r) + struct samr_ChangePasswordUser *r) +{ + struct dcesrv_handle *h; + struct samr_account_state *a_state; + struct ldb_message **res, mod, *msg; + int i, ret; + struct samr_Hash *lmPwdHash=NULL, *ntPwdHash=NULL; + struct samr_Hash new_lmPwdHash, new_ntPwdHash, checkHash; + NTSTATUS status = NT_STATUS_OK; + const char * const attrs[] = { "lmPwdHash", "ntPwdHash" , NULL }; + + DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER); + + a_state = h->data; + + /* fetch the old hashes */ + ret = samdb_search(a_state->sam_ctx, mem_ctx, NULL, &res, attrs, + "dn=%s", a_state->account_dn); + if (ret != 1) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + msg = res[0]; + + /* basic sanity checking on parameters */ + 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; + } + if (!r->in.cross1_present || !r->in.nt_cross) { + return NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED; + } + if (!r->in.cross2_present || !r->in.lm_cross) { + return NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED; + } + + ret = samdb_result_hashes(mem_ctx, msg, "lmPwdHash", &lmPwdHash); + if (ret != 1) { + return NT_STATUS_WRONG_PASSWORD; + } + ret = samdb_result_hashes(mem_ctx, msg, "ntPwdHash", &ntPwdHash); + if (ret != 1) { + return NT_STATUS_WRONG_PASSWORD; + } + + /* decrypt and check the new lm hash */ + D_P16(lmPwdHash->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, lmPwdHash->hash, 16) != 0) { + return NT_STATUS_WRONG_PASSWORD; + } + + /* decrypt and check the new nt hash */ + D_P16(ntPwdHash->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, ntPwdHash->hash, 16) != 0) { + return NT_STATUS_WRONG_PASSWORD; + } + + /* check the nt cross hash */ + D_P16(lmPwdHash->hash, r->in.nt_cross->hash, checkHash.hash); + if (memcmp(checkHash.hash, new_ntPwdHash.hash, 16) != 0) { + return NT_STATUS_WRONG_PASSWORD; + } + + /* check the lm cross hash */ + D_P16(ntPwdHash->hash, r->in.lm_cross->hash, checkHash.hash); + if (memcmp(checkHash.hash, new_lmPwdHash.hash, 16) != 0) { + return NT_STATUS_WRONG_PASSWORD; + } + + ZERO_STRUCT(mod); + mod.dn = talloc_strdup(mem_ctx, a_state->account_dn); + if (!mod.dn) { + return NT_STATUS_NO_MEMORY; + } + + status = samdb_set_password(a_state->sam_ctx, mem_ctx, + a_state->account_dn, a_state->domain_state->domain_dn, + &mod, NULL, &new_lmPwdHash, &new_ntPwdHash, True); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + for (i=0;isam_ctx, mem_ctx, &mod); + if (ret != 0) { + return NT_STATUS_UNSUCCESSFUL; + } + + return NT_STATUS_OK; +} + +/* + samr_OemChangePasswordUser2 +*/ +static NTSTATUS samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct samr_OemChangePasswordUser2 *r) +{ + NTSTATUS status; + char new_pass[512]; + uint32 new_pass_len; + struct samr_CryptPassword *pwbuf = r->in.password; + void *sam_ctx; + const char *user_dn, *domain_dn; + int ret; + struct ldb_message **res, mod; + const char * const attrs[] = { "objectSid", "lmPwdHash", NULL }; + const char *domain_sid; + struct samr_Hash *lmPwdHash; + + if (pwbuf == NULL) { + return NT_STATUS_WRONG_PASSWORD; + } + + /* this call doesn't take a policy handle, so we need to open + the sam db from scratch */ + sam_ctx = samdb_connect(); + 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 = samdb_search(sam_ctx, + mem_ctx, NULL, &res, attrs, + "(&(sAMAccountName=%s)(objectclass=user))", + r->in.account->name); + if (ret != 1) { + samdb_close(sam_ctx); + return NT_STATUS_NO_SUCH_USER; + } + + user_dn = res[0]->dn; + + ret = samdb_result_hashes(mem_ctx, res[0], "lmPwdHash", &lmPwdHash); + if (ret != 1) { + samdb_close(sam_ctx); + return NT_STATUS_WRONG_PASSWORD; + } + + /* decrypt the password we have been given */ + SamOEMhash(pwbuf->data, lmPwdHash->hash, 516); + + if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass), + &new_pass_len, STR_ASCII)) { + DEBUG(3,("samr: failed to decode password buffer\n")); + samdb_close(sam_ctx); + return NT_STATUS_WRONG_PASSWORD; + } + + /* work out the domain dn */ + domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid"); + if (domain_sid == NULL) { + samdb_close(sam_ctx); + return NT_STATUS_NO_SUCH_USER; + } + + domain_dn = samdb_search_string(sam_ctx, mem_ctx, NULL, "dn", + "(objectSid=%s)", domain_sid); + if (!domain_dn) { + samdb_close(sam_ctx); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + + ZERO_STRUCT(mod); + mod.dn = talloc_strdup(mem_ctx, user_dn); + if (!mod.dn) { + samdb_close(sam_ctx); + return NT_STATUS_NO_MEMORY; + } + + /* set the password - samdb needs to know both the domain and user DNs, + so the domain password policy can be used */ + status = samdb_set_password(sam_ctx, mem_ctx, + user_dn, domain_dn, + &mod, new_pass, + NULL, NULL, + True); + if (!NT_STATUS_IS_OK(status)) { + samdb_close(sam_ctx); + return status; + } + + /* modify the samdb record */ + ret = samdb_modify(sam_ctx, mem_ctx, &mod); + if (ret != 0) { + samdb_close(sam_ctx); + return NT_STATUS_UNSUCCESSFUL; + } + + samdb_close(sam_ctx); + return NT_STATUS_OK; +} + + +/* + samr_ChangePasswordUser2 +*/ +static NTSTATUS samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct samr_ChangePasswordUser2 *r) { DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR); } +/* + samr_ChangePasswordUser3 +*/ +static NTSTATUS samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, + struct samr_ChangePasswordUser3 *r) +{ + DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR); +} + + + + /* samr_GetGroupsForUser */ @@ -2000,26 +2226,6 @@ static NTSTATUS samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dc } -/* - samr_OemChangePasswordUser2 -*/ -static NTSTATUS samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct samr_OemChangePasswordUser2 *r) -{ - DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR); -} - - -/* - samr_ChangePasswordUser2 -*/ -static NTSTATUS samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct samr_ChangePasswordUser2 *r) -{ - DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR); -} - - /* samr_GetDomPwInfo @@ -2152,16 +2358,6 @@ static NTSTATUS samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *me } -/* - samr_ChangePasswordUser3 -*/ -static NTSTATUS samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct samr_ChangePasswordUser3 *r) -{ - DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR); -} - - /* samr_Connect5 */ diff --git a/source4/rpc_server/samr/samdb.c b/source4/rpc_server/samr/samdb.c index 76de26222d..c9d7d601b2 100644 --- a/source4/rpc_server/samr/samdb.c +++ b/source4/rpc_server/samr/samdb.c @@ -313,6 +313,33 @@ uint32 samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg, return sid->sub_auths[sid->num_auths-1]; } +/* + pull a dom_sid structure from a objectSid in a result set. +*/ +struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr) +{ + const char *sidstr = ldb_msg_find_string(msg, attr, NULL); + if (!sidstr) return NULL; + + return dom_sid_parse_talloc(mem_ctx, sidstr); +} + +/* + pull a sid prefix from a objectSid in a result set. + this is used to find the domain sid for a user +*/ +const char *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr) +{ + struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr); + if (!sid || sid->num_auths < 1) return NULL; + + sid->num_auths--; + + return dom_sid_string(mem_ctx, sid); +} + /* pull a NTTIME in a result set. */ -- cgit