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