Move a comment where it belongs
[ira/wip.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    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "librpc/gen_ndr/ndr_samr.h"
26 #include "rpc_server/dcerpc_server.h"
27 #include "rpc_server/common/common.h"
28 #include "rpc_server/samr/dcesrv_samr.h"
29 #include "system/time.h"
30 #include "lib/ldb/include/ldb.h"
31 #include "lib/ldb/include/ldb_errors.h"
32 #include "dsdb/common/flags.h"
33 #include "dsdb/samdb/samdb.h"
34 #include "libcli/ldap/ldap_ndr.h"
35 #include "libcli/security/security.h"
36 #include "rpc_server/samr/proto.h"
37 #include "../lib/util/util_ldb.h"
38 #include "param/param.h"
39
40 /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
41
42 #define QUERY_STRING(msg, field, attr) \
43         info->field.string = samdb_result_string(msg, attr, "");
44 #define QUERY_UINT(msg, field, attr) \
45         info->field = samdb_result_uint(msg, attr, 0);
46 #define QUERY_RID(msg, field, attr) \
47         info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
48 #define QUERY_UINT64(msg, field, attr) \
49         info->field = samdb_result_uint64(msg, attr, 0);
50 #define QUERY_APASSC(msg, field, attr) \
51         info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
52                                                          a_state->domain_state->domain_dn, msg, attr);
53 #define QUERY_FPASSC(msg, field, attr) \
54         info->field = samdb_result_force_password_change(sam_ctx, mem_ctx, \
55                                                          a_state->domain_state->domain_dn, msg);
56 #define QUERY_LHOURS(msg, field, attr) \
57         info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
58 #define QUERY_AFLAGS(msg, field, attr) \
59         info->field = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, a_state->domain_state->domain_dn);
60 #define QUERY_PARAMETERS(msg, field, attr) \
61         info->field = samdb_result_parameters(mem_ctx, msg, attr);
62
63
64 /* these are used to make the Set[User|Group]Info code easier to follow */
65
66 #define SET_STRING(msg, field, attr) do {                               \
67         struct ldb_message_element *set_el;                             \
68         if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
69         if (r->in.info->field.string[0] == '\0') {                      \
70                 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL)) { \
71                         return NT_STATUS_NO_MEMORY;                     \
72                 }                                                       \
73         }                                                               \
74         if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != 0) { \
75                 return NT_STATUS_NO_MEMORY;                             \
76         }                                                               \
77         set_el = ldb_msg_find_element(msg, attr);                       \
78         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
79 } while (0)
80
81 #define SET_UINT(msg, field, attr) do {                                 \
82         struct ldb_message_element *set_el;                             \
83         if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
84                 return NT_STATUS_NO_MEMORY;                             \
85         }                                                               \
86         set_el = ldb_msg_find_element(msg, attr);                       \
87         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
88 } while (0)                                                             
89                                                                         
90 #define SET_INT64(msg, field, attr) do {                                \
91         struct ldb_message_element *set_el;                             \
92         if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
93                 return NT_STATUS_NO_MEMORY;                             \
94         }                                                               \
95         set_el = ldb_msg_find_element(msg, attr);                       \
96         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
97 } while (0)                                                             
98                                                                         
99 #define SET_UINT64(msg, field, attr) do {                               \
100         struct ldb_message_element *set_el;                             \
101         if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
102                 return NT_STATUS_NO_MEMORY;                             \
103         }                                                               \
104         set_el = ldb_msg_find_element(msg, attr);                       \
105         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
106 } while (0)                                                             
107
108 #define CHECK_FOR_MULTIPLES(value, flag, poss_flags)    \
109         do { \
110                 if ((value & flag) && ((value & flag) != (value & (poss_flags)))) { \
111                         return NT_STATUS_INVALID_PARAMETER;             \
112                 }                                                       \
113         } while (0)                                                     \
114         
115 /* Set account flags, discarding flags that cannot be set with SAMR */                                                          
116 #define SET_AFLAGS(msg, field, attr) do {                               \
117         struct ldb_message_element *set_el;                             \
118         if ((r->in.info->field & (ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST)) == 0) { \
119                 return NT_STATUS_INVALID_PARAMETER; \
120         }                                                               \
121         CHECK_FOR_MULTIPLES(r->in.info->field, ACB_NORMAL, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
122         CHECK_FOR_MULTIPLES(r->in.info->field, ACB_DOMTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
123         CHECK_FOR_MULTIPLES(r->in.info->field, ACB_WSTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
124         CHECK_FOR_MULTIPLES(r->in.info->field, ACB_SVRTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
125         if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, (r->in.info->field & ~(ACB_AUTOLOCK|ACB_PW_EXPIRED))) != 0) { \
126                 return NT_STATUS_NO_MEMORY;                             \
127         }                                                               \
128         set_el = ldb_msg_find_element(msg, attr);                       \
129         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
130 } while (0)                                                             
131                                                                         
132 #define SET_LHOURS(msg, field, attr) do {                               \
133         struct ldb_message_element *set_el;                             \
134         if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
135                 return NT_STATUS_NO_MEMORY;                             \
136         }                                                               \
137         set_el = ldb_msg_find_element(msg, attr);                       \
138         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
139 } while (0)
140
141 #define SET_PARAMETERS(msg, field, attr) do {                           \
142         struct ldb_message_element *set_el;                             \
143         if (r->in.info->field.length != 0) {                            \
144                 if (samdb_msg_add_parameters(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
145                         return NT_STATUS_NO_MEMORY;                     \
146                 }                                                       \
147                 set_el = ldb_msg_find_element(msg, attr);               \
148                 set_el->flags = LDB_FLAG_MOD_REPLACE;                   \
149         }                                                               \
150 } while (0)
151
152
153
154 /* 
155   samr_Connect 
156
157   create a connection to the SAM database
158 */
159 static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
160                              struct samr_Connect *r)
161 {
162         struct samr_connect_state *c_state;
163         struct dcesrv_handle *handle;
164
165         ZERO_STRUCTP(r->out.connect_handle);
166
167         c_state = talloc(dce_call->conn, struct samr_connect_state);
168         if (!c_state) {
169                 return NT_STATUS_NO_MEMORY;
170         }
171
172         /* make sure the sam database is accessible */
173         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); 
174         if (c_state->sam_ctx == NULL) {
175                 talloc_free(c_state);
176                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
177         }
178
179
180         handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_CONNECT);
181         if (!handle) {
182                 talloc_free(c_state);
183                 return NT_STATUS_NO_MEMORY;
184         }
185
186         handle->data = talloc_steal(handle, c_state);
187
188         c_state->access_mask = r->in.access_mask;
189         *r->out.connect_handle = handle->wire_handle;
190
191         return NT_STATUS_OK;
192 }
193
194
195 /* 
196   samr_Close 
197 */
198 static NTSTATUS dcesrv_samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
199                            struct samr_Close *r)
200 {
201         struct dcesrv_handle *h;
202
203         *r->out.handle = *r->in.handle;
204
205         DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
206
207         talloc_free(h);
208
209         ZERO_STRUCTP(r->out.handle);
210
211         return NT_STATUS_OK;
212 }
213
214
215 /* 
216   samr_SetSecurity 
217 */
218 static NTSTATUS dcesrv_samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
219                                  struct samr_SetSecurity *r)
220 {
221         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
222 }
223
224
225 /* 
226   samr_QuerySecurity 
227 */
228 static NTSTATUS dcesrv_samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
229                                    struct samr_QuerySecurity *r)
230 {
231         struct dcesrv_handle *h;
232         struct sec_desc_buf *sd;
233
234         *r->out.sdbuf = NULL;
235
236         DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
237
238         sd = talloc(mem_ctx, struct sec_desc_buf);
239         if (sd == NULL) {
240                 return NT_STATUS_NO_MEMORY;
241         }
242
243         sd->sd = samdb_default_security_descriptor(mem_ctx);
244
245         *r->out.sdbuf = sd;
246
247         return NT_STATUS_OK;
248 }
249
250
251 /* 
252   samr_Shutdown 
253
254   we refuse this operation completely. If a admin wants to shutdown samr
255   in Samba then they should use the samba admin tools to disable the samr pipe
256 */
257 static NTSTATUS dcesrv_samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
258                               struct samr_Shutdown *r)
259 {
260         return NT_STATUS_ACCESS_DENIED;
261 }
262
263
264 /* 
265   samr_LookupDomain 
266
267   this maps from a domain name to a SID
268 */
269 static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
270                                   struct samr_LookupDomain *r)
271 {
272         struct samr_connect_state *c_state;
273         struct dcesrv_handle *h;
274         struct dom_sid *sid;
275         const char * const dom_attrs[] = { "objectSid", NULL};
276         struct ldb_message **dom_msgs;
277         int ret;
278
279         *r->out.sid = NULL;
280
281         DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
282
283         c_state = h->data;
284
285         if (r->in.domain_name->string == NULL) {
286                 return NT_STATUS_INVALID_PARAMETER;
287         }
288
289         if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
290                 ret = gendb_search(c_state->sam_ctx,
291                                    mem_ctx, NULL, &dom_msgs, dom_attrs,
292                                    "(objectClass=builtinDomain)");
293         } else if (strcasecmp_m(r->in.domain_name->string, lp_sam_name(dce_call->conn->dce_ctx->lp_ctx)) == 0) {
294                 ret = gendb_search_dn(c_state->sam_ctx,
295                                       mem_ctx, ldb_get_default_basedn(c_state->sam_ctx), 
296                                       &dom_msgs, dom_attrs);
297         } else {
298                 return NT_STATUS_NO_SUCH_DOMAIN;
299         }
300         if (ret != 1) {
301                 return NT_STATUS_NO_SUCH_DOMAIN;
302         }
303         
304         sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
305                                    "objectSid");
306                 
307         if (sid == NULL) {
308                 return NT_STATUS_NO_SUCH_DOMAIN;
309         }
310
311         *r->out.sid = sid;
312
313         return NT_STATUS_OK;
314 }
315
316
317 /* 
318   samr_EnumDomains 
319
320   list the domains in the SAM
321 */
322 static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
323                                  struct samr_EnumDomains *r)
324 {
325         struct samr_connect_state *c_state;
326         struct dcesrv_handle *h;
327         struct samr_SamArray *array;
328         int i, start_i;
329
330         *r->out.resume_handle = 0;
331         *r->out.sam = NULL;
332         *r->out.num_entries = 0;
333
334         DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
335
336         c_state = h->data;
337
338         *r->out.resume_handle = 2;
339
340         start_i = *r->in.resume_handle;
341
342         if (start_i >= 2) {
343                 /* search past end of list is not an error for this call */
344                 return NT_STATUS_OK;
345         }
346
347         array = talloc(mem_ctx, struct samr_SamArray);
348         if (array == NULL) {
349                 return NT_STATUS_NO_MEMORY;
350         }
351                 
352         array->count = 0;
353         array->entries = NULL;
354
355         array->entries = talloc_array(mem_ctx, struct samr_SamEntry, 2 - start_i);
356         if (array->entries == NULL) {
357                 return NT_STATUS_NO_MEMORY;
358         }
359
360         for (i=0;i<2-start_i;i++) {
361                 array->entries[i].idx = start_i + i;
362                 if (i == 0) {
363                         array->entries[i].name.string = lp_sam_name(dce_call->conn->dce_ctx->lp_ctx);
364                 } else {
365                         array->entries[i].name.string = "BUILTIN";
366                 }
367         }
368
369         *r->out.sam = array;
370         *r->out.num_entries = i;
371         array->count = *r->out.num_entries;
372
373         return NT_STATUS_OK;
374 }
375
376
377 /* 
378   samr_OpenDomain 
379 */
380 static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
381                                 struct samr_OpenDomain *r)
382 {
383         struct dcesrv_handle *h_conn, *h_domain;
384         struct samr_connect_state *c_state;
385         struct samr_domain_state *d_state;
386         const char * const dom_attrs[] = { "cn", NULL};
387         struct ldb_message **dom_msgs;
388         int ret;
389
390         ZERO_STRUCTP(r->out.domain_handle);
391
392         DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
393
394         c_state = h_conn->data;
395
396         if (r->in.sid == NULL) {
397                 return NT_STATUS_INVALID_PARAMETER;
398         }
399
400         d_state = talloc(c_state, struct samr_domain_state);
401         if (!d_state) {
402                 return NT_STATUS_NO_MEMORY;
403         }
404
405         d_state->domain_sid = talloc_steal(d_state, r->in.sid);
406
407         if (dom_sid_equal(d_state->domain_sid, dom_sid_parse_talloc(mem_ctx, SID_BUILTIN))) {
408                 d_state->builtin = true;
409                 d_state->domain_name = "BUILTIN";
410         } else {
411                 d_state->builtin = false;
412                 d_state->domain_name = lp_sam_name(dce_call->conn->dce_ctx->lp_ctx);
413         }
414
415         ret = gendb_search(c_state->sam_ctx,
416                            mem_ctx, ldb_get_default_basedn(c_state->sam_ctx), &dom_msgs, dom_attrs,
417                            "(objectSid=%s)", 
418                            ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
419         
420         if (ret == 0) {
421                 talloc_free(d_state);
422                 return NT_STATUS_NO_SUCH_DOMAIN;
423         } else if (ret > 1) {
424                 talloc_free(d_state);
425                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
426         } else if (ret == -1) {
427                 talloc_free(d_state);
428                 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx)));
429                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
430         }
431
432         d_state->domain_dn = talloc_steal(d_state, dom_msgs[0]->dn);
433         d_state->role = lp_server_role(dce_call->conn->dce_ctx->lp_ctx);
434         d_state->connect_state = talloc_reference(d_state, c_state);
435         d_state->sam_ctx = c_state->sam_ctx;
436         d_state->access_mask = r->in.access_mask;
437
438         d_state->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
439
440         h_domain = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_DOMAIN);
441         if (!h_domain) {
442                 talloc_free(d_state);
443                 return NT_STATUS_NO_MEMORY;
444         }
445         
446         h_domain->data = talloc_steal(h_domain, d_state);
447
448         *r->out.domain_handle = h_domain->wire_handle;
449
450         return NT_STATUS_OK;
451 }
452
453 /*
454   return DomInfo1
455 */
456 static NTSTATUS dcesrv_samr_info_DomInfo1(struct samr_domain_state *state,
457                                    TALLOC_CTX *mem_ctx,
458                                     struct ldb_message **dom_msgs,
459                                    struct samr_DomInfo1 *info)
460 {
461         info->min_password_length =
462                 samdb_result_uint(dom_msgs[0], "minPwdLength", 0);
463         info->password_history_length =
464                 samdb_result_uint(dom_msgs[0], "pwdHistoryLength", 0);
465         info->password_properties = 
466                 samdb_result_uint(dom_msgs[0], "pwdProperties", 0);
467         info->max_password_age = 
468                 samdb_result_int64(dom_msgs[0], "maxPwdAge", 0);
469         info->min_password_age = 
470                 samdb_result_int64(dom_msgs[0], "minPwdAge", 0);
471
472         return NT_STATUS_OK;
473 }
474
475 /*
476   return DomInfo2
477 */
478 static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state *state, 
479                                                        TALLOC_CTX *mem_ctx,
480                                                        struct ldb_message **dom_msgs,
481                                                        struct samr_DomGeneralInformation *info)
482 {
483         /* This pulls the NetBIOS name from the 
484            cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
485            string */
486         info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx, dom_msgs[0], "fSMORoleOwner");
487
488         if (!info->primary.string) {
489                 info->primary.string = lp_netbios_name(state->lp_ctx);
490         }
491
492         info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff", 
493                                                             0x8000000000000000LL);
494
495         info->oem_information.string = samdb_result_string(dom_msgs[0], "oEMInformation", NULL);
496         info->domain_name.string  = state->domain_name;
497
498         info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount", 
499                                                  0);
500         switch (state->role) {
501         case ROLE_DOMAIN_CONTROLLER:
502                 /* This pulls the NetBIOS name from the 
503                    cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
504                    string */
505                 if (samdb_is_pdc(state->sam_ctx)) {
506                         info->role = SAMR_ROLE_DOMAIN_PDC;
507                 } else {
508                         info->role = SAMR_ROLE_DOMAIN_BDC;
509                 }
510                 break;
511         case ROLE_DOMAIN_MEMBER:
512                 info->role = SAMR_ROLE_DOMAIN_MEMBER;
513                 break;
514         case ROLE_STANDALONE:
515                 info->role = SAMR_ROLE_STANDALONE;
516                 break;
517         }
518
519         /* No users in BUILTIN, and the LOCAL group types are only in builtin, and the global group type is never in BUILTIN */
520         info->num_users = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn, 
521                                              "(objectClass=user)");
522         info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
523                                               "(&(objectClass=group)(sAMAccountType=%u))",
524                                               ATYPE_GLOBAL_GROUP);
525         info->num_aliases = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
526                                                "(&(objectClass=group)(sAMAccountType=%u))",
527                                                ATYPE_LOCAL_GROUP);
528
529         return NT_STATUS_OK;
530 }
531
532 /*
533   return DomInfo3
534 */
535 static NTSTATUS dcesrv_samr_info_DomInfo3(struct samr_domain_state *state,
536                                    TALLOC_CTX *mem_ctx,
537                                     struct ldb_message **dom_msgs,
538                                    struct samr_DomInfo3 *info)
539 {
540         info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff", 
541                                                       0x8000000000000000LL);
542
543         return NT_STATUS_OK;
544 }
545
546 /*
547   return DomInfo4
548 */
549 static NTSTATUS dcesrv_samr_info_DomOEMInformation(struct samr_domain_state *state,
550                                    TALLOC_CTX *mem_ctx,
551                                     struct ldb_message **dom_msgs,
552                                    struct samr_DomOEMInformation *info)
553 {
554         info->oem_information.string = samdb_result_string(dom_msgs[0], "oEMInformation", NULL);
555
556         return NT_STATUS_OK;
557 }
558
559 /*
560   return DomInfo5
561 */
562 static NTSTATUS dcesrv_samr_info_DomInfo5(struct samr_domain_state *state,
563                                    TALLOC_CTX *mem_ctx,
564                                     struct ldb_message **dom_msgs,
565                                    struct samr_DomInfo5 *info)
566 {
567         info->domain_name.string  = state->domain_name;
568
569         return NT_STATUS_OK;
570 }
571
572 /*
573   return DomInfo6
574 */
575 static NTSTATUS dcesrv_samr_info_DomInfo6(struct samr_domain_state *state,
576                                    TALLOC_CTX *mem_ctx,
577                                    struct ldb_message **dom_msgs,
578                                    struct samr_DomInfo6 *info)
579 {
580         /* This pulls the NetBIOS name from the 
581            cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
582            string */
583         info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx, 
584                                                       dom_msgs[0], "fSMORoleOwner");
585
586         if (!info->primary.string) {
587                 info->primary.string = lp_netbios_name(state->lp_ctx);
588         }
589
590         return NT_STATUS_OK;
591 }
592
593 /*
594   return DomInfo7
595 */
596 static NTSTATUS dcesrv_samr_info_DomInfo7(struct samr_domain_state *state,
597                                    TALLOC_CTX *mem_ctx,
598                                     struct ldb_message **dom_msgs,
599                                    struct samr_DomInfo7 *info)
600 {
601
602         switch (state->role) {
603         case ROLE_DOMAIN_CONTROLLER:
604                 /* This pulls the NetBIOS name from the 
605                    cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
606                    string */
607                 if (samdb_is_pdc(state->sam_ctx)) {
608                         info->role = SAMR_ROLE_DOMAIN_PDC;
609                 } else {
610                         info->role = SAMR_ROLE_DOMAIN_BDC;
611                 }
612                 break;
613         case ROLE_DOMAIN_MEMBER:
614                 info->role = SAMR_ROLE_DOMAIN_MEMBER;
615                 break;
616         case ROLE_STANDALONE:
617                 info->role = SAMR_ROLE_STANDALONE;
618                 break;
619         }
620
621         return NT_STATUS_OK;
622 }
623
624 /*
625   return DomInfo8
626 */
627 static NTSTATUS dcesrv_samr_info_DomInfo8(struct samr_domain_state *state,
628                                    TALLOC_CTX *mem_ctx,
629                                     struct ldb_message **dom_msgs,
630                                    struct samr_DomInfo8 *info)
631 {
632         info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount", 
633                                                time(NULL));
634
635         info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
636                                                      0x0LL);
637
638         return NT_STATUS_OK;
639 }
640
641 /*
642   return DomInfo9
643 */
644 static NTSTATUS dcesrv_samr_info_DomInfo9(struct samr_domain_state *state,
645                                    TALLOC_CTX *mem_ctx,
646                                     struct ldb_message **dom_msgs,
647                                    struct samr_DomInfo9 *info)
648 {
649         info->domain_server_state = DOMAIN_SERVER_ENABLED;
650
651         return NT_STATUS_OK;
652 }
653
654 /*
655   return DomInfo11
656 */
657 static NTSTATUS dcesrv_samr_info_DomGeneralInformation2(struct samr_domain_state *state,
658                                     TALLOC_CTX *mem_ctx,
659                                     struct ldb_message **dom_msgs,
660                                     struct samr_DomGeneralInformation2 *info)
661 {
662         NTSTATUS status;
663         status = dcesrv_samr_info_DomGeneralInformation(state, mem_ctx, dom_msgs, &info->general);
664         if (!NT_STATUS_IS_OK(status)) {
665                 return status;
666         }
667         
668         info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration", 
669                                                     -18000000000LL);
670         info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
671                                                     -18000000000LL);
672         info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
673
674         return NT_STATUS_OK;
675 }
676
677 /*
678   return DomInfo12
679 */
680 static NTSTATUS dcesrv_samr_info_DomInfo12(struct samr_domain_state *state,
681                                    TALLOC_CTX *mem_ctx,
682                                     struct ldb_message **dom_msgs,
683                                    struct samr_DomInfo12 *info)
684 {
685         info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration", 
686                                                     -18000000000LL);
687         info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
688                                                     -18000000000LL);
689         info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
690
691         return NT_STATUS_OK;
692 }
693
694 /*
695   return DomInfo13
696 */
697 static NTSTATUS dcesrv_samr_info_DomInfo13(struct samr_domain_state *state,
698                                     TALLOC_CTX *mem_ctx,
699                                     struct ldb_message **dom_msgs,
700                                     struct samr_DomInfo13 *info)
701 {
702         info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount", 
703                                                time(NULL));
704
705         info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
706                                                      0x0LL);
707
708         info->modified_count_at_last_promotion = 0;
709
710         return NT_STATUS_OK;
711 }
712
713 /* 
714   samr_QueryDomainInfo 
715 */
716 static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
717                                      struct samr_QueryDomainInfo *r)
718 {
719         struct dcesrv_handle *h;
720         struct samr_domain_state *d_state;
721         union samr_DomainInfo *info;
722
723         struct ldb_message **dom_msgs;
724         const char * const *attrs = NULL;
725         
726         *r->out.info = NULL;
727
728         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
729
730         d_state = h->data;
731
732         info = talloc(mem_ctx, union samr_DomainInfo);
733         if (!info) {
734                 return NT_STATUS_NO_MEMORY;
735         }
736
737         switch (r->in.level) {
738         case 1: 
739         {
740                 static const char * const attrs2[] = { "minPwdLength", "pwdHistoryLength",
741                                                        "pwdProperties", "maxPwdAge",
742                                                        "minPwdAge", NULL };
743                 attrs = attrs2;
744                 break;
745         }
746         case 2:
747         {
748                 static const char * const attrs2[] = {"forceLogoff",
749                                                       "oEMInformation", 
750                                                       "modifiedCount", 
751                                                       "fSMORoleOwner",
752                                                       NULL};
753                 attrs = attrs2;
754                 break;
755         }
756         case 3:
757         {
758                 static const char * const attrs2[] = {"forceLogoff", 
759                                                       NULL};
760                 attrs = attrs2;
761                 break;
762         }
763         case 4:
764         {
765                 static const char * const attrs2[] = {"oEMInformation", 
766                                                       NULL};
767                 attrs = attrs2;
768                 break;
769         }
770         case 5:
771         {
772                 attrs = NULL;
773                 break;
774         }
775         case 6:
776         {
777                 static const char * const attrs2[] = {"fSMORoleOwner", 
778                                                       NULL};
779                 attrs = attrs2;
780                 break;
781         }
782         case 7:
783         {
784                 attrs = NULL;
785                 break;
786         }
787         case 8:
788         {
789                 static const char * const attrs2[] = { "modifiedCount", 
790                                                        "creationTime", 
791                                                        NULL };
792                 attrs = attrs2;
793                 break;
794         }
795         case 9:
796                 attrs = NULL;
797                 break;          
798         case 11:
799         {
800                 static const char * const attrs2[] = { "oEMInformation", "forceLogoff", 
801                                                        "modifiedCount", 
802                                                        "lockoutDuration", 
803                                                        "lockOutObservationWindow", 
804                                                        "lockoutThreshold", 
805                                                        NULL};
806                 attrs = attrs2;
807                 break;
808         }
809         case 12:
810         {
811                 static const char * const attrs2[] = { "lockoutDuration", 
812                                                        "lockOutObservationWindow", 
813                                                        "lockoutThreshold", 
814                                                        NULL};
815                 attrs = attrs2;
816                 break;
817         }
818         case 13:
819         {
820                 static const char * const attrs2[] = { "modifiedCount", 
821                                                        "creationTime", 
822                                                        NULL };
823                 attrs = attrs2;
824                 break;
825         }
826         }
827
828         /* some levels don't need a search */
829         if (attrs) {
830                 int ret;
831                 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
832                                       d_state->domain_dn, &dom_msgs, attrs);
833                 if (ret != 1) {
834                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
835                 }
836         }
837
838         *r->out.info = info;
839
840         ZERO_STRUCTP(info);
841
842         switch (r->in.level) {
843         case 1:
844                 return dcesrv_samr_info_DomInfo1(d_state, mem_ctx, dom_msgs, 
845                                                  &info->info1);
846         case 2:
847                 return dcesrv_samr_info_DomGeneralInformation(d_state, mem_ctx, dom_msgs, 
848                                                               &info->general);
849         case 3:
850                 return dcesrv_samr_info_DomInfo3(d_state, mem_ctx, dom_msgs, 
851                                                  &info->info3);
852         case 4:
853                 return dcesrv_samr_info_DomOEMInformation(d_state, mem_ctx, dom_msgs, 
854                                                           &info->oem);
855         case 5:
856                 return dcesrv_samr_info_DomInfo5(d_state, mem_ctx, dom_msgs, 
857                                                  &info->info5);
858         case 6:
859                 return dcesrv_samr_info_DomInfo6(d_state, mem_ctx, dom_msgs, 
860                                                  &info->info6);
861         case 7:
862                 return dcesrv_samr_info_DomInfo7(d_state, mem_ctx, dom_msgs, 
863                                                  &info->info7);
864         case 8:
865                 return dcesrv_samr_info_DomInfo8(d_state, mem_ctx, dom_msgs, 
866                                                  &info->info8);
867         case 9:
868                 return dcesrv_samr_info_DomInfo9(d_state, mem_ctx, dom_msgs, 
869                                                  &info->info9);
870         case 11:
871                 return dcesrv_samr_info_DomGeneralInformation2(d_state, mem_ctx, dom_msgs, 
872                                                                &info->general2);
873         case 12:
874                 return dcesrv_samr_info_DomInfo12(d_state, mem_ctx, dom_msgs, 
875                                                   &info->info12);
876         case 13:
877                 return dcesrv_samr_info_DomInfo13(d_state, mem_ctx, dom_msgs, 
878                                                   &info->info13);
879         }
880
881         return NT_STATUS_INVALID_INFO_CLASS;
882 }
883
884
885 /* 
886   samr_SetDomainInfo 
887 */
888 static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
889                        struct samr_SetDomainInfo *r)
890 {
891         struct dcesrv_handle *h;
892         struct samr_domain_state *d_state;
893         struct ldb_message *msg;
894         int ret;
895         struct ldb_context *sam_ctx;
896
897         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
898
899         d_state = h->data;
900         sam_ctx = d_state->sam_ctx;
901
902         msg = ldb_msg_new(mem_ctx);
903         if (msg == NULL) {
904                 return NT_STATUS_NO_MEMORY;
905         }
906
907         msg->dn = talloc_reference(mem_ctx, d_state->domain_dn);
908         if (!msg->dn) {
909                 return NT_STATUS_NO_MEMORY;
910         }
911
912         switch (r->in.level) {
913         case 1:
914                 SET_UINT  (msg, info1.min_password_length,     "minPwdLength");
915                 SET_UINT  (msg, info1.password_history_length, "pwdHistoryLength");
916                 SET_UINT  (msg, info1.password_properties,     "pwdProperties");
917                 SET_INT64  (msg, info1.max_password_age,       "maxPwdAge");
918                 SET_INT64  (msg, info1.min_password_age,       "minPwdAge");
919                 break;
920         case 3:
921                 SET_UINT64  (msg, info3.force_logoff_time,     "forceLogoff");
922                 break;
923         case 4:
924                 SET_STRING(msg, oem.oem_information,           "oEMInformation");
925                 break;
926
927         case 6:
928         case 7:
929         case 9:
930                 /* No op, we don't know where to set these */
931                 return NT_STATUS_OK;
932
933         case 12:
934                 
935                 SET_INT64  (msg, info12.lockout_duration,      "lockoutDuration");
936                 SET_INT64  (msg, info12.lockout_window,        "lockOutObservationWindow");
937                 SET_INT64  (msg, info12.lockout_threshold,     "lockoutThreshold");
938                 break;
939
940         default:
941                 /* many info classes are not valid for SetDomainInfo */
942                 return NT_STATUS_INVALID_INFO_CLASS;
943         }
944
945         /* modify the samdb record */
946         ret = ldb_modify(sam_ctx, msg);
947         if (ret != 0) {
948                 DEBUG(1,("Failed to modify record %s: %s\n",
949                          ldb_dn_get_linearized(d_state->domain_dn),
950                          ldb_errstring(sam_ctx)));
951
952                 /* we really need samdb.c to return NTSTATUS */
953                 return NT_STATUS_UNSUCCESSFUL;
954         }
955
956         return NT_STATUS_OK;
957 }
958
959 /* 
960   samr_CreateDomainGroup 
961 */
962 static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
963                                        struct samr_CreateDomainGroup *r)
964 {
965         struct samr_domain_state *d_state;
966         struct samr_account_state *a_state;
967         struct dcesrv_handle *h;
968         const char *name;
969         struct ldb_message *msg;
970         struct dom_sid *sid;
971         const char *groupname;
972         struct dcesrv_handle *g_handle;
973         int ret;
974
975         ZERO_STRUCTP(r->out.group_handle);
976         *r->out.rid = 0;
977
978         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
979
980         d_state = h->data;
981
982         if (d_state->builtin) {
983                 DEBUG(5, ("Cannot create a domain group in the BUILTIN domain"));
984                 return NT_STATUS_ACCESS_DENIED;
985         }
986
987         groupname = r->in.name->string;
988
989         if (groupname == NULL) {
990                 return NT_STATUS_INVALID_PARAMETER;
991         }
992
993         /* check if the group already exists */
994         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL, 
995                                    "sAMAccountName",
996                                    "(&(sAMAccountName=%s)(objectclass=group))",
997                                    ldb_binary_encode_string(mem_ctx, groupname));
998         if (name != NULL) {
999                 return NT_STATUS_GROUP_EXISTS;
1000         }
1001
1002         msg = ldb_msg_new(mem_ctx);
1003         if (msg == NULL) {
1004                 return NT_STATUS_NO_MEMORY;
1005         }
1006
1007         /* add core elements to the ldb_message for the user */
1008         msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1009         ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", groupname);
1010         if (!msg->dn) {
1011                 return NT_STATUS_NO_MEMORY;
1012         }
1013         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", groupname);
1014         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1015                              
1016         /* create the group */
1017         ret = ldb_add(d_state->sam_ctx, msg);
1018         switch (ret) {
1019         case  LDB_SUCCESS:
1020                 break;
1021         case  LDB_ERR_ENTRY_ALREADY_EXISTS:
1022                 DEBUG(0,("Failed to create group record %s: %s\n",
1023                          ldb_dn_get_linearized(msg->dn),
1024                          ldb_errstring(d_state->sam_ctx)));
1025                 return NT_STATUS_GROUP_EXISTS;
1026         case  LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1027                 DEBUG(0,("Failed to create group record %s: %s\n",
1028                          ldb_dn_get_linearized(msg->dn),
1029                          ldb_errstring(d_state->sam_ctx)));
1030                 return NT_STATUS_ACCESS_DENIED;
1031         default:
1032                 DEBUG(0,("Failed to create group record %s: %s\n",
1033                          ldb_dn_get_linearized(msg->dn),
1034                          ldb_errstring(d_state->sam_ctx)));
1035                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1036         }
1037
1038         a_state = talloc(d_state, struct samr_account_state);
1039         if (!a_state) {
1040                 return NT_STATUS_NO_MEMORY;
1041         }
1042         a_state->sam_ctx = d_state->sam_ctx;
1043         a_state->access_mask = r->in.access_mask;
1044         a_state->domain_state = talloc_reference(a_state, d_state);
1045         a_state->account_dn = talloc_steal(a_state, msg->dn);
1046
1047         /* retrieve the sid for the group just created */
1048         sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1049                                    msg->dn, "objectSid", NULL);
1050         if (sid == NULL) {
1051                 return NT_STATUS_UNSUCCESSFUL;
1052         }
1053
1054         a_state->account_name = talloc_strdup(a_state, groupname);
1055         if (!a_state->account_name) {
1056                 return NT_STATUS_NO_MEMORY;
1057         }
1058
1059         /* create the policy handle */
1060         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1061         if (!g_handle) {
1062                 return NT_STATUS_NO_MEMORY;
1063         }
1064
1065         g_handle->data = talloc_steal(g_handle, a_state);
1066
1067         *r->out.group_handle = g_handle->wire_handle;
1068         *r->out.rid = sid->sub_auths[sid->num_auths-1];
1069
1070         return NT_STATUS_OK;
1071 }
1072
1073
1074 /*
1075   comparison function for sorting SamEntry array
1076 */
1077 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
1078 {
1079         return e1->idx - e2->idx;
1080 }
1081
1082 /* 
1083   samr_EnumDomainGroups 
1084 */
1085 static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1086                                       struct samr_EnumDomainGroups *r)
1087 {
1088         struct dcesrv_handle *h;
1089         struct samr_domain_state *d_state;
1090         struct ldb_message **res;
1091         int ldb_cnt, count, i, first;
1092         struct samr_SamEntry *entries;
1093         const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1094         struct samr_SamArray *sam;
1095
1096         *r->out.resume_handle = 0;
1097         *r->out.sam = NULL;
1098         *r->out.num_entries = 0;
1099
1100         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1101
1102         d_state = h->data;
1103
1104         /* search for all domain groups in this domain. This could possibly be
1105            cached and resumed based on resume_key */
1106         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1107                                       d_state->domain_dn, &res, attrs,
1108                                       d_state->domain_sid,
1109                                       "(&(grouptype=%d)(objectclass=group))",
1110                                       GTYPE_SECURITY_GLOBAL_GROUP);
1111         if (ldb_cnt == -1) {
1112                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1113         }
1114
1115         /* convert to SamEntry format */
1116         entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1117         if (!entries) {
1118                 return NT_STATUS_NO_MEMORY;
1119         }
1120
1121         count = 0;
1122
1123         for (i=0;i<ldb_cnt;i++) {
1124                 struct dom_sid *group_sid;
1125
1126                 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
1127                                                  "objectSid");
1128                 if (group_sid == NULL)
1129                         continue;
1130
1131                 entries[count].idx =
1132                         group_sid->sub_auths[group_sid->num_auths-1];
1133                 entries[count].name.string =
1134                         samdb_result_string(res[i], "sAMAccountName", "");
1135                 count += 1;
1136         }
1137
1138         /* sort the results by rid */
1139         qsort(entries, count, sizeof(struct samr_SamEntry), 
1140               (comparison_fn_t)compare_SamEntry);
1141
1142         /* find the first entry to return */
1143         for (first=0;
1144              first<count && entries[first].idx <= *r->in.resume_handle;
1145              first++) ;
1146
1147         /* return the rest, limit by max_size. Note that we 
1148            use the w2k3 element size value of 54 */
1149         *r->out.num_entries = count - first;
1150         *r->out.num_entries = MIN(*r->out.num_entries,
1151                                  1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1152
1153         sam = talloc(mem_ctx, struct samr_SamArray);
1154         if (!sam) {
1155                 return NT_STATUS_NO_MEMORY;
1156         }
1157
1158         sam->entries = entries+first;
1159         sam->count = *r->out.num_entries;
1160
1161         *r->out.sam = sam;
1162
1163         if (*r->out.num_entries < count - first) {
1164                 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1165                 return STATUS_MORE_ENTRIES;
1166         }
1167
1168         return NT_STATUS_OK;
1169 }
1170
1171
1172 /* 
1173   samr_CreateUser2 
1174
1175   This call uses transactions to ensure we don't get a new conflicting
1176   user while we are processing this, and to ensure the user either
1177   completly exists, or does not.
1178 */
1179 static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1180                                  struct samr_CreateUser2 *r)
1181 {
1182         struct samr_domain_state *d_state;
1183         struct samr_account_state *a_state;
1184         struct dcesrv_handle *h;
1185         const char *name;
1186         struct ldb_message *msg;
1187         struct dom_sid *sid;
1188         const char *account_name;
1189         struct dcesrv_handle *u_handle;
1190         int ret;
1191         const char *container, *obj_class=NULL;
1192         char *cn_name;
1193         int cn_name_len;
1194
1195         const char *attrs[] = {
1196                 "objectSid", 
1197                 "userAccountControl",
1198                 NULL
1199         };
1200
1201         uint32_t user_account_control;
1202
1203         struct ldb_message **msgs;
1204
1205         ZERO_STRUCTP(r->out.user_handle);
1206         *r->out.access_granted = 0;
1207         *r->out.rid = 0;
1208
1209         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1210
1211         d_state = h->data;
1212
1213         if (d_state->builtin) {
1214                 DEBUG(5, ("Cannot create a user in the BUILTIN domain"));
1215                 return NT_STATUS_ACCESS_DENIED;
1216         } else if (r->in.acct_flags == ACB_DOMTRUST) {
1217                 /* Domain trust accounts must be created by the LSA calls */
1218                 return NT_STATUS_ACCESS_DENIED;
1219         }
1220         account_name = r->in.account_name->string;
1221
1222         if (account_name == NULL) {
1223                 return NT_STATUS_INVALID_PARAMETER;
1224         }
1225
1226         /*
1227          * Start a transaction, so we can query and do a subsequent atomic
1228          * modify
1229          */
1230
1231         ret = ldb_transaction_start(d_state->sam_ctx);
1232         if (ret != 0) {
1233                 DEBUG(0,("Failed to start a transaction for user creation: %s\n",
1234                          ldb_errstring(d_state->sam_ctx)));
1235                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1236         }
1237
1238         /* check if the user already exists */
1239         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL, 
1240                                    "sAMAccountName", 
1241                                    "(&(sAMAccountName=%s)(objectclass=user))", 
1242                                    ldb_binary_encode_string(mem_ctx, account_name));
1243         if (name != NULL) {
1244                 ldb_transaction_cancel(d_state->sam_ctx);
1245                 return NT_STATUS_USER_EXISTS;
1246         }
1247
1248         msg = ldb_msg_new(mem_ctx);
1249         if (msg == NULL) {
1250                 ldb_transaction_cancel(d_state->sam_ctx);
1251                 return NT_STATUS_NO_MEMORY;
1252         }
1253
1254         cn_name   = talloc_strdup(mem_ctx, account_name);
1255         if (!cn_name) {
1256                 ldb_transaction_cancel(d_state->sam_ctx);
1257                 return NT_STATUS_NO_MEMORY;
1258         }
1259
1260         cn_name_len = strlen(cn_name);
1261
1262         /* This must be one of these values *only* */
1263         if (r->in.acct_flags == ACB_NORMAL) {
1264                 container = "CN=Users";
1265                 obj_class = "user";
1266
1267         } else if (r->in.acct_flags == ACB_WSTRUST) {
1268                 if (cn_name[cn_name_len - 1] != '$') {
1269                         ldb_transaction_cancel(d_state->sam_ctx);
1270                         return NT_STATUS_FOOBAR;
1271                 }
1272                 cn_name[cn_name_len - 1] = '\0';
1273                 container = "CN=Computers";
1274                 obj_class = "computer";
1275                 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "primaryGroupID", DOMAIN_RID_DOMAIN_MEMBERS);
1276
1277         } else if (r->in.acct_flags == ACB_SVRTRUST) {
1278                 if (cn_name[cn_name_len - 1] != '$') {
1279                         ldb_transaction_cancel(d_state->sam_ctx);
1280                         return NT_STATUS_FOOBAR;                
1281                 }
1282                 cn_name[cn_name_len - 1] = '\0';
1283                 container = "OU=Domain Controllers";
1284                 obj_class = "computer";
1285                 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "primaryGroupID", DOMAIN_RID_DCS);
1286         } else {
1287                 ldb_transaction_cancel(d_state->sam_ctx);
1288                 return NT_STATUS_INVALID_PARAMETER;
1289         }
1290
1291         /* add core elements to the ldb_message for the user */
1292         msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1293         if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s,%s", cn_name, container)) {
1294                 ldb_transaction_cancel(d_state->sam_ctx);
1295                 return NT_STATUS_FOOBAR;
1296         }
1297
1298         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", account_name);
1299         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", obj_class);
1300
1301         /* create the user */
1302         ret = ldb_add(d_state->sam_ctx, msg);
1303         switch (ret) {
1304         case LDB_SUCCESS:
1305                 break;
1306         case LDB_ERR_ENTRY_ALREADY_EXISTS:
1307                 ldb_transaction_cancel(d_state->sam_ctx);
1308                 DEBUG(0,("Failed to create user record %s: %s\n",
1309                          ldb_dn_get_linearized(msg->dn),
1310                          ldb_errstring(d_state->sam_ctx)));
1311                 return NT_STATUS_USER_EXISTS;
1312         case LDB_ERR_UNWILLING_TO_PERFORM:
1313         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1314                 ldb_transaction_cancel(d_state->sam_ctx);
1315                 DEBUG(0,("Failed to create user record %s: %s\n",
1316                          ldb_dn_get_linearized(msg->dn),
1317                          ldb_errstring(d_state->sam_ctx)));
1318                 return NT_STATUS_ACCESS_DENIED;
1319         default:
1320                 ldb_transaction_cancel(d_state->sam_ctx);
1321                 DEBUG(0,("Failed to create user record %s: %s\n",
1322                          ldb_dn_get_linearized(msg->dn),
1323                          ldb_errstring(d_state->sam_ctx)));
1324                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1325         }
1326
1327         a_state = talloc(d_state, struct samr_account_state);
1328         if (!a_state) {
1329                 ldb_transaction_cancel(d_state->sam_ctx);
1330                 return NT_STATUS_NO_MEMORY;
1331         }
1332         a_state->sam_ctx = d_state->sam_ctx;
1333         a_state->access_mask = r->in.access_mask;
1334         a_state->domain_state = talloc_reference(a_state, d_state);
1335         a_state->account_dn = talloc_steal(a_state, msg->dn);
1336
1337         /* retrieve the sid and account control bits for the user just created */
1338         ret = gendb_search_dn(d_state->sam_ctx, a_state,
1339                               msg->dn, &msgs, attrs);
1340
1341         if (ret != 1) {
1342                 ldb_transaction_cancel(d_state->sam_ctx);
1343                 DEBUG(0,("Apparently we failed to create an account record, as %s now doesn't exist\n",
1344                          ldb_dn_get_linearized(msg->dn)));
1345                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1346         }
1347         sid = samdb_result_dom_sid(mem_ctx, msgs[0], "objectSid");
1348         if (sid == NULL) {
1349                 ldb_transaction_cancel(d_state->sam_ctx);
1350                 DEBUG(0,("Apparently we failed to get the objectSid of the just created account record %s\n",
1351                          ldb_dn_get_linearized(msg->dn)));
1352                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1353         }
1354
1355         /* Change the account control to be the correct account type.
1356          * The default is for a workstation account */
1357         user_account_control = samdb_result_uint(msgs[0], "userAccountControl", 0);
1358         user_account_control = (user_account_control & 
1359                                 ~(UF_NORMAL_ACCOUNT |
1360                                   UF_INTERDOMAIN_TRUST_ACCOUNT | 
1361                                   UF_WORKSTATION_TRUST_ACCOUNT | 
1362                                   UF_SERVER_TRUST_ACCOUNT));
1363         user_account_control |= samdb_acb2uf(r->in.acct_flags);
1364
1365         talloc_free(msg);
1366         msg = ldb_msg_new(mem_ctx);
1367         if (msg == NULL) {
1368                 ldb_transaction_cancel(d_state->sam_ctx);
1369                 return NT_STATUS_NO_MEMORY;
1370         }
1371
1372         msg->dn = ldb_dn_copy(msg, a_state->account_dn);
1373
1374         if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, msg, 
1375                                "userAccountControl", 
1376                                user_account_control) != 0) { 
1377                 ldb_transaction_cancel(d_state->sam_ctx);
1378                 return NT_STATUS_NO_MEMORY; 
1379         }
1380
1381         /* modify the samdb record */
1382         ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
1383         if (ret != 0) {
1384                 DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n",
1385                          ldb_dn_get_linearized(msg->dn),
1386                          ldb_errstring(d_state->sam_ctx)));
1387                 ldb_transaction_cancel(d_state->sam_ctx);
1388
1389                 /* we really need samdb.c to return NTSTATUS */
1390                 return NT_STATUS_UNSUCCESSFUL;
1391         }
1392
1393         ret = ldb_transaction_commit(d_state->sam_ctx);
1394         if (ret != 0) {
1395                 DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n",
1396                          ldb_dn_get_linearized(msg->dn),
1397                          ldb_errstring(d_state->sam_ctx)));
1398                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1399         }
1400
1401         a_state->account_name = talloc_steal(a_state, account_name);
1402         if (!a_state->account_name) {
1403                 return NT_STATUS_NO_MEMORY;
1404         }
1405
1406         /* create the policy handle */
1407         u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
1408         if (!u_handle) {
1409                 return NT_STATUS_NO_MEMORY;
1410         }
1411
1412         u_handle->data = talloc_steal(u_handle, a_state);
1413
1414         *r->out.user_handle = u_handle->wire_handle;
1415         *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1416
1417         *r->out.rid = sid->sub_auths[sid->num_auths-1];
1418
1419         return NT_STATUS_OK;
1420 }
1421
1422
1423 /* 
1424   samr_CreateUser 
1425 */
1426 static NTSTATUS dcesrv_samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1427                                 struct samr_CreateUser *r)
1428 {
1429         struct samr_CreateUser2 r2;
1430         uint32_t access_granted = 0;
1431
1432
1433         /* a simple wrapper around samr_CreateUser2 works nicely */
1434         r2.in.domain_handle = r->in.domain_handle;
1435         r2.in.account_name = r->in.account_name;
1436         r2.in.acct_flags = ACB_NORMAL;
1437         r2.in.access_mask = r->in.access_mask;
1438         r2.out.user_handle = r->out.user_handle;
1439         r2.out.access_granted = &access_granted;
1440         r2.out.rid = r->out.rid;
1441
1442         return dcesrv_samr_CreateUser2(dce_call, mem_ctx, &r2);
1443 }
1444
1445 /* 
1446   samr_EnumDomainUsers 
1447 */
1448 static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1449                                      struct samr_EnumDomainUsers *r)
1450 {
1451         struct dcesrv_handle *h;
1452         struct samr_domain_state *d_state;
1453         struct ldb_result *res;
1454         int ret, num_filtered_entries, i, first;
1455         struct samr_SamEntry *entries;
1456         const char * const attrs[] = { "objectSid", "sAMAccountName", "userAccountControl", NULL };
1457         struct samr_SamArray *sam;
1458
1459         *r->out.resume_handle = 0;
1460         *r->out.sam = NULL;
1461         *r->out.num_entries = 0;
1462
1463         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1464
1465         d_state = h->data;
1466         
1467         /* don't have to worry about users in the builtin domain, as there are none */
1468         ret = ldb_search(d_state->sam_ctx, mem_ctx, &res, d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs, "objectClass=user");
1469
1470         if (ret != LDB_SUCCESS) {
1471                 DEBUG(3, ("Failed to search for Domain Users in %s: %s\n", 
1472                           ldb_dn_get_linearized(d_state->domain_dn), ldb_errstring(d_state->sam_ctx)));
1473                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1474         }
1475
1476         /* convert to SamEntry format */
1477         entries = talloc_array(mem_ctx, struct samr_SamEntry, res->count);
1478         if (!entries) {
1479                 return NT_STATUS_NO_MEMORY;
1480         }
1481         num_filtered_entries = 0;
1482         for (i=0;i<res->count;i++) {
1483                 /* Check if a mask has been requested */
1484                 if (r->in.acct_flags
1485                     && ((samdb_result_acct_flags(d_state->sam_ctx, mem_ctx, res->msgs[i], 
1486                                                  d_state->domain_dn) & r->in.acct_flags) == 0)) {
1487                         continue;
1488                 }
1489                 entries[num_filtered_entries].idx = samdb_result_rid_from_sid(mem_ctx, res->msgs[i], "objectSid", 0);
1490                 entries[num_filtered_entries].name.string = samdb_result_string(res->msgs[i], "sAMAccountName", "");
1491                 num_filtered_entries++;
1492         }
1493
1494         /* sort the results by rid */
1495         qsort(entries, num_filtered_entries, sizeof(struct samr_SamEntry), 
1496               (comparison_fn_t)compare_SamEntry);
1497
1498         /* find the first entry to return */
1499         for (first=0;
1500              first<num_filtered_entries && entries[first].idx <= *r->in.resume_handle;
1501              first++) ;
1502
1503         /* return the rest, limit by max_size. Note that we 
1504            use the w2k3 element size value of 54 */
1505         *r->out.num_entries = num_filtered_entries - first;
1506         *r->out.num_entries = MIN(*r->out.num_entries,
1507                                  1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1508
1509         sam = talloc(mem_ctx, struct samr_SamArray);
1510         if (!sam) {
1511                 return NT_STATUS_NO_MEMORY;
1512         }
1513
1514         sam->entries = entries+first;
1515         sam->count = *r->out.num_entries;
1516
1517         *r->out.sam = sam;
1518
1519         if (first == num_filtered_entries) {
1520                 return NT_STATUS_OK;
1521         }
1522
1523         if (*r->out.num_entries < num_filtered_entries - first) {
1524                 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1525                 return STATUS_MORE_ENTRIES;
1526         }
1527
1528         return NT_STATUS_OK;
1529 }
1530
1531
1532 /* 
1533   samr_CreateDomAlias 
1534 */
1535 static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1536                        struct samr_CreateDomAlias *r)
1537 {
1538         struct samr_domain_state *d_state;
1539         struct samr_account_state *a_state;
1540         struct dcesrv_handle *h;
1541         const char *alias_name, *name;
1542         struct ldb_message *msg;
1543         struct dom_sid *sid;
1544         struct dcesrv_handle *a_handle;
1545         int ret;
1546
1547         ZERO_STRUCTP(r->out.alias_handle);
1548         *r->out.rid = 0;
1549
1550         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1551
1552         d_state = h->data;
1553
1554         if (d_state->builtin) {
1555                 DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain"));
1556                 return NT_STATUS_ACCESS_DENIED;
1557         }
1558
1559         alias_name = r->in.alias_name->string;
1560
1561         if (alias_name == NULL) {
1562                 return NT_STATUS_INVALID_PARAMETER;
1563         }
1564
1565         /* Check if alias already exists */
1566         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1567                                    "sAMAccountName",
1568                                    "(sAMAccountName=%s)(objectclass=group))",
1569                                    ldb_binary_encode_string(mem_ctx, alias_name));
1570
1571         if (name != NULL) {
1572                 return NT_STATUS_ALIAS_EXISTS;
1573         }
1574
1575         msg = ldb_msg_new(mem_ctx);
1576         if (msg == NULL) {
1577                 return NT_STATUS_NO_MEMORY;
1578         }
1579
1580         /* add core elements to the ldb_message for the alias */
1581         msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1582         ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", alias_name);
1583         if (!msg->dn) {
1584                 return NT_STATUS_NO_MEMORY;
1585         }
1586
1587         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", alias_name);
1588         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1589         samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "groupType", GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1590
1591         /* create the alias */
1592         ret = ldb_add(d_state->sam_ctx, msg);
1593         switch (ret) {
1594         case LDB_SUCCESS:
1595                 break;
1596         case LDB_ERR_ENTRY_ALREADY_EXISTS:
1597                 return NT_STATUS_ALIAS_EXISTS;
1598         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1599                 return NT_STATUS_ACCESS_DENIED;
1600         default:
1601                 DEBUG(0,("Failed to create alias record %s: %s\n",
1602                          ldb_dn_get_linearized(msg->dn),
1603                          ldb_errstring(d_state->sam_ctx)));
1604                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1605         }
1606
1607         a_state = talloc(d_state, struct samr_account_state);
1608         if (!a_state) {
1609                 return NT_STATUS_NO_MEMORY;
1610         }
1611
1612         a_state->sam_ctx = d_state->sam_ctx;
1613         a_state->access_mask = r->in.access_mask;
1614         a_state->domain_state = talloc_reference(a_state, d_state);
1615         a_state->account_dn = talloc_steal(a_state, msg->dn);
1616
1617         /* retrieve the sid for the alias just created */
1618         sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1619                                    msg->dn, "objectSid", NULL);
1620
1621         a_state->account_name = talloc_strdup(a_state, alias_name);
1622         if (!a_state->account_name) {
1623                 return NT_STATUS_NO_MEMORY;
1624         }
1625
1626         /* create the policy handle */
1627         a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1628         if (a_handle == NULL)
1629                 return NT_STATUS_NO_MEMORY;
1630
1631         a_handle->data = talloc_steal(a_handle, a_state);
1632
1633         *r->out.alias_handle = a_handle->wire_handle;
1634
1635         *r->out.rid = sid->sub_auths[sid->num_auths-1];
1636
1637         return NT_STATUS_OK;
1638 }
1639
1640
1641 /* 
1642   samr_EnumDomainAliases 
1643 */
1644 static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1645                        struct samr_EnumDomainAliases *r)
1646 {
1647         struct dcesrv_handle *h;
1648         struct samr_domain_state *d_state;
1649         struct ldb_message **res;
1650         int ldb_cnt, count, i, first;
1651         struct samr_SamEntry *entries;
1652         const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1653         struct samr_SamArray *sam;
1654
1655         *r->out.resume_handle = 0;
1656         *r->out.sam = NULL;
1657         *r->out.num_entries = 0;
1658
1659         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1660
1661         d_state = h->data;
1662
1663         /* search for all domain groups in this domain. This could possibly be
1664            cached and resumed based on resume_key */
1665         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1666                                       d_state->domain_dn,
1667                                       &res, attrs, 
1668                                       d_state->domain_sid,
1669                                       "(&(|(grouptype=%d)(grouptype=%d)))"
1670                                       "(objectclass=group))",
1671                                       GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1672                                       GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1673         if (ldb_cnt == -1) {
1674                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1675         }
1676         if (ldb_cnt == 0) {
1677                 return NT_STATUS_OK;
1678         }
1679
1680         /* convert to SamEntry format */
1681         entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1682         if (!entries) {
1683                 return NT_STATUS_NO_MEMORY;
1684         }
1685
1686         count = 0;
1687
1688         for (i=0;i<ldb_cnt;i++) {
1689                 struct dom_sid *alias_sid;
1690
1691                 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1692                                                  "objectSid");
1693
1694                 if (alias_sid == NULL)
1695                         continue;
1696
1697                 entries[count].idx =
1698                         alias_sid->sub_auths[alias_sid->num_auths-1];
1699                 entries[count].name.string =
1700                         samdb_result_string(res[i], "sAMAccountName", "");
1701                 count += 1;
1702         }
1703
1704         /* sort the results by rid */
1705         qsort(entries, count, sizeof(struct samr_SamEntry), 
1706               (comparison_fn_t)compare_SamEntry);
1707
1708         /* find the first entry to return */
1709         for (first=0;
1710              first<count && entries[first].idx <= *r->in.resume_handle;
1711              first++) ;
1712
1713         if (first == count) {
1714                 return NT_STATUS_OK;
1715         }
1716
1717         *r->out.num_entries = count - first;
1718         *r->out.num_entries = MIN(*r->out.num_entries, 1000);
1719
1720         sam = talloc(mem_ctx, struct samr_SamArray);
1721         if (!sam) {
1722                 return NT_STATUS_NO_MEMORY;
1723         }
1724
1725         sam->entries = entries+first;
1726         sam->count = *r->out.num_entries;
1727
1728         *r->out.sam = sam;
1729
1730         if (*r->out.num_entries < count - first) {
1731                 *r->out.resume_handle =
1732                         entries[first+*r->out.num_entries-1].idx;
1733                 return STATUS_MORE_ENTRIES;
1734         }
1735
1736         return NT_STATUS_OK;
1737 }
1738
1739
1740 /* 
1741   samr_GetAliasMembership 
1742 */
1743 static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1744                        struct samr_GetAliasMembership *r)
1745 {
1746         struct dcesrv_handle *h;
1747         struct samr_domain_state *d_state;
1748         struct ldb_message **res;
1749         int i, count = 0;
1750
1751         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1752
1753         d_state = h->data;
1754
1755         if (r->in.sids->num_sids > 0) {
1756                 const char *filter;
1757                 const char * const attrs[2] = { "objectSid", NULL };
1758
1759                 filter = talloc_asprintf(mem_ctx,
1760                                          "(&(|(grouptype=%d)(grouptype=%d))"
1761                                          "(objectclass=group)(|",
1762                                          GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1763                                          GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1764                 if (filter == NULL)
1765                         return NT_STATUS_NO_MEMORY;
1766
1767                 for (i=0; i<r->in.sids->num_sids; i++) {
1768                         const char *memberdn;
1769
1770                         memberdn = 
1771                                 samdb_search_string(d_state->sam_ctx,
1772                                                     mem_ctx, NULL, "distinguishedName",
1773                                                     "(objectSid=%s)",
1774                                                     ldap_encode_ndr_dom_sid(mem_ctx, 
1775                                                                             r->in.sids->sids[i].sid));
1776
1777                         if (memberdn == NULL)
1778                                 continue;
1779
1780                         filter = talloc_asprintf(mem_ctx, "%s(member=%s)",
1781                                                  filter, memberdn);
1782                         if (filter == NULL)
1783                                 return NT_STATUS_NO_MEMORY;
1784                 }
1785
1786                 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1787                                             d_state->domain_dn, &res, attrs,
1788                                             d_state->domain_sid, "%s))", filter);
1789                 if (count < 0)
1790                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1791         }
1792
1793         r->out.rids->count = 0;
1794         r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1795         if (r->out.rids->ids == NULL)
1796                 return NT_STATUS_NO_MEMORY;
1797
1798         for (i=0; i<count; i++) {
1799                 struct dom_sid *alias_sid;
1800
1801                 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1802
1803                 if (alias_sid == NULL) {
1804                         DEBUG(0, ("Could not find objectSid\n"));
1805                         continue;
1806                 }
1807
1808                 r->out.rids->ids[r->out.rids->count] =
1809                         alias_sid->sub_auths[alias_sid->num_auths-1];
1810                 r->out.rids->count += 1;
1811         }
1812
1813         return NT_STATUS_OK;
1814 }
1815
1816
1817 /* 
1818   samr_LookupNames 
1819 */
1820 static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1821                                  struct samr_LookupNames *r)
1822 {
1823         struct dcesrv_handle *h;
1824         struct samr_domain_state *d_state;
1825         int i, num_mapped;
1826         NTSTATUS status = NT_STATUS_OK;
1827         const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1828         int count;
1829
1830         ZERO_STRUCTP(r->out.rids);
1831         ZERO_STRUCTP(r->out.types);
1832
1833         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1834
1835         d_state = h->data;
1836
1837         if (r->in.num_names == 0) {
1838                 return NT_STATUS_OK;
1839         }
1840
1841         r->out.rids->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1842         r->out.types->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1843         if (!r->out.rids->ids || !r->out.types->ids) {
1844                 return NT_STATUS_NO_MEMORY;
1845         }
1846         r->out.rids->count = r->in.num_names;
1847         r->out.types->count = r->in.num_names;
1848
1849         num_mapped = 0;
1850
1851         for (i=0;i<r->in.num_names;i++) {
1852                 struct ldb_message **res;
1853                 struct dom_sid *sid;
1854                 uint32_t atype, rtype;
1855
1856                 r->out.rids->ids[i] = 0;
1857                 r->out.types->ids[i] = SID_NAME_UNKNOWN;
1858
1859                 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs, 
1860                                      "sAMAccountName=%s", 
1861                                      ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1862                 if (count != 1) {
1863                         status = STATUS_SOME_UNMAPPED;
1864                         continue;
1865                 }
1866
1867                 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1868                 if (sid == NULL) {
1869                         status = STATUS_SOME_UNMAPPED;
1870                         continue;
1871                 }
1872                 
1873                 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1874                 if (atype == 0) {
1875                         status = STATUS_SOME_UNMAPPED;
1876                         continue;
1877                 }
1878
1879                 rtype = samdb_atype_map(atype);
1880                 
1881                 if (rtype == SID_NAME_UNKNOWN) {
1882                         status = STATUS_SOME_UNMAPPED;
1883                         continue;
1884                 }
1885
1886                 r->out.rids->ids[i] = sid->sub_auths[sid->num_auths-1];
1887                 r->out.types->ids[i] = rtype;
1888                 num_mapped++;
1889         }
1890         
1891         if (num_mapped == 0) {
1892                 return NT_STATUS_NONE_MAPPED;
1893         }
1894         return status;
1895 }
1896
1897
1898 /* 
1899   samr_LookupRids 
1900 */
1901 static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1902                        struct samr_LookupRids *r)
1903 {
1904         struct dcesrv_handle *h;
1905         struct samr_domain_state *d_state;
1906         int i, total;
1907         NTSTATUS status = NT_STATUS_OK;
1908         struct lsa_String *names;
1909         uint32_t *ids;
1910
1911         ZERO_STRUCTP(r->out.names);
1912         ZERO_STRUCTP(r->out.types);
1913
1914         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1915
1916         d_state = h->data;
1917
1918         if (r->in.num_rids == 0)
1919                 return NT_STATUS_OK;
1920
1921         names = talloc_array(mem_ctx, struct lsa_String, r->in.num_rids);
1922         ids = talloc_array(mem_ctx, uint32_t, r->in.num_rids);
1923
1924         if ((names == NULL) || (ids == NULL))
1925                 return NT_STATUS_NO_MEMORY;
1926
1927         total = 0;
1928
1929         for (i=0; i<r->in.num_rids; i++) {
1930                 struct ldb_message **res;
1931                 int count;
1932                 const char * const attrs[] = {  "sAMAccountType",
1933                                                 "sAMAccountName", NULL };
1934                 uint32_t atype;
1935                 struct dom_sid *sid;
1936
1937                 ids[i] = SID_NAME_UNKNOWN;
1938
1939                 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rids[i]);
1940                 if (sid == NULL) {
1941                         names[i].string = NULL;
1942                         status = STATUS_SOME_UNMAPPED;
1943                         continue;
1944                 }
1945                 
1946                 count = gendb_search(d_state->sam_ctx, mem_ctx,
1947                                      d_state->domain_dn, &res, attrs,
1948                                      "(objectSid=%s)", 
1949                                      ldap_encode_ndr_dom_sid(mem_ctx, sid));
1950                 if (count != 1) {
1951                         names[i].string = NULL;
1952                         status = STATUS_SOME_UNMAPPED;
1953                         continue;
1954                 }
1955
1956                 names[i].string = samdb_result_string(res[0], "sAMAccountName",
1957                                                       NULL);
1958
1959                 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1960                 if (atype == 0) {
1961                         status = STATUS_SOME_UNMAPPED;
1962                         continue;
1963                 }
1964
1965                 ids[i] = samdb_atype_map(atype);
1966                 
1967                 if (ids[i] == SID_NAME_UNKNOWN) {
1968                         status = STATUS_SOME_UNMAPPED;
1969                         continue;
1970                 }
1971         }
1972
1973         r->out.names->names = names;
1974         r->out.names->count = r->in.num_rids;
1975
1976         r->out.types->ids = ids;
1977         r->out.types->count = r->in.num_rids;
1978
1979         return status;
1980 }
1981
1982
1983 /* 
1984   samr_OpenGroup 
1985 */
1986 static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1987                        struct samr_OpenGroup *r)
1988 {
1989         struct samr_domain_state *d_state;
1990         struct samr_account_state *a_state;
1991         struct dcesrv_handle *h;
1992         const char *groupname;
1993         struct dom_sid *sid;
1994         struct ldb_message **msgs;
1995         struct dcesrv_handle *g_handle;
1996         const char * const attrs[2] = { "sAMAccountName", NULL };
1997         int ret;
1998
1999         ZERO_STRUCTP(r->out.group_handle);
2000
2001         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2002
2003         d_state = h->data;
2004
2005         /* form the group SID */
2006         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2007         if (!sid) {
2008                 return NT_STATUS_NO_MEMORY;
2009         }
2010
2011         /* search for the group record */
2012         ret = gendb_search(d_state->sam_ctx,
2013                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2014                            "(&(objectSid=%s)(objectclass=group)"
2015                            "(grouptype=%d))",
2016                            ldap_encode_ndr_dom_sid(mem_ctx, sid),
2017                            GTYPE_SECURITY_GLOBAL_GROUP);
2018         if (ret == 0) {
2019                 return NT_STATUS_NO_SUCH_GROUP;
2020         }
2021         if (ret != 1) {
2022                 DEBUG(0,("Found %d records matching sid %s\n", 
2023                          ret, dom_sid_string(mem_ctx, sid)));
2024                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2025         }
2026
2027         groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2028         if (groupname == NULL) {
2029                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2030                          dom_sid_string(mem_ctx, sid)));
2031                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2032         }
2033
2034         a_state = talloc(d_state, struct samr_account_state);
2035         if (!a_state) {
2036                 return NT_STATUS_NO_MEMORY;
2037         }
2038         a_state->sam_ctx = d_state->sam_ctx;
2039         a_state->access_mask = r->in.access_mask;
2040         a_state->domain_state = talloc_reference(a_state, d_state);
2041         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2042         a_state->account_sid = talloc_steal(a_state, sid);
2043         a_state->account_name = talloc_strdup(a_state, groupname);
2044         if (!a_state->account_name) {
2045                 return NT_STATUS_NO_MEMORY;
2046         }
2047
2048         /* create the policy handle */
2049         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
2050         if (!g_handle) {
2051                 return NT_STATUS_NO_MEMORY;
2052         }
2053
2054         g_handle->data = talloc_steal(g_handle, a_state);
2055
2056         *r->out.group_handle = g_handle->wire_handle;
2057
2058         return NT_STATUS_OK;
2059 }
2060
2061 /* 
2062   samr_QueryGroupInfo 
2063 */
2064 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2065                        struct samr_QueryGroupInfo *r)
2066 {
2067         struct dcesrv_handle *h;
2068         struct samr_account_state *a_state;
2069         struct ldb_message *msg;
2070         struct ldb_result *res;
2071         const char * const attrs[4] = { "sAMAccountName", "description",
2072                                         "numMembers", NULL };
2073         int ret;
2074         union samr_GroupInfo *info;
2075
2076         *r->out.info = NULL;
2077
2078         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2079
2080         a_state = h->data;
2081         
2082         ret = ldb_search(a_state->sam_ctx, mem_ctx, &res, a_state->account_dn, LDB_SCOPE_SUBTREE, attrs, "objectClass=*");
2083         
2084         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2085                 return NT_STATUS_NO_SUCH_GROUP;
2086         } else if (ret != LDB_SUCCESS) {
2087                 DEBUG(2, ("Error reading group info: %s\n", ldb_errstring(a_state->sam_ctx)));
2088                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2089         }
2090
2091         if (res->count != 1) {
2092                 DEBUG(2, ("Error finding group info, got %d entries\n", res->count));
2093                 
2094                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2095         }
2096         msg = res->msgs[0];
2097
2098         /* allocate the info structure */
2099         info = talloc_zero(mem_ctx, union samr_GroupInfo);
2100         if (info == NULL) {
2101                 return NT_STATUS_NO_MEMORY;
2102         }
2103
2104         /* Fill in the level */
2105         switch (r->in.level) {
2106         case GROUPINFOALL:
2107                 QUERY_STRING(msg, all.name,        "sAMAccountName");
2108                 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2109                 QUERY_UINT  (msg, all.num_members,      "numMembers")
2110                 QUERY_STRING(msg, all.description, "description");
2111                 break;
2112         case GROUPINFONAME:
2113                 QUERY_STRING(msg, name,            "sAMAccountName");
2114                 break;
2115         case GROUPINFOATTRIBUTES:
2116                 info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2117                 break;
2118         case GROUPINFODESCRIPTION:
2119                 QUERY_STRING(msg, description, "description");
2120                 break;
2121         case GROUPINFOALL2:
2122                 QUERY_STRING(msg, all2.name,        "sAMAccountName");
2123                 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2124                 QUERY_UINT  (msg, all2.num_members,      "numMembers")
2125                 QUERY_STRING(msg, all2.description, "description");
2126                 break;
2127         default:
2128                 talloc_free(info);
2129                 return NT_STATUS_INVALID_INFO_CLASS;
2130         }
2131
2132         *r->out.info = info;
2133
2134         return NT_STATUS_OK;
2135 }
2136
2137
2138 /* 
2139   samr_SetGroupInfo 
2140 */
2141 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2142                                   struct samr_SetGroupInfo *r)
2143 {
2144         struct dcesrv_handle *h;
2145         struct samr_account_state *g_state;
2146         struct ldb_message *msg;
2147         struct ldb_context *sam_ctx;
2148         int ret;
2149
2150         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2151
2152         g_state = h->data;
2153         sam_ctx = g_state->sam_ctx;
2154
2155         msg = ldb_msg_new(mem_ctx);
2156         if (msg == NULL) {
2157                 return NT_STATUS_NO_MEMORY;
2158         }       
2159
2160         msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
2161         if (!msg->dn) {
2162                 return NT_STATUS_NO_MEMORY;
2163         }
2164
2165         switch (r->in.level) {
2166         case GROUPINFODESCRIPTION:
2167                 SET_STRING(msg, description,         "description");
2168                 break;
2169         case GROUPINFONAME:
2170                 /* On W2k3 this does not change the name, it changes the
2171                  * sAMAccountName attribute */
2172                 SET_STRING(msg, name,                "sAMAccountName");
2173                 break;
2174         case GROUPINFOATTRIBUTES:
2175                 /* This does not do anything obviously visible in W2k3 LDAP */
2176                 return NT_STATUS_OK;
2177         default:
2178                 return NT_STATUS_INVALID_INFO_CLASS;
2179         }
2180
2181         /* modify the samdb record */
2182         ret = ldb_modify(g_state->sam_ctx, msg);
2183         if (ret != 0) {
2184                 /* we really need samdb.c to return NTSTATUS */
2185                 return NT_STATUS_UNSUCCESSFUL;
2186         }
2187
2188         return NT_STATUS_OK;
2189 }
2190
2191
2192 /* 
2193   samr_AddGroupMember 
2194 */
2195 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2196                        struct samr_AddGroupMember *r)
2197 {
2198         struct dcesrv_handle *h;
2199         struct samr_account_state *a_state;
2200         struct samr_domain_state *d_state;
2201         struct ldb_message *mod;
2202         struct dom_sid *membersid;
2203         const char *memberdn;
2204         struct ldb_result *res;
2205         const char * const attrs[] = { NULL };
2206         int ret;
2207
2208         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2209
2210         a_state = h->data;
2211         d_state = a_state->domain_state;
2212
2213         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2214         if (membersid == NULL)
2215                 return NT_STATUS_NO_MEMORY;
2216
2217         /* In native mode, AD can also nest domain groups. Not sure yet
2218          * whether this is also available via RPC. */
2219         ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2220                                  d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2221                                  "(&(objectSid=%s)(objectclass=user))",
2222                                  ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2223
2224         if (ret != 0) {
2225                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2226         }
2227
2228         if (res->count == 0) {
2229                 return NT_STATUS_NO_SUCH_USER;
2230         }
2231                 
2232         if (res->count > 1) {
2233                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2234         }
2235
2236         memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2237
2238         if (memberdn == NULL)
2239                 return NT_STATUS_NO_MEMORY;
2240
2241         mod = ldb_msg_new(mem_ctx);
2242         if (mod == NULL) {
2243                 return NT_STATUS_NO_MEMORY;
2244         }
2245
2246         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2247
2248         if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2249                                  memberdn) != 0)
2250                 return NT_STATUS_UNSUCCESSFUL;
2251
2252         ret = ldb_modify(a_state->sam_ctx, mod);
2253         switch (ret) {
2254         case LDB_SUCCESS:
2255                 return NT_STATUS_OK;
2256         case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
2257                 return NT_STATUS_MEMBER_IN_GROUP;
2258         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2259                 return NT_STATUS_ACCESS_DENIED;
2260         default:
2261                 return NT_STATUS_UNSUCCESSFUL;
2262         }
2263
2264 }
2265
2266
2267 /* 
2268   samr_DeleteDomainGroup 
2269 */
2270 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2271                        struct samr_DeleteDomainGroup *r)
2272 {
2273         struct dcesrv_handle *h;
2274         struct samr_account_state *a_state;
2275         int ret;
2276
2277         *r->out.group_handle = *r->in.group_handle;
2278
2279         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2280
2281         a_state = h->data;
2282
2283         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2284         if (ret != 0) {
2285                 return NT_STATUS_UNSUCCESSFUL;
2286         }
2287
2288         ZERO_STRUCTP(r->out.group_handle);
2289
2290         return NT_STATUS_OK;
2291 }
2292
2293
2294 /* 
2295   samr_DeleteGroupMember 
2296 */
2297 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2298                        struct samr_DeleteGroupMember *r)
2299 {
2300         struct dcesrv_handle *h;
2301         struct samr_account_state *a_state;
2302         struct samr_domain_state *d_state;
2303         struct ldb_message *mod;
2304         struct dom_sid *membersid;
2305         const char *memberdn;
2306         struct ldb_result *res;
2307         const char * const attrs[] = { NULL };
2308         int ret;
2309
2310         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2311
2312         a_state = h->data;
2313         d_state = a_state->domain_state;
2314
2315         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2316         if (membersid == NULL)
2317                 return NT_STATUS_NO_MEMORY;
2318
2319         /* In native mode, AD can also nest domain groups. Not sure yet
2320          * whether this is also available via RPC. */
2321         ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2322                                  d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2323                                  "(&(objectSid=%s)(objectclass=user))",
2324                                  ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2325
2326         if (ret != 0) {
2327                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2328         }
2329
2330         if (res->count == 0) {
2331                 return NT_STATUS_NO_SUCH_USER;
2332         }
2333                 
2334         if (res->count > 1) {
2335                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2336         }
2337
2338         memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2339
2340         if (memberdn == NULL)
2341                 return NT_STATUS_NO_MEMORY;
2342
2343         mod = ldb_msg_new(mem_ctx);
2344         if (mod == NULL) {
2345                 return NT_STATUS_NO_MEMORY;
2346         }
2347
2348         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2349
2350         if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2351                                  memberdn) != 0) {
2352                 return NT_STATUS_NO_MEMORY;
2353         }
2354
2355         ret = ldb_modify(a_state->sam_ctx, mod);
2356         switch (ret) {
2357         case LDB_SUCCESS:
2358                 return NT_STATUS_OK;
2359         case LDB_ERR_NO_SUCH_ATTRIBUTE:
2360                 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2361         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2362                 return NT_STATUS_ACCESS_DENIED;
2363         default:
2364                 return NT_STATUS_UNSUCCESSFUL;
2365         }
2366
2367 }
2368
2369
2370 /* 
2371   samr_QueryGroupMember 
2372 */
2373 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2374                                       struct samr_QueryGroupMember *r)
2375 {
2376         struct dcesrv_handle *h;
2377         struct samr_account_state *a_state;
2378         struct ldb_message **res;
2379         struct ldb_message_element *el;
2380         struct samr_RidTypeArray *array;
2381         const char * const attrs[2] = { "member", NULL };
2382         int ret;
2383
2384         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2385
2386         a_state = h->data;
2387
2388         /* pull the member attribute */
2389         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2390                               a_state->account_dn, &res, attrs);
2391
2392         if (ret != 1) {
2393                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2394         }
2395
2396         array = talloc(mem_ctx, struct samr_RidTypeArray);
2397
2398         if (array == NULL)
2399                 return NT_STATUS_NO_MEMORY;
2400
2401         ZERO_STRUCTP(array);
2402
2403         el = ldb_msg_find_element(res[0], "member");
2404
2405         if (el != NULL) {
2406                 int i;
2407
2408                 array->count = el->num_values;
2409
2410                 array->rids = talloc_array(mem_ctx, uint32_t,
2411                                              el->num_values);
2412                 if (array->rids == NULL)
2413                         return NT_STATUS_NO_MEMORY;
2414
2415                 array->types = talloc_array(mem_ctx, uint32_t,
2416                                             el->num_values);
2417                 if (array->types == NULL)
2418                         return NT_STATUS_NO_MEMORY;
2419
2420                 for (i=0; i<el->num_values; i++) {
2421                         struct ldb_message **res2;
2422                         const char * const attrs2[2] = { "objectSid", NULL };
2423                         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2424                                            ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2425                                            &res2, attrs2);
2426                         if (ret != 1)
2427                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2428
2429                         array->rids[i] =
2430                                 samdb_result_rid_from_sid(mem_ctx, res2[0],
2431                                                           "objectSid", 0);
2432
2433                         if (array->rids[i] == 0)
2434                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2435
2436                         array->types[i] = 7; /* RID type of some kind, not sure what the value means. */
2437                 }
2438         }
2439
2440         *r->out.rids = array;
2441
2442         return NT_STATUS_OK;
2443 }
2444
2445
2446 /* 
2447   samr_SetMemberAttributesOfGroup 
2448 */
2449 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2450                        struct samr_SetMemberAttributesOfGroup *r)
2451 {
2452         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2453 }
2454
2455
2456 /* 
2457   samr_OpenAlias 
2458 */
2459 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2460                        struct samr_OpenAlias *r)
2461 {
2462         struct samr_domain_state *d_state;
2463         struct samr_account_state *a_state;
2464         struct dcesrv_handle *h;
2465         const char *alias_name;
2466         struct dom_sid *sid;
2467         struct ldb_message **msgs;
2468         struct dcesrv_handle *g_handle;
2469         const char * const attrs[2] = { "sAMAccountName", NULL };
2470         int ret;
2471
2472         ZERO_STRUCTP(r->out.alias_handle);
2473
2474         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2475
2476         d_state = h->data;
2477
2478         /* form the alias SID */
2479         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2480         if (sid == NULL)
2481                 return NT_STATUS_NO_MEMORY;
2482
2483         /* search for the group record */
2484         ret = gendb_search(d_state->sam_ctx,
2485                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2486                            "(&(objectSid=%s)(objectclass=group)"
2487                            "(|(grouptype=%d)(grouptype=%d)))",
2488                            ldap_encode_ndr_dom_sid(mem_ctx, sid),
2489                            GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2490                            GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2491         if (ret == 0) {
2492                 return NT_STATUS_NO_SUCH_ALIAS;
2493         }
2494         if (ret != 1) {
2495                 DEBUG(0,("Found %d records matching sid %s\n", 
2496                          ret, dom_sid_string(mem_ctx, sid)));
2497                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2498         }
2499
2500         alias_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2501         if (alias_name == NULL) {
2502                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2503                          dom_sid_string(mem_ctx, sid)));
2504                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2505         }
2506
2507         a_state = talloc(d_state, struct samr_account_state);
2508         if (!a_state) {
2509                 return NT_STATUS_NO_MEMORY;
2510         }
2511         a_state->sam_ctx = d_state->sam_ctx;
2512         a_state->access_mask = r->in.access_mask;
2513         a_state->domain_state = talloc_reference(a_state, d_state);
2514         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2515         a_state->account_sid = talloc_steal(a_state, sid);
2516         a_state->account_name = talloc_strdup(a_state, alias_name);
2517         if (!a_state->account_name) {
2518                 return NT_STATUS_NO_MEMORY;
2519         }
2520
2521         /* create the policy handle */
2522         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2523         if (!g_handle) {
2524                 return NT_STATUS_NO_MEMORY;
2525         }
2526
2527         g_handle->data = talloc_steal(g_handle, a_state);
2528
2529         *r->out.alias_handle = g_handle->wire_handle;
2530
2531         return NT_STATUS_OK;
2532 }
2533
2534
2535 /* 
2536   samr_QueryAliasInfo 
2537 */
2538 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2539                        struct samr_QueryAliasInfo *r)
2540 {
2541         struct dcesrv_handle *h;
2542         struct samr_account_state *a_state;
2543         struct ldb_message *msg, **res;
2544         const char * const attrs[4] = { "sAMAccountName", "description",
2545                                         "numMembers", NULL };
2546         int ret;
2547         union samr_AliasInfo *info;
2548
2549         *r->out.info = NULL;
2550
2551         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2552
2553         a_state = h->data;
2554
2555         /* pull all the alias attributes */
2556         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2557                               a_state->account_dn ,&res, attrs);
2558         if (ret != 1) {
2559                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2560         }
2561         msg = res[0];
2562
2563         /* allocate the info structure */
2564         info = talloc_zero(mem_ctx, union samr_AliasInfo);
2565         if (info == NULL) {
2566                 return NT_STATUS_NO_MEMORY;
2567         }
2568
2569         switch(r->in.level) {
2570         case ALIASINFOALL:
2571                 QUERY_STRING(msg, all.name, "sAMAccountName");
2572                 QUERY_UINT  (msg, all.num_members, "numMembers");
2573                 QUERY_STRING(msg, all.description, "description");
2574                 break;
2575         case ALIASINFONAME:
2576                 QUERY_STRING(msg, name, "sAMAccountName");
2577                 break;
2578         case ALIASINFODESCRIPTION:
2579                 QUERY_STRING(msg, description, "description");
2580                 break;
2581         default:
2582                 talloc_free(info);
2583                 return NT_STATUS_INVALID_INFO_CLASS;
2584         }
2585
2586         *r->out.info = info;
2587
2588         return NT_STATUS_OK;
2589 }
2590
2591
2592 /* 
2593   samr_SetAliasInfo 
2594 */
2595 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2596                        struct samr_SetAliasInfo *r)
2597 {
2598         struct dcesrv_handle *h;
2599         struct samr_account_state *a_state;
2600         struct ldb_message *msg;
2601         struct ldb_context *sam_ctx;
2602         int ret;
2603
2604         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2605
2606         a_state = h->data;
2607         sam_ctx = a_state->sam_ctx;
2608
2609         msg = ldb_msg_new(mem_ctx);
2610         if (msg == NULL) {
2611                 return NT_STATUS_NO_MEMORY;
2612         }
2613
2614         msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2615         if (!msg->dn) {
2616                 return NT_STATUS_NO_MEMORY;
2617         }
2618
2619         switch (r->in.level) {
2620         case ALIASINFODESCRIPTION:
2621                 SET_STRING(msg, description,         "description");
2622                 break;
2623         case ALIASINFONAME:
2624                 /* On W2k3 this does not change the name, it changes the
2625                  * sAMAccountName attribute */
2626                 SET_STRING(msg, name,                "sAMAccountName");
2627                 break;
2628         default:
2629                 return NT_STATUS_INVALID_INFO_CLASS;
2630         }
2631
2632         /* modify the samdb record */
2633         ret = ldb_modify(a_state->sam_ctx, msg);
2634         if (ret != 0) {
2635                 /* we really need samdb.c to return NTSTATUS */
2636                 return NT_STATUS_UNSUCCESSFUL;
2637         }
2638
2639         return NT_STATUS_OK;
2640 }
2641
2642
2643 /* 
2644   samr_DeleteDomAlias 
2645 */
2646 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2647                        struct samr_DeleteDomAlias *r)
2648 {
2649         struct dcesrv_handle *h;
2650         struct samr_account_state *a_state;
2651         int ret;
2652
2653         *r->out.alias_handle = *r->in.alias_handle;
2654
2655         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2656
2657         a_state = h->data;
2658
2659         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2660         if (ret != 0) {
2661                 return NT_STATUS_UNSUCCESSFUL;
2662         }
2663
2664         ZERO_STRUCTP(r->out.alias_handle);
2665
2666         return NT_STATUS_OK;
2667 }
2668
2669
2670 /* 
2671   samr_AddAliasMember 
2672 */
2673 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2674                        struct samr_AddAliasMember *r)
2675 {
2676         struct dcesrv_handle *h;
2677         struct samr_account_state *a_state;
2678         struct samr_domain_state *d_state;
2679         struct ldb_message *mod;
2680         struct ldb_message **msgs;
2681         const char * const attrs[] = { NULL };
2682         struct ldb_dn *memberdn = NULL;
2683         int ret;
2684         NTSTATUS status;
2685
2686         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2687
2688         a_state = h->data;
2689         d_state = a_state->domain_state;
2690
2691         ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2692                            &msgs, attrs, "(objectsid=%s)", 
2693                            ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2694
2695         if (ret == 1) {
2696                 memberdn = msgs[0]->dn;
2697         } else  if (ret > 1) {
2698                 DEBUG(0,("Found %d records matching sid %s\n", 
2699                          ret, dom_sid_string(mem_ctx, r->in.sid)));
2700                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2701         } else if (ret == 0) {
2702                 status = samdb_create_foreign_security_principal(d_state->sam_ctx, mem_ctx, 
2703                                                                  r->in.sid, &memberdn);
2704                 if (!NT_STATUS_IS_OK(status)) {
2705                         return status;
2706                 }
2707         } else {
2708                 DEBUG(0, ("samdb_search returned %d: %s\n", ret, ldb_errstring(d_state->sam_ctx)));
2709         }
2710
2711         if (memberdn == NULL) {
2712                 DEBUG(0, ("Could not find memberdn\n"));
2713                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2714         }
2715
2716         mod = ldb_msg_new(mem_ctx);
2717         if (mod == NULL) {
2718                 return NT_STATUS_NO_MEMORY;
2719         }
2720
2721         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2722
2723         if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2724                                  ldb_dn_alloc_linearized(mem_ctx, memberdn)) != 0)
2725                 return NT_STATUS_UNSUCCESSFUL;
2726
2727         if (ldb_modify(a_state->sam_ctx, mod) != 0)
2728                 return NT_STATUS_UNSUCCESSFUL;
2729
2730         return NT_STATUS_OK;
2731 }
2732
2733
2734 /* 
2735   samr_DeleteAliasMember 
2736 */
2737 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2738                        struct samr_DeleteAliasMember *r)
2739 {
2740         struct dcesrv_handle *h;
2741         struct samr_account_state *a_state;
2742         struct samr_domain_state *d_state;
2743         struct ldb_message *mod;
2744         const char *memberdn;
2745
2746         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2747
2748         a_state = h->data;
2749         d_state = a_state->domain_state;
2750
2751         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2752                                        "distinguishedName", "(objectSid=%s)", 
2753                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2754
2755         if (memberdn == NULL)
2756                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
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         if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2766                                  memberdn) != 0)
2767                 return NT_STATUS_UNSUCCESSFUL;
2768
2769         if (ldb_modify(a_state->sam_ctx, mod) != 0)
2770                 return NT_STATUS_UNSUCCESSFUL;
2771
2772         return NT_STATUS_OK;
2773 }
2774
2775
2776 /* 
2777   samr_GetMembersInAlias 
2778 */
2779 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2780                        struct samr_GetMembersInAlias *r)
2781 {
2782         struct dcesrv_handle *h;
2783         struct samr_account_state *a_state;
2784         struct samr_domain_state *d_state;
2785         struct ldb_message **msgs;
2786         struct lsa_SidPtr *sids;
2787         struct ldb_message_element *el;
2788         const char * const attrs[2] = { "member", NULL};
2789         int ret;
2790
2791         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2792
2793         a_state = h->data;
2794         d_state = a_state->domain_state;
2795
2796         ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
2797                               a_state->account_dn, &msgs, attrs);
2798
2799         if (ret == -1) {
2800                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2801         } else if (ret == 0) {
2802                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2803         } else if (ret != 1) {
2804                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2805         }
2806
2807         r->out.sids->num_sids = 0;
2808         r->out.sids->sids = NULL;
2809
2810         el = ldb_msg_find_element(msgs[0], "member");
2811
2812         if (el != NULL) {
2813                 int i;
2814
2815                 sids = talloc_array(mem_ctx, struct lsa_SidPtr,
2816                                       el->num_values);
2817
2818                 if (sids == NULL)
2819                         return NT_STATUS_NO_MEMORY;
2820
2821                 for (i=0; i<el->num_values; i++) {
2822                         struct ldb_message **msgs2;
2823                         const char * const attrs2[2] = { "objectSid", NULL };
2824                         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2825                                               ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2826                                               &msgs2, attrs2);
2827                         if (ret != 1)
2828                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2829
2830                         sids[i].sid = samdb_result_dom_sid(mem_ctx, msgs2[0],
2831                                                            "objectSid");
2832
2833                         if (sids[i].sid == NULL)
2834                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2835                 }
2836                 r->out.sids->num_sids = el->num_values;
2837                 r->out.sids->sids = sids;
2838         }
2839
2840         return NT_STATUS_OK;
2841 }
2842
2843 /* 
2844   samr_OpenUser 
2845 */
2846 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2847                               struct samr_OpenUser *r)
2848 {
2849         struct samr_domain_state *d_state;
2850         struct samr_account_state *a_state;
2851         struct dcesrv_handle *h;
2852         const char *account_name;
2853         struct dom_sid *sid;
2854         struct ldb_message **msgs;
2855         struct dcesrv_handle *u_handle;
2856         const char * const attrs[2] = { "sAMAccountName", NULL };
2857         int ret;
2858
2859         ZERO_STRUCTP(r->out.user_handle);
2860
2861         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2862
2863         d_state = h->data;
2864
2865         /* form the users SID */
2866         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2867         if (!sid) {
2868                 return NT_STATUS_NO_MEMORY;
2869         }
2870
2871         /* search for the user record */
2872         ret = gendb_search(d_state->sam_ctx,
2873                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2874                            "(&(objectSid=%s)(objectclass=user))", 
2875                            ldap_encode_ndr_dom_sid(mem_ctx, sid));
2876         if (ret == 0) {
2877                 return NT_STATUS_NO_SUCH_USER;
2878         }
2879         if (ret != 1) {
2880                 DEBUG(0,("Found %d records matching sid %s\n", ret, 
2881                          dom_sid_string(mem_ctx, sid)));
2882                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2883         }
2884
2885         account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2886         if (account_name == NULL) {
2887                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2888                          dom_sid_string(mem_ctx, sid)));
2889                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2890         }
2891
2892         a_state = talloc(mem_ctx, struct samr_account_state);
2893         if (!a_state) {
2894                 return NT_STATUS_NO_MEMORY;
2895         }
2896         a_state->sam_ctx = d_state->sam_ctx;
2897         a_state->access_mask = r->in.access_mask;
2898         a_state->domain_state = talloc_reference(a_state, d_state);
2899         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2900         a_state->account_sid = talloc_steal(a_state, sid);
2901         a_state->account_name = talloc_strdup(a_state, account_name);
2902         if (!a_state->account_name) {
2903                 return NT_STATUS_NO_MEMORY;
2904         }
2905
2906         /* create the policy handle */
2907         u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2908         if (!u_handle) {
2909                 return NT_STATUS_NO_MEMORY;
2910         }
2911
2912         u_handle->data = talloc_steal(u_handle, a_state);
2913
2914         *r->out.user_handle = u_handle->wire_handle;
2915
2916         return NT_STATUS_OK;
2917
2918 }
2919
2920
2921 /* 
2922   samr_DeleteUser 
2923 */
2924 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2925                                 struct samr_DeleteUser *r)
2926 {
2927         struct dcesrv_handle *h;
2928         struct samr_account_state *a_state;
2929         int ret;
2930
2931         *r->out.user_handle = *r->in.user_handle;
2932
2933         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2934
2935         a_state = h->data;
2936
2937         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2938         if (ret != 0) {
2939                 DEBUG(1, ("Failed to delete user: %s: %s\n", 
2940                           ldb_dn_get_linearized(a_state->account_dn), 
2941                           ldb_errstring(a_state->sam_ctx)));
2942                 return NT_STATUS_UNSUCCESSFUL;
2943         }
2944
2945         ZERO_STRUCTP(r->out.user_handle);
2946
2947         return NT_STATUS_OK;
2948 }
2949
2950
2951 /* 
2952   samr_QueryUserInfo 
2953 */
2954 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2955                                    struct samr_QueryUserInfo *r)
2956 {
2957         struct dcesrv_handle *h;
2958         struct samr_account_state *a_state;
2959         struct ldb_message *msg, **res;
2960         int ret;
2961         struct ldb_context *sam_ctx;
2962
2963         const char * const *attrs = NULL;
2964         union samr_UserInfo *info;
2965
2966         *r->out.info = NULL;
2967
2968         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2969
2970         a_state = h->data;
2971         sam_ctx = a_state->sam_ctx;
2972
2973         /* fill in the reply */
2974         switch (r->in.level) {
2975         case 1:
2976         {
2977                 static const char * const attrs2[] = {"sAMAccountName", "displayName",
2978                                                       "primaryroupID", "description",
2979                                                       "comment", NULL};
2980                 attrs = attrs2;
2981                 break;
2982         }
2983         case 2:
2984         {
2985                 static const char * const attrs2[] = {"comment", "countryCode", "codePage", NULL};
2986                 attrs = attrs2;
2987                 break;
2988         }
2989         case 3:
2990         {
2991                 static const char * const attrs2[] = {"sAMAccountName",
2992                                                       "displayName",
2993                                                       "objectSid",
2994                                                       "primaryGroupID",
2995                                                       "homeDirectory",
2996                                                       "homeDrive",
2997                                                       "scriptPath",
2998                                                       "profilePath",
2999                                                       "userWorkstations",
3000                                                       "lastLogon",
3001                                                       "lastLogoff",
3002                                                       "pwdLastSet",
3003                                                       "logonHours",
3004                                                       "badPwdCount",
3005                                                       "logonCount",
3006                                                       "userAccountControl", NULL};
3007                 attrs = attrs2;
3008                 break;
3009         }
3010         case 4:
3011         {
3012                 static const char * const attrs2[] = {"logonHours", NULL};
3013                 attrs = attrs2;
3014                 break;
3015         }
3016         case 5:
3017         {
3018                 static const char * const attrs2[] = {"sAMAccountName", 
3019                                                       "displayName",
3020                                                       "objectSid",
3021                                                       "primaryGroupID",
3022                                                       "homeDirectory",
3023                                                       "homeDrive",
3024                                                       "scriptPath", 
3025                                                       "profilePath",
3026                                                       "description",
3027                                                       "userWorkstations",
3028                                                       "lastLogon",
3029                                                       "lastLogoff",
3030                                                       "logonHours",
3031                                                       "badPwdCount",
3032                                                       "logonCount",
3033                                                       "pwdLastSet",
3034                                                       "accountExpires",
3035                                                       "userAccountControl",
3036                                                       NULL};
3037                 attrs = attrs2;
3038                 break;
3039         }
3040         case 6:
3041         {
3042                 static const char * const attrs2[] = {"sAMAccountName", "displayName", NULL};
3043                 attrs = attrs2;
3044                 break;
3045         }
3046         case 7:
3047         {
3048                 static const char * const attrs2[] = {"sAMAccountName", NULL};
3049                 attrs = attrs2;
3050                 break;
3051         }
3052         case 8:
3053         {
3054                 static const char * const attrs2[] = {"displayName", NULL};
3055                 attrs = attrs2;
3056                 break;
3057         }
3058         case 9:
3059         {
3060                 static const char * const attrs2[] = {"primaryGroupID", NULL};
3061                 attrs = attrs2;
3062                 break;
3063         }
3064         case 10:
3065         {
3066                 static const char * const attrs2[] = {"homeDirectory", "homeDrive", NULL};
3067                 attrs = attrs2;
3068                 break;
3069         }
3070         case 11:
3071         {
3072                 static const char * const attrs2[] = {"scriptPath", NULL};
3073                 attrs = attrs2;
3074                 break;
3075         }
3076         case 12:
3077         {
3078                 static const char * const attrs2[] = {"profilePath", NULL};
3079                 attrs = attrs2;
3080                 break;
3081         }
3082         case 13:
3083         {
3084                 static const char * const attrs2[] = {"description", NULL};
3085                 attrs = attrs2;
3086                 break;
3087         }
3088         case 14:
3089         {
3090                 static const char * const attrs2[] = {"userWorkstations", NULL};
3091                 attrs = attrs2;
3092                 break;
3093         }
3094         case 16:
3095         {
3096                 static const char * const attrs2[] = {"userAccountControl", "pwdLastSet", NULL};
3097                 attrs = attrs2;