s4-rpcserver: use TYPESAFE_QSORT() in rpc servers
[obnox/samba/samba-obnox.git] / source4 / rpc_server / samr / dcesrv_samr.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    endpoint server for the samr pipe
5
6    Copyright (C) Andrew Tridgell 2004
7    Copyright (C) Volker Lendecke 2004
8    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
9    Copyright (C) Matthias Dieter Wallnöfer 2009
10    
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15    
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20    
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26 #include "librpc/gen_ndr/ndr_samr.h"
27 #include "rpc_server/dcerpc_server.h"
28 #include "rpc_server/common/common.h"
29 #include "rpc_server/samr/dcesrv_samr.h"
30 #include "system/time.h"
31 #include "lib/ldb/include/ldb.h"
32 #include "lib/ldb/include/ldb_errors.h"
33 #include "../libds/common/flags.h"
34 #include "dsdb/samdb/samdb.h"
35 #include "libcli/ldap/ldap_ndr.h"
36 #include "libcli/security/security.h"
37 #include "rpc_server/samr/proto.h"
38 #include "../lib/util/util_ldb.h"
39 #include "param/param.h"
40 #include "lib/util/tsort.h"
41
42 /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
43
44 #define QUERY_STRING(msg, field, attr) \
45         info->field.string = samdb_result_string(msg, attr, "");
46 #define QUERY_UINT(msg, field, attr) \
47         info->field = samdb_result_uint(msg, attr, 0);
48 #define QUERY_RID(msg, field, attr) \
49         info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
50 #define QUERY_UINT64(msg, field, attr) \
51         info->field = samdb_result_uint64(msg, attr, 0);
52 #define QUERY_APASSC(msg, field, attr) \
53         info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
54                                                          a_state->domain_state->domain_dn, msg, attr);
55 #define QUERY_FPASSC(msg, field, attr) \
56         info->field = samdb_result_force_password_change(sam_ctx, mem_ctx, \
57                                                          a_state->domain_state->domain_dn, msg);
58 #define QUERY_LHOURS(msg, field, attr) \
59         info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
60 #define QUERY_AFLAGS(msg, field, attr) \
61         info->field = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, a_state->domain_state->domain_dn);
62 #define QUERY_PARAMETERS(msg, field, attr) \
63         info->field = samdb_result_parameters(mem_ctx, msg, attr);
64
65
66 /* these are used to make the Set[User|Group]Info code easier to follow */
67
68 #define SET_STRING(msg, field, attr) do {                               \
69         struct ldb_message_element *set_el;                             \
70         if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
71         if (r->in.info->field.string[0] == '\0') {                      \
72                 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL)) { \
73                         return NT_STATUS_NO_MEMORY;                     \
74                 }                                                       \
75         }                                                               \
76         if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != 0) { \
77                 return NT_STATUS_NO_MEMORY;                             \
78         }                                                               \
79         set_el = ldb_msg_find_element(msg, attr);                       \
80         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
81 } while (0)
82
83 #define SET_UINT(msg, field, attr) do {                                 \
84         struct ldb_message_element *set_el;                             \
85         if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
86                 return NT_STATUS_NO_MEMORY;                             \
87         }                                                               \
88         set_el = ldb_msg_find_element(msg, attr);                       \
89         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
90 } while (0)                                                             
91                                                                         
92 #define SET_INT64(msg, field, attr) do {                                \
93         struct ldb_message_element *set_el;                             \
94         if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
95                 return NT_STATUS_NO_MEMORY;                             \
96         }                                                               \
97         set_el = ldb_msg_find_element(msg, attr);                       \
98         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
99 } while (0)                                                             
100                                                                         
101 #define SET_UINT64(msg, field, attr) do {                               \
102         struct ldb_message_element *set_el;                             \
103         if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
104                 return NT_STATUS_NO_MEMORY;                             \
105         }                                                               \
106         set_el = ldb_msg_find_element(msg, attr);                       \
107         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
108 } while (0)                                                             
109
110 #define CHECK_FOR_MULTIPLES(value, flag, poss_flags)    \
111         do { \
112                 if ((value & flag) && ((value & flag) != (value & (poss_flags)))) { \
113                         return NT_STATUS_INVALID_PARAMETER;             \
114                 }                                                       \
115         } while (0)                                                     \
116         
117 /* Set account flags, discarding flags that cannot be set with SAMR */                                                          
118 #define SET_AFLAGS(msg, field, attr) do {                               \
119         struct ldb_message_element *set_el;                             \
120         if ((r->in.info->field & (ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST)) == 0) { \
121                 return NT_STATUS_INVALID_PARAMETER; \
122         }                                                               \
123         CHECK_FOR_MULTIPLES(r->in.info->field, ACB_NORMAL, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
124         CHECK_FOR_MULTIPLES(r->in.info->field, ACB_DOMTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
125         CHECK_FOR_MULTIPLES(r->in.info->field, ACB_WSTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
126         CHECK_FOR_MULTIPLES(r->in.info->field, ACB_SVRTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
127         if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, (r->in.info->field & ~(ACB_AUTOLOCK|ACB_PW_EXPIRED))) != 0) { \
128                 return NT_STATUS_NO_MEMORY;                             \
129         }                                                               \
130         set_el = ldb_msg_find_element(msg, attr);                       \
131         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
132 } while (0)                                                             
133                                                                         
134 #define SET_LHOURS(msg, field, attr) do {                               \
135         struct ldb_message_element *set_el;                             \
136         if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
137                 return NT_STATUS_NO_MEMORY;                             \
138         }                                                               \
139         set_el = ldb_msg_find_element(msg, attr);                       \
140         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
141 } while (0)
142
143 #define SET_PARAMETERS(msg, field, attr) do {                           \
144         struct ldb_message_element *set_el;                             \
145         if (r->in.info->field.length != 0) {                            \
146                 if (samdb_msg_add_parameters(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
147                         return NT_STATUS_NO_MEMORY;                     \
148                 }                                                       \
149                 set_el = ldb_msg_find_element(msg, attr);               \
150                 set_el->flags = LDB_FLAG_MOD_REPLACE;                   \
151         }                                                               \
152 } while (0)
153
154
155
156 /* 
157   samr_Connect 
158
159   create a connection to the SAM database
160 */
161 static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
162                              struct samr_Connect *r)
163 {
164         struct samr_connect_state *c_state;
165         struct dcesrv_handle *handle;
166
167         ZERO_STRUCTP(r->out.connect_handle);
168
169         c_state = talloc(mem_ctx, struct samr_connect_state);
170         if (!c_state) {
171                 return NT_STATUS_NO_MEMORY;
172         }
173
174         /* make sure the sam database is accessible */
175         c_state->sam_ctx = samdb_connect(c_state, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info); 
176         if (c_state->sam_ctx == NULL) {
177                 talloc_free(c_state);
178                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
179         }
180
181
182         handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_CONNECT);
183         if (!handle) {
184                 talloc_free(c_state);
185                 return NT_STATUS_NO_MEMORY;
186         }
187
188         handle->data = talloc_steal(handle, c_state);
189
190         c_state->access_mask = r->in.access_mask;
191         *r->out.connect_handle = handle->wire_handle;
192
193         return NT_STATUS_OK;
194 }
195
196
197 /* 
198   samr_Close 
199 */
200 static NTSTATUS dcesrv_samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
201                            struct samr_Close *r)
202 {
203         struct dcesrv_handle *h;
204
205         *r->out.handle = *r->in.handle;
206
207         DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
208
209         talloc_free(h);
210
211         ZERO_STRUCTP(r->out.handle);
212
213         return NT_STATUS_OK;
214 }
215
216
217 /* 
218   samr_SetSecurity 
219 */
220 static NTSTATUS dcesrv_samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
221                                  struct samr_SetSecurity *r)
222 {
223         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
224 }
225
226
227 /* 
228   samr_QuerySecurity 
229 */
230 static NTSTATUS dcesrv_samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
231                                    struct samr_QuerySecurity *r)
232 {
233         struct dcesrv_handle *h;
234         struct sec_desc_buf *sd;
235
236         *r->out.sdbuf = NULL;
237
238         DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
239
240         sd = talloc(mem_ctx, struct sec_desc_buf);
241         if (sd == NULL) {
242                 return NT_STATUS_NO_MEMORY;
243         }
244
245         sd->sd = samdb_default_security_descriptor(mem_ctx);
246
247         *r->out.sdbuf = sd;
248
249         return NT_STATUS_OK;
250 }
251
252
253 /* 
254   samr_Shutdown 
255
256   we refuse this operation completely. If a admin wants to shutdown samr
257   in Samba then they should use the samba admin tools to disable the samr pipe
258 */
259 static NTSTATUS dcesrv_samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
260                               struct samr_Shutdown *r)
261 {
262         return NT_STATUS_ACCESS_DENIED;
263 }
264
265
266 /* 
267   samr_LookupDomain 
268
269   this maps from a domain name to a SID
270 */
271 static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
272                                   struct samr_LookupDomain *r)
273 {
274         struct samr_connect_state *c_state;
275         struct dcesrv_handle *h;
276         struct dom_sid *sid;
277         const char * const dom_attrs[] = { "objectSid", NULL};
278         struct ldb_message **dom_msgs;
279         int ret;
280
281         *r->out.sid = NULL;
282
283         DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
284
285         c_state = h->data;
286
287         if (r->in.domain_name->string == NULL) {
288                 return NT_STATUS_INVALID_PARAMETER;
289         }
290
291         if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
292                 ret = gendb_search(c_state->sam_ctx,
293                                    mem_ctx, NULL, &dom_msgs, dom_attrs,
294                                    "(objectClass=builtinDomain)");
295         } else if (strcasecmp_m(r->in.domain_name->string, lp_sam_name(dce_call->conn->dce_ctx->lp_ctx)) == 0) {
296                 ret = gendb_search_dn(c_state->sam_ctx,
297                                       mem_ctx, ldb_get_default_basedn(c_state->sam_ctx), 
298                                       &dom_msgs, dom_attrs);
299         } else {
300                 return NT_STATUS_NO_SUCH_DOMAIN;
301         }
302         if (ret != 1) {
303                 return NT_STATUS_NO_SUCH_DOMAIN;
304         }
305         
306         sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
307                                    "objectSid");
308                 
309         if (sid == NULL) {
310                 return NT_STATUS_NO_SUCH_DOMAIN;
311         }
312
313         *r->out.sid = sid;
314
315         return NT_STATUS_OK;
316 }
317
318
319 /* 
320   samr_EnumDomains 
321
322   list the domains in the SAM
323 */
324 static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
325                                  struct samr_EnumDomains *r)
326 {
327         struct samr_connect_state *c_state;
328         struct dcesrv_handle *h;
329         struct samr_SamArray *array;
330         int i, start_i;
331
332         *r->out.resume_handle = 0;
333         *r->out.sam = NULL;
334         *r->out.num_entries = 0;
335
336         DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
337
338         c_state = h->data;
339
340         *r->out.resume_handle = 2;
341
342         start_i = *r->in.resume_handle;
343
344         if (start_i >= 2) {
345                 /* search past end of list is not an error for this call */
346                 return NT_STATUS_OK;
347         }
348
349         array = talloc(mem_ctx, struct samr_SamArray);
350         if (array == NULL) {
351                 return NT_STATUS_NO_MEMORY;
352         }
353                 
354         array->count = 0;
355         array->entries = NULL;
356
357         array->entries = talloc_array(mem_ctx, struct samr_SamEntry, 2 - start_i);
358         if (array->entries == NULL) {
359                 return NT_STATUS_NO_MEMORY;
360         }
361
362         for (i=0;i<2-start_i;i++) {
363                 array->entries[i].idx = start_i + i;
364                 if (i == 0) {
365                         array->entries[i].name.string = lp_sam_name(dce_call->conn->dce_ctx->lp_ctx);
366                 } else {
367                         array->entries[i].name.string = "BUILTIN";
368                 }
369         }
370
371         *r->out.sam = array;
372         *r->out.num_entries = i;
373         array->count = *r->out.num_entries;
374
375         return NT_STATUS_OK;
376 }
377
378
379 /* 
380   samr_OpenDomain 
381 */
382 static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
383                                 struct samr_OpenDomain *r)
384 {
385         struct dcesrv_handle *h_conn, *h_domain;
386         struct samr_connect_state *c_state;
387         struct samr_domain_state *d_state;
388         const char * const dom_attrs[] = { "cn", NULL};
389         struct ldb_message **dom_msgs;
390         int ret;
391
392         ZERO_STRUCTP(r->out.domain_handle);
393
394         DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
395
396         c_state = h_conn->data;
397
398         if (r->in.sid == NULL) {
399                 return NT_STATUS_INVALID_PARAMETER;
400         }
401
402         d_state = talloc(mem_ctx, struct samr_domain_state);
403         if (!d_state) {
404                 return NT_STATUS_NO_MEMORY;
405         }
406
407         d_state->domain_sid = talloc_steal(d_state, r->in.sid);
408
409         if (dom_sid_equal(d_state->domain_sid, dom_sid_parse_talloc(mem_ctx, SID_BUILTIN))) {
410                 d_state->builtin = true;
411                 d_state->domain_name = "BUILTIN";
412         } else {
413                 d_state->builtin = false;
414                 d_state->domain_name = lp_sam_name(dce_call->conn->dce_ctx->lp_ctx);
415         }
416
417         ret = gendb_search(c_state->sam_ctx,
418                            mem_ctx, ldb_get_default_basedn(c_state->sam_ctx), &dom_msgs, dom_attrs,
419                            "(objectSid=%s)", 
420                            ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
421         
422         if (ret == 0) {
423                 talloc_free(d_state);
424                 return NT_STATUS_NO_SUCH_DOMAIN;
425         } else if (ret > 1) {
426                 talloc_free(d_state);
427                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
428         } else if (ret == -1) {
429                 talloc_free(d_state);
430                 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx)));
431                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
432         }
433
434         d_state->domain_dn = talloc_steal(d_state, dom_msgs[0]->dn);
435         d_state->role = lp_server_role(dce_call->conn->dce_ctx->lp_ctx);
436         d_state->connect_state = talloc_reference(d_state, c_state);
437         d_state->sam_ctx = c_state->sam_ctx;
438         d_state->access_mask = r->in.access_mask;
439
440         d_state->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
441
442         h_domain = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_DOMAIN);
443         if (!h_domain) {
444                 talloc_free(d_state);
445                 return NT_STATUS_NO_MEMORY;
446         }
447         
448         h_domain->data = talloc_steal(h_domain, d_state);
449
450         *r->out.domain_handle = h_domain->wire_handle;
451
452         return NT_STATUS_OK;
453 }
454
455 /*
456   return DomInfo1
457 */
458 static NTSTATUS dcesrv_samr_info_DomInfo1(struct samr_domain_state *state,
459                                    TALLOC_CTX *mem_ctx,
460                                     struct ldb_message **dom_msgs,
461                                    struct samr_DomInfo1 *info)
462 {
463         info->min_password_length =
464                 samdb_result_uint(dom_msgs[0], "minPwdLength", 0);
465         info->password_history_length =
466                 samdb_result_uint(dom_msgs[0], "pwdHistoryLength", 0);
467         info->password_properties = 
468                 samdb_result_uint(dom_msgs[0], "pwdProperties", 0);
469         info->max_password_age = 
470                 samdb_result_int64(dom_msgs[0], "maxPwdAge", 0);
471         info->min_password_age = 
472                 samdb_result_int64(dom_msgs[0], "minPwdAge", 0);
473
474         return NT_STATUS_OK;
475 }
476
477 /*
478   return DomInfo2
479 */
480 static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state *state, 
481                                                        TALLOC_CTX *mem_ctx,
482                                                        struct ldb_message **dom_msgs,
483                                                        struct samr_DomGeneralInformation *info)
484 {
485         /* This pulls the NetBIOS name from the 
486            cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
487            string */
488         info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx, dom_msgs[0], "fSMORoleOwner");
489
490         if (!info->primary.string) {
491                 info->primary.string = lp_netbios_name(state->lp_ctx);
492         }
493
494         info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff", 
495                                                             0x8000000000000000LL);
496
497         info->oem_information.string = samdb_result_string(dom_msgs[0], "oEMInformation", NULL);
498         info->domain_name.string  = state->domain_name;
499
500         info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount", 
501                                                  0);
502         switch (state->role) {
503         case ROLE_DOMAIN_CONTROLLER:
504                 /* This pulls the NetBIOS name from the 
505                    cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
506                    string */
507                 if (samdb_is_pdc(state->sam_ctx)) {
508                         info->role = SAMR_ROLE_DOMAIN_PDC;
509                 } else {
510                         info->role = SAMR_ROLE_DOMAIN_BDC;
511                 }
512                 break;
513         case ROLE_DOMAIN_MEMBER:
514                 info->role = SAMR_ROLE_DOMAIN_MEMBER;
515                 break;
516         case ROLE_STANDALONE:
517                 info->role = SAMR_ROLE_STANDALONE;
518                 break;
519         }
520
521         /* No users in BUILTIN, and the LOCAL group types are only in builtin, and the global group type is never in BUILTIN */
522         info->num_users = samdb_search_count(state->sam_ctx, state->domain_dn,
523                                              "(objectClass=user)");
524         info->num_groups = samdb_search_count(state->sam_ctx, state->domain_dn,
525                                               "(&(objectClass=group)(groupType=%u))",
526                                               GTYPE_SECURITY_GLOBAL_GROUP);
527         info->num_aliases = samdb_search_count(state->sam_ctx, state->domain_dn,
528                                                "(&(objectClass=group)(groupType=%u))",
529                                                GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
530
531         return NT_STATUS_OK;
532 }
533
534 /*
535   return DomInfo3
536 */
537 static NTSTATUS dcesrv_samr_info_DomInfo3(struct samr_domain_state *state,
538                                    TALLOC_CTX *mem_ctx,
539                                     struct ldb_message **dom_msgs,
540                                    struct samr_DomInfo3 *info)
541 {
542         info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff", 
543                                                       0x8000000000000000LL);
544
545         return NT_STATUS_OK;
546 }
547
548 /*
549   return DomInfo4
550 */
551 static NTSTATUS dcesrv_samr_info_DomOEMInformation(struct samr_domain_state *state,
552                                    TALLOC_CTX *mem_ctx,
553                                     struct ldb_message **dom_msgs,
554                                    struct samr_DomOEMInformation *info)
555 {
556         info->oem_information.string = samdb_result_string(dom_msgs[0], "oEMInformation", NULL);
557
558         return NT_STATUS_OK;
559 }
560
561 /*
562   return DomInfo5
563 */
564 static NTSTATUS dcesrv_samr_info_DomInfo5(struct samr_domain_state *state,
565                                    TALLOC_CTX *mem_ctx,
566                                     struct ldb_message **dom_msgs,
567                                    struct samr_DomInfo5 *info)
568 {
569         info->domain_name.string  = state->domain_name;
570
571         return NT_STATUS_OK;
572 }
573
574 /*
575   return DomInfo6
576 */
577 static NTSTATUS dcesrv_samr_info_DomInfo6(struct samr_domain_state *state,
578                                    TALLOC_CTX *mem_ctx,
579                                    struct ldb_message **dom_msgs,
580                                    struct samr_DomInfo6 *info)
581 {
582         /* This pulls the NetBIOS name from the 
583            cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
584            string */
585         info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx, 
586                                                       dom_msgs[0], "fSMORoleOwner");
587
588         if (!info->primary.string) {
589                 info->primary.string = lp_netbios_name(state->lp_ctx);
590         }
591
592         return NT_STATUS_OK;
593 }
594
595 /*
596   return DomInfo7
597 */
598 static NTSTATUS dcesrv_samr_info_DomInfo7(struct samr_domain_state *state,
599                                    TALLOC_CTX *mem_ctx,
600                                     struct ldb_message **dom_msgs,
601                                    struct samr_DomInfo7 *info)
602 {
603
604         switch (state->role) {
605         case ROLE_DOMAIN_CONTROLLER:
606                 /* This pulls the NetBIOS name from the 
607                    cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
608                    string */
609                 if (samdb_is_pdc(state->sam_ctx)) {
610                         info->role = SAMR_ROLE_DOMAIN_PDC;
611                 } else {
612                         info->role = SAMR_ROLE_DOMAIN_BDC;
613                 }
614                 break;
615         case ROLE_DOMAIN_MEMBER:
616                 info->role = SAMR_ROLE_DOMAIN_MEMBER;
617                 break;
618         case ROLE_STANDALONE:
619                 info->role = SAMR_ROLE_STANDALONE;
620                 break;
621         }
622
623         return NT_STATUS_OK;
624 }
625
626 /*
627   return DomInfo8
628 */
629 static NTSTATUS dcesrv_samr_info_DomInfo8(struct samr_domain_state *state,
630                                    TALLOC_CTX *mem_ctx,
631                                     struct ldb_message **dom_msgs,
632                                    struct samr_DomInfo8 *info)
633 {
634         info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount", 
635                                                time(NULL));
636
637         info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
638                                                      0x0LL);
639
640         return NT_STATUS_OK;
641 }
642
643 /*
644   return DomInfo9
645 */
646 static NTSTATUS dcesrv_samr_info_DomInfo9(struct samr_domain_state *state,
647                                    TALLOC_CTX *mem_ctx,
648                                     struct ldb_message **dom_msgs,
649                                    struct samr_DomInfo9 *info)
650 {
651         info->domain_server_state = DOMAIN_SERVER_ENABLED;
652
653         return NT_STATUS_OK;
654 }
655
656 /*
657   return DomInfo11
658 */
659 static NTSTATUS dcesrv_samr_info_DomGeneralInformation2(struct samr_domain_state *state,
660                                     TALLOC_CTX *mem_ctx,
661                                     struct ldb_message **dom_msgs,
662                                     struct samr_DomGeneralInformation2 *info)
663 {
664         NTSTATUS status;
665         status = dcesrv_samr_info_DomGeneralInformation(state, mem_ctx, dom_msgs, &info->general);
666         if (!NT_STATUS_IS_OK(status)) {
667                 return status;
668         }
669         
670         info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration", 
671                                                     -18000000000LL);
672         info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
673                                                     -18000000000LL);
674         info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
675
676         return NT_STATUS_OK;
677 }
678
679 /*
680   return DomInfo12
681 */
682 static NTSTATUS dcesrv_samr_info_DomInfo12(struct samr_domain_state *state,
683                                    TALLOC_CTX *mem_ctx,
684                                     struct ldb_message **dom_msgs,
685                                    struct samr_DomInfo12 *info)
686 {
687         info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration", 
688                                                     -18000000000LL);
689         info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
690                                                     -18000000000LL);
691         info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
692
693         return NT_STATUS_OK;
694 }
695
696 /*
697   return DomInfo13
698 */
699 static NTSTATUS dcesrv_samr_info_DomInfo13(struct samr_domain_state *state,
700                                     TALLOC_CTX *mem_ctx,
701                                     struct ldb_message **dom_msgs,
702                                     struct samr_DomInfo13 *info)
703 {
704         info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount", 
705                                                time(NULL));
706
707         info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
708                                                      0x0LL);
709
710         info->modified_count_at_last_promotion = 0;
711
712         return NT_STATUS_OK;
713 }
714
715 /* 
716   samr_QueryDomainInfo 
717 */
718 static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
719                                      struct samr_QueryDomainInfo *r)
720 {
721         struct dcesrv_handle *h;
722         struct samr_domain_state *d_state;
723         union samr_DomainInfo *info;
724
725         struct ldb_message **dom_msgs;
726         const char * const *attrs = NULL;
727         
728         *r->out.info = NULL;
729
730         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
731
732         d_state = h->data;
733
734         info = talloc(mem_ctx, union samr_DomainInfo);
735         if (!info) {
736                 return NT_STATUS_NO_MEMORY;
737         }
738
739         switch (r->in.level) {
740         case 1: 
741         {
742                 static const char * const attrs2[] = { "minPwdLength",
743                                                        "pwdHistoryLength",
744                                                        "pwdProperties",
745                                                        "maxPwdAge",
746                                                        "minPwdAge",
747                                                        NULL };
748                 attrs = attrs2;
749                 break;
750         }
751         case 2:
752         {
753                 static const char * const attrs2[] = {"forceLogoff",
754                                                       "oEMInformation", 
755                                                       "modifiedCount", 
756                                                       "fSMORoleOwner",
757                                                       NULL};
758                 attrs = attrs2;
759                 break;
760         }
761         case 3:
762         {
763                 static const char * const attrs2[] = {"forceLogoff", 
764                                                       NULL};
765                 attrs = attrs2;
766                 break;
767         }
768         case 4:
769         {
770                 static const char * const attrs2[] = {"oEMInformation", 
771                                                       NULL};
772                 attrs = attrs2;
773                 break;
774         }
775         case 5:
776         {
777                 attrs = NULL;
778                 break;
779         }
780         case 6:
781         {
782                 static const char * const attrs2[] = {"fSMORoleOwner", 
783                                                       NULL};
784                 attrs = attrs2;
785                 break;
786         }
787         case 7:
788         {
789                 attrs = NULL;
790                 break;
791         }
792         case 8:
793         {
794                 static const char * const attrs2[] = { "modifiedCount", 
795                                                        "creationTime", 
796                                                        NULL };
797                 attrs = attrs2;
798                 break;
799         }
800         case 9:
801         {
802                 attrs = NULL;
803                 break;
804         }
805         case 11:
806         {
807                 static const char * const attrs2[] = { "oEMInformation",
808                                                        "forceLogoff",
809                                                        "modifiedCount", 
810                                                        "lockoutDuration", 
811                                                        "lockOutObservationWindow", 
812                                                        "lockoutThreshold", 
813                                                        NULL};
814                 attrs = attrs2;
815                 break;
816         }
817         case 12:
818         {
819                 static const char * const attrs2[] = { "lockoutDuration", 
820                                                        "lockOutObservationWindow", 
821                                                        "lockoutThreshold", 
822                                                        NULL};
823                 attrs = attrs2;
824                 break;
825         }
826         case 13:
827         {
828                 static const char * const attrs2[] = { "modifiedCount", 
829                                                        "creationTime", 
830                                                        NULL };
831                 attrs = attrs2;
832                 break;
833         }
834         default:
835         {
836                 return NT_STATUS_INVALID_INFO_CLASS;
837         }
838         }
839
840         /* some levels don't need a search */
841         if (attrs) {
842                 int ret;
843                 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
844                                       d_state->domain_dn, &dom_msgs, attrs);
845                 if (ret != 1) {
846                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
847                 }
848         }
849
850         *r->out.info = info;
851
852         ZERO_STRUCTP(info);
853
854         switch (r->in.level) {
855         case 1:
856                 return dcesrv_samr_info_DomInfo1(d_state, mem_ctx, dom_msgs, 
857                                                  &info->info1);
858         case 2:
859                 return dcesrv_samr_info_DomGeneralInformation(d_state, mem_ctx, dom_msgs, 
860                                                               &info->general);
861         case 3:
862                 return dcesrv_samr_info_DomInfo3(d_state, mem_ctx, dom_msgs, 
863                                                  &info->info3);
864         case 4:
865                 return dcesrv_samr_info_DomOEMInformation(d_state, mem_ctx, dom_msgs, 
866                                                           &info->oem);
867         case 5:
868                 return dcesrv_samr_info_DomInfo5(d_state, mem_ctx, dom_msgs, 
869                                                  &info->info5);
870         case 6:
871                 return dcesrv_samr_info_DomInfo6(d_state, mem_ctx, dom_msgs, 
872                                                  &info->info6);
873         case 7:
874                 return dcesrv_samr_info_DomInfo7(d_state, mem_ctx, dom_msgs, 
875                                                  &info->info7);
876         case 8:
877                 return dcesrv_samr_info_DomInfo8(d_state, mem_ctx, dom_msgs, 
878                                                  &info->info8);
879         case 9:
880                 return dcesrv_samr_info_DomInfo9(d_state, mem_ctx, dom_msgs, 
881                                                  &info->info9);
882         case 11:
883                 return dcesrv_samr_info_DomGeneralInformation2(d_state, mem_ctx, dom_msgs, 
884                                                                &info->general2);
885         case 12:
886                 return dcesrv_samr_info_DomInfo12(d_state, mem_ctx, dom_msgs, 
887                                                   &info->info12);
888         case 13:
889                 return dcesrv_samr_info_DomInfo13(d_state, mem_ctx, dom_msgs, 
890                                                   &info->info13);
891         default:
892                 return NT_STATUS_INVALID_INFO_CLASS;
893         }
894 }
895
896
897 /* 
898   samr_SetDomainInfo 
899 */
900 static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
901                        struct samr_SetDomainInfo *r)
902 {
903         struct dcesrv_handle *h;
904         struct samr_domain_state *d_state;
905         struct ldb_message *msg;
906         int ret;
907         struct ldb_context *sam_ctx;
908
909         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
910
911         d_state = h->data;
912         sam_ctx = d_state->sam_ctx;
913
914         msg = ldb_msg_new(mem_ctx);
915         if (msg == NULL) {
916                 return NT_STATUS_NO_MEMORY;
917         }
918
919         msg->dn = talloc_reference(mem_ctx, d_state->domain_dn);
920         if (!msg->dn) {
921                 return NT_STATUS_NO_MEMORY;
922         }
923
924         switch (r->in.level) {
925         case 1:
926                 SET_UINT  (msg, info1.min_password_length,     "minPwdLength");
927                 SET_UINT  (msg, info1.password_history_length, "pwdHistoryLength");
928                 SET_UINT  (msg, info1.password_properties,     "pwdProperties");
929                 SET_INT64  (msg, info1.max_password_age,       "maxPwdAge");
930                 SET_INT64  (msg, info1.min_password_age,       "minPwdAge");
931                 break;
932         case 3:
933                 SET_UINT64  (msg, info3.force_logoff_time,     "forceLogoff");
934                 break;
935         case 4:
936                 SET_STRING(msg, oem.oem_information,           "oEMInformation");
937                 break;
938
939         case 6:
940         case 7:
941         case 9:
942                 /* No op, we don't know where to set these */
943                 return NT_STATUS_OK;
944
945         case 12:
946                 /*
947                  * It is not possible to set lockout_duration < lockout_window.
948                  * (The test is the other way around since the negative numbers
949                  *  are stored...)
950                  *
951                  * TODO:
952                  *   This check should be moved to the backend, i.e. to some
953                  *   ldb module under dsdb/samdb/ldb_modules/ .
954                  *
955                  * This constraint is documented here for the samr rpc service:
956                  * MS-SAMR 3.1.1.6 Attribute Constraints for Originating Updates
957                  * http://msdn.microsoft.com/en-us/library/cc245667%28PROT.10%29.aspx
958                  *
959                  * And here for the ldap backend:
960                  * MS-ADTS 3.1.1.5.3.2 Constraints
961                  * http://msdn.microsoft.com/en-us/library/cc223462(PROT.10).aspx
962                  */
963                 if (r->in.info->info12.lockout_duration >
964                     r->in.info->info12.lockout_window)
965                 {
966                         return NT_STATUS_INVALID_PARAMETER;
967                 }
968                 SET_INT64  (msg, info12.lockout_duration,      "lockoutDuration");
969                 SET_INT64  (msg, info12.lockout_window,        "lockOutObservationWindow");
970                 SET_INT64  (msg, info12.lockout_threshold,     "lockoutThreshold");
971                 break;
972
973         default:
974                 /* many info classes are not valid for SetDomainInfo */
975                 return NT_STATUS_INVALID_INFO_CLASS;
976         }
977
978         /* modify the samdb record */
979         ret = ldb_modify(sam_ctx, msg);
980         if (ret != LDB_SUCCESS) {
981                 DEBUG(1,("Failed to modify record %s: %s\n",
982                          ldb_dn_get_linearized(d_state->domain_dn),
983                          ldb_errstring(sam_ctx)));
984
985                 /* we really need samdb.c to return NTSTATUS */
986                 return NT_STATUS_UNSUCCESSFUL;
987         }
988
989         return NT_STATUS_OK;
990 }
991
992 /* 
993   samr_CreateDomainGroup 
994 */
995 static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
996                                        struct samr_CreateDomainGroup *r)
997 {
998         struct samr_domain_state *d_state;
999         struct samr_account_state *a_state;
1000         struct dcesrv_handle *h;
1001         const char *name;
1002         struct ldb_message *msg;
1003         struct dom_sid *sid;
1004         const char *groupname;
1005         struct dcesrv_handle *g_handle;
1006         int ret;
1007
1008         ZERO_STRUCTP(r->out.group_handle);
1009         *r->out.rid = 0;
1010
1011         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1012
1013         d_state = h->data;
1014
1015         if (d_state->builtin) {
1016                 DEBUG(5, ("Cannot create a domain group in the BUILTIN domain"));
1017                 return NT_STATUS_ACCESS_DENIED;
1018         }
1019
1020         groupname = r->in.name->string;
1021
1022         if (groupname == NULL) {
1023                 return NT_STATUS_INVALID_PARAMETER;
1024         }
1025
1026         /* check if the group already exists */
1027         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL, 
1028                                    "sAMAccountName",
1029                                    "(&(sAMAccountName=%s)(objectclass=group))",
1030                                    ldb_binary_encode_string(mem_ctx, groupname));
1031         if (name != NULL) {
1032                 return NT_STATUS_GROUP_EXISTS;
1033         }
1034
1035         msg = ldb_msg_new(mem_ctx);
1036         if (msg == NULL) {
1037                 return NT_STATUS_NO_MEMORY;
1038         }
1039
1040         /* add core elements to the ldb_message for the user */
1041         msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1042         ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", groupname);
1043         if (!msg->dn) {
1044                 return NT_STATUS_NO_MEMORY;
1045         }
1046         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", groupname);
1047         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1048                              
1049         /* create the group */
1050         ret = ldb_add(d_state->sam_ctx, msg);
1051         switch (ret) {
1052         case  LDB_SUCCESS:
1053                 break;
1054         case  LDB_ERR_ENTRY_ALREADY_EXISTS:
1055                 DEBUG(0,("Failed to create group record %s: %s\n",
1056                          ldb_dn_get_linearized(msg->dn),
1057                          ldb_errstring(d_state->sam_ctx)));
1058                 return NT_STATUS_GROUP_EXISTS;
1059         case  LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1060                 DEBUG(0,("Failed to create group record %s: %s\n",
1061                          ldb_dn_get_linearized(msg->dn),
1062                          ldb_errstring(d_state->sam_ctx)));
1063                 return NT_STATUS_ACCESS_DENIED;
1064         default:
1065                 DEBUG(0,("Failed to create group record %s: %s\n",
1066                          ldb_dn_get_linearized(msg->dn),
1067                          ldb_errstring(d_state->sam_ctx)));
1068                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1069         }
1070
1071         a_state = talloc(mem_ctx, struct samr_account_state);
1072         if (!a_state) {
1073                 return NT_STATUS_NO_MEMORY;
1074         }
1075         a_state->sam_ctx = d_state->sam_ctx;
1076         a_state->access_mask = r->in.access_mask;
1077         a_state->domain_state = talloc_reference(a_state, d_state);
1078         a_state->account_dn = talloc_steal(a_state, msg->dn);
1079
1080         /* retrieve the sid for the group just created */
1081         sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1082                                    msg->dn, "objectSid", NULL);
1083         if (sid == NULL) {
1084                 return NT_STATUS_UNSUCCESSFUL;
1085         }
1086
1087         a_state->account_name = talloc_strdup(a_state, groupname);
1088         if (!a_state->account_name) {
1089                 return NT_STATUS_NO_MEMORY;
1090         }
1091
1092         /* create the policy handle */
1093         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1094         if (!g_handle) {
1095                 return NT_STATUS_NO_MEMORY;
1096         }
1097
1098         g_handle->data = talloc_steal(g_handle, a_state);
1099
1100         *r->out.group_handle = g_handle->wire_handle;
1101         *r->out.rid = sid->sub_auths[sid->num_auths-1];
1102
1103         return NT_STATUS_OK;
1104 }
1105
1106
1107 /*
1108   comparison function for sorting SamEntry array
1109 */
1110 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
1111 {
1112         return e1->idx - e2->idx;
1113 }
1114
1115 /* 
1116   samr_EnumDomainGroups 
1117 */
1118 static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1119                                       struct samr_EnumDomainGroups *r)
1120 {
1121         struct dcesrv_handle *h;
1122         struct samr_domain_state *d_state;
1123         struct ldb_message **res;
1124         int ldb_cnt, count, i, first;
1125         struct samr_SamEntry *entries;
1126         const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1127         struct samr_SamArray *sam;
1128
1129         *r->out.resume_handle = 0;
1130         *r->out.sam = NULL;
1131         *r->out.num_entries = 0;
1132
1133         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1134
1135         d_state = h->data;
1136
1137         /* search for all domain groups in this domain. This could possibly be
1138            cached and resumed based on resume_key */
1139         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1140                                       d_state->domain_dn, &res, attrs,
1141                                       d_state->domain_sid,
1142                                       "(&(grouptype=%d)(objectclass=group))",
1143                                       GTYPE_SECURITY_GLOBAL_GROUP);
1144         if (ldb_cnt == -1) {
1145                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1146         }
1147
1148         /* convert to SamEntry format */
1149         entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1150         if (!entries) {
1151                 return NT_STATUS_NO_MEMORY;
1152         }
1153
1154         count = 0;
1155
1156         for (i=0;i<ldb_cnt;i++) {
1157                 struct dom_sid *group_sid;
1158
1159                 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
1160                                                  "objectSid");
1161                 if (group_sid == NULL)
1162                         continue;
1163
1164                 entries[count].idx =
1165                         group_sid->sub_auths[group_sid->num_auths-1];
1166                 entries[count].name.string =
1167                         samdb_result_string(res[i], "sAMAccountName", "");
1168                 count += 1;
1169         }
1170
1171         /* sort the results by rid */
1172         TYPESAFE_QSORT(entries, count, compare_SamEntry);
1173
1174         /* find the first entry to return */
1175         for (first=0;
1176              first<count && entries[first].idx <= *r->in.resume_handle;
1177              first++) ;
1178
1179         /* return the rest, limit by max_size. Note that we 
1180            use the w2k3 element size value of 54 */
1181         *r->out.num_entries = count - first;
1182         *r->out.num_entries = MIN(*r->out.num_entries,
1183                                  1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1184
1185         sam = talloc(mem_ctx, struct samr_SamArray);
1186         if (!sam) {
1187                 return NT_STATUS_NO_MEMORY;
1188         }
1189
1190         sam->entries = entries+first;
1191         sam->count = *r->out.num_entries;
1192
1193         *r->out.sam = sam;
1194
1195         if (*r->out.num_entries < count - first) {
1196                 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1197                 return STATUS_MORE_ENTRIES;
1198         }
1199
1200         return NT_STATUS_OK;
1201 }
1202
1203
1204 /* 
1205   samr_CreateUser2 
1206
1207   This call uses transactions to ensure we don't get a new conflicting
1208   user while we are processing this, and to ensure the user either
1209   completly exists, or does not.
1210 */
1211 static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1212                                  struct samr_CreateUser2 *r)
1213 {
1214         struct samr_domain_state *d_state;
1215         struct samr_account_state *a_state;
1216         struct dcesrv_handle *h;
1217         const char *name;
1218         struct ldb_message *msg;
1219         struct dom_sid *sid;
1220         const char *account_name;
1221         struct dcesrv_handle *u_handle;
1222         int ret;
1223         const char *container, *obj_class=NULL;
1224         char *cn_name;
1225         int cn_name_len;
1226
1227         const char *attrs[] = {
1228                 "objectSid", 
1229                 "userAccountControl",
1230                 NULL
1231         };
1232
1233         uint32_t user_account_control;
1234
1235         struct ldb_message **msgs;
1236
1237         ZERO_STRUCTP(r->out.user_handle);
1238         *r->out.access_granted = 0;
1239         *r->out.rid = 0;
1240
1241         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1242
1243         d_state = h->data;
1244
1245         if (d_state->builtin) {
1246                 DEBUG(5, ("Cannot create a user in the BUILTIN domain"));
1247                 return NT_STATUS_ACCESS_DENIED;
1248         } else if (r->in.acct_flags == ACB_DOMTRUST) {
1249                 /* Domain trust accounts must be created by the LSA calls */
1250                 return NT_STATUS_ACCESS_DENIED;
1251         }
1252         account_name = r->in.account_name->string;
1253
1254         if (account_name == NULL) {
1255                 return NT_STATUS_INVALID_PARAMETER;
1256         }
1257
1258         /*
1259          * Start a transaction, so we can query and do a subsequent atomic
1260          * modify
1261          */
1262
1263         ret = ldb_transaction_start(d_state->sam_ctx);
1264         if (ret != LDB_SUCCESS) {
1265                 DEBUG(0,("Failed to start a transaction for user creation: %s\n",
1266                          ldb_errstring(d_state->sam_ctx)));
1267                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1268         }
1269
1270         /* check if the user already exists */
1271         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL, 
1272                                    "sAMAccountName", 
1273                                    "(&(sAMAccountName=%s)(objectclass=user))", 
1274                                    ldb_binary_encode_string(mem_ctx, account_name));
1275         if (name != NULL) {
1276                 ldb_transaction_cancel(d_state->sam_ctx);
1277                 return NT_STATUS_USER_EXISTS;
1278         }
1279
1280         msg = ldb_msg_new(mem_ctx);
1281         if (msg == NULL) {
1282                 ldb_transaction_cancel(d_state->sam_ctx);
1283                 return NT_STATUS_NO_MEMORY;
1284         }
1285
1286         cn_name   = talloc_strdup(mem_ctx, account_name);
1287         if (!cn_name) {
1288                 ldb_transaction_cancel(d_state->sam_ctx);
1289                 return NT_STATUS_NO_MEMORY;
1290         }
1291
1292         cn_name_len = strlen(cn_name);
1293
1294         /* This must be one of these values *only* */
1295         if (r->in.acct_flags == ACB_NORMAL) {
1296                 container = "CN=Users";
1297                 obj_class = "user";
1298
1299         } else if (r->in.acct_flags == ACB_WSTRUST) {
1300                 if (cn_name[cn_name_len - 1] != '$') {
1301                         ldb_transaction_cancel(d_state->sam_ctx);
1302                         return NT_STATUS_FOOBAR;
1303                 }
1304                 cn_name[cn_name_len - 1] = '\0';
1305                 container = "CN=Computers";
1306                 obj_class = "computer";
1307                 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg,
1308                         "primaryGroupID", DOMAIN_RID_DOMAIN_MEMBERS);
1309
1310         } else if (r->in.acct_flags == ACB_SVRTRUST) {
1311                 if (cn_name[cn_name_len - 1] != '$') {
1312                         ldb_transaction_cancel(d_state->sam_ctx);
1313                         return NT_STATUS_FOOBAR;                
1314                 }
1315                 cn_name[cn_name_len - 1] = '\0';
1316                 container = "OU=Domain Controllers";
1317                 obj_class = "computer";
1318                 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg,
1319                         "primaryGroupID", DOMAIN_RID_DCS);
1320         } else {
1321                 ldb_transaction_cancel(d_state->sam_ctx);
1322                 return NT_STATUS_INVALID_PARAMETER;
1323         }
1324
1325         /* add core elements to the ldb_message for the user */
1326         msg->dn = ldb_dn_copy(msg, d_state->domain_dn);
1327         if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s,%s", cn_name, container)) {
1328                 ldb_transaction_cancel(d_state->sam_ctx);
1329                 return NT_STATUS_FOOBAR;
1330         }
1331
1332         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName",
1333                 account_name);
1334         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass",
1335                 obj_class);
1336
1337         /* create the user */
1338         ret = ldb_add(d_state->sam_ctx, msg);
1339         switch (ret) {
1340         case LDB_SUCCESS:
1341                 break;
1342         case LDB_ERR_ENTRY_ALREADY_EXISTS:
1343                 ldb_transaction_cancel(d_state->sam_ctx);
1344                 DEBUG(0,("Failed to create user record %s: %s\n",
1345                          ldb_dn_get_linearized(msg->dn),
1346                          ldb_errstring(d_state->sam_ctx)));
1347                 return NT_STATUS_USER_EXISTS;
1348         case LDB_ERR_UNWILLING_TO_PERFORM:
1349         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1350                 ldb_transaction_cancel(d_state->sam_ctx);
1351                 DEBUG(0,("Failed to create user record %s: %s\n",
1352                          ldb_dn_get_linearized(msg->dn),
1353                          ldb_errstring(d_state->sam_ctx)));
1354                 return NT_STATUS_ACCESS_DENIED;
1355         default:
1356                 ldb_transaction_cancel(d_state->sam_ctx);
1357                 DEBUG(0,("Failed to create user record %s: %s\n",
1358                          ldb_dn_get_linearized(msg->dn),
1359                          ldb_errstring(d_state->sam_ctx)));
1360                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1361         }
1362
1363         a_state = talloc(mem_ctx, struct samr_account_state);
1364         if (!a_state) {
1365                 ldb_transaction_cancel(d_state->sam_ctx);
1366                 return NT_STATUS_NO_MEMORY;
1367         }
1368         a_state->sam_ctx = d_state->sam_ctx;
1369         a_state->access_mask = r->in.access_mask;
1370         a_state->domain_state = talloc_reference(a_state, d_state);
1371         a_state->account_dn = talloc_steal(a_state, msg->dn);
1372
1373         /* retrieve the sid and account control bits for the user just created */
1374         ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
1375                               msg->dn, &msgs, attrs);
1376
1377         if (ret != 1) {
1378                 ldb_transaction_cancel(d_state->sam_ctx);
1379                 DEBUG(0,("Apparently we failed to create an account record, as %s now doesn't exist\n",
1380                          ldb_dn_get_linearized(msg->dn)));
1381                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1382         }
1383         sid = samdb_result_dom_sid(mem_ctx, msgs[0], "objectSid");
1384         if (sid == NULL) {
1385                 ldb_transaction_cancel(d_state->sam_ctx);
1386                 DEBUG(0,("Apparently we failed to get the objectSid of the just created account record %s\n",
1387                          ldb_dn_get_linearized(msg->dn)));
1388                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1389         }
1390
1391         /* Change the account control to be the correct account type.
1392          * The default is for a workstation account */
1393         user_account_control = samdb_result_uint(msgs[0], "userAccountControl", 0);
1394         user_account_control = (user_account_control & 
1395                                 ~(UF_NORMAL_ACCOUNT |
1396                                   UF_INTERDOMAIN_TRUST_ACCOUNT | 
1397                                   UF_WORKSTATION_TRUST_ACCOUNT | 
1398                                   UF_SERVER_TRUST_ACCOUNT));
1399         user_account_control |= ds_acb2uf(r->in.acct_flags);
1400
1401         talloc_free(msg);
1402         msg = ldb_msg_new(mem_ctx);
1403         if (msg == NULL) {
1404                 ldb_transaction_cancel(d_state->sam_ctx);
1405                 return NT_STATUS_NO_MEMORY;
1406         }
1407
1408         msg->dn = ldb_dn_copy(msg, a_state->account_dn);
1409
1410         if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, msg, 
1411                                "userAccountControl", 
1412                                user_account_control) != 0) { 
1413                 ldb_transaction_cancel(d_state->sam_ctx);
1414                 return NT_STATUS_NO_MEMORY; 
1415         }
1416
1417         /* modify the samdb record */
1418         ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
1419         if (ret != LDB_SUCCESS) {
1420                 DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n",
1421                          ldb_dn_get_linearized(msg->dn),
1422                          ldb_errstring(d_state->sam_ctx)));
1423                 ldb_transaction_cancel(d_state->sam_ctx);
1424
1425                 /* we really need samdb.c to return NTSTATUS */
1426                 return NT_STATUS_UNSUCCESSFUL;
1427         }
1428
1429         ret = ldb_transaction_commit(d_state->sam_ctx);
1430         if (ret != LDB_SUCCESS) {
1431                 DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n",
1432                          ldb_dn_get_linearized(msg->dn),
1433                          ldb_errstring(d_state->sam_ctx)));
1434                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1435         }
1436
1437         a_state->account_name = talloc_steal(a_state, account_name);
1438         if (!a_state->account_name) {
1439                 return NT_STATUS_NO_MEMORY;
1440         }
1441
1442         /* create the policy handle */
1443         u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
1444         if (!u_handle) {
1445                 return NT_STATUS_NO_MEMORY;
1446         }
1447
1448         u_handle->data = talloc_steal(u_handle, a_state);
1449
1450         *r->out.user_handle = u_handle->wire_handle;
1451         *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1452
1453         *r->out.rid = sid->sub_auths[sid->num_auths-1];
1454
1455         return NT_STATUS_OK;
1456 }
1457
1458
1459 /* 
1460   samr_CreateUser 
1461 */
1462 static NTSTATUS dcesrv_samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1463                                 struct samr_CreateUser *r)
1464 {
1465         struct samr_CreateUser2 r2;
1466         uint32_t access_granted = 0;
1467
1468
1469         /* a simple wrapper around samr_CreateUser2 works nicely */
1470         r2.in.domain_handle = r->in.domain_handle;
1471         r2.in.account_name = r->in.account_name;
1472         r2.in.acct_flags = ACB_NORMAL;
1473         r2.in.access_mask = r->in.access_mask;
1474         r2.out.user_handle = r->out.user_handle;
1475         r2.out.access_granted = &access_granted;
1476         r2.out.rid = r->out.rid;
1477
1478         return dcesrv_samr_CreateUser2(dce_call, mem_ctx, &r2);
1479 }
1480
1481 /* 
1482   samr_EnumDomainUsers 
1483 */
1484 static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1485                                      struct samr_EnumDomainUsers *r)
1486 {
1487         struct dcesrv_handle *h;
1488         struct samr_domain_state *d_state;
1489         struct ldb_result *res;
1490         int ret, num_filtered_entries, i, first;
1491         struct samr_SamEntry *entries;
1492         const char * const attrs[] = { "objectSid", "sAMAccountName",
1493                 "userAccountControl", NULL };
1494         struct samr_SamArray *sam;
1495
1496         *r->out.resume_handle = 0;
1497         *r->out.sam = NULL;
1498         *r->out.num_entries = 0;
1499
1500         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1501
1502         d_state = h->data;
1503         
1504         /* don't have to worry about users in the builtin domain, as there are none */
1505         ret = ldb_search(d_state->sam_ctx, mem_ctx, &res, d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs, "objectClass=user");
1506
1507         if (ret != LDB_SUCCESS) {
1508                 DEBUG(3, ("Failed to search for Domain Users in %s: %s\n", 
1509                           ldb_dn_get_linearized(d_state->domain_dn), ldb_errstring(d_state->sam_ctx)));
1510                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1511         }
1512
1513         /* convert to SamEntry format */
1514         entries = talloc_array(mem_ctx, struct samr_SamEntry, res->count);
1515         if (!entries) {
1516                 return NT_STATUS_NO_MEMORY;
1517         }
1518         num_filtered_entries = 0;
1519         for (i=0;i<res->count;i++) {
1520                 /* Check if a mask has been requested */
1521                 if (r->in.acct_flags
1522                     && ((samdb_result_acct_flags(d_state->sam_ctx, mem_ctx, res->msgs[i], 
1523                                                  d_state->domain_dn) & r->in.acct_flags) == 0)) {
1524                         continue;
1525                 }
1526                 entries[num_filtered_entries].idx = samdb_result_rid_from_sid(mem_ctx, res->msgs[i], "objectSid", 0);
1527                 entries[num_filtered_entries].name.string = samdb_result_string(res->msgs[i], "sAMAccountName", "");
1528                 num_filtered_entries++;
1529         }
1530
1531         /* sort the results by rid */
1532         TYPESAFE_QSORT(entries, num_filtered_entries, compare_SamEntry);
1533
1534         /* find the first entry to return */
1535         for (first=0;
1536              first<num_filtered_entries && entries[first].idx <= *r->in.resume_handle;
1537              first++) ;
1538
1539         /* return the rest, limit by max_size. Note that we 
1540            use the w2k3 element size value of 54 */
1541         *r->out.num_entries = num_filtered_entries - first;
1542         *r->out.num_entries = MIN(*r->out.num_entries,
1543                                  1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1544
1545         sam = talloc(mem_ctx, struct samr_SamArray);
1546         if (!sam) {
1547                 return NT_STATUS_NO_MEMORY;
1548         }
1549
1550         sam->entries = entries+first;
1551         sam->count = *r->out.num_entries;
1552
1553         *r->out.sam = sam;
1554
1555         if (first == num_filtered_entries) {
1556                 return NT_STATUS_OK;
1557         }
1558
1559         if (*r->out.num_entries < num_filtered_entries - first) {
1560                 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1561                 return STATUS_MORE_ENTRIES;
1562         }
1563
1564         return NT_STATUS_OK;
1565 }
1566
1567
1568 /* 
1569   samr_CreateDomAlias 
1570 */
1571 static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1572                        struct samr_CreateDomAlias *r)
1573 {
1574         struct samr_domain_state *d_state;
1575         struct samr_account_state *a_state;
1576         struct dcesrv_handle *h;
1577         const char *alias_name, *name;
1578         struct ldb_message *msg;
1579         struct dom_sid *sid;
1580         struct dcesrv_handle *a_handle;
1581         int ret;
1582
1583         ZERO_STRUCTP(r->out.alias_handle);
1584         *r->out.rid = 0;
1585
1586         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1587
1588         d_state = h->data;
1589
1590         if (d_state->builtin) {
1591                 DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain"));
1592                 return NT_STATUS_ACCESS_DENIED;
1593         }
1594
1595         alias_name = r->in.alias_name->string;
1596
1597         if (alias_name == NULL) {
1598                 return NT_STATUS_INVALID_PARAMETER;
1599         }
1600
1601         /* Check if alias already exists */
1602         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1603                                    "sAMAccountName",
1604                                    "(sAMAccountName=%s)(objectclass=group))",
1605                                    ldb_binary_encode_string(mem_ctx, alias_name));
1606
1607         if (name != NULL) {
1608                 return NT_STATUS_ALIAS_EXISTS;
1609         }
1610
1611         msg = ldb_msg_new(mem_ctx);
1612         if (msg == NULL) {
1613                 return NT_STATUS_NO_MEMORY;
1614         }
1615
1616         /* add core elements to the ldb_message for the alias */
1617         msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1618         ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", alias_name);
1619         if (!msg->dn) {
1620                 return NT_STATUS_NO_MEMORY;
1621         }
1622
1623         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", alias_name);
1624         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1625         samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "groupType", GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1626
1627         /* create the alias */
1628         ret = ldb_add(d_state->sam_ctx, msg);
1629         switch (ret) {
1630         case LDB_SUCCESS:
1631                 break;
1632         case LDB_ERR_ENTRY_ALREADY_EXISTS:
1633                 return NT_STATUS_ALIAS_EXISTS;
1634         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1635                 return NT_STATUS_ACCESS_DENIED;
1636         default:
1637                 DEBUG(0,("Failed to create alias record %s: %s\n",
1638                          ldb_dn_get_linearized(msg->dn),
1639                          ldb_errstring(d_state->sam_ctx)));
1640                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1641         }
1642
1643         a_state = talloc(mem_ctx, struct samr_account_state);
1644         if (!a_state) {
1645                 return NT_STATUS_NO_MEMORY;
1646         }
1647
1648         a_state->sam_ctx = d_state->sam_ctx;
1649         a_state->access_mask = r->in.access_mask;
1650         a_state->domain_state = talloc_reference(a_state, d_state);
1651         a_state->account_dn = talloc_steal(a_state, msg->dn);
1652
1653         /* retrieve the sid for the alias just created */
1654         sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1655                                    msg->dn, "objectSid", NULL);
1656
1657         a_state->account_name = talloc_strdup(a_state, alias_name);
1658         if (!a_state->account_name) {
1659                 return NT_STATUS_NO_MEMORY;
1660         }
1661
1662         /* create the policy handle */
1663         a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1664         if (a_handle == NULL)
1665                 return NT_STATUS_NO_MEMORY;
1666
1667         a_handle->data = talloc_steal(a_handle, a_state);
1668
1669         *r->out.alias_handle = a_handle->wire_handle;
1670
1671         *r->out.rid = sid->sub_auths[sid->num_auths-1];
1672
1673         return NT_STATUS_OK;
1674 }
1675
1676
1677 /* 
1678   samr_EnumDomainAliases 
1679 */
1680 static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1681                        struct samr_EnumDomainAliases *r)
1682 {
1683         struct dcesrv_handle *h;
1684         struct samr_domain_state *d_state;
1685         struct ldb_message **res;
1686         int ldb_cnt, count, i, first;
1687         struct samr_SamEntry *entries;
1688         const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1689         struct samr_SamArray *sam;
1690
1691         *r->out.resume_handle = 0;
1692         *r->out.sam = NULL;
1693         *r->out.num_entries = 0;
1694
1695         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1696
1697         d_state = h->data;
1698
1699         /* search for all domain groups in this domain. This could possibly be
1700            cached and resumed based on resume_key */
1701         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1702                                       d_state->domain_dn,
1703                                       &res, attrs, 
1704                                       d_state->domain_sid,
1705                                       "(&(|(grouptype=%d)(grouptype=%d)))"
1706                                       "(objectclass=group))",
1707                                       GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1708                                       GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1709         if (ldb_cnt == -1) {
1710                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1711         }
1712         if (ldb_cnt == 0) {
1713                 return NT_STATUS_OK;
1714         }
1715
1716         /* convert to SamEntry format */
1717         entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1718         if (!entries) {
1719                 return NT_STATUS_NO_MEMORY;
1720         }
1721
1722         count = 0;
1723
1724         for (i=0;i<ldb_cnt;i++) {
1725                 struct dom_sid *alias_sid;
1726
1727                 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1728                                                  "objectSid");
1729
1730                 if (alias_sid == NULL)
1731                         continue;
1732
1733                 entries[count].idx =
1734                         alias_sid->sub_auths[alias_sid->num_auths-1];
1735                 entries[count].name.string =
1736                         samdb_result_string(res[i], "sAMAccountName", "");
1737                 count += 1;
1738         }
1739
1740         /* sort the results by rid */
1741         TYPESAFE_QSORT(entries, count, compare_SamEntry);
1742
1743         /* find the first entry to return */
1744         for (first=0;
1745              first<count && entries[first].idx <= *r->in.resume_handle;
1746              first++) ;
1747
1748         if (first == count) {
1749                 return NT_STATUS_OK;
1750         }
1751
1752         *r->out.num_entries = count - first;
1753         *r->out.num_entries = MIN(*r->out.num_entries, 1000);
1754
1755         sam = talloc(mem_ctx, struct samr_SamArray);
1756         if (!sam) {
1757                 return NT_STATUS_NO_MEMORY;
1758         }
1759
1760         sam->entries = entries+first;
1761         sam->count = *r->out.num_entries;
1762
1763         *r->out.sam = sam;
1764
1765         if (*r->out.num_entries < count - first) {
1766                 *r->out.resume_handle =
1767                         entries[first+*r->out.num_entries-1].idx;
1768                 return STATUS_MORE_ENTRIES;
1769         }
1770
1771         return NT_STATUS_OK;
1772 }
1773
1774
1775 /* 
1776   samr_GetAliasMembership 
1777 */
1778 static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1779                        struct samr_GetAliasMembership *r)
1780 {
1781         struct dcesrv_handle *h;
1782         struct samr_domain_state *d_state;
1783         struct ldb_message **res;
1784         int i, count = 0;
1785
1786         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1787
1788         d_state = h->data;
1789
1790         if (r->in.sids->num_sids > 0) {
1791                 const char *filter;
1792                 const char * const attrs[2] = { "objectSid", NULL };
1793
1794                 filter = talloc_asprintf(mem_ctx,
1795                                          "(&(|(grouptype=%d)(grouptype=%d))"
1796                                          "(objectclass=group)(|",
1797                                          GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1798                                          GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1799                 if (filter == NULL)
1800                         return NT_STATUS_NO_MEMORY;
1801
1802                 for (i=0; i<r->in.sids->num_sids; i++) {
1803                         const char *memberdn;
1804
1805                         memberdn = 
1806                                 samdb_search_string(d_state->sam_ctx,
1807                                                     mem_ctx, NULL,
1808                                                     "distinguishedName",
1809                                                     "(objectSid=%s)",
1810                                                     ldap_encode_ndr_dom_sid(mem_ctx, 
1811                                                                             r->in.sids->sids[i].sid));
1812
1813                         if (memberdn == NULL)
1814                                 continue;
1815
1816                         filter = talloc_asprintf(mem_ctx, "%s(member=%s)",
1817                                                  filter, memberdn);
1818                         if (filter == NULL)
1819                                 return NT_STATUS_NO_MEMORY;
1820                 }
1821
1822                 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1823                                             d_state->domain_dn, &res, attrs,
1824                                             d_state->domain_sid, "%s))", filter);
1825                 if (count < 0)
1826                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1827         }
1828
1829         r->out.rids->count = 0;
1830         r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1831         if (r->out.rids->ids == NULL)
1832                 return NT_STATUS_NO_MEMORY;
1833
1834         for (i=0; i<count; i++) {
1835                 struct dom_sid *alias_sid;
1836
1837                 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1838
1839                 if (alias_sid == NULL) {
1840                         DEBUG(0, ("Could not find objectSid\n"));
1841                         continue;
1842                 }
1843
1844                 r->out.rids->ids[r->out.rids->count] =
1845                         alias_sid->sub_auths[alias_sid->num_auths-1];
1846                 r->out.rids->count += 1;
1847         }
1848
1849         return NT_STATUS_OK;
1850 }
1851
1852
1853 /* 
1854   samr_LookupNames 
1855 */
1856 static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1857                                  struct samr_LookupNames *r)
1858 {
1859         struct dcesrv_handle *h;
1860         struct samr_domain_state *d_state;
1861         int i, num_mapped;
1862         NTSTATUS status = NT_STATUS_OK;
1863         const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1864         int count;
1865
1866         ZERO_STRUCTP(r->out.rids);
1867         ZERO_STRUCTP(r->out.types);
1868
1869         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1870
1871         d_state = h->data;
1872
1873         if (r->in.num_names == 0) {
1874                 return NT_STATUS_OK;
1875         }
1876
1877         r->out.rids->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1878         r->out.types->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1879         if (!r->out.rids->ids || !r->out.types->ids) {
1880                 return NT_STATUS_NO_MEMORY;
1881         }
1882         r->out.rids->count = r->in.num_names;
1883         r->out.types->count = r->in.num_names;
1884
1885         num_mapped = 0;
1886
1887         for (i=0;i<r->in.num_names;i++) {
1888                 struct ldb_message **res;
1889                 struct dom_sid *sid;
1890                 uint32_t atype, rtype;
1891
1892                 r->out.rids->ids[i] = 0;
1893                 r->out.types->ids[i] = SID_NAME_UNKNOWN;
1894
1895                 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs, 
1896                                      "sAMAccountName=%s", 
1897                                      ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1898                 if (count != 1) {
1899                         status = STATUS_SOME_UNMAPPED;
1900                         continue;
1901                 }
1902
1903                 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1904                 if (sid == NULL) {
1905                         status = STATUS_SOME_UNMAPPED;
1906                         continue;
1907                 }
1908                 
1909                 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1910                 if (atype == 0) {
1911                         status = STATUS_SOME_UNMAPPED;
1912                         continue;
1913                 }
1914
1915                 rtype = ds_atype_map(atype);
1916                 
1917                 if (rtype == SID_NAME_UNKNOWN) {
1918                         status = STATUS_SOME_UNMAPPED;
1919                         continue;
1920                 }
1921
1922                 r->out.rids->ids[i] = sid->sub_auths[sid->num_auths-1];
1923                 r->out.types->ids[i] = rtype;
1924                 num_mapped++;
1925         }
1926         
1927         if (num_mapped == 0) {
1928                 return NT_STATUS_NONE_MAPPED;
1929         }
1930         return status;
1931 }
1932
1933
1934 /* 
1935   samr_LookupRids 
1936 */
1937 static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1938                        struct samr_LookupRids *r)
1939 {
1940         struct dcesrv_handle *h;
1941         struct samr_domain_state *d_state;
1942         int i, total;
1943         NTSTATUS status = NT_STATUS_OK;
1944         struct lsa_String *names;
1945         uint32_t *ids;
1946
1947         ZERO_STRUCTP(r->out.names);
1948         ZERO_STRUCTP(r->out.types);
1949
1950         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1951
1952         d_state = h->data;
1953
1954         if (r->in.num_rids == 0)
1955                 return NT_STATUS_OK;
1956
1957         names = talloc_array(mem_ctx, struct lsa_String, r->in.num_rids);
1958         ids = talloc_array(mem_ctx, uint32_t, r->in.num_rids);
1959
1960         if ((names == NULL) || (ids == NULL))
1961                 return NT_STATUS_NO_MEMORY;
1962
1963         total = 0;
1964
1965         for (i=0; i<r->in.num_rids; i++) {
1966                 struct ldb_message **res;
1967                 int count;
1968                 const char * const attrs[] = {  "sAMAccountType",
1969                                                 "sAMAccountName", NULL };
1970                 uint32_t atype;
1971                 struct dom_sid *sid;
1972
1973                 ids[i] = SID_NAME_UNKNOWN;
1974
1975                 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid,
1976                         r->in.rids[i]);
1977                 if (sid == NULL) {
1978                         names[i].string = NULL;
1979                         status = STATUS_SOME_UNMAPPED;
1980                         continue;
1981                 }
1982                 
1983                 count = gendb_search(d_state->sam_ctx, mem_ctx,
1984                                      d_state->domain_dn, &res, attrs,
1985                                      "(objectSid=%s)", 
1986                                      ldap_encode_ndr_dom_sid(mem_ctx, sid));
1987                 if (count != 1) {
1988                         names[i].string = NULL;
1989                         status = STATUS_SOME_UNMAPPED;
1990                         continue;
1991                 }
1992
1993                 names[i].string = samdb_result_string(res[0], "sAMAccountName",
1994                                                       NULL);
1995
1996                 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1997                 if (atype == 0) {
1998                         status = STATUS_SOME_UNMAPPED;
1999                         continue;
2000                 }
2001
2002                 ids[i] = ds_atype_map(atype);
2003                 
2004                 if (ids[i] == SID_NAME_UNKNOWN) {
2005                         status = STATUS_SOME_UNMAPPED;
2006                         continue;
2007                 }
2008         }
2009
2010         r->out.names->names = names;
2011         r->out.names->count = r->in.num_rids;
2012
2013         r->out.types->ids = ids;
2014         r->out.types->count = r->in.num_rids;
2015
2016         return status;
2017 }
2018
2019
2020 /* 
2021   samr_OpenGroup 
2022 */
2023 static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2024                        struct samr_OpenGroup *r)
2025 {
2026         struct samr_domain_state *d_state;
2027         struct samr_account_state *a_state;
2028         struct dcesrv_handle *h;
2029         const char *groupname;
2030         struct dom_sid *sid;
2031         struct ldb_message **msgs;
2032         struct dcesrv_handle *g_handle;
2033         const char * const attrs[2] = { "sAMAccountName", NULL };
2034         int ret;
2035
2036         ZERO_STRUCTP(r->out.group_handle);
2037
2038         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2039
2040         d_state = h->data;
2041
2042         /* form the group SID */
2043         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2044         if (!sid) {
2045                 return NT_STATUS_NO_MEMORY;
2046         }
2047
2048         /* search for the group record */
2049         ret = gendb_search(d_state->sam_ctx,
2050                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2051                            "(&(objectSid=%s)(objectclass=group)"
2052                            "(grouptype=%d))",
2053                            ldap_encode_ndr_dom_sid(mem_ctx, sid),
2054                            GTYPE_SECURITY_GLOBAL_GROUP);
2055         if (ret == 0) {
2056                 return NT_STATUS_NO_SUCH_GROUP;
2057         }
2058         if (ret != 1) {
2059                 DEBUG(0,("Found %d records matching sid %s\n", 
2060                          ret, dom_sid_string(mem_ctx, sid)));
2061                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2062         }
2063
2064         groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2065         if (groupname == NULL) {
2066                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2067                          dom_sid_string(mem_ctx, sid)));
2068                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2069         }
2070
2071         a_state = talloc(mem_ctx, struct samr_account_state);
2072         if (!a_state) {
2073                 return NT_STATUS_NO_MEMORY;
2074         }
2075         a_state->sam_ctx = d_state->sam_ctx;
2076         a_state->access_mask = r->in.access_mask;
2077         a_state->domain_state = talloc_reference(a_state, d_state);
2078         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2079         a_state->account_sid = talloc_steal(a_state, sid);
2080         a_state->account_name = talloc_strdup(a_state, groupname);
2081         if (!a_state->account_name) {
2082                 return NT_STATUS_NO_MEMORY;
2083         }
2084
2085         /* create the policy handle */
2086         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
2087         if (!g_handle) {
2088                 return NT_STATUS_NO_MEMORY;
2089         }
2090
2091         g_handle->data = talloc_steal(g_handle, a_state);
2092
2093         *r->out.group_handle = g_handle->wire_handle;
2094
2095         return NT_STATUS_OK;
2096 }
2097
2098 /* 
2099   samr_QueryGroupInfo 
2100 */
2101 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2102                        struct samr_QueryGroupInfo *r)
2103 {
2104         struct dcesrv_handle *h;
2105         struct samr_account_state *a_state;
2106         struct ldb_message *msg;
2107         struct ldb_result *res;
2108         const char * const attrs[4] = { "sAMAccountName", "description",
2109                                         "numMembers", NULL };
2110         int ret;
2111         union samr_GroupInfo *info;
2112
2113         *r->out.info = NULL;
2114
2115         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2116
2117         a_state = h->data;
2118         
2119         ret = ldb_search(a_state->sam_ctx, mem_ctx, &res, a_state->account_dn,
2120                 LDB_SCOPE_SUBTREE, attrs, "objectClass=*");
2121         
2122         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2123                 return NT_STATUS_NO_SUCH_GROUP;
2124         } else if (ret != LDB_SUCCESS) {
2125                 DEBUG(2, ("Error reading group info: %s\n", ldb_errstring(a_state->sam_ctx)));
2126                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2127         }
2128
2129         if (res->count != 1) {
2130                 DEBUG(2, ("Error finding group info, got %d entries\n", res->count));
2131                 
2132                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2133         }
2134         msg = res->msgs[0];
2135
2136         /* allocate the info structure */
2137         info = talloc_zero(mem_ctx, union samr_GroupInfo);
2138         if (info == NULL) {
2139                 return NT_STATUS_NO_MEMORY;
2140         }
2141
2142         /* Fill in the level */
2143         switch (r->in.level) {
2144         case GROUPINFOALL:
2145                 QUERY_STRING(msg, all.name,        "sAMAccountName");
2146                 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2147                 QUERY_UINT  (msg, all.num_members,      "numMembers")
2148                 QUERY_STRING(msg, all.description, "description");
2149                 break;
2150         case GROUPINFONAME:
2151                 QUERY_STRING(msg, name,            "sAMAccountName");
2152                 break;
2153         case GROUPINFOATTRIBUTES:
2154                 info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2155                 break;
2156         case GROUPINFODESCRIPTION:
2157                 QUERY_STRING(msg, description, "description");
2158                 break;
2159         case GROUPINFOALL2:
2160                 QUERY_STRING(msg, all2.name,        "sAMAccountName");
2161                 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2162                 QUERY_UINT  (msg, all2.num_members,      "numMembers")
2163                 QUERY_STRING(msg, all2.description, "description");
2164                 break;
2165         default:
2166                 talloc_free(info);
2167                 return NT_STATUS_INVALID_INFO_CLASS;
2168         }
2169
2170         *r->out.info = info;
2171
2172         return NT_STATUS_OK;
2173 }
2174
2175
2176 /* 
2177   samr_SetGroupInfo 
2178 */
2179 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2180                                   struct samr_SetGroupInfo *r)
2181 {
2182         struct dcesrv_handle *h;
2183         struct samr_account_state *g_state;
2184         struct ldb_message *msg;
2185         struct ldb_context *sam_ctx;
2186         int ret;
2187
2188         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2189
2190         g_state = h->data;
2191         sam_ctx = g_state->sam_ctx;
2192
2193         msg = ldb_msg_new(mem_ctx);
2194         if (msg == NULL) {
2195                 return NT_STATUS_NO_MEMORY;
2196         }       
2197
2198         msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
2199         if (!msg->dn) {
2200                 return NT_STATUS_NO_MEMORY;
2201         }
2202
2203         switch (r->in.level) {
2204         case GROUPINFODESCRIPTION:
2205                 SET_STRING(msg, description,         "description");
2206                 break;
2207         case GROUPINFONAME:
2208                 /* On W2k3 this does not change the name, it changes the
2209                  * sAMAccountName attribute */
2210                 SET_STRING(msg, name,                "sAMAccountName");
2211                 break;
2212         case GROUPINFOATTRIBUTES:
2213                 /* This does not do anything obviously visible in W2k3 LDAP */
2214                 return NT_STATUS_OK;
2215         default:
2216                 return NT_STATUS_INVALID_INFO_CLASS;
2217         }
2218
2219         /* modify the samdb record */
2220         ret = ldb_modify(g_state->sam_ctx, msg);
2221         if (ret != LDB_SUCCESS) {
2222                 /* we really need samdb.c to return NTSTATUS */
2223                 return NT_STATUS_UNSUCCESSFUL;
2224         }
2225
2226         return NT_STATUS_OK;
2227 }
2228
2229
2230 /* 
2231   samr_AddGroupMember 
2232 */
2233 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2234                        struct samr_AddGroupMember *r)
2235 {
2236         struct dcesrv_handle *h;
2237         struct samr_account_state *a_state;
2238         struct samr_domain_state *d_state;
2239         struct ldb_message *mod;
2240         struct dom_sid *membersid;
2241         const char *memberdn;
2242         struct ldb_result *res;
2243         const char * const attrs[] = { NULL };
2244         int ret;
2245
2246         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2247
2248         a_state = h->data;
2249         d_state = a_state->domain_state;
2250
2251         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2252         if (membersid == NULL) {
2253                 return NT_STATUS_NO_MEMORY;
2254         }
2255
2256         /* In native mode, AD can also nest domain groups. Not sure yet
2257          * whether this is also available via RPC. */
2258         ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2259                                  d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2260                                  "(&(objectSid=%s)(objectclass=user))",
2261                                  ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2262
2263         if (ret != LDB_SUCCESS) {
2264                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2265         }
2266
2267         if (res->count == 0) {
2268                 return NT_STATUS_NO_SUCH_USER;
2269         }
2270                 
2271         if (res->count > 1) {
2272                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2273         }
2274
2275         memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2276
2277         if (memberdn == NULL)
2278                 return NT_STATUS_NO_MEMORY;
2279
2280         mod = ldb_msg_new(mem_ctx);
2281         if (mod == NULL) {
2282                 return NT_STATUS_NO_MEMORY;
2283         }
2284
2285         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2286
2287         ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2288                                                                 memberdn);
2289         if (ret != LDB_SUCCESS) {
2290                 return NT_STATUS_UNSUCCESSFUL;
2291         }
2292
2293         ret = ldb_modify(a_state->sam_ctx, mod);
2294         switch (ret) {
2295         case LDB_SUCCESS:
2296                 return NT_STATUS_OK;
2297         case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
2298                 return NT_STATUS_MEMBER_IN_GROUP;
2299         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2300                 return NT_STATUS_ACCESS_DENIED;
2301         default:
2302                 return NT_STATUS_UNSUCCESSFUL;
2303         }
2304 }
2305
2306
2307 /* 
2308   samr_DeleteDomainGroup 
2309 */
2310 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2311                        struct samr_DeleteDomainGroup *r)
2312 {
2313         struct dcesrv_handle *h;
2314         struct samr_account_state *a_state;
2315         int ret;
2316
2317         *r->out.group_handle = *r->in.group_handle;
2318
2319         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2320
2321         a_state = h->data;
2322
2323         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2324         if (ret != LDB_SUCCESS) {
2325                 return NT_STATUS_UNSUCCESSFUL;
2326         }
2327
2328         talloc_free(h);
2329         ZERO_STRUCTP(r->out.group_handle);
2330
2331         return NT_STATUS_OK;
2332 }
2333
2334
2335 /* 
2336   samr_DeleteGroupMember 
2337 */
2338 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2339                        struct samr_DeleteGroupMember *r)
2340 {
2341         struct dcesrv_handle *h;
2342         struct samr_account_state *a_state;
2343         struct samr_domain_state *d_state;
2344         struct ldb_message *mod;
2345         struct dom_sid *membersid;
2346         const char *memberdn;
2347         struct ldb_result *res;
2348         const char * const attrs[] = { NULL };
2349         int ret;
2350
2351         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2352
2353         a_state = h->data;
2354         d_state = a_state->domain_state;
2355
2356         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2357         if (membersid == NULL)
2358                 return NT_STATUS_NO_MEMORY;
2359
2360         /* In native mode, AD can also nest domain groups. Not sure yet
2361          * whether this is also available via RPC. */
2362         ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2363                                  d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2364                                  "(&(objectSid=%s)(objectclass=user))",
2365                                  ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2366
2367         if (ret != LDB_SUCCESS) {
2368                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2369         }
2370
2371         if (res->count == 0) {
2372                 return NT_STATUS_NO_SUCH_USER;
2373         }
2374                 
2375         if (res->count > 1) {
2376                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2377         }
2378
2379         memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2380
2381         if (memberdn == NULL)
2382                 return NT_STATUS_NO_MEMORY;
2383
2384         mod = ldb_msg_new(mem_ctx);
2385         if (mod == NULL) {
2386                 return NT_STATUS_NO_MEMORY;
2387         }
2388
2389         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2390
2391         ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2392                                                                 memberdn);
2393         if (ret != LDB_SUCCESS) {
2394                 return NT_STATUS_NO_MEMORY;
2395         }
2396
2397         ret = ldb_modify(a_state->sam_ctx, mod);
2398         switch (ret) {
2399         case LDB_SUCCESS:
2400                 return NT_STATUS_OK;
2401         case LDB_ERR_NO_SUCH_ATTRIBUTE:
2402                 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2403         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2404                 return NT_STATUS_ACCESS_DENIED;
2405         default:
2406                 return NT_STATUS_UNSUCCESSFUL;
2407         }
2408 }
2409
2410
2411 /* 
2412   samr_QueryGroupMember 
2413 */
2414 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2415                                       struct samr_QueryGroupMember *r)
2416 {
2417         struct dcesrv_handle *h;
2418         struct samr_account_state *a_state;
2419         struct ldb_message **res;
2420         struct ldb_message_element *el;
2421         struct samr_RidTypeArray *array;
2422         const char * const attrs[2] = { "member", NULL };
2423         int ret;
2424
2425         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2426
2427         a_state = h->data;
2428
2429         /* pull the member attribute */
2430         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2431                               a_state->account_dn, &res, attrs);
2432
2433         if (ret != 1) {
2434                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2435         }
2436
2437         array = talloc(mem_ctx, struct samr_RidTypeArray);
2438
2439         if (array == NULL)
2440                 return NT_STATUS_NO_MEMORY;
2441
2442         ZERO_STRUCTP(array);
2443
2444         el = ldb_msg_find_element(res[0], "member");
2445
2446         if (el != NULL) {
2447                 int i;
2448
2449                 array->count = el->num_values;
2450
2451                 array->rids = talloc_array(mem_ctx, uint32_t,
2452                                              el->num_values);
2453                 if (array->rids == NULL)
2454                         return NT_STATUS_NO_MEMORY;
2455
2456                 array->types = talloc_array(mem_ctx, uint32_t,
2457                                             el->num_values);
2458                 if (array->types == NULL)
2459                         return NT_STATUS_NO_MEMORY;
2460
2461                 for (i=0; i<el->num_values; i++) {
2462                         struct ldb_message **res2;
2463                         const char * const attrs2[2] = { "objectSid", NULL };
2464                         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2465                                            ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2466                                            &res2, attrs2);
2467                         if (ret != 1)
2468                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2469
2470                         array->rids[i] =
2471                                 samdb_result_rid_from_sid(mem_ctx, res2[0],
2472                                                           "objectSid", 0);
2473
2474                         if (array->rids[i] == 0)
2475                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2476
2477                         array->types[i] = 7; /* RID type of some kind, not sure what the value means. */
2478                 }
2479         }
2480
2481         *r->out.rids = array;
2482
2483         return NT_STATUS_OK;
2484 }
2485
2486
2487 /* 
2488   samr_SetMemberAttributesOfGroup 
2489 */
2490 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2491                        struct samr_SetMemberAttributesOfGroup *r)
2492 {
2493         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2494 }
2495
2496
2497 /* 
2498   samr_OpenAlias 
2499 */
2500 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2501                        struct samr_OpenAlias *r)
2502 {
2503         struct samr_domain_state *d_state;
2504         struct samr_account_state *a_state;
2505         struct dcesrv_handle *h;
2506         const char *alias_name;
2507         struct dom_sid *sid;
2508         struct ldb_message **msgs;
2509         struct dcesrv_handle *g_handle;
2510         const char * const attrs[2] = { "sAMAccountName", NULL };
2511         int ret;
2512
2513         ZERO_STRUCTP(r->out.alias_handle);
2514
2515         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2516
2517         d_state = h->data;
2518
2519         /* form the alias SID */
2520         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2521         if (sid == NULL)
2522                 return NT_STATUS_NO_MEMORY;
2523
2524         /* search for the group record */
2525         ret = gendb_search(d_state->sam_ctx,
2526                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2527                            "(&(objectSid=%s)(objectclass=group)"
2528                            "(|(grouptype=%d)(grouptype=%d)))",
2529                            ldap_encode_ndr_dom_sid(mem_ctx, sid),
2530                            GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2531                            GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2532         if (ret == 0) {
2533                 return NT_STATUS_NO_SUCH_ALIAS;
2534         }
2535         if (ret != 1) {
2536                 DEBUG(0,("Found %d records matching sid %s\n", 
2537                          ret, dom_sid_string(mem_ctx, sid)));
2538                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2539         }
2540
2541         alias_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2542         if (alias_name == NULL) {
2543                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2544                          dom_sid_string(mem_ctx, sid)));
2545                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2546         }
2547
2548         a_state = talloc(mem_ctx, struct samr_account_state);
2549         if (!a_state) {
2550                 return NT_STATUS_NO_MEMORY;
2551         }
2552         a_state->sam_ctx = d_state->sam_ctx;
2553         a_state->access_mask = r->in.access_mask;
2554         a_state->domain_state = talloc_reference(a_state, d_state);
2555         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2556         a_state->account_sid = talloc_steal(a_state, sid);
2557         a_state->account_name = talloc_strdup(a_state, alias_name);
2558         if (!a_state->account_name) {
2559                 return NT_STATUS_NO_MEMORY;
2560         }
2561
2562         /* create the policy handle */
2563         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2564         if (!g_handle) {
2565                 return NT_STATUS_NO_MEMORY;
2566         }
2567
2568         g_handle->data = talloc_steal(g_handle, a_state);
2569
2570         *r->out.alias_handle = g_handle->wire_handle;
2571
2572         return NT_STATUS_OK;
2573 }
2574
2575
2576 /* 
2577   samr_QueryAliasInfo 
2578 */
2579 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2580                        struct samr_QueryAliasInfo *r)
2581 {
2582         struct dcesrv_handle *h;
2583         struct samr_account_state *a_state;
2584         struct ldb_message *msg, **res;
2585         const char * const attrs[4] = { "sAMAccountName", "description",
2586                                         "numMembers", NULL };
2587         int ret;
2588         union samr_AliasInfo *info;
2589
2590         *r->out.info = NULL;
2591
2592         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2593
2594         a_state = h->data;
2595
2596         /* pull all the alias attributes */
2597         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2598                               a_state->account_dn ,&res, attrs);
2599         if (ret != 1) {
2600                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2601         }
2602         msg = res[0];
2603
2604         /* allocate the info structure */
2605         info = talloc_zero(mem_ctx, union samr_AliasInfo);
2606         if (info == NULL) {
2607                 return NT_STATUS_NO_MEMORY;
2608         }
2609
2610         switch(r->in.level) {
2611         case ALIASINFOALL:
2612                 QUERY_STRING(msg, all.name, "sAMAccountName");
2613                 QUERY_UINT  (msg, all.num_members, "numMembers");
2614                 QUERY_STRING(msg, all.description, "description");
2615                 break;
2616         case ALIASINFONAME:
2617                 QUERY_STRING(msg, name, "sAMAccountName");
2618                 break;
2619         case ALIASINFODESCRIPTION:
2620                 QUERY_STRING(msg, description, "description");
2621                 break;
2622         default:
2623                 talloc_free(info);
2624                 return NT_STATUS_INVALID_INFO_CLASS;
2625         }
2626
2627         *r->out.info = info;
2628
2629         return NT_STATUS_OK;
2630 }
2631
2632
2633 /* 
2634   samr_SetAliasInfo 
2635 */
2636 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2637                        struct samr_SetAliasInfo *r)
2638 {
2639         struct dcesrv_handle *h;
2640         struct samr_account_state *a_state;
2641         struct ldb_message *msg;
2642         struct ldb_context *sam_ctx;
2643         int ret;
2644
2645         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2646
2647         a_state = h->data;
2648         sam_ctx = a_state->sam_ctx;
2649
2650         msg = ldb_msg_new(mem_ctx);
2651         if (msg == NULL) {
2652                 return NT_STATUS_NO_MEMORY;
2653         }
2654
2655         msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2656         if (!msg->dn) {
2657                 return NT_STATUS_NO_MEMORY;
2658         }
2659
2660         switch (r->in.level) {
2661         case ALIASINFODESCRIPTION:
2662                 SET_STRING(msg, description,         "description");
2663                 break;
2664         case ALIASINFONAME:
2665                 /* On W2k3 this does not change the name, it changes the
2666                  * sAMAccountName attribute */
2667                 SET_STRING(msg, name,                "sAMAccountName");
2668                 break;
2669         default:
2670                 return NT_STATUS_INVALID_INFO_CLASS;
2671         }
2672
2673         /* modify the samdb record */
2674         ret = ldb_modify(a_state->sam_ctx, msg);
2675         if (ret != LDB_SUCCESS) {
2676                 /* we really need samdb.c to return NTSTATUS */
2677                 return NT_STATUS_UNSUCCESSFUL;
2678         }
2679
2680         return NT_STATUS_OK;
2681 }
2682
2683
2684 /* 
2685   samr_DeleteDomAlias 
2686 */
2687 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2688                        struct samr_DeleteDomAlias *r)
2689 {
2690         struct dcesrv_handle *h;
2691         struct samr_account_state *a_state;
2692         int ret;
2693
2694         *r->out.alias_handle = *r->in.alias_handle;
2695
2696         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2697
2698         a_state = h->data;
2699
2700         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2701         if (ret != LDB_SUCCESS) {
2702                 return NT_STATUS_UNSUCCESSFUL;
2703         }
2704
2705         talloc_free(h);
2706         ZERO_STRUCTP(r->out.alias_handle);
2707
2708         return NT_STATUS_OK;
2709 }
2710
2711
2712 /* 
2713   samr_AddAliasMember 
2714 */
2715 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2716                        struct samr_AddAliasMember *r)
2717 {
2718         struct dcesrv_handle *h;
2719         struct samr_account_state *a_state;
2720         struct samr_domain_state *d_state;
2721         struct ldb_message *mod;
2722         struct ldb_message **msgs;
2723         const char * const attrs[] = { NULL };
2724         struct ldb_dn *memberdn = NULL;
2725         int ret;
2726         NTSTATUS status;
2727
2728         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2729
2730         a_state = h->data;
2731         d_state = a_state->domain_state;
2732
2733         ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2734                            &msgs, attrs, "(objectsid=%s)", 
2735                            ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2736
2737         if (ret == 1) {
2738                 memberdn = msgs[0]->dn;
2739         } else  if (ret > 1) {
2740                 DEBUG(0,("Found %d records matching sid %s\n", 
2741                          ret, dom_sid_string(mem_ctx, r->in.sid)));
2742                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2743         } else if (ret == 0) {
2744                 status = samdb_create_foreign_security_principal(
2745                         d_state->sam_ctx, mem_ctx, r->in.sid, &memberdn);
2746                 if (!NT_STATUS_IS_OK(status)) {
2747                         return status;
2748                 }
2749         } else {
2750                 DEBUG(0, ("samdb_search returned %d: %s\n", ret, ldb_errstring(d_state->sam_ctx)));
2751         }
2752
2753         if (memberdn == NULL) {
2754                 DEBUG(0, ("Could not find memberdn\n"));
2755                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2756         }
2757
2758         mod = ldb_msg_new(mem_ctx);
2759         if (mod == NULL) {
2760                 return NT_STATUS_NO_MEMORY;
2761         }
2762
2763         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2764
2765         ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2766                                  ldb_dn_alloc_linearized(mem_ctx, memberdn));
2767         if (ret != LDB_SUCCESS) {
2768                 return NT_STATUS_UNSUCCESSFUL;
2769         }
2770
2771         if (ldb_modify(a_state->sam_ctx, mod) != LDB_SUCCESS) {
2772                 return NT_STATUS_UNSUCCESSFUL;
2773         }
2774
2775         return NT_STATUS_OK;
2776 }
2777
2778
2779 /* 
2780   samr_DeleteAliasMember 
2781 */
2782 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2783                        struct samr_DeleteAliasMember *r)
2784 {
2785         struct dcesrv_handle *h;
2786         struct samr_account_state *a_state;
2787         struct samr_domain_state *d_state;
2788         struct ldb_message *mod;
2789         const char *memberdn;
2790         int ret;
2791
2792         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2793
2794         a_state = h->data;
2795         d_state = a_state->domain_state;
2796
2797         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2798                                        "distinguishedName", "(objectSid=%s)", 
2799                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2800
2801         if (memberdn == NULL)
2802                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2803
2804         mod = ldb_msg_new(mem_ctx);
2805         if (mod == NULL) {
2806                 return NT_STATUS_NO_MEMORY;
2807         }
2808
2809         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2810
2811         ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2812                                                                  memberdn);
2813         if (ret != LDB_SUCCESS)
2814                 return NT_STATUS_UNSUCCESSFUL;
2815
2816         if (ldb_modify(a_state->sam_ctx, mod) != LDB_SUCCESS)
2817                 return NT_STATUS_UNSUCCESSFUL;
2818
2819         return NT_STATUS_OK;
2820 }
2821
2822
2823 /* 
2824   samr_GetMembersInAlias 
2825 */
2826 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2827                        struct samr_GetMembersInAlias *r)
2828 {
2829         struct dcesrv_handle *h;
2830         struct samr_account_state *a_state;
2831         struct samr_domain_state *d_state;
2832         struct ldb_message **msgs;
2833         struct lsa_SidPtr *sids;
2834         struct ldb_message_element *el;
2835         const char * const attrs[2] = { "member", NULL};
2836         int ret;
2837
2838         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2839
2840         a_state = h->data;
2841         d_state = a_state->domain_state;
2842
2843         ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
2844                               a_state->account_dn, &msgs, attrs);
2845
2846         if (ret == -1) {
2847                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2848         } else if (ret == 0) {
2849                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2850         } else if (ret != 1) {
2851                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2852         }
2853
2854         r->out.sids->num_sids = 0;
2855         r->out.sids->sids = NULL;
2856
2857         el = ldb_msg_find_element(msgs[0], "member");
2858
2859         if (el != NULL) {
2860                 int i;
2861
2862                 sids = talloc_array(mem_ctx, struct lsa_SidPtr,
2863                                       el->num_values);
2864
2865                 if (sids == NULL)
2866                         return NT_STATUS_NO_MEMORY;
2867
2868                 for (i=0; i<el->num_values; i++) {
2869                         struct ldb_message **msgs2;
2870                         const char * const attrs2[2] = { "objectSid", NULL };
2871                         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2872                                               ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2873                                               &msgs2, attrs2);
2874                         if (ret != 1)
2875                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2876
2877                         sids[i].sid = samdb_result_dom_sid(mem_ctx, msgs2[0],
2878                                                            "objectSid");
2879
2880                         if (sids[i].sid == NULL)
2881                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2882                 }
2883                 r->out.sids->num_sids = el->num_values;
2884                 r->out.sids->sids = sids;
2885         }
2886
2887         return NT_STATUS_OK;
2888 }
2889
2890 /* 
2891   samr_OpenUser 
2892 */
2893 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2894                               struct samr_OpenUser *r)
2895 {
2896         struct samr_domain_state *d_state;
2897         struct samr_account_state *a_state;
2898         struct dcesrv_handle *h;
2899         const char *account_name;
2900         struct dom_sid *sid;
2901         struct ldb_message **msgs;
2902         struct dcesrv_handle *u_handle;
2903         const char * const attrs[2] = { "sAMAccountName", NULL };
2904         int ret;
2905
2906         ZERO_STRUCTP(r->out.user_handle);
2907
2908         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2909
2910         d_state = h->data;
2911
2912         /* form the users SID */
2913         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2914         if (!sid) {
2915                 return NT_STATUS_NO_MEMORY;
2916         }
2917
2918         /* search for the user record */
2919         ret = gendb_search(d_state->sam_ctx,
2920                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2921                            "(&(objectSid=%s)(objectclass=user))", 
2922                            ldap_encode_ndr_dom_sid(mem_ctx, sid));
2923         if (ret == 0) {
2924                 return NT_STATUS_NO_SUCH_USER;
2925         }
2926         if (ret != 1) {
2927                 DEBUG(0,("Found %d records matching sid %s\n", ret, 
2928                          dom_sid_string(mem_ctx, sid)));
2929                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2930         }
2931
2932         account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2933         if (account_name == NULL) {
2934                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2935                          dom_sid_string(mem_ctx, sid)));
2936                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2937         }
2938
2939         a_state = talloc(mem_ctx, struct samr_account_state);
2940         if (!a_state) {
2941                 return NT_STATUS_NO_MEMORY;
2942         }
2943         a_state->sam_ctx = d_state->sam_ctx;
2944         a_state->access_mask = r->in.access_mask;
2945         a_state->domain_state = talloc_reference(a_state, d_state);
2946         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2947         a_state->account_sid = talloc_steal(a_state, sid);
2948         a_state->account_name = talloc_strdup(a_state, account_name);
2949         if (!a_state->account_name) {
2950                 return NT_STATUS_NO_MEMORY;
2951         }
2952
2953         /* create the policy handle */
2954         u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2955         if (!u_handle) {
2956                 return NT_STATUS_NO_MEMORY;
2957         }
2958
2959         u_handle->data = talloc_steal(u_handle, a_state);
2960
2961         *r->out.user_handle = u_handle->wire_handle;
2962
2963         return NT_STATUS_OK;
2964
2965 }
2966
2967
2968 /* 
2969   samr_DeleteUser 
2970 */
2971 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2972                                 struct samr_DeleteUser *r)
2973 {
2974         struct dcesrv_handle *h;
2975         struct samr_account_state *a_state;
2976         int ret;
2977
2978         *r->out.user_handle = *r->in.user_handle;
2979
2980         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2981
2982         a_state = h->data;
2983
2984         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2985         if (ret != LDB_SUCCESS) {
2986                 DEBUG(1, ("Failed to delete user: %s: %s\n", 
2987                           ldb_dn_get_linearized(a_state->account_dn), 
2988                           ldb_errstring(a_state->sam_ctx)));
2989                 return NT_STATUS_UNSUCCESSFUL;
2990         }
2991
2992         talloc_free(h);
2993         ZERO_STRUCTP(r->out.user_handle);
2994
2995         return NT_STATUS_OK;
2996 }
2997
2998
2999 /* 
3000   samr_QueryUserInfo 
3001 */
3002 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3003                                    struct samr_QueryUserInfo *r)
3004 {
3005         struct dcesrv_handle *h;
3006         struct samr_account_state *a_state;
3007         struct ldb_message *msg, **res;
3008         int ret;
3009         struct ldb_context *sam_ctx;
3010
3011         const char * const *attrs = NULL;
3012         union samr_UserInfo *info;
3013
3014         *r->out.info = NULL;
3015
3016         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3017
3018         a_state = h->data;
3019         sam_ctx = a_state->sam_ctx;
3020
3021         /* fill in the reply */
3022         switch (r->in.level) {
3023         case 1:
3024         {
3025                 static const char * const attrs2[] = {"sAMAccountName",
3026                                                       "displayName",
3027                                                       "primaryroupID",
3028                                                       "description",
3029                                                       "comment",
3030                                                       NULL};
3031                 attrs = attrs2;
3032                 break;
3033         }
3034         case 2:
3035         {
3036                 static const char * const attrs2[] = {"comment",
3037                                                       "countryCode",
3038                                                       "codePage",
3039                                                       NULL};
3040                 attrs = attrs2;
3041                 break;
3042         }
3043         case 3:
3044         {
3045                 static const char * const attrs2[] = {"sAMAccountName",
3046                                                       "displayName",
3047                                                       "objectSid",
3048                                                       "primaryGroupID",
3049                                                       "homeDirectory",
3050                                                       "homeDrive",
3051                                                       "scriptPath",
3052                                                       "profilePath",
3053                                                       "userWorkstations",
3054                                                       "lastLogon",
3055                                                       "lastLogoff",
3056                                                       "pwdLastSet",
3057                                                       "logonHours",
3058                                                       "badPwdCount",
3059                                                       "logonCount",
3060                                                       "userAccountControl",
3061                                                       NULL};
3062                 attrs = attrs2;
3063                 break;
3064         }
3065         case 4:
3066         {
3067                 static const char * const attrs2[] = {"logonHours",
3068                                                       NULL};
3069                 attrs = attrs2;
3070                 break;
3071         }
3072         case 5:
3073         {
3074                 static const char * const attrs2[] = {"sAMAccountName", 
3075                                                       "displayName",
3076                                                       "objectSid",
3077                                                       "primaryGroupID",
3078                                                       "homeDirectory",
3079                                                       "homeDrive",
3080                                                       "scriptPath", 
3081                                                       "profilePath",
3082                                                       "description",
3083                                                       "userWorkstations",
3084                                                       "lastLogon",
3085                                                       "lastLogoff",
3086                                                       "logonHours",
3087                                                       "badPwdCount",
3088                                                       "logonCount",
3089                                                       "pwdLastSet",
3090                                                       "accountExpires",
3091                                                       "userAccountControl",
3092                                                       NULL};
3093                 attrs = attrs2;
3094                 break;
3095         }
3096         case 6:
3097         {
3098                 static const char * const attrs2[] = {"sAMAccountName",
3099                                                       "displayName",
3100                                                       NULL};
3101                 attrs = attrs2;
3102                 break;
3103         }
3104         case 7:
3105         {
3106                 static const char * const attrs2[] = {"sAMAccountName",
3107                                                       NULL};
3108                 attrs = attrs2;
3109                 break;
3110         }
3111         case 8:
3112         {
3113                 static const char * const attrs2[] = {"displayName",
3114                                                       NULL};
3115                 attrs = attrs2;
3116                 break;
3117         }
3118         case 9:
3119         {
3120                 static const char * const attrs2[] = {"primaryGroupID",
3121                                                       NULL};
3122                 attrs = attrs2;
3123                 break;
3124         }
3125         case 10:
3126         {
3127                 static const char * const attrs2[] = {"homeDirectory",
3128                                                       "homeDrive",
3129                                                       NULL};
3130                 attrs = attrs2;
3131                 break;
3132         }
3133         case 11:
3134         {
3135                 static const char * const attrs2[] = {"scriptPath",
3136                                                       NULL};
3137                 attrs = attrs2;
3138                 break;
3139         }
3140         case 12:
3141         {
3142                 static const char * const attrs2[] = {"profilePath",
3143                                                       NULL};
3144                 attrs = attrs2;
3145                 break;
3146         }
3147         case 13:
3148         {
3149                 static const char * const attrs2[] = {"description",
3150                                                       NULL};
3151                 attrs = attrs2;
3152                 break;
3153         }
3154         case 14:
3155         {
3156                 static const char * const attrs2[] = {"userWorkstations",
3157                                                       NULL};
3158                 attrs = attrs2;
3159                 break;
3160         }
3161         case 16:
3162         {
3163                 static const char * const attrs2[] = {"userAccountControl",
3164                                                       "pwdLastSet",
3165                                                       NULL};
3166                 attrs = attrs2;
3167                 break;
3168         }
3169         case 17:
3170         {
3171                 static const char * const attrs2[] = {"accountExpires",
3172                                                       NULL};
3173                 attrs = attrs2;
3174                 break;
3175         }
3176         case 18:
3177         {
3178                 return NT_STATUS_NOT_SUPPORTED;
3179         }
3180         case 20:
3181         {
3182                 static const char * const attrs2[] = {"userParameters",
3183                                                       NULL};
3184                 attrs = attrs2;
3185                 break;
3186         }
3187         case 21:
3188         {
3189                 static const char * const attrs2[] = {"lastLogon",
3190                                                       "lastLogoff",
3191                                                       "pwdLastSet",
3192                                                       "accountExpires",
3193                                                       "sAMAccountName",
3194                                                       "displayName",
3195                                                       "homeDirectory",
3196                                                       "homeDrive",
3197                                                       "scriptPath",
3198                                                       "profilePath",
3199                                                       "description",
3200                                                       "userWorkstations",
3201                                                       "comment",
3202                                                       "userParameters",
3203                                                       "objectSid",
3204                                                       "primaryGroupID",
3205                                                       "userAccountControl",
3206                                                       "logonHours",
3207                                                       "badPwdCount",
3208                                                       "logonCount",
3209                                                       "countryCode",
3210                                                       "codePage",
3211                                                       NULL};
3212                 attrs = attrs2;
3213                 break;
3214         }
3215         case 23:
3216         case 24:
3217         case 25:
3218         case 26:
3219         {
3220                 return NT_STATUS_NOT_SUPPORTED;
3221         }
3222         default:
3223         {
3224                 return NT_STATUS_INVALID_INFO_CLASS;
3225         }
3226         }
3227
3228         /* pull all the user attributes */
3229         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
3230                               a_state->account_dn ,&res, attrs);
3231         if (ret != 1) {
3232                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3233         }
3234         msg = res[0];
3235
3236         /* allocate the info structure */
3237         info = talloc_zero(mem_ctx, union samr_UserInfo);
3238         if (info == NULL) {
3239                 return NT_STATUS_NO_MEMORY;
3240         }
3241
3242         /* fill in the reply */
3243         switch (r->in.level) {
3244         case 1:
3245                 QUERY_STRING(msg, info1.account_name,          "sAMAccountName");
3246                 QUERY_STRING(msg, info1.full_name,             "displayName");
3247                 QUERY_UINT  (msg, info1.primary_gid,           "primaryGroupID");
3248                 QUERY_STRING(msg, info1.description,           "description");
3249                 QUERY_STRING(msg, info1.comment,               "comment");
3250                 break;
3251
3252         case 2:
3253                 QUERY_STRING(msg, info2.comment,               "comment");
3254                 QUERY_UINT  (msg, info2.country_code,          "countryCode");
3255                 QUERY_UINT  (msg, info2.code_page,             "codePage");
3256                 break;
3257
3258         case 3:
3259                 QUERY_STRING(msg, info3.account_name,          "sAMAccountName");
3260                 QUERY_STRING(msg, info3.full_name,             "displayName");
3261                 QUERY_RID   (msg, info3.rid,                   "objectSid");
3262                 QUERY_UINT  (msg, info3.primary_gid,           "primaryGroupID");
3263                 QUERY_STRING(msg, info3.home_directory,        "homeDirectory");
3264                 QUERY_STRING(msg, info3.home_drive,            "homeDrive");
3265                 QUERY_STRING(msg, info3.logon_script,          "scriptPath");
3266                 QUERY_STRING(msg, info3.profile_path,          "profilePath");
3267                 QUERY_STRING(msg, info3.workstations,          "userWorkstations");
3268                 QUERY_UINT64(msg, info3.last_logon,            "lastLogon");
3269                 QUERY_UINT64(msg, info3.last_logoff,           "lastLogoff");
3270                 QUERY_UINT64(msg, info3.last_password_change,  "pwdLastSet");
3271                 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
3272                 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
3273                 QUERY_LHOURS(msg, info3.logon_hours,           "logonHours");
3274                 QUERY_UINT  (msg, info3.bad_password_count,    "badPwdCount");
3275                 QUERY_UINT  (msg, info3.logon_count,           "logonCount");
3276                 QUERY_AFLAGS(msg, info3.acct_flags,            "userAccountControl");
3277                 break;
3278
3279         case 4:
3280                 QUERY_LHOURS(msg, info4.logon_hours,           "logonHours");
3281                 break;
3282
3283         case 5:
3284                 QUERY_STRING(msg, info5.account_name,          "sAMAccountName");
3285                 QUERY_STRING(msg, info5.full_name,             "displayName");
3286                 QUERY_RID   (msg, info5.rid,                   "objectSid");
3287                 QUERY_UINT  (msg, info5.primary_gid,           "primaryGroupID");
3288                 QUERY_STRING(msg, info5.home_directory,        "homeDirectory");
3289                 QUERY_STRING(msg, info5.home_drive,            "homeDrive");
3290                 QUERY_STRING(msg, info5.logon_script,          "scriptPath");
3291                 QUERY_STRING(msg, info5.profile_path,          "profilePath");
3292                 QUERY_STRING(msg, info5.description,           "description");
3293                 QUERY_STRING(msg, info5.workstations,          "userWorkstations");
3294                 QUERY_UINT64(msg, info5.last_logon,            "lastLogon");
3295                 QUERY_UINT64(msg, info5.last_logoff,           "lastLogoff");
3296                 QUERY_LHOURS(msg, info5.logon_hours,           "logonHours");
3297                 QUERY_UINT  (msg, info5.bad_password_count,    "badPwdCount");
3298                 QUERY_UINT  (msg, info5.logon_count,           "logonCount");
3299                 QUERY_UINT64(msg, info5.last_password_change,  "pwdLastSet");
3300                 QUERY_UINT64(msg, info5.acct_expiry,           "accountExpires");
3301                 QUERY_AFLAGS(msg, info5.acct_flags,            "userAccountControl");
3302                 break;
3303
3304         case 6:
3305                 QUERY_STRING(msg, info6.account_name,   "sAMAccountName");
3306                 QUERY_STRING(msg, info6.full_name,      "displayName");
3307                 break;
3308
3309         case 7:
3310                 QUERY_STRING(msg, info7.account_name,   "sAMAccountName");
3311                 break;
3312
3313         case 8:
3314                 QUERY_STRING(msg, info8.full_name,      "displayName");
3315                 break;
3316
3317         case 9:
3318                 QUERY_UINT  (msg, info9.primary_gid,    "primaryGroupID");
3319                 break;
3320
3321         case 10:
3322                 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3323                 QUERY_STRING(msg, info10.home_drive,    "homeDrive");
3324                 break;
3325
3326         case 11:
3327                 QUERY_STRING(msg, info11.logon_script,  "scriptPath");
3328                 break;
3329
3330         case 12:
3331                 QUERY_STRING(msg, info12.profile_path,  "profilePath");
3332                 break;
3333
3334         case 13:
3335                 QUERY_STRING(msg, info13.description,   "description");
3336                 break;
3337
3338         case 14:
3339                 QUERY_STRING(msg, info14.workstations,  "userWorkstations");
3340                 break;
3341
3342         case 16:
3343                 QUERY_AFLAGS(msg, info16.acct_flags,    "userAccountControl");
3344                 break;
3345
3346         case 17:
3347                 QUERY_UINT64(msg, info17.acct_expiry,   "accountExpires");
3348                 break;
3349
3350         case 20:
3351                 QUERY_PARAMETERS(msg, info20.parameters,    "userParameters");
3352                 break;
3353
3354         case 21:
3355                 QUERY_UINT64(msg, info21.last_logon,           "lastLogon");
3356                 QUERY_UINT64(msg, info21.last_logoff,          "lastLogoff");
3357                 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3358                 QUERY_UINT64(msg, info21.acct_expiry,          "accountExpires");
3359                 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3360                 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3361                 QUERY_STRING(msg, info21.account_name,         "sAMAccountName");
3362                 QUERY_STRING(msg, info21.full_name,            "displayName");
3363                 QUERY_STRING(msg, info21.home_directory,       "homeDirectory");
3364                 QUERY_STRING(msg, info21.home_drive,           "homeDrive");
3365                 QUERY_STRING(msg, info21.logon_script,         "scriptPath");
3366                 QUERY_STRING(msg, info21.profile_path,         "profilePath");
3367                 QUERY_STRING(msg, info21.description,          "description");
3368                 QUERY_STRING(msg, info21.workstations,         "userWorkstations");
3369                 QUERY_STRING(msg, info21.comment,              "comment");
3370                 QUERY_PARAMETERS(msg, info21.parameters,       "userParameters");
3371                 QUERY_RID   (msg, info21.rid,                  "objectSid");
3372                 QUERY_UINT  (msg, info21.primary_gid,          "primaryGroupID");
3373                 QUERY_AFLAGS(msg, info21.acct_flags,           "userAccountControl");
3374                 info->info21.fields_present = 0x00FFFFFF;
3375                 QUERY_LHOURS(msg, info21.logon_hours,          "logonHours");
3376                 QUERY_UINT  (msg, info21.bad_password_count,   "badPwdCount");
3377                 QUERY_UINT  (msg, info21.logon_count,          "logonCount");
3378                 QUERY_UINT  (msg, info21.country_code,         "countryCode");
3379                 QUERY_UINT  (msg, info21.code_page,            "codePage");
3380                 break;
3381                 
3382
3383         default:
3384                 talloc_free(info);
3385                 return NT_STATUS_INVALID_INFO_CLASS;
3386         }
3387
3388         *r->out.info = info;
3389
3390         return NT_STATUS_OK;
3391 }
3392
3393
3394 /* 
3395   samr_SetUserInfo 
3396 */
3397 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3398                                  struct samr_SetUserInfo *r)
3399 {
3400         struct dcesrv_handle *h;
3401         struct samr_account_state *a_state;
3402         struct ldb_message *msg;
3403         int ret;
3404         NTSTATUS status = NT_STATUS_OK;
3405         struct ldb_context *sam_ctx;
3406
3407         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3408
3409         a_state = h->data;
3410         sam_ctx = a_state->sam_ctx;
3411
3412         msg = ldb_msg_new(mem_ctx);
3413         if (msg == NULL) {
3414                 return NT_STATUS_NO_MEMORY;
3415         }
3416
3417         msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3418         if (!msg->dn) {
3419                 return NT_STATUS_NO_MEMORY;
3420         }
3421
3422         switch (r->in.level) {
3423         case 2:
3424                 SET_STRING(msg, info2.comment,          "comment");
3425                 SET_UINT  (msg, info2.country_code,     "countryCode");
3426                 SET_UINT  (msg, info2.code_page,        "codePage");
3427                 break;
3428
3429         case 4:
3430                 SET_LHOURS(msg, info4.logon_hours,      "logonHours");
3431                 break;
3432
3433         case 6:
3434                 SET_STRING(msg, info6.account_name,     "samAccountName");
3435                 SET_STRING(msg, info6.full_name,        "displayName");
3436                 break;
3437
3438         case 7:
3439                 SET_STRING(msg, info7.account_name,     "samAccountName");
3440                 break;
3441
3442         case 8:
3443                 SET_STRING(msg, info8.full_name,        "displayName");
3444                 break;
3445
3446         case 9:
3447                 SET_UINT(msg, info9.primary_gid,        "primaryGroupID");
3448                 break;
3449
3450         case 10:
3451                 SET_STRING(msg, info10.home_directory,  "homeDirectory");
3452                 SET_STRING(msg, info10.home_drive,      "homeDrive");
3453                 break;
3454
3455         case 11:
3456                 SET_STRING(msg, info11.logon_script,    "scriptPath");
3457                 break;
3458
3459         case 12:
3460                 SET_STRING(msg, info12.profile_path,    "profilePath");
3461                 break;
3462
3463         case 13:
3464                 SET_STRING(msg, info13.description,     "description");
3465                 break;
3466
3467         case 14:
3468                 SET_STRING(msg, info14.workstations,    "userWorkstations");
3469                 break;
3470
3471         case 16:
3472                 SET_AFLAGS(msg, info16.acct_flags,      "userAccountControl");
3473                 break;
3474
3475         case 17:
3476                 SET_UINT64(msg, info17.acct_expiry,     "accountExpires");
3477                 break;
3478
3479         case 20:
3480                 SET_PARAMETERS(msg, info20.parameters,      "userParameters");
3481                 break;
3482
3483         case 21:
3484 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3485                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3486                         SET_UINT64(msg, info21.acct_expiry,    "accountExpires");
3487                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
3488                         SET_STRING(msg, info21.account_name,   "samAccountName");
3489                 IFSET(SAMR_FIELD_FULL_NAME) 
3490                         SET_STRING(msg, info21.full_name,      "displayName");
3491                 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3492                         SET_STRING(msg, info21.home_directory, "homeDirectory");
3493                 IFSET(SAMR_FIELD_HOME_DRIVE)
3494                         SET_STRING(msg, info21.home_drive,     "homeDrive");
3495                 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3496                         SET_STRING(msg, info21.logon_script,   "scriptPath");
3497                 IFSET(SAMR_FIELD_PROFILE_PATH)
3498                         SET_STRING(msg, info21.profile_path,   "profilePath");
3499                 IFSET(SAMR_FIELD_DESCRIPTION)
3500                         SET_STRING(msg, info21.description,    "description");
3501                 IFSET(SAMR_FIELD_WORKSTATIONS)
3502                         SET_STRING(msg, info21.workstations,   "userWorkstations");
3503                 IFSET(SAMR_FIELD_COMMENT)
3504                         SET_STRING(msg, info21.comment,        "comment");
3505                 IFSET(SAMR_FIELD_PARAMETERS)   
3506                         SET_PARAMETERS(msg, info21.parameters, "userParameters");
3507                 IFSET(SAMR_FIELD_PRIMARY_GID)
3508                         SET_UINT(msg, info21.primary_gid,      "primaryGroupID");
3509                 IFSET(SAMR_FIELD_ACCT_FLAGS)
3510                         SET_AFLAGS(msg, info21.acct_flags,     "userAccountControl");
3511                 IFSET(SAMR_FIELD_LOGON_HOURS)
3512                         SET_LHOURS(msg, info21.logon_hours,    "logonHours");
3513                 IFSET(SAMR_FIELD_COUNTRY_CODE)
3514                         SET_UINT  (msg, info21.country_code,   "countryCode");
3515                 IFSET(SAMR_FIELD_CODE_PAGE)
3516                         SET_UINT  (msg, info21.code_page,      "codePage");
3517 #undef IFSET
3518                 break;
3519
3520         case 23:
3521 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3522                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3523                         SET_UINT64(msg, info23.info.acct_expiry,    "accountExpires");
3524                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
3525                         SET_STRING(msg, info23.info.account_name,   "samAccountName");
3526                 IFSET(SAMR_FIELD_FULL_NAME)
3527                         SET_STRING(msg, info23.info.full_name,      "displayName");
3528                 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3529                         SET_STRING(msg, info23.info.home_directory, "homeDirectory");
3530                 IFSET(SAMR_FIELD_HOME_DRIVE)
3531                         SET_STRING(msg, info23.info.home_drive,     "homeDrive");
3532                 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3533                         SET_STRING(msg, info23.info.logon_script,   "scriptPath");
3534                 IFSET(SAMR_FIELD_PROFILE_PATH)
3535                         SET_STRING(msg, info23.info.profile_path,   "profilePath");
3536                 IFSET(SAMR_FIELD_DESCRIPTION)
3537                         SET_STRING(msg, info23.info.description,    "description");
3538                 IFSET(SAMR_FIELD_WORKSTATIONS)
3539                         SET_STRING(msg, info23.info.workstations,   "userWorkstations");
3540                 IFSET(SAMR_FIELD_COMMENT)
3541                         SET_STRING(msg, info23.info.comment,        "comment");
3542                 IFSET(SAMR_FIELD_PARAMETERS)
3543                         SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3544                 IFSET(SAMR_FIELD_PRIMARY_GID)
3545                         SET_UINT(msg, info23.info.primary_gid,      "primaryGroupID");
3546                 IFSET(SAMR_FIELD_ACCT_FLAGS)
3547                         SET_AFLAGS(msg, info23.info.acct_flags,     "userAccountControl");
3548                 IFSET(SAMR_FIELD_LOGON_HOURS)
3549                         SET_LHOURS(msg, info23.info.logon_hours,    "logonHours");
3550                 IFSET(SAMR_FIELD_COUNTRY_CODE)
3551                         SET_UINT  (msg, info23.info.country_code,   "countryCode");
3552                 IFSET(SAMR_FIELD_CODE_PAGE)
3553                         SET_UINT  (msg, info23.info.code_page,      "codePage");
3554
3555                 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3556                         status = samr_set_password(dce_call,
3557                                                    a_state->sam_ctx,
3558                                                    a_state->account_dn,
3559                                                    a_state->domain_state->domain_dn,
3560                                                    mem_ctx, msg, 
3561                                                    &r->in.info->info23.password);
3562                 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3563                         status = samr_set_password(dce_call,
3564                                                    a_state->sam_ctx,
3565                                                    a_state->account_dn,
3566                                                    a_state->domain_state->domain_dn,
3567                                                    mem_ctx, msg, 
3568                                                    &r->in.info->info23.password);
3569                 }
3570 #undef IFSET
3571                 break;
3572
3573                 /* the set password levels are handled separately */
3574         case 24:
3575                 status = samr_set_password(dce_call,
3576                                            a_state->sam_ctx,
3577                                            a_state->account_dn,
3578                                            a_state->domain_state->domain_dn,
3579                                            mem_ctx, msg, 
3580                                            &r->in.info->info24.password);
3581                 break;
3582
3583         case 25:
3584 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3585                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3586                         SET_UINT64(msg, info25.info.acct_expiry,    "accountExpires");
3587                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
3588                         SET_STRING(msg, info25.info.account_name,   "samAccountName");
3589                 IFSET(SAMR_FIELD_FULL_NAME)
3590                         SET_STRING(msg, info25.info.full_name,      "displayName");
3591                 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3592                         SET_STRING(msg, info25.info.home_directory, "homeDirectory");
3593                 IFSET(SAMR_FIELD_HOME_DRIVE)
3594                         SET_STRING(msg, info25.info.home_drive,     "homeDrive");
3595                 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3596                         SET_STRING(msg, info25.info.logon_script,   "scriptPath");
3597                 IFSET(SAMR_FIELD_PROFILE_PATH)
3598                         SET_STRING(msg, info25.info.profile_path,   "profilePath");
3599                 IFSET(SAMR_FIELD_DESCRIPTION)
3600                         SET_STRING(msg, info25.info.description,    "description");
3601                 IFSET(SAMR_FIELD_WORKSTATIONS)
3602                         SET_STRING(msg, info25.info.workstations,   "userWorkstations");
3603                 IFSET(SAMR_FIELD_COMMENT)
3604                         SET_STRING(msg, info25.info.comment,        "comment");
3605                 IFSET(SAMR_FIELD_PARAMETERS)
3606                         SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
3607                 IFSET(SAMR_FIELD_PRIMARY_GID)
3608                         SET_UINT(msg, info25.info.primary_gid,      "primaryGroupID");
3609                 IFSET(SAMR_FIELD_ACCT_FLAGS)
3610                         SET_AFLAGS(msg, info25.info.acct_flags,     "userAccountControl");
3611                 IFSET(SAMR_FIELD_LOGON_HOURS)
3612                         SET_LHOURS(msg, info25.info.logon_hours,    "logonHours");
3613                 IFSET(SAMR_FIELD_COUNTRY_CODE)
3614                         SET_UINT  (msg, info25.info.country_code,   "countryCode");
3615                 IFSET(SAMR_FIELD_CODE_PAGE)
3616                         SET_UINT  (msg, info25.info.code_page,      "codePage");
3617
3618                 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3619                         status = samr_set_password_ex(dce_call,
3620                                                       a_state->sam_ctx,
3621                                                       a_state->account_dn,
3622                                                       a_state->domain_state->domain_dn,
3623                                                       mem_ctx, msg, 
3624                                                       &r->in.info->info25.password);
3625                 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3626                         status = samr_set_password_ex(dce_call,
3627                                                       a_state->sam_ctx,
3628                                                       a_state->account_dn,
3629                                                       a_state->domain_state->domain_dn,
3630                                                       mem_ctx, msg, 
3631                                                       &r->in.info->info25.password);
3632                 }
3633 #undef IFSET
3634                 break;
3635
3636                 /* the set password levels are handled separately */
3637         case 26:
3638                 status = samr_set_password_ex(dce_call,
3639                                               a_state->sam_ctx,
3640                                               a_state->account_dn,
3641                                               a_state->domain_state->domain_dn,
3642                                               mem_ctx, msg, 
3643                                               &r->in.info->info26.password);
3644                 break;
3645                 
3646
3647         default:
3648                 /* many info classes are not valid for SetUserInfo */
3649                 return NT_STATUS_INVALID_INFO_CLASS;
3650         }
3651
3652         if (!NT_STATUS_IS_OK(status)) {
3653                 return status;
3654         }
3655
3656         /* modify the samdb record */
3657         if (msg->num_elements > 0) {
3658                 ret = ldb_modify(a_state->sam_ctx, msg);
3659                 if (ret != LDB_SUCCESS) {
3660                         DEBUG(1,("Failed to modify record %s: %s\n",
3661                                  ldb_dn_get_linearized(a_state->account_dn),
3662                                  ldb_errstring(a_state->sam_ctx)));
3663
3664                         /* we really need samdb.c to return NTSTATUS */
3665                         return NT_STATUS_UNSUCCESSFUL;
3666                 }
3667         }
3668
3669         return NT_STATUS_OK;
3670 }
3671
3672
3673 /* 
3674   samr_GetGroupsForUser 
3675 */
3676 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3677                        struct samr_GetGroupsForUser *r)
3678 {
3679         struct dcesrv_handle *h;
3680         struct samr_account_state *a_state;
3681         struct samr_domain_state *d_state;
3682         struct ldb_message **res;
3683         const char * const attrs[2] = { "objectSid", NULL };
3684         struct samr_RidWithAttributeArray *array;
3685         int i, count;
3686
3687         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3688
3689         a_state = h->data;
3690         d_state = a_state->domain_state;
3691
3692         count = samdb_search_domain(a_state->sam_ctx, mem_ctx,
3693                                     d_state->domain_dn, &res,
3694                                     attrs, d_state->domain_sid,
3695                                     "(&(member=%s)(grouptype=%d)(objectclass=group))",
3696                                     ldb_dn_get_linearized(a_state->account_dn),
3697                                     GTYPE_SECURITY_GLOBAL_GROUP);
3698         if (count < 0)
3699                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3700
3701         array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3702         if (array == NULL)
3703                 return NT_STATUS_NO_MEMORY;
3704
3705         array->count = 0;
3706         array->rids = NULL;
3707
3708         array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3709                                             count + 1);
3710         if (array->rids == NULL)
3711                 return NT_STATUS_NO_MEMORY;
3712
3713         /* Adds the primary group */
3714         array->rids[0].rid = samdb_search_uint(a_state->sam_ctx, mem_ctx,
3715                                                ~0, a_state->account_dn,
3716                                                "primaryGroupID", NULL);
3717         array->rids[0].attributes = SE_GROUP_MANDATORY
3718                         | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3719         array->count += 1;
3720
3721         /* Adds the additional groups */
3722         for (i = 0; i < count; i++) {
3723                 struct dom_sid *group_sid;
3724
3725                 group_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
3726                 if (group_sid == NULL) {
3727                         DEBUG(0, ("Couldn't find objectSid attrib\n"));
3728                         continue;
3729                 }
3730
3731                 array->rids[i + 1].rid =
3732                         group_sid->sub_auths[group_sid->num_auths-1];
3733                 array->rids[i + 1].attributes = SE_GROUP_MANDATORY
3734                         | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3735                 array->count += 1;
3736         }
3737
3738         *r->out.rids = array;
3739
3740         return NT_STATUS_OK;
3741 }
3742
3743
3744 /* 
3745   samr_QueryDisplayInfo 
3746 */
3747 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3748                        struct samr_QueryDisplayInfo *r)
3749 {
3750         struct dcesrv_handle *h;
3751         struct samr_domain_state *d_state;
3752         struct ldb_message **res;
3753         int ldb_cnt, count, i;
3754         const char * const attrs[] = { "objectSid", "sAMAccountName",
3755                 "displayName", "description", "userAccountControl",
3756                 "pwdLastSet", NULL };
3757         struct samr_DispEntryFull *entriesFull = NULL;
3758         struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3759         struct samr_DispEntryAscii *entriesAscii = NULL;
3760         struct samr_DispEntryGeneral *entriesGeneral = NULL;
3761         const char *filter;
3762
3763         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3764
3765         d_state = h->data;
3766
3767         switch (r->in.level) {
3768         case 1:
3769         case 4:
3770                 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3771                                          "(sAMAccountType=%u))",
3772                                          ATYPE_NORMAL_ACCOUNT);
3773                 break;
3774         case 2:
3775                 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3776                                          "(sAMAccountType=%u))",
3777                                          ATYPE_WORKSTATION_TRUST);
3778                 break;
3779         case 3:
3780         case 5:
3781                 filter = talloc_asprintf(mem_ctx, "(&(grouptype=%d)"
3782                                          "(objectclass=group))",
3783                                          GTYPE_SECURITY_GLOBAL_GROUP);
3784                 break;
3785         default:
3786                 return NT_STATUS_INVALID_INFO_CLASS;
3787         }
3788
3789         /* search for all requested objects in this domain. This could
3790            possibly be cached and resumed based on resume_key */
3791         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3792                                       d_state->domain_dn, &res, attrs,
3793                                       d_state->domain_sid, "%s", filter);
3794         if (ldb_cnt == -1) {
3795                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3796         }
3797         if (ldb_cnt == 0 || r->in.max_entries == 0) {
3798                 return NT_STATUS_OK;
3799         }
3800
3801         switch (r->in.level) {
3802         case 1:
3803                 entriesGeneral = talloc_array(mem_ctx,
3804                                              struct samr_DispEntryGeneral,
3805                                              ldb_cnt);
3806                 break;
3807         case 2:
3808                 entriesFull = talloc_array(mem_ctx,
3809                                              struct samr_DispEntryFull,
3810                                              ldb_cnt);
3811                 break;
3812         case 3:
3813                 entriesFullGroup = talloc_array(mem_ctx,
3814                                              struct samr_DispEntryFullGroup,
3815                                              ldb_cnt);
3816                 break;
3817         case 4:
3818         case 5:
3819                 entriesAscii = talloc_array(mem_ctx,
3820                                               struct samr_DispEntryAscii,
3821                                               ldb_cnt);
3822                 break;
3823         }
3824
3825         if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3826             (entriesAscii == NULL) && (entriesFullGroup == NULL))
3827                 return NT_STATUS_NO_MEMORY;
3828
3829         count = 0;
3830
3831         for (i=0; i<ldb_cnt; i++) {
3832                 struct dom_sid *objectsid;
3833
3834                 objectsid = samdb_result_dom_sid(mem_ctx, res[i],
3835                                                  "objectSid");
3836                 if (objectsid == NULL)
3837                         continue;
3838
3839                 switch(r->in.level) {
3840                 case 1:
3841                         entriesGeneral[count].idx = count + 1;
3842                         entriesGeneral[count].rid = 
3843                                 objectsid->sub_auths[objectsid->num_auths-1];
3844                         entriesGeneral[count].acct_flags =
3845                                 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3846                                                         res[i], 
3847                                                         d_state->domain_dn);
3848                         entriesGeneral[count].account_name.string =
3849                                 samdb_result_string(res[i],
3850                                                     "sAMAccountName", "");
3851                         entriesGeneral[count].full_name.string =
3852                                 samdb_result_string(res[i], "displayName", "");
3853                         entriesGeneral[count].description.string =
3854                                 samdb_result_string(res[i], "description", "");
3855                         break;
3856                 case 2:
3857                         entriesFull[count].idx = count + 1;
3858                         entriesFull[count].rid =
3859                                 objectsid->sub_auths[objectsid->num_auths-1];
3860
3861                         /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3862                         entriesFull[count].acct_flags =
3863                                 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3864                                                         res[i], 
3865                                                         d_state->domain_dn) | ACB_NORMAL;
3866                         entriesFull[count].account_name.string =
3867                                 samdb_result_string(res[i], "sAMAccountName",
3868                                                     "");
3869                         entriesFull[count].description.string =
3870                                 samdb_result_string(res[i], "description", "");
3871                         break;
3872                 case 3:
3873                         entriesFullGroup[count].idx = count + 1;
3874                         entriesFullGroup[count].rid =
3875                                 objectsid->sub_auths[objectsid->num_auths-1];
3876                         /* We get a "7" here for groups */
3877                         entriesFullGroup[count].acct_flags
3878                                 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3879                         entriesFullGroup[count].account_name.string =
3880                                 samdb_result_string(res[i], "sAMAccountName",
3881                                                     "");
3882                         entriesFullGroup[count].description.string =
3883                                 samdb_result_string(res[i], "description", "");
3884                         break;
3885                 case 4:
3886                 case 5:
3887                         entriesAscii[count].idx = count + 1;
3888                         entriesAscii[count].account_name.string =
3889                                 samdb_result_string(res[i], "sAMAccountName",
3890                                                     "");
3891                         break;
3892                 }
3893
3894                 count += 1;
3895         }
3896
3897         *r->out.total_size = count;
3898
3899         if (r->in.start_idx >= count) {
3900                 *r->out.returned_size = 0;
3901                 switch(r->in.level) {
3902                 case 1:
3903                         r->out.info->info1.count = *r->out.returned_size;
3904                         r->out.info->info1.entries = NULL;
3905                         break;
3906                 case 2:
3907                         r->out.info->info2.count = *r->out.returned_size;
3908                         r->out.info->info2.entries = NULL;
3909                         break;
3910                 case 3:
3911                         r->out.info->info3.count = *r->out.returned_size;
3912                         r->out.info->info3.entries = NULL;
3913                         break;
3914                 case 4:
3915                         r->out.info->info4.count = *r->out.returned_size;
3916                         r->out.info->info4.entries = NULL;
3917                         break;
3918                 case 5:
3919                         r->out.info->info5.count = *r->out.returned_size;
3920                         r->out.info->info5.entries = NULL;
3921                         break;
3922                 }
3923         } else {
3924                 *r->out.returned_size = MIN(count - r->in.start_idx,
3925                                            r->in.max_entries);
3926                 switch(r->in.level) {
3927                 case 1:
3928                         r->out.info->info1.count = *r->out.returned_size;
3929                         r->out.info->info1.entries =
3930                                 &(entriesGeneral[r->in.start_idx]);
3931                         break;
3932                 case 2:
3933                         r->out.info->info2.count = *r->out.returned_size;
3934                         r->out.info->info2.entries =
3935                                 &(entriesFull[r->in.start_idx]);
3936                         break;
3937                 case 3:
3938                         r->out.info->info3.count = *r->out.returned_size;
3939                         r->out.info->info3.entries =
3940                                 &(entriesFullGroup[r->in.start_idx]);
3941                         break;
3942                 case 4:
3943                         r->out.info->info4.count = *r->out.returned_size;
3944                         r->out.info->info4.entries =
3945                                 &(entriesAscii[r->in.start_idx]);
3946                         break;
3947                 case 5:
3948                         r->out.info->info5.count = *r->out.returned_size;
3949                         r->out.info->info5.entries =
3950                                 &(entriesAscii[r->in.start_idx]);
3951                         break;
3952                 }
3953         }
3954
3955         return (*r->out.returned_size < (count - r->in.start_idx)) ?
3956                 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3957 }
3958
3959
3960 /* 
3961   samr_GetDisplayEnumerationIndex 
3962 */
3963 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3964                        struct samr_GetDisplayEnumerationIndex *r)
3965 {
3966         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3967 }
3968
3969
3970 /* 
3971   samr_TestPrivateFunctionsDomain 
3972 */
3973 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3974                        struct samr_TestPrivateFunctionsDomain *r)
3975 {
3976         return NT_STATUS_NOT_IMPLEMENTED;
3977 }
3978
3979
3980 /* 
3981   samr_TestPrivateFunctionsUser 
3982 */
3983 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3984                        struct samr_TestPrivateFunctionsUser *r)
3985 {
3986         return NT_STATUS_NOT_IMPLEMENTED;
3987 }
3988
3989
3990 /* 
3991   samr_GetUserPwInfo 
3992 */
3993 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3994                                    struct samr_GetUserPwInfo *r)
3995 {
3996         struct dcesrv_handle *h;
3997         struct samr_account_state *a_state;
3998
3999         ZERO_STRUCTP(r->out.info);
4000
4001         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
4002
4003         a_state = h->data;
4004
4005         r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx,
4006                 mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength",
4007                 NULL);
4008         r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx,
4009                 mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL);
4010
4011         return NT_STATUS_OK;
4012 }
4013
4014
4015 /* 
4016   samr_RemoveMemberFromForeignDomain 
4017 */
4018 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4019                        struct samr_RemoveMemberFromForeignDomain *r)
4020 {
4021         struct dcesrv_handle *h;
4022         struct samr_domain_state *d_state;
4023         const char *memberdn;
4024         struct ldb_message **res;
4025         const char * const attrs[3] = { "distinguishedName", "objectSid", NULL };
4026         int i, count;
4027
4028         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4029
4030         d_state = h->data;
4031
4032         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
4033                                        "distinguishedName", "(objectSid=%s)", 
4034                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
4035         /* Nothing to do */
4036         if (memberdn == NULL) {
4037                 return NT_STATUS_OK;
4038         }
4039
4040         /* TODO: Does this call only remove alias members, or does it do this
4041          * for domain groups as well? */
4042
4043         count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
4044                                     d_state->domain_dn, &res, attrs,
4045                                     d_state->domain_sid,
4046                                     "(&(member=%s)(objectClass=group)"
4047                                     "(|(groupType=%d)(groupType=%d)))",
4048                                     memberdn,
4049                                     GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
4050                                     GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
4051
4052         if (count < 0)
4053                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4054
4055         for (i=0; i<count; i++) {
4056                 struct ldb_message *mod;
4057
4058                 mod = ldb_msg_new(mem_ctx);
4059                 if (mod == NULL) {
4060                         return NT_STATUS_NO_MEMORY;
4061                 }
4062
4063                 mod->dn = samdb_result_dn(d_state->sam_ctx, mod, res[i], "distinguishedName", NULL);
4064                 if (mod->dn == NULL) {
4065                         talloc_free(mod);
4066                         continue;
4067                 }
4068
4069                 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
4070                                          "member", memberdn) != LDB_SUCCESS)
4071                         return NT_STATUS_NO_MEMORY;
4072
4073                 if (ldb_modify(d_state->sam_ctx, mod) != LDB_SUCCESS)
4074                         return NT_STATUS_UNSUCCESSFUL;
4075
4076                 talloc_free(mod);
4077         }
4078
4079         return NT_STATUS_OK;
4080 }
4081
4082
4083 /* 
4084   samr_QueryDomainInfo2 
4085
4086   just an alias for samr_QueryDomainInfo
4087 */
4088 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4089                        struct samr_QueryDomainInfo2 *r)
4090 {
4091         struct samr_QueryDomainInfo r1;
4092         NTSTATUS status;
4093
4094         ZERO_STRUCT(r1.out);
4095         r1.in.domain_handle = r->in.domain_handle;
4096         r1.in.level  = r->in.level;
4097         r1.out.info  = r->out.info;
4098
4099         status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
4100         
4101         return status;
4102 }
4103
4104
4105 /* 
4106   samr_QueryUserInfo2 
4107
4108   just an alias for samr_QueryUserInfo
4109 */
4110 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4111                                     struct samr_QueryUserInfo2 *r)
4112 {
4113         struct samr_QueryUserInfo r1;
4114         NTSTATUS status;
4115
4116         r1.in.user_handle = r->in.user_handle;
4117         r1.in.level  = r->in.level;
4118         r1.out.info  = r->out.info;
4119         
4120         status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
4121
4122         return status;
4123 }
4124
4125
4126 /* 
4127   samr_QueryDisplayInfo2 
4128 */
4129 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4130                                        struct samr_QueryDisplayInfo2 *r)
4131 {
4132         struct samr_QueryDisplayInfo q;
4133         NTSTATUS result;
4134
4135         q.in.domain_handle = r->in.domain_handle;
4136         q.in.level = r->in.level;
4137         q.in.start_idx = r->in.start_idx;
4138         q.in.max_entries = r->in.max_entries;
4139         q.in.buf_size = r->in.buf_size;
4140         q.out.total_size = r->out.total_size;
4141         q.out.returned_size = r->out.returned_size;
4142         q.out.info = r->out.info;
4143
4144         result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4145
4146         return result;
4147 }
4148
4149
4150 /* 
4151   samr_GetDisplayEnumerationIndex2 
4152 */
4153 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4154                        struct samr_GetDisplayEnumerationIndex2 *r)
4155 {
4156         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4157 }
4158
4159
4160 /* 
4161   samr_QueryDisplayInfo3 
4162 */
4163 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4164                        struct samr_QueryDisplayInfo3 *r)
4165 {
4166         struct samr_QueryDisplayInfo q;
4167         NTSTATUS result;
4168
4169         q.in.domain_handle = r->in.domain_handle;
4170         q.in.level = r->in.level;
4171         q.in.start_idx = r->in.start_idx;
4172         q.in.max_entries = r->in.max_entries;
4173         q.in.buf_size = r->in.buf_size;
4174         q.out.total_size = r->out.total_size;
4175         q.out.returned_size = r->out.returned_size;
4176         q.out.info = r->out.info;
4177
4178         result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4179
4180         return result;
4181 }
4182
4183
4184 /* 
4185   samr_AddMultipleMembersToAlias 
4186 */
4187 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4188                        struct samr_AddMultipleMembersToAlias *r)
4189 {
4190         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4191 }
4192
4193
4194 /* 
4195   samr_RemoveMultipleMembersFromAlias 
4196 */
4197 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4198                        struct samr_RemoveMultipleMembersFromAlias *r)
4199 {
4200         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4201 }
4202
4203
4204 /* 
4205   samr_GetDomPwInfo 
4206
4207   this fetches the default password properties for a domain
4208
4209   note that w2k3 completely ignores the domain name in this call, and 
4210   always returns the information for the servers primary domain
4211 */
4212 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4213                                   struct samr_GetDomPwInfo *r)
4214 {
4215         struct ldb_message **msgs;
4216         int ret;
4217         const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4218         struct ldb_context *sam_ctx;
4219
4220         ZERO_STRUCTP(r->out.info);
4221
4222         sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
4223                                          dce_call->conn->dce_ctx->lp_ctx,
4224                                          dce_call->conn->auth_state.session_info);
4225         if (sam_ctx == NULL) {
4226                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4227         }
4228
4229         /* The domain name in this call is ignored */
4230         ret = gendb_search_dn(sam_ctx, 
4231                            mem_ctx, NULL, &msgs, attrs);
4232         if (ret <= 0) {
4233                 talloc_free(sam_ctx);
4234
4235                 return NT_STATUS_NO_SUCH_DOMAIN;
4236         }
4237         if (ret > 1) {
4238                 talloc_free(msgs);
4239                 talloc_free(sam_ctx);
4240
4241                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4242         }
4243
4244         r->out.info->min_password_length = samdb_result_uint(msgs[0],
4245                 "minPwdLength", 0);
4246         r->out.info->password_properties = samdb_result_uint(msgs[0],
4247                 "pwdProperties", 1);
4248
4249         talloc_free(msgs);
4250         talloc_unlink(mem_ctx, sam_ctx);
4251
4252         return NT_STATUS_OK;
4253 }
4254
4255
4256 /* 
4257   samr_Connect2 
4258 */
4259 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4260                               struct samr_Connect2 *r)
4261 {
4262         struct samr_Connect c;
4263
4264         c.in.system_name = NULL;
4265         c.in.access_mask = r->in.access_mask;
4266         c.out.connect_handle = r->out.connect_handle;
4267
4268         return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4269 }
4270
4271
4272 /* 
4273   samr_SetUserInfo2 
4274
4275   just an alias for samr_SetUserInfo
4276 */
4277 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4278                                   struct samr_SetUserInfo2 *r)
4279 {
4280         struct samr_SetUserInfo r2;
4281
4282         r2.in.user_handle = r->in.user_handle;
4283         r2.in.level = r->in.level;
4284         r2.in.info = r->in.info;
4285
4286         return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
4287 }
4288
4289
4290 /* 
4291   samr_SetBootKeyInformation 
4292 */
4293 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4294                        struct samr_SetBootKeyInformation *r)
4295 {
4296         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4297 }
4298
4299
4300 /* 
4301   samr_GetBootKeyInformation 
4302 */
4303 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4304                        struct samr_GetBootKeyInformation *r)
4305 {
4306         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4307 }
4308
4309
4310 /* 
4311   samr_Connect3 
4312 */
4313 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4314                        struct samr_Connect3 *r)
4315 {
4316         struct samr_Connect c;
4317
4318         c.in.system_name = NULL;
4319         c.in.access_mask = r->in.access_mask;
4320         c.out.connect_handle = r->out.connect_handle;
4321
4322         return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4323 }
4324
4325
4326 /* 
4327   samr_Connect4 
4328 */
4329 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4330                        struct samr_Connect4 *r)
4331 {
4332         struct samr_Connect c;
4333
4334         c.in.system_name = NULL;
4335         c.in.access_mask = r->in.access_mask;
4336         c.out.connect_handle = r->out.connect_handle;
4337
4338         return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4339 }
4340
4341
4342 /* 
4343   samr_Connect5 
4344 */
4345 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4346                               struct samr_Connect5 *r)
4347 {
4348         struct samr_Connect c;
4349         NTSTATUS status;
4350
4351         c.in.system_name = NULL;
4352         c.in.access_mask = r->in.access_mask;
4353         c.out.connect_handle = r->out.connect_handle;
4354
4355         status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4356
4357         r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
4358         r->out.info_out->info1.unknown2 = 0;
4359         *r->out.level_out = r->in.level_in;
4360
4361         return status;
4362 }
4363
4364
4365 /* 
4366   samr_RidToSid 
4367 */
4368 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4369                               struct samr_RidToSid *r)
4370 {
4371         struct samr_domain_state *d_state;
4372         struct dcesrv_handle *h;
4373
4374         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4375
4376         d_state = h->data;
4377
4378         /* form the users SID */
4379         *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4380         if (!*r->out.sid) {
4381                 return NT_STATUS_NO_MEMORY;
4382         }
4383
4384         return NT_STATUS_OK;
4385 }
4386
4387
4388 /* 
4389   samr_SetDsrmPassword 
4390 */
4391 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4392                        struct samr_SetDsrmPassword *r)
4393 {
4394         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4395 }
4396
4397
4398 /* 
4399   samr_ValidatePassword
4400
4401   For now the call checks the password complexity (if active) and the minimum
4402   password length on level 2 and 3. Level 1 is ignored for now.
4403 */
4404 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
4405                                              TALLOC_CTX *mem_ctx,
4406                                              struct samr_ValidatePassword *r)
4407 {
4408         struct samr_GetDomPwInfo r2;
4409         struct samr_PwInfo pwInfo;
4410         DATA_BLOB password;
4411         enum samr_ValidationStatus res;
4412         NTSTATUS status;
4413
4414         (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
4415
4416         r2.in.domain_name = NULL;
4417         r2.out.info = &pwInfo;
4418         status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2);
4419         if (!NT_STATUS_IS_OK(status)) {
4420                 return status;
4421         }
4422
4423         switch (r->in.level) {
4424         case NetValidateAuthentication:
4425                 /* we don't support this yet */
4426                 return NT_STATUS_NOT_SUPPORTED;
4427         break;
4428         case NetValidatePasswordChange:
4429                 password = data_blob_const(r->in.req->req2.password.string,
4430                                            r->in.req->req2.password.length);
4431                 res = samdb_check_password(&password,
4432                                            pwInfo.password_properties,
4433                                            pwInfo.min_password_length);
4434                 (*r->out.rep)->ctr2.status = res;
4435         break;
4436         case NetValidatePasswordReset:
4437                 password = data_blob_const(r->in.req->req3.password.string,
4438                                            r->in.req->req3.password.length);
4439                 res = samdb_check_password(&password,
4440                                            pwInfo.password_properties,
4441                                            pwInfo.min_password_length);
4442                 (*r->out.rep)->ctr3.status = res;
4443         break;
4444         default:
4445                 return NT_STATUS_INVALID_INFO_CLASS;
4446         break;
4447         }
4448
4449         return NT_STATUS_OK;
4450 }
4451
4452
4453 /* include the generated boilerplate */
4454 #include "librpc/gen_ndr/ndr_samr_s.c"