summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2004-05-09 09:39:47 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:51:50 -0500
commit54a695f7edf7c40a92391aa94ddbbd2db8b11ec3 (patch)
tree066b3c3b2002916159b69dd5a633ef6f5dc2b920 /source4
parentb91eb9e73a1329576698a1ce4f1e5bef3b63adb0 (diff)
downloadsamba-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.h13
-rw-r--r--source4/lib/ldb/common/ldb_msg.c36
-rw-r--r--source4/lib/time.c26
-rw-r--r--source4/librpc/idl/samr.idl21
-rw-r--r--source4/rpc_server/samr/dcesrv_samr.c224
-rw-r--r--source4/rpc_server/samr/samdb.c135
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,