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