diff options
author | Andrew Bartlett <abartlet@samba.org> | 2004-05-15 07:51:38 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:53:46 -0500 |
commit | 064e7447bebd715c8351d9a0ee31f648990f2336 (patch) | |
tree | 156925cd7c8d4616f0eca3a743b7323b3b0b23b7 /source4/rpc_server/samr | |
parent | 31b9470996632d717c3c74482308e200906fdb8f (diff) | |
download | samba-064e7447bebd715c8351d9a0ee31f648990f2336.tar.gz samba-064e7447bebd715c8351d9a0ee31f648990f2336.tar.bz2 samba-064e7447bebd715c8351d9a0ee31f648990f2336.zip |
r743: Start on a NETLOGON server in Samba4.
Currently this only authentiates the machine, not real users.
As a consequence of running the Samba4 NETLOGON test against Samba4, I
found a number of issues in the SAMR server, which I have addressed.
There are more templates in the provison.ldif for this reason.
I also added some debug to our credentials code, and fixed some bugs
in the auth_sam module.
The static buffer in generate_random_string() bit me badly, so I
removed it in favor of a talloc based system.
Andrew Bartlett
(This used to be commit 94624e519b66def97758b8a48a01ffe9029176f0)
Diffstat (limited to 'source4/rpc_server/samr')
-rw-r--r-- | source4/rpc_server/samr/dcesrv_samr.c | 77 | ||||
-rw-r--r-- | source4/rpc_server/samr/samdb.c | 202 | ||||
-rw-r--r-- | source4/rpc_server/samr/samr_utils.c | 134 |
3 files changed, 308 insertions, 105 deletions
diff --git a/source4/rpc_server/samr/dcesrv_samr.c b/source4/rpc_server/samr/dcesrv_samr.c index d5a028ce09..847b30e71c 100644 --- a/source4/rpc_server/samr/dcesrv_samr.c +++ b/source4/rpc_server/samr/dcesrv_samr.c @@ -603,6 +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; ZERO_STRUCTP(r->out.acct_handle); *r->out.access_granted = 0; @@ -628,14 +629,55 @@ static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX ZERO_STRUCT(msg); - /* pull in all the template attributes */ - ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg, - "(&(name=TemplateUser)(objectclass=userTemplate))"); - if (ret != 0) { - DEBUG(1,("Failed to load TemplateUser from samdb\n")); - return NT_STATUS_INTERNAL_DB_CORRUPTION; + /* This must be one of these values *only* */ + if (r->in.acct_flags == ACB_NORMAL) { + /* pull in all the template attributes */ + ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg, + "(&(name=TemplateUser)(objectclass=userTemplate))"); + if (ret != 0) { + DEBUG(1,("Failed to load TemplateUser from samdb\n")); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + container = "Users"; + + } else if (r->in.acct_flags == ACB_WSTRUST) { + /* pull in all the template attributes */ + ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg, + "(&(name=TemplateMemberServer)(objectclass=userTemplate))"); + if (ret != 0) { + DEBUG(1,("Failed to load TemplateMemberServer from samdb\n")); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + container = "Computers"; + + } else if (r->in.acct_flags == ACB_SVRTRUST) { + /* pull in all the template attributes */ + ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg, + "(&(name=TemplateDomainController)(objectclass=userTemplate))"); + if (ret != 0) { + DEBUG(1,("Failed to load TemplateDomainController from samdb\n")); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + container = "DomainControllers"; + + } else if (r->in.acct_flags == ACB_DOMTRUST) { + /* pull in all the template attributes */ + ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg, + "(&(name=TemplateTrustingDomain)(objectclass=userTemplate))"); + if (ret != 0) { + DEBUG(1,("Failed to load TemplateTrustingDomain from samdb\n")); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + container = "ForeignDomains"; /* FIXME: Is this correct?*/ + + } else { + return NT_STATUS_INVALID_PARAMETER; } - + /* allocate a rid */ status = samdb_allocate_next_id(d_state->sam_ctx, mem_ctx, d_state->domain_dn, "nextRid", &rid); @@ -650,7 +692,7 @@ static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX } /* add core elements to the ldb_message for the user */ - msg.dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Users,%s", username, d_state->domain_dn); + msg.dn = talloc_asprintf(mem_ctx, "CN=%s,CN=%s,%s", username, container, d_state->domain_dn); if (!msg.dn) { return NT_STATUS_NO_MEMORY; } @@ -723,7 +765,7 @@ static NTSTATUS samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX * /* a simple wrapper around samr_CreateUser2 works nicely */ r2.in.handle = r->in.handle; r2.in.username = r->in.username; - r2.in.acct_flags = 1234; + r2.in.acct_flags = ACB_NORMAL; r2.in.access_mask = r->in.access_mask; r2.out.acct_handle = r->out.acct_handle; r2.out.access_granted = &access_granted; @@ -914,18 +956,9 @@ static NTSTATUS samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX continue; } - switch (atype & 0xF0000000) { - case ATYPE_ACCOUNT: - rtype = SID_NAME_USER; - break; - case ATYPE_GLOBAL_GROUP: - rtype = SID_NAME_DOM_GRP; - break; - case ATYPE_LOCAL_GROUP: - rtype = SID_NAME_ALIAS; - break; - default: - DEBUG(1,("Unknown sAMAccountType 0x%08x\n", atype)); + rtype = samdb_atype_map(atype); + + if (rtype == SID_NAME_UNKNOWN) { status = STATUS_SOME_UNMAPPED; continue; } @@ -1654,7 +1687,7 @@ static NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call, so the domain password policy can be used */ return samdb_set_password(a_state->sam_ctx, mem_ctx, a_state->account_dn, a_state->domain_state->domain_dn, - msg, new_pass); + msg, new_pass, False /* This is a password set, not change */); } /* diff --git a/source4/rpc_server/samr/samdb.c b/source4/rpc_server/samr/samdb.c index 2fa17af8ea..2489dae684 100644 --- a/source4/rpc_server/samr/samdb.c +++ b/source4/rpc_server/samr/samdb.c @@ -416,6 +416,68 @@ uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg, return count; } +NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg, + uint8 **lm_pwd, uint8 **nt_pwd) +{ + + const char *unicodePwd = samdb_result_string(msg, "unicodePwd", NULL); + + struct samr_Hash *lmPwdHash, *ntPwdHash; + if (unicodePwd) { + if (nt_pwd) { + ntPwdHash = talloc_p(mem_ctx, struct samr_Hash); + if (!ntPwdHash) { + return NT_STATUS_NO_MEMORY; + } + + E_md4hash(unicodePwd, ntPwdHash->hash); + *nt_pwd = ntPwdHash->hash; + } + + if (lm_pwd) { + BOOL lm_hash_ok; + + lmPwdHash = talloc_p(mem_ctx, struct samr_Hash); + if (!lmPwdHash) { + return NT_STATUS_NO_MEMORY; + } + + /* compute the new nt and lm hashes */ + lm_hash_ok = E_deshash(unicodePwd, lmPwdHash->hash); + + if (lm_hash_ok) { + *lm_pwd = lmPwdHash->hash; + } else { + *lm_pwd = NULL; + } + } + } else { + if (nt_pwd) { + int num_nt; + num_nt = samdb_result_hashes(mem_ctx, msg, "ntPwdHash", &ntPwdHash); + if (num_nt == 0) { + nt_pwd = NULL; + } else if (num_nt > 1) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } else { + *nt_pwd = ntPwdHash[0].hash; + } + } + if (lm_pwd) { + int num_lm; + num_lm = samdb_result_hashes(mem_ctx, msg, "lmPwdHash", &lmPwdHash); + if (num_lm == 0) { + *lm_pwd = NULL; + } else if (num_lm > 1) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } else { + *lm_pwd = lmPwdHash[0].hash; + } + } + + } + return NT_STATUS_OK; +} /* pull a samr_LogonHours structutre from a result set. @@ -438,36 +500,13 @@ struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_ return hours; } -/* mapping between ADS userAccountControl and SAMR acct_flags */ -static const struct { - uint32 uf, acb; -} acct_flags_map[] = { - { UF_ACCOUNTDISABLE, ACB_DISABLED }, - { UF_HOMEDIR_REQUIRED, ACB_HOMDIRREQ }, - { UF_PASSWD_NOTREQD, ACB_PWNOTREQ }, - { UF_TEMP_DUPLICATE_ACCOUNT, ACB_TEMPDUP }, - { UF_NORMAL_ACCOUNT, ACB_NORMAL }, - { UF_MNS_LOGON_ACCOUNT, ACB_MNS }, - { UF_INTERDOMAIN_TRUST_ACCOUNT, ACB_DOMTRUST }, - { UF_WORKSTATION_TRUST_ACCOUNT, ACB_WSTRUST }, - { UF_SERVER_TRUST_ACCOUNT, ACB_SVRTRUST }, - { UF_DONT_EXPIRE_PASSWD, ACB_PWNOEXP }, - { UF_LOCKOUT, ACB_AUTOLOCK } -}; - /* pull a set of account_flags from a result set. */ -uint32 samdb_result_acct_flags(struct ldb_message *msg, const char *attr) +uint16 samdb_result_acct_flags(struct ldb_message *msg, const char *attr) { uint_t userAccountControl = ldb_msg_find_uint(msg, attr, 0); - uint32 i, ret = 0; - for (i=0;i<ARRAY_SIZE(acct_flags_map);i++) { - if (acct_flags_map[i].uf & userAccountControl) { - ret |= acct_flags_map[i].acb; - } - } - return ret; + return samdb_uf2acb(userAccountControl); } /* @@ -707,13 +746,7 @@ int samdb_msg_add_hashes(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg int samdb_msg_add_acct_flags(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr_name, uint32 v) { - uint_t i, flags = 0; - for (i=0;i<ARRAY_SIZE(acct_flags_map);i++) { - if (acct_flags_map[i].acb & v) { - flags |= acct_flags_map[i].uf; - } - } - return samdb_msg_add_uint(ctx, mem_ctx, msg, attr_name, flags); + return samdb_msg_add_uint(ctx, mem_ctx, msg, attr_name, samdb_acb2uf(v)); } /* @@ -808,7 +841,8 @@ static BOOL samdb_password_complexity_ok(const char *pass) */ NTSTATUS samdb_set_password(void *ctx, TALLOC_CTX *mem_ctx, const char *user_dn, const char *domain_dn, - struct ldb_message *mod, const char *new_pass) + struct ldb_message *mod, const char *new_pass, + BOOL user_change) { const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory", "ntPwdHistory", "unicodePwd", @@ -863,71 +897,73 @@ NTSTATUS samdb_set_password(void *ctx, TALLOC_CTX *mem_ctx, minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0); minPwdAge = samdb_result_double(res[0], "minPwdAge", 0); - /* are all password changes disallowed? */ - if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) { - return NT_STATUS_PASSWORD_RESTRICTION; - } - - /* can this user change password? */ - if (userAccountControl & UF_PASSWD_CANT_CHANGE) { - return NT_STATUS_PASSWORD_RESTRICTION; - } - - /* check the various password restrictions */ - if (minPwdLength > str_charnum(new_pass)) { - return NT_STATUS_PASSWORD_RESTRICTION; - } - - /* yes, this is a minus. The ages are in negative 100nsec units! */ - if (pwdLastSet - minPwdAge > now_double) { - return NT_STATUS_PASSWORD_RESTRICTION; - } - - /* possibly check password complexity */ - if (pwdProperties & DOMAIN_PASSWORD_COMPLEX && - !samdb_password_complexity_ok(new_pass)) { - return NT_STATUS_PASSWORD_RESTRICTION; - } - /* compute the new nt and lm hashes */ lm_hash_ok = E_deshash(new_pass, lmNewHash.hash); E_md4hash(new_pass, ntNewHash.hash); - /* check the immediately past password */ - if (pwdHistoryLength > 0) { - if (lm_hash_ok && memcmp(lmNewHash.hash, lmPwdHash.hash, 16) == 0) { + if (user_change) { + /* are all password changes disallowed? */ + if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) { return NT_STATUS_PASSWORD_RESTRICTION; } - if (memcmp(ntNewHash.hash, ntPwdHash.hash, 16) == 0) { + + /* can this user change password? */ + if (userAccountControl & UF_PASSWD_CANT_CHANGE) { return NT_STATUS_PASSWORD_RESTRICTION; } - } - - /* check the password history */ - lmPwdHistory_len = MIN(lmPwdHistory_len, pwdHistoryLength); - ntPwdHistory_len = MIN(ntPwdHistory_len, pwdHistoryLength); - - if (pwdHistoryLength > 0) { - if (unicodePwd && strcmp(unicodePwd, new_pass) == 0) { + + /* yes, this is a minus. The ages are in negative 100nsec units! */ + if (pwdLastSet - minPwdAge > now_double) { return NT_STATUS_PASSWORD_RESTRICTION; } - if (lm_hash_ok && memcmp(lmNewHash.hash, lmPwdHash.hash, 16) == 0) { - return NT_STATUS_PASSWORD_RESTRICTION; + + /* check the immediately past password */ + if (pwdHistoryLength > 0) { + if (lm_hash_ok && memcmp(lmNewHash.hash, lmPwdHash.hash, 16) == 0) { + return NT_STATUS_PASSWORD_RESTRICTION; + } + if (memcmp(ntNewHash.hash, ntPwdHash.hash, 16) == 0) { + return NT_STATUS_PASSWORD_RESTRICTION; + } } - if (memcmp(ntNewHash.hash, ntPwdHash.hash, 16) == 0) { - return NT_STATUS_PASSWORD_RESTRICTION; + + /* check the password history */ + lmPwdHistory_len = MIN(lmPwdHistory_len, pwdHistoryLength); + ntPwdHistory_len = MIN(ntPwdHistory_len, pwdHistoryLength); + + if (pwdHistoryLength > 0) { + if (unicodePwd && strcmp(unicodePwd, new_pass) == 0) { + return NT_STATUS_PASSWORD_RESTRICTION; + } + if (lm_hash_ok && memcmp(lmNewHash.hash, lmPwdHash.hash, 16) == 0) { + return NT_STATUS_PASSWORD_RESTRICTION; + } + if (memcmp(ntNewHash.hash, ntPwdHash.hash, 16) == 0) { + return NT_STATUS_PASSWORD_RESTRICTION; + } + } + + for (i=0;lm_hash_ok && i<lmPwdHistory_len;i++) { + if (memcmp(lmNewHash.hash, lmPwdHistory[i].hash, 16) == 0) { + return NT_STATUS_PASSWORD_RESTRICTION; + } + } + for (i=0;i<ntPwdHistory_len;i++) { + if (memcmp(ntNewHash.hash, ntPwdHistory[i].hash, 16) == 0) { + return NT_STATUS_PASSWORD_RESTRICTION; + } } } - for (i=0;lm_hash_ok && i<lmPwdHistory_len;i++) { - if (memcmp(lmNewHash.hash, lmPwdHistory[i].hash, 16) == 0) { - return NT_STATUS_PASSWORD_RESTRICTION; - } + /* check the various password restrictions */ + if (minPwdLength > str_charnum(new_pass)) { + return NT_STATUS_PASSWORD_RESTRICTION; } - for (i=0;i<ntPwdHistory_len;i++) { - if (memcmp(ntNewHash.hash, ntPwdHistory[i].hash, 16) == 0) { - return NT_STATUS_PASSWORD_RESTRICTION; - } + + /* possibly check password complexity */ + if (pwdProperties & DOMAIN_PASSWORD_COMPLEX && + !samdb_password_complexity_ok(new_pass)) { + return NT_STATUS_PASSWORD_RESTRICTION; } #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0) diff --git a/source4/rpc_server/samr/samr_utils.c b/source4/rpc_server/samr/samr_utils.c new file mode 100644 index 0000000000..247b2d47f4 --- /dev/null +++ b/source4/rpc_server/samr/samr_utils.c @@ -0,0 +1,134 @@ +/* + Unix SMB/CIFS implementation. + helper mapping functions for the SAMDB server + + Copyright (C) Stefan (metze) Metzmacher 2002 + Copyright (C) Andrew Tridgell 2004 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/* +translated the ACB_CTRL Flags to UserFlags (userAccountControl) +*/ +/* mapping between ADS userAccountControl and SAMR acct_flags */ +static const struct { + uint32 uf; + uint16 acb; +} acct_flags_map[] = { + { UF_ACCOUNTDISABLE, ACB_DISABLED }, + { UF_HOMEDIR_REQUIRED, ACB_HOMDIRREQ }, + { UF_PASSWD_NOTREQD, ACB_PWNOTREQ }, + { UF_TEMP_DUPLICATE_ACCOUNT, ACB_TEMPDUP }, + { UF_NORMAL_ACCOUNT, ACB_NORMAL }, + { UF_MNS_LOGON_ACCOUNT, ACB_MNS }, + { UF_INTERDOMAIN_TRUST_ACCOUNT, ACB_DOMTRUST }, + { UF_WORKSTATION_TRUST_ACCOUNT, ACB_WSTRUST }, + { UF_SERVER_TRUST_ACCOUNT, ACB_SVRTRUST }, + { UF_DONT_EXPIRE_PASSWD, ACB_PWNOEXP }, + { UF_LOCKOUT, ACB_AUTOLOCK } +}; + +uint32 samdb_acb2uf(uint16 acb) +{ + uint32 i, ret = 0; + for (i=0;i<ARRAY_SIZE(acct_flags_map);i++) { + if (acct_flags_map[i].acb & acb) { + ret |= acct_flags_map[i].uf; + } + } + return ret; +} + +/* +translated the UserFlags (userAccountControl) to ACB_CTRL Flags +*/ +uint16 samdb_uf2acb(uint32 uf) +{ + uint32 i; + uint16 ret = 0; + for (i=0;i<ARRAY_SIZE(acct_flags_map);i++) { + if (acct_flags_map[i].uf & uf) { + ret |= acct_flags_map[i].acb; + } + } + return ret; +} + +/* +get the accountType from the UserFlags +*/ +uint32 samdb_uf2atype(uint32 uf) +{ + uint32 atype = 0x00000000; + + if (uf & UF_NORMAL_ACCOUNT) atype = ATYPE_NORMAL_ACCOUNT; + else if (uf & UF_TEMP_DUPLICATE_ACCOUNT) atype = ATYPE_NORMAL_ACCOUNT; + else if (uf & UF_SERVER_TRUST_ACCOUNT) atype = ATYPE_WORKSTATION_TRUST; + else if (uf & UF_WORKSTATION_TRUST_ACCOUNT) atype = ATYPE_WORKSTATION_TRUST; + else if (uf & UF_INTERDOMAIN_TRUST_ACCOUNT) atype = ATYPE_INTERDOMAIN_TRUST; + + return atype; +} + +/* +get the accountType from the groupType +*/ +uint32 samdb_gtype2atype(uint32 gtype) +{ + uint32 atype = 0x00000000; + + switch(gtype) { + case GTYPE_SECURITY_BUILTIN_LOCAL_GROUP: + atype = ATYPE_SECURITY_LOCAL_GROUP; + break; + case GTYPE_SECURITY_DOMAIN_LOCAL_GROUP: + atype = ATYPE_SECURITY_LOCAL_GROUP; + break; + case GTYPE_SECURITY_GLOBAL_GROUP: + atype = ATYPE_SECURITY_GLOBAL_GROUP; + break; + + case GTYPE_DISTRIBUTION_GLOBAL_GROUP: + atype = ATYPE_DISTRIBUTION_GLOBAL_GROUP; + break; + case GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP: + atype = ATYPE_DISTRIBUTION_UNIVERSAL_GROUP; + break; + case GTYPE_DISTRIBUTION_UNIVERSAL_GROUP: + atype = ATYPE_DISTRIBUTION_LOCAL_GROUP; + break; + } + + return atype; +} + +/* turn a sAMAccountType into a SID_NAME_USE */ +enum SID_NAME_USE samdb_atype_map(uint32 atype) +{ + switch (atype & 0xF0000000) { + case ATYPE_GLOBAL_GROUP: + return SID_NAME_DOM_GRP; + case ATYPE_SECURITY_LOCAL_GROUP: + return SID_NAME_ALIAS; + case ATYPE_ACCOUNT: + return SID_NAME_USER; + default: + DEBUG(1,("hmm, need to map account type 0x%x\n", atype)); + } + return SID_NAME_UNKNOWN; +} |