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