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