diff options
author | Andrew Tridgell <tridge@samba.org> | 2004-05-09 09:39:47 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:51:50 -0500 |
commit | 54a695f7edf7c40a92391aa94ddbbd2db8b11ec3 (patch) | |
tree | 066b3c3b2002916159b69dd5a633ef6f5dc2b920 /source4 | |
parent | b91eb9e73a1329576698a1ce4f1e5bef3b63adb0 (diff) | |
download | samba-54a695f7edf7c40a92391aa94ddbbd2db8b11ec3.tar.gz samba-54a695f7edf7c40a92391aa94ddbbd2db8b11ec3.tar.bz2 samba-54a695f7edf7c40a92391aa94ddbbd2db8b11ec3.zip |
r601: added the server code for all the samr_SetUserInfo and samr_QueryUserInfo levels except for the password
set levels.
This means that a large part of the RPC-SAMR torture test now runs correctly against Samba4
(This used to be commit ec0a51898f543578e755207d81ed5c1524861c64)
Diffstat (limited to 'source4')
-rw-r--r-- | source4/include/smb.h | 13 | ||||
-rw-r--r-- | source4/lib/ldb/common/ldb_msg.c | 36 | ||||
-rw-r--r-- | source4/lib/time.c | 26 | ||||
-rw-r--r-- | source4/librpc/idl/samr.idl | 21 | ||||
-rw-r--r-- | source4/rpc_server/samr/dcesrv_samr.c | 224 | ||||
-rw-r--r-- | source4/rpc_server/samr/samdb.c | 135 |
6 files changed, 400 insertions, 55 deletions
diff --git a/source4/include/smb.h b/source4/include/smb.h index 6e87e158b2..6982a0dae0 100644 --- a/source4/include/smb.h +++ b/source4/include/smb.h @@ -236,19 +236,6 @@ typedef smb_ucs2_t wfstring[FSTRING_LEN]; /* turn a 7 bit character into a ucs2 character */ #define UCS2_CHAR(c) ((c) << UCS2_SHIFT) -/* Allowable account control bits */ -#define ACB_DISABLED 0x0001 /* 1 = User account disabled */ -#define ACB_HOMDIRREQ 0x0002 /* 1 = Home directory required */ -#define ACB_PWNOTREQ 0x0004 /* 1 = User password not required */ -#define ACB_TEMPDUP 0x0008 /* 1 = Temporary duplicate account */ -#define ACB_NORMAL 0x0010 /* 1 = Normal user account */ -#define ACB_MNS 0x0020 /* 1 = MNS logon user account */ -#define ACB_DOMTRUST 0x0040 /* 1 = Interdomain trust account */ -#define ACB_WSTRUST 0x0080 /* 1 = Workstation trust account */ -#define ACB_SVRTRUST 0x0100 /* 1 = Server trust account */ -#define ACB_PWNOEXP 0x0200 /* 1 = User password does not expire */ -#define ACB_AUTOLOCK 0x0400 /* 1 = Account auto locked */ - #define MAX_HOURS_LEN 32 #ifndef MAXSUBAUTHS diff --git a/source4/lib/ldb/common/ldb_msg.c b/source4/lib/ldb/common/ldb_msg.c index 01f32751e1..59d480a33a 100644 --- a/source4/lib/ldb/common/ldb_msg.c +++ b/source4/lib/ldb/common/ldb_msg.c @@ -136,7 +136,7 @@ int ldb_msg_add(struct ldb_context *ldb, */ int ldb_msg_add_value(struct ldb_context *ldb, struct ldb_message *msg, - char *attr_name, + const char *attr_name, struct ldb_val *val) { struct ldb_message_element *el; @@ -200,51 +200,59 @@ int ldb_msg_element_compare(struct ldb_message_element *el1, return 0; } - /* convenience functions to return common types from a message these return the first value if the attribute is multi-valued */ +const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, const char *attr_name) +{ + struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name); + if (!el || el->num_values == 0) { + return NULL; + } + return &el->values[0]; +} + int ldb_msg_find_int(const struct ldb_message *msg, const char *attr_name, int default_value) { - struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name); - if (!el || el->num_values == 0) { + const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name); + if (!v || !v->data) { return default_value; } - return strtol(el->values[0].data, NULL, 0); + return strtol(v->data, NULL, 0); } unsigned int ldb_msg_find_uint(const struct ldb_message *msg, const char *attr_name, int default_value) { - struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name); - if (!el || el->num_values == 0) { + const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name); + if (!v || !v->data) { return default_value; } - return strtoul(el->values[0].data, NULL, 0); + return strtoul(v->data, NULL, 0); } double ldb_msg_find_double(const struct ldb_message *msg, const char *attr_name, double default_value) { - struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name); - if (!el || el->num_values == 0) { + const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name); + if (!v || !v->data) { return default_value; } - return strtod(el->values[0].data, NULL); + return strtod(v->data, NULL); } const char *ldb_msg_find_string(const struct ldb_message *msg, const char *attr_name, const char *default_value) { - struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name); - if (!el || el->num_values == 0) { + const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name); + if (!v || !v->data) { return default_value; } - return el->values[0].data; + return v->data; } diff --git a/source4/lib/time.c b/source4/lib/time.c index 65b85b2180..ba650668c5 100644 --- a/source4/lib/time.c +++ b/source4/lib/time.c @@ -428,21 +428,31 @@ NTTIME pull_nttime(void *base, uint16 offset) return ret; } +/* + convert a NTTIME to a double in 100-nano-seconds since 1601 +*/ +double nttime_to_double_nt(NTTIME t) +{ + const double t32 = 4294967296.0; + return t.high*t32 + t.low; +} /* - parse a nttime as a integer in a string and return a NTTIME + convert a double in 100-nano-seconds since 1601 to a NTTIME */ -NTTIME nttime_from_string(const char *s) +NTTIME nttime_from_double_nt(double t) { - double t = 0; const double t32 = 4294967296.0; NTTIME ret; - /* i wish we could rely on 64 bit systems and sscanf %llu */ - if (sscanf(s, "%lf", &t) != 1) { - ret.low = 0; - ret.high = 0; - } ret.high = t / t32; ret.low = t - (ret.high*t32); return ret; } + +/* + parse a nttime as a large integer in a string and return a NTTIME +*/ +NTTIME nttime_from_string(const char *s) +{ + return nttime_from_double_nt(strtod(s, NULL)); +} diff --git a/source4/librpc/idl/samr.idl b/source4/librpc/idl/samr.idl index 070331933b..2ff4e86cd1 100644 --- a/source4/librpc/idl/samr.idl +++ b/source4/librpc/idl/samr.idl @@ -13,6 +13,20 @@ pointer_default(unique) ] interface samr { + /* account control (acct_flags) bits */ + const int ACB_DISABLED = 0x0001; /* 1 = User account disabled */ + const int ACB_HOMDIRREQ = 0x0002; /* 1 = Home directory required */ + const int ACB_PWNOTREQ = 0x0004; /* 1 = User password not required */ + const int ACB_TEMPDUP = 0x0008; /* 1 = Temporary duplicate account */ + const int ACB_NORMAL = 0x0010; /* 1 = Normal user account */ + const int ACB_MNS = 0x0020; /* 1 = MNS logon user account */ + const int ACB_DOMTRUST = 0x0040; /* 1 = Interdomain trust account */ + const int ACB_WSTRUST = 0x0080; /* 1 = Workstation trust account */ + const int ACB_SVRTRUST = 0x0100; /* 1 = Server trust account */ + const int ACB_PWNOEXP = 0x0200; /* 1 = User password does not expire */ + const int ACB_AUTOLOCK = 0x0400; /* 1 = Account auto locked */ + + /******************/ /* Function: 0x00 */ NTSTATUS samr_Connect ( @@ -263,6 +277,7 @@ /************************/ /* Function 0x0d */ + /* w2k3 treats max_size as max_users*54 and sets the resume_handle as the rid of the last user sent */ @@ -569,7 +584,7 @@ typedef struct { samr_Name username; samr_Name full_name; - uint32 Rid; + uint32 rid; uint32 primary_gid; samr_Name home_directory; samr_Name home_drive; @@ -630,7 +645,7 @@ } samr_UserInfo9; typedef struct { - samr_Name home_dir; + samr_Name home_directory; samr_Name home_drive; } samr_UserInfo10; @@ -684,7 +699,7 @@ NTTIME force_pwd_change; samr_Name username; samr_Name full_name; - samr_Name home_dir; + samr_Name home_directory; samr_Name home_drive; samr_Name logon_script; samr_Name profile; diff --git a/source4/rpc_server/samr/dcesrv_samr.c b/source4/rpc_server/samr/dcesrv_samr.c index 9de81c33e5..a4e5d4f189 100644 --- a/source4/rpc_server/samr/dcesrv_samr.c +++ b/source4/rpc_server/samr/dcesrv_samr.c @@ -1100,6 +1100,17 @@ static NTSTATUS samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX * r->out.info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0); #define QUERY_NTTIME(msg, field, attr) \ r->out.info->field = samdb_result_nttime(msg, attr, 0); +#define QUERY_APASSC(msg, field, attr) \ + r->out.info->field = samdb_result_allow_pwd_change(state->sam_ctx, mem_ctx, \ + state->domain_state->basedn, msg, attr); +#define QUERY_FPASSC(msg, field, attr) \ + r->out.info->field = samdb_result_force_pwd_change(state->sam_ctx, mem_ctx, \ + state->domain_state->basedn, msg, attr); +#define QUERY_LHOURS(msg, field, attr) \ + r->out.info->field = samdb_result_logon_hours(mem_ctx, msg, attr); +#define QUERY_AFLAGS(msg, field, attr) \ + r->out.info->field = samdb_result_acct_flags(msg, attr); + /* samr_QueryUserInfo @@ -1152,7 +1163,7 @@ static NTSTATUS samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CT case 3: QUERY_STRING(msg, info3.username.name, "sAMAccountName"); QUERY_STRING(msg, info3.full_name.name, "displayName"); - QUERY_RID (msg, info3.Rid, "objectSid"); + QUERY_RID (msg, info3.rid, "objectSid"); QUERY_UINT (msg, info3.primary_gid, "primaryGroupID"); QUERY_STRING(msg, info3.home_directory.name, "homeDirectory"); QUERY_STRING(msg, info3.home_drive.name, "homeDrive"); @@ -1162,15 +1173,117 @@ static NTSTATUS samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CT QUERY_NTTIME(msg, info3.last_logon, "lastLogon"); QUERY_NTTIME(msg, info3.last_logoff, "lastLogoff"); QUERY_NTTIME(msg, info3.last_pwd_change, "pwdLastSet"); -/* - QUERY_APASSC(msg, info2.allow_pwd_change, "pwdLastSet"); - QUERY_LHOURS(msg, info2.logon_hours, "logonHours"); - QUERY_UINT (msg, info2.bad_pwd_count, "badPwdCount"); - QUERY_UINT (msg, info2.num_logons, "logonCount"); - QUERY_AFLAGS(msg, info2.acct_flags, "userAccountControl"); -*/ + QUERY_APASSC(msg, info3.allow_pwd_change, "pwdLastSet"); + QUERY_FPASSC(msg, info3.force_pwd_change, "pwdLastSet"); + QUERY_LHOURS(msg, info3.logon_hours, "logonHours"); + QUERY_UINT (msg, info3.bad_pwd_count, "badPwdCount"); + QUERY_UINT (msg, info3.num_logons, "logonCount"); + QUERY_AFLAGS(msg, info3.acct_flags, "userAccountControl"); + break; + + case 4: + QUERY_LHOURS(msg, info4.logon_hours, "logonHours"); + break; + + case 5: + QUERY_STRING(msg, info5.username.name, "sAMAccountName"); + QUERY_STRING(msg, info5.full_name.name, "displayName"); + QUERY_RID (msg, info5.rid, "objectSid"); + QUERY_UINT (msg, info5.primary_gid, "primaryGroupID"); + QUERY_STRING(msg, info5.home_directory.name, "homeDirectory"); + QUERY_STRING(msg, info5.home_drive.name, "homeDrive"); + QUERY_STRING(msg, info5.logon_script.name, "scriptPath"); + QUERY_STRING(msg, info5.profile.name, "profilePath"); + QUERY_STRING(msg, info5.description.name, "description"); + QUERY_STRING(msg, info5.workstations.name, "userWorkstations"); + QUERY_NTTIME(msg, info5.last_logon, "lastLogon"); + QUERY_NTTIME(msg, info5.last_logoff, "lastLogoff"); + QUERY_LHOURS(msg, info5.logon_hours, "logonHours"); + QUERY_UINT (msg, info5.bad_pwd_count, "badPwdCount"); + QUERY_UINT (msg, info5.num_logons, "logonCount"); + QUERY_NTTIME(msg, info5.last_pwd_change, "pwdLastSet"); + QUERY_NTTIME(msg, info5.acct_expiry, "accountExpires"); + QUERY_AFLAGS(msg, info5.acct_flags, "userAccountControl"); + break; + + case 6: + QUERY_STRING(msg, info6.username.name, "sAMAccountName"); + QUERY_STRING(msg, info6.full_name.name, "displayName"); + break; + + case 7: + QUERY_STRING(msg, info7.username.name, "sAMAccountName"); + break; + + case 8: + QUERY_STRING(msg, info8.full_name.name, "displayName"); + break; + + case 9: + QUERY_UINT (msg, info9.primary_gid, "primaryGroupID"); + break; + + case 10: + QUERY_STRING(msg, info10.home_directory.name, "homeDirectory"); + QUERY_STRING(msg, info10.home_drive.name, "homeDrive"); + break; + + case 11: + QUERY_STRING(msg, info11.logon_script.name, "scriptPath"); break; + case 12: + QUERY_STRING(msg, info12.profile.name, "profilePath"); + break; + + case 13: + QUERY_STRING(msg, info13.description.name, "description"); + break; + + case 14: + QUERY_STRING(msg, info14.workstations.name, "userWorkstations"); + break; + + case 16: + QUERY_AFLAGS(msg, info16.acct_flags, "userAccountControl"); + break; + + case 17: + QUERY_NTTIME(msg, info17.acct_expiry, "accountExpires"); + + case 20: + QUERY_STRING(msg, info20.callback.name, "userParameters"); + break; + + case 21: + QUERY_NTTIME(msg, info21.last_logon, "lastLogon"); + QUERY_NTTIME(msg, info21.last_logoff, "lastLogoff"); + QUERY_NTTIME(msg, info21.last_pwd_change, "pwdLastSet"); + QUERY_NTTIME(msg, info21.acct_expiry, "accountExpires"); + QUERY_APASSC(msg, info21.allow_pwd_change, "pwdLastSet"); + QUERY_FPASSC(msg, info21.force_pwd_change, "pwdLastSet"); + QUERY_STRING(msg, info21.username.name, "sAMAccountName"); + QUERY_STRING(msg, info21.full_name.name, "displayName"); + QUERY_STRING(msg, info21.home_directory.name, "homeDirectory"); + QUERY_STRING(msg, info21.home_drive.name, "homeDrive"); + QUERY_STRING(msg, info21.logon_script.name, "scriptPath"); + QUERY_STRING(msg, info21.profile.name, "profilePath"); + QUERY_STRING(msg, info21.description.name, "description"); + QUERY_STRING(msg, info21.workstations.name, "userWorkstations"); + QUERY_STRING(msg, info21.comment.name, "comment"); + QUERY_STRING(msg, info21.callback.name, "userParameters"); + QUERY_RID (msg, info21.rid, "objectSid"); + QUERY_UINT (msg, info21.primary_gid, "primaryGroupID"); + QUERY_AFLAGS(msg, info21.acct_flags, "userAccountControl"); + r->out.info->info21.fields_present = 0x00FFFFFF; + QUERY_LHOURS(msg, info21.logon_hours, "logonHours"); + QUERY_UINT (msg, info21.bad_pwd_count, "badPwdCount"); + QUERY_UINT (msg, info21.num_logons, "logonCount"); + QUERY_UINT (msg, info21.country_code, "countryCode"); + QUERY_UINT (msg, info21.code_page, "codePage"); + break; + + default: r->out.info = NULL; return NT_STATUS_INVALID_INFO_CLASS; @@ -1179,6 +1292,7 @@ static NTSTATUS samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CT return NT_STATUS_OK; } + /* these are used to make the SetUserInfo code easier to follow */ #define SET_STRING(mod, field, attr) do { \ if (r->in.info->field == NULL) return NT_STATUS_INVALID_PARAMETER; \ @@ -1193,6 +1307,17 @@ static NTSTATUS samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CT } \ } while (0) +#define SET_AFLAGS(msg, field, attr) do { \ + if (samdb_msg_add_acct_flags(state->sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \ + return NT_STATUS_NO_MEMORY; \ + } \ +} while (0) + +#define SET_LHOURS(msg, field, attr) do { \ + if (samdb_msg_add_logon_hours(state->sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \ + return NT_STATUS_NO_MEMORY; \ + } \ +} while (0) /* samr_SetUserInfo @@ -1202,7 +1327,7 @@ static NTSTATUS samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX { struct dcesrv_handle *h; struct samr_account_state *state; - struct ldb_message mod; + struct ldb_message mod, *msg = &mod; int i, ret; DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER); @@ -1217,9 +1342,68 @@ static NTSTATUS samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX switch (r->in.level) { case 2: - SET_STRING(&mod, info2.comment.name, "description"); - SET_UINT (&mod, info2.country_code, "countryCode"); - SET_UINT (&mod, info2.code_page, "codePage"); + SET_STRING(msg, info2.comment.name, "comment"); + SET_UINT (msg, info2.country_code, "countryCode"); + SET_UINT (msg, info2.code_page, "codePage"); + break; + + case 4: + SET_LHOURS(msg, info4.logon_hours, "logonHours"); + break; + + case 6: + SET_STRING(msg, info6.full_name.name, "displayName"); + break; + + case 8: + SET_STRING(msg, info8.full_name.name, "displayName"); + break; + + case 9: + SET_UINT(msg, info9.primary_gid, "primaryGroupID"); + break; + + case 10: + SET_STRING(msg, info10.home_directory.name, "homeDirectory"); + SET_STRING(msg, info10.home_drive.name, "homeDrive"); + break; + + case 11: + SET_STRING(msg, info11.logon_script.name, "scriptPath"); + break; + + case 12: + SET_STRING(msg, info12.profile.name, "profilePath"); + break; + + case 13: + SET_STRING(msg, info13.description.name, "description"); + break; + + case 14: + SET_STRING(msg, info14.workstations.name, "userWorkstations"); + break; + + case 16: + SET_AFLAGS(msg, info16.acct_flags, "userAccountControl"); + break; + + case 20: + SET_STRING(msg, info20.callback.name, "userParameters"); + break; + + case 21: +#define IFSET(bit) if (bit & r->in.info->info21.fields_present) + IFSET(SAMR_FIELD_NAME) SET_STRING(msg, info21.full_name.name, "displayName"); + IFSET(SAMR_FIELD_DESCRIPTION) SET_STRING(msg, info21.description.name, "description"); + IFSET(SAMR_FIELD_COMMENT) SET_STRING(msg, info21.comment.name, "comment"); + IFSET(SAMR_FIELD_LOGON_SCRIPT) SET_STRING(msg, info21.logon_script.name, "scriptPath"); + IFSET(SAMR_FIELD_PROFILE) SET_STRING(msg, info21.profile.name, "profilePath"); + IFSET(SAMR_FIELD_WORKSTATION) SET_STRING(msg, info21.workstations.name, "userWorkstations"); + IFSET(SAMR_FIELD_LOGON_HOURS) SET_LHOURS(msg, info21.logon_hours, "logonHours"); + IFSET(SAMR_FIELD_CALLBACK) SET_STRING(msg, info21.callback.name, "userParameters"); + IFSET(SAMR_FIELD_COUNTRY_CODE) SET_UINT(msg, info21.country_code, "countryCode"); + IFSET(SAMR_FIELD_CODE_PAGE) SET_UINT(msg, info21.code_page, "codePage"); break; default: @@ -1335,11 +1519,23 @@ static NTSTATUS samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC /* samr_QueryUserInfo2 + + just an alias for samr_QueryUserInfo */ static NTSTATUS samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct samr_QueryUserInfo2 *r) + struct samr_QueryUserInfo2 *r) { - DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR); + struct samr_QueryUserInfo r1; + NTSTATUS status; + + r1.in.handle = r->in.handle; + r1.in.level = r->in.level; + + status = samr_QueryUserInfo(dce_call, mem_ctx, &r1); + + r->out.info = r1.out.info; + + return status; } diff --git a/source4/rpc_server/samr/samdb.c b/source4/rpc_server/samr/samdb.c index d9c4c40008..5aae82e39d 100644 --- a/source4/rpc_server/samr/samdb.c +++ b/source4/rpc_server/samr/samdb.c @@ -287,15 +287,115 @@ uint32 samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg, } /* - pull a rid from a objectSid in a result set. + pull a NTTIME in a result set. */ -NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, - const char *default_value) +NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, const char *default_value) { const char *str = ldb_msg_find_string(msg, attr, default_value); return nttime_from_string(str); } +/* + pull a double (really a large integer) from a result set. +*/ +double samdb_result_double(struct ldb_message *msg, const char *attr, double default_value) +{ + return ldb_msg_find_double(msg, attr, default_value); +} + + +/* + construct the allow_pwd_change field from the PwdLastSet attribute and the + domain password settings +*/ +NTTIME samdb_result_allow_pwd_change(void *ctx, TALLOC_CTX *mem_ctx, + const char *domain_dn, struct ldb_message *msg, const char *attr) +{ + double attr_time = samdb_result_double(msg, attr, 0); + if (attr_time > 0) { + const char *minPwdAge = samdb_search_string(ctx, mem_ctx, NULL, "minPwdAge", + "dn=%s", domain_dn); + if (minPwdAge) { + /* yes, this is a -= not a += as minPwdAge is stored as the negative + of the number of 100-nano-seconds */ + attr_time -= strtod(minPwdAge, NULL); + } + } + return nttime_from_double_nt(attr_time); +} + +/* + construct the force_pwd_change field from the PwdLastSet attribute and the + domain password settings +*/ +NTTIME samdb_result_force_pwd_change(void *ctx, TALLOC_CTX *mem_ctx, + const char *domain_dn, struct ldb_message *msg, const char *attr) +{ + double attr_time = samdb_result_double(msg, attr, 0); + if (attr_time > 0) { + const char *maxPwdAge = samdb_search_string(ctx, mem_ctx, NULL, "maxPwdAge", + "dn=%s", domain_dn); + if (!maxPwdAge || strcmp(maxPwdAge, "0") == 0) { + attr_time = 0; + } else { + attr_time -= strtod(maxPwdAge, NULL); + } + } + return nttime_from_double_nt(attr_time); +} + +/* + pull a samr_LogonHours structutre from a result set. +*/ +struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr) +{ + struct samr_LogonHours hours; + const int units_per_week = 168; + const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr); + ZERO_STRUCT(hours); + hours.bitmap = talloc_array_p(mem_ctx, uint8, units_per_week); + if (!hours.bitmap) { + return hours; + } + hours.units_per_week = units_per_week; + memset(hours.bitmap, 0xFF, units_per_week); + if (val) { + memcpy(hours.bitmap, val->data, MIN(val->length, units_per_week)); + } + 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) +{ + 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; +} /* copy from a template record to a message @@ -463,6 +563,35 @@ int samdb_msg_add_uint(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg, } /* + add a acct_flags element to a message +*/ +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); +} + +/* + add a logon_hours element to a message +*/ +int samdb_msg_add_logon_hours(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, struct samr_LogonHours hours) +{ + struct samdb_context *sam_ctx = ctx; + struct ldb_val val; + val.length = hours.units_per_week / 8; + val.data = hours.bitmap; + ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx); + return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val); +} + +/* set a string element in a message */ int samdb_msg_set_string(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg, |