r12427: Move SAMR CreateUser2 to transactions, and re-add support for
[samba.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   TODO: This should do some form of locking, especially around the rid allocation
710 */
711 static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
712                                  struct samr_CreateUser2 *r)
713 {
714         struct samr_domain_state *d_state;
715         struct samr_account_state *a_state;
716         struct dcesrv_handle *h;
717         const char *name;
718         struct ldb_message *msg;
719         struct dom_sid *sid;
720         const char *account_name;
721         struct dcesrv_handle *u_handle;
722         int ret;
723         const char *container, *obj_class=NULL;
724         char *cn_name;
725         int cn_name_len;
726
727         const char *attrs[] = {
728                 "objectSid", 
729                 "userAccountControl",
730                 NULL
731         };
732
733         uint32_t user_account_control;
734
735         struct ldb_message **msgs;
736
737         ZERO_STRUCTP(r->out.user_handle);
738         *r->out.access_granted = 0;
739         *r->out.rid = 0;
740
741         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
742
743         d_state = h->data;
744
745         account_name = r->in.account_name->string;
746
747         if (account_name == NULL) {
748                 return NT_STATUS_INVALID_PARAMETER;
749         }
750
751         ret = ldb_transaction_start(d_state->sam_ctx);
752         if (ret != 0) {
753                 DEBUG(0,("Failed to start a transaction for user creation\n"));
754                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
755         }
756
757         /* check if the user already exists */
758         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL, 
759                                    "sAMAccountName", 
760                                    "(&(sAMAccountName=%s)(objectclass=user))", 
761                                    ldb_binary_encode_string(mem_ctx, account_name));
762         if (name != NULL) {
763                 ldb_transaction_cancel(d_state->sam_ctx);
764                 return NT_STATUS_USER_EXISTS;
765         }
766
767         msg = ldb_msg_new(mem_ctx);
768         if (msg == NULL) {
769                 ldb_transaction_cancel(d_state->sam_ctx);
770                 return NT_STATUS_NO_MEMORY;
771         }
772
773         cn_name   = talloc_strdup(mem_ctx, account_name);
774         NT_STATUS_HAVE_NO_MEMORY(cn_name);
775         cn_name_len = strlen(cn_name);
776
777         /* This must be one of these values *only* */
778         if (r->in.acct_flags == ACB_NORMAL) {
779                 container = "Users";
780                 obj_class = "user";
781
782         } else if (r->in.acct_flags == ACB_WSTRUST) {
783                 if (cn_name[cn_name_len - 1] != '$') {
784                         return NT_STATUS_FOOBAR;
785                 }
786                 cn_name[cn_name_len - 1] = '\0';
787                 container = "Computers";
788                 obj_class = "computer";
789
790         } else if (r->in.acct_flags == ACB_SVRTRUST) {
791                 if (cn_name[cn_name_len - 1] != '$') {
792                         return NT_STATUS_FOOBAR;                
793                 }
794                 cn_name[cn_name_len - 1] = '\0';
795                 container = "Domain Controllers";
796                 obj_class = "computer";
797
798         } else if (r->in.acct_flags == ACB_DOMTRUST) {
799                 container = "Users";
800                 obj_class = "user";
801
802         } else {
803                 ldb_transaction_cancel(d_state->sam_ctx);
804                 return NT_STATUS_INVALID_PARAMETER;
805         }
806
807         /* add core elements to the ldb_message for the user */
808         msg->dn = ldb_dn_build_child(mem_ctx, "CN", cn_name, ldb_dn_build_child(mem_ctx, "CN", container, d_state->domain_dn));
809         if (!msg->dn) {
810                 ldb_transaction_cancel(d_state->sam_ctx);
811                 return NT_STATUS_NO_MEMORY;             
812         }
813         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", account_name);
814         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", obj_class);
815         
816         /* Start a transaction, so we can query and do a subsequent atomic modify */
817         
818         /* create the user */
819         ret = samdb_add(d_state->sam_ctx, mem_ctx, msg);
820         if (ret != 0) {
821                 ldb_transaction_cancel(d_state->sam_ctx);
822                 DEBUG(0,("Failed to create user record %s\n",
823                          ldb_dn_linearize(mem_ctx, msg->dn)));
824                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
825         }
826
827         a_state = talloc(d_state, struct samr_account_state);
828         if (!a_state) {
829                 ldb_transaction_cancel(d_state->sam_ctx);
830                 return NT_STATUS_NO_MEMORY;
831         }
832         a_state->sam_ctx = d_state->sam_ctx;
833         a_state->access_mask = r->in.access_mask;
834         a_state->domain_state = talloc_reference(a_state, d_state);
835         a_state->account_dn = talloc_steal(a_state, msg->dn);
836
837         /* retrieve the sid and account control bits for the user just created */
838         ret = gendb_search_dn(d_state->sam_ctx, a_state,
839                               msg->dn, &msgs, attrs);
840
841         if (ret != 1) {
842                 ldb_transaction_cancel(d_state->sam_ctx);
843                 DEBUG(0,("Apparently we failed to create an account record, as %s now doesn't exist\n",
844                          ldb_dn_linearize(mem_ctx, msg->dn)));
845                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
846         }
847         sid = samdb_result_dom_sid(mem_ctx, msgs[0], "objectSid");
848         if (sid == NULL) {
849                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
850         }
851
852         user_account_control = samdb_result_uint(msgs[0], "userAccountControl", 0);
853         user_account_control = (user_account_control & ~(UF_NORMAL_ACCOUNT|UF_INTERDOMAIN_TRUST_ACCOUNT|UF_WORKSTATION_TRUST_ACCOUNT|UF_SERVER_TRUST_ACCOUNT));
854         user_account_control |= samdb_acb2uf(r->in.acct_flags);
855
856         talloc_free(msg);
857         msg = ldb_msg_new(mem_ctx);
858         if (msg == NULL) {
859                 ldb_transaction_cancel(d_state->sam_ctx);
860                 return NT_STATUS_NO_MEMORY;
861         }
862
863         msg->dn = a_state->account_dn;
864
865         if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, msg, 
866                                "userAccountControl", 
867                                user_account_control) != 0) { 
868                 ldb_transaction_cancel(d_state->sam_ctx);
869                 return NT_STATUS_NO_MEMORY; 
870         }
871
872         /* modify the samdb record */
873         ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
874         if (ret != 0) {
875                 DEBUG(0,("Failed to modify account record %s to set userAccountControl\n",
876                          ldb_dn_linearize(mem_ctx, msg->dn)));
877                 ldb_transaction_cancel(d_state->sam_ctx);
878
879                 /* we really need samdb.c to return NTSTATUS */
880                 return NT_STATUS_UNSUCCESSFUL;
881         }
882
883         ldb_transaction_commit(d_state->sam_ctx);
884         if (ret != 0) {
885                 DEBUG(0,("Failed to commit transaction to add and modify account record %s\n",
886                          ldb_dn_linearize(mem_ctx, msg->dn)));
887                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
888         }
889
890         a_state->account_name = talloc_steal(a_state, account_name);
891         if (!a_state->account_name) {
892                 return NT_STATUS_NO_MEMORY;
893         }
894
895         /* create the policy handle */
896         u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
897         if (!u_handle) {
898                 return NT_STATUS_NO_MEMORY;
899         }
900
901         u_handle->data = talloc_steal(u_handle, a_state);
902
903         *r->out.user_handle = u_handle->wire_handle;
904         *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
905
906         *r->out.rid = sid->sub_auths[sid->num_auths-1];
907
908         return NT_STATUS_OK;
909 }
910
911
912 /* 
913   samr_CreateUser 
914 */
915 static NTSTATUS samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
916                                 struct samr_CreateUser *r)
917 {
918         struct samr_CreateUser2 r2;
919         uint32_t access_granted = 0;
920
921
922         /* a simple wrapper around samr_CreateUser2 works nicely */
923         r2.in.domain_handle = r->in.domain_handle;
924         r2.in.account_name = r->in.account_name;
925         r2.in.acct_flags = ACB_NORMAL;
926         r2.in.access_mask = r->in.access_mask;
927         r2.out.user_handle = r->out.user_handle;
928         r2.out.access_granted = &access_granted;
929         r2.out.rid = r->out.rid;
930
931         return samr_CreateUser2(dce_call, mem_ctx, &r2);
932 }
933
934 /* 
935   samr_EnumDomainUsers 
936 */
937 static NTSTATUS samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
938                                      struct samr_EnumDomainUsers *r)
939 {
940         struct dcesrv_handle *h;
941         struct samr_domain_state *d_state;
942         struct ldb_message **res;
943         int count, i, first;
944         struct samr_SamEntry *entries;
945         const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
946
947         *r->out.resume_handle = 0;
948         r->out.sam = NULL;
949         r->out.num_entries = 0;
950
951         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
952
953         d_state = h->data;
954         
955         /* search for all users in this domain. This could possibly be cached and 
956            resumed based on resume_key */
957         count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs, 
958                              "objectclass=user");
959         if (count == -1) {
960                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
961         }
962         if (count == 0 || r->in.max_size == 0) {
963                 return NT_STATUS_OK;
964         }
965
966         /* convert to SamEntry format */
967         entries = talloc_array(mem_ctx, struct samr_SamEntry, count);
968         if (!entries) {
969                 return NT_STATUS_NO_MEMORY;
970         }
971         for (i=0;i<count;i++) {
972                 entries[i].idx = samdb_result_rid_from_sid(mem_ctx, res[i], "objectSid", 0);
973                 entries[i].name.string = samdb_result_string(res[i], "sAMAccountName", "");
974         }
975
976         /* sort the results by rid */
977         qsort(entries, count, sizeof(struct samr_SamEntry), 
978               (comparison_fn_t)compare_SamEntry);
979
980         /* find the first entry to return */
981         for (first=0;
982              first<count && entries[first].idx <= *r->in.resume_handle;
983              first++) ;
984
985         if (first == count) {
986                 return NT_STATUS_OK;
987         }
988
989         /* return the rest, limit by max_size. Note that we 
990            use the w2k3 element size value of 54 */
991         r->out.num_entries = count - first;
992         r->out.num_entries = MIN(r->out.num_entries, 
993                                  1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
994
995         r->out.sam = talloc(mem_ctx, struct samr_SamArray);
996         if (!r->out.sam) {
997                 return NT_STATUS_NO_MEMORY;
998         }
999
1000         r->out.sam->entries = entries+first;
1001         r->out.sam->count = r->out.num_entries;
1002
1003         if (r->out.num_entries < count - first) {
1004                 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
1005                 return STATUS_MORE_ENTRIES;
1006         }
1007
1008         return NT_STATUS_OK;
1009 }
1010
1011
1012 /* 
1013   samr_CreateDomAlias 
1014 */
1015 static NTSTATUS samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1016                        struct samr_CreateDomAlias *r)
1017 {
1018         struct samr_domain_state *d_state;
1019         struct samr_account_state *a_state;
1020         struct dcesrv_handle *h;
1021         const char *alias_name, *name;
1022         struct ldb_message *msg;
1023         struct dom_sid *sid;
1024         struct dcesrv_handle *a_handle;
1025         int ret;
1026
1027         ZERO_STRUCTP(r->out.alias_handle);
1028         *r->out.rid = 0;
1029
1030         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1031
1032         d_state = h->data;
1033
1034         alias_name = r->in.alias_name->string;
1035
1036         if (alias_name == NULL) {
1037                 return NT_STATUS_INVALID_PARAMETER;
1038         }
1039
1040         /* Check if alias already exists */
1041         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1042                                    "sAMAccountName",
1043                                    "(sAMAccountName=%s)(objectclass=group))",
1044                                    ldb_binary_encode_string(mem_ctx, alias_name));
1045
1046         if (name != NULL) {
1047                 return NT_STATUS_ALIAS_EXISTS;
1048         }
1049
1050         msg = ldb_msg_new(mem_ctx);
1051         if (msg == NULL) {
1052                 return NT_STATUS_NO_MEMORY;
1053         }
1054
1055         /* add core elements to the ldb_message for the alias */
1056         msg->dn = ldb_dn_string_compose(mem_ctx, d_state->domain_dn,
1057                                         "CN=%s, CN=Users", alias_name);
1058         if (!msg->dn) {
1059                 return NT_STATUS_NO_MEMORY;
1060         }
1061
1062         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", alias_name);
1063         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1064         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "groupType", "0x80000004");
1065
1066         /* create the alias */
1067         ret = samdb_add(d_state->sam_ctx, mem_ctx, msg);
1068         if (ret != 0) {
1069                 DEBUG(0,("Failed to create alias record %s\n",
1070                          ldb_dn_linearize(mem_ctx, msg->dn)));
1071                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1072         }
1073
1074         a_state = talloc(d_state, struct samr_account_state);
1075         if (!a_state) {
1076                 return NT_STATUS_NO_MEMORY;
1077         }
1078
1079         a_state->sam_ctx = d_state->sam_ctx;
1080         a_state->access_mask = r->in.access_mask;
1081         a_state->domain_state = talloc_reference(a_state, d_state);
1082         a_state->account_dn = talloc_steal(a_state, msg->dn);
1083
1084         /* retrieve the sid for the alias just created */
1085         sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1086                                    msg->dn, "objectSid", NULL);
1087
1088         a_state->account_name = talloc_strdup(a_state, alias_name);
1089         if (!a_state->account_name) {
1090                 return NT_STATUS_NO_MEMORY;
1091         }
1092
1093         /* create the policy handle */
1094         a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1095         if (a_handle == NULL)
1096                 return NT_STATUS_NO_MEMORY;
1097
1098         a_handle->data = talloc_steal(a_handle, a_state);
1099
1100         *r->out.alias_handle = a_handle->wire_handle;
1101
1102         *r->out.rid = sid->sub_auths[sid->num_auths-1];
1103
1104         return NT_STATUS_OK;
1105 }
1106
1107
1108 /* 
1109   samr_EnumDomainAliases 
1110 */
1111 static NTSTATUS samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1112                        struct samr_EnumDomainAliases *r)
1113 {
1114         struct dcesrv_handle *h;
1115         struct samr_domain_state *d_state;
1116         struct ldb_message **res;
1117         int ldb_cnt, count, i, first;
1118         struct samr_SamEntry *entries;
1119         const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1120
1121         *r->out.resume_handle = 0;
1122         r->out.sam = NULL;
1123         r->out.num_entries = 0;
1124
1125         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1126
1127         d_state = h->data;
1128
1129         /* search for all domain groups in this domain. This could possibly be
1130            cached and resumed based on resume_key */
1131         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1132                                       d_state->domain_dn,
1133                                       &res, attrs, 
1134                                       d_state->domain_sid,
1135                                       "(&(|(grouptype=%s)(grouptype=%s)))"
1136                                       "(objectclass=group))",
1137                                       ldb_hexstr(mem_ctx,
1138                                                  GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
1139                                       ldb_hexstr(mem_ctx,
1140                                                  GTYPE_SECURITY_DOMAIN_LOCAL_GROUP));
1141         if (ldb_cnt == -1) {
1142                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1143         }
1144         if (ldb_cnt == 0) {
1145                 return NT_STATUS_OK;
1146         }
1147
1148         /* convert to SamEntry format */
1149         entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1150         if (!entries) {
1151                 return NT_STATUS_NO_MEMORY;
1152         }
1153
1154         count = 0;
1155
1156         for (i=0;i<ldb_cnt;i++) {
1157                 struct dom_sid *alias_sid;
1158
1159                 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1160                                                  "objectSid");
1161
1162                 if (alias_sid == NULL)
1163                         continue;
1164
1165                 entries[count].idx =
1166                         alias_sid->sub_auths[alias_sid->num_auths-1];
1167                 entries[count].name.string =
1168                         samdb_result_string(res[i], "sAMAccountName", "");
1169                 count += 1;
1170         }
1171
1172         /* sort the results by rid */
1173         qsort(entries, count, sizeof(struct samr_SamEntry), 
1174               (comparison_fn_t)compare_SamEntry);
1175
1176         /* find the first entry to return */
1177         for (first=0;
1178              first<count && entries[first].idx <= *r->in.resume_handle;
1179              first++) ;
1180
1181         if (first == count) {
1182                 return NT_STATUS_OK;
1183         }
1184
1185         r->out.num_entries = count - first;
1186         r->out.num_entries = MIN(r->out.num_entries, 1000);
1187
1188         r->out.sam = talloc(mem_ctx, struct samr_SamArray);
1189         if (!r->out.sam) {
1190                 return NT_STATUS_NO_MEMORY;
1191         }
1192
1193         r->out.sam->entries = entries+first;
1194         r->out.sam->count = r->out.num_entries;
1195
1196         if (r->out.num_entries < count - first) {
1197                 *r->out.resume_handle =
1198                         entries[first+r->out.num_entries-1].idx;
1199                 return STATUS_MORE_ENTRIES;
1200         }
1201
1202         return NT_STATUS_OK;
1203 }
1204
1205
1206 /* 
1207   samr_GetAliasMembership 
1208 */
1209 static NTSTATUS samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1210                        struct samr_GetAliasMembership *r)
1211 {
1212         struct dcesrv_handle *h;
1213         struct samr_domain_state *d_state;
1214         struct ldb_message **res;
1215         int i, count = 0;
1216
1217         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1218
1219         d_state = h->data;
1220
1221         if (r->in.sids->num_sids > 0) {
1222                 const char *filter;
1223                 const char * const attrs[2] = { "objectSid", NULL };
1224
1225                 filter = talloc_asprintf(mem_ctx,
1226                                          "(&(|(grouptype=%s)(grouptype=%s))"
1227                                          "(objectclass=group)(|",
1228                                          ldb_hexstr(mem_ctx,
1229                                                     GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
1230                                          ldb_hexstr(mem_ctx,
1231                                                     GTYPE_SECURITY_DOMAIN_LOCAL_GROUP));
1232                 if (filter == NULL)
1233                         return NT_STATUS_NO_MEMORY;
1234
1235                 for (i=0; i<r->in.sids->num_sids; i++) {
1236                         const char *memberdn;
1237
1238                         memberdn = 
1239                                 samdb_search_string(d_state->sam_ctx,
1240                                                     mem_ctx, NULL, "distinguishedName",
1241                                                     "(objectSid=%s)",
1242                                                     ldap_encode_ndr_dom_sid(mem_ctx, 
1243                                                                             r->in.sids->sids[i].sid));
1244
1245                         if (memberdn == NULL)
1246                                 continue;
1247
1248                         filter = talloc_asprintf(mem_ctx, "%s(member=%s)",
1249                                                  filter, memberdn);
1250                         if (filter == NULL)
1251                                 return NT_STATUS_NO_MEMORY;
1252                 }
1253
1254                 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1255                                             d_state->domain_dn, &res, attrs,
1256                                             d_state->domain_sid, "%s))", filter);
1257                 if (count < 0)
1258                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1259         }
1260
1261         r->out.rids->count = 0;
1262         r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1263         if (r->out.rids->ids == NULL)
1264                 return NT_STATUS_NO_MEMORY;
1265
1266         for (i=0; i<count; i++) {
1267                 struct dom_sid *alias_sid;
1268
1269                 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1270
1271                 if (alias_sid == NULL) {
1272                         DEBUG(0, ("Could not find objectSid\n"));
1273                         continue;
1274                 }
1275
1276                 r->out.rids->ids[r->out.rids->count] =
1277                         alias_sid->sub_auths[alias_sid->num_auths-1];
1278                 r->out.rids->count += 1;
1279         }
1280
1281         return NT_STATUS_OK;
1282 }
1283
1284
1285 /* 
1286   samr_LookupNames 
1287 */
1288 static NTSTATUS samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1289                                  struct samr_LookupNames *r)
1290 {
1291         struct dcesrv_handle *h;
1292         struct samr_domain_state *d_state;
1293         int i;
1294         NTSTATUS status = NT_STATUS_OK;
1295         const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1296         int count;
1297
1298         ZERO_STRUCT(r->out.rids);
1299         ZERO_STRUCT(r->out.types);
1300
1301         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1302
1303         d_state = h->data;
1304
1305         if (r->in.num_names == 0) {
1306                 return NT_STATUS_OK;
1307         }
1308
1309         r->out.rids.ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1310         r->out.types.ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1311         if (!r->out.rids.ids || !r->out.types.ids) {
1312                 return NT_STATUS_NO_MEMORY;
1313         }
1314         r->out.rids.count = r->in.num_names;
1315         r->out.types.count = r->in.num_names;
1316
1317         for (i=0;i<r->in.num_names;i++) {
1318                 struct ldb_message **res;
1319                 struct dom_sid *sid;
1320                 uint32_t atype, rtype;
1321
1322                 r->out.rids.ids[i] = 0;
1323                 r->out.types.ids[i] = SID_NAME_UNKNOWN;
1324
1325                 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs, 
1326                                      "sAMAccountName=%s", 
1327                                      ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1328                 if (count != 1) {
1329                         status = STATUS_SOME_UNMAPPED;
1330                         continue;
1331                 }
1332
1333                 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1334                 if (sid == NULL) {
1335                         status = STATUS_SOME_UNMAPPED;
1336                         continue;
1337                 }
1338                 
1339                 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1340                 if (atype == 0) {
1341                         status = STATUS_SOME_UNMAPPED;
1342                         continue;
1343                 }
1344
1345                 rtype = samdb_atype_map(atype);
1346                 
1347                 if (rtype == SID_NAME_UNKNOWN) {
1348                         status = STATUS_SOME_UNMAPPED;
1349                         continue;
1350                 }
1351
1352                 r->out.rids.ids[i] = sid->sub_auths[sid->num_auths-1];
1353                 r->out.types.ids[i] = rtype;
1354         }
1355         
1356
1357         return status;
1358 }
1359
1360
1361 /* 
1362   samr_LookupRids 
1363 */
1364 static NTSTATUS samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1365                        struct samr_LookupRids *r)
1366 {
1367         struct dcesrv_handle *h;
1368         struct samr_domain_state *d_state;
1369         int i, total;
1370         NTSTATUS status = NT_STATUS_OK;
1371         struct lsa_String *names;
1372         uint32_t *ids;
1373
1374         ZERO_STRUCT(r->out.names);
1375         ZERO_STRUCT(r->out.types);
1376
1377         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1378
1379         d_state = h->data;
1380
1381         if (r->in.num_rids == 0)
1382                 return NT_STATUS_OK;
1383
1384         names = talloc_array(mem_ctx, struct lsa_String, r->in.num_rids);
1385         ids = talloc_array(mem_ctx, uint32_t, r->in.num_rids);
1386
1387         if ((names == NULL) || (ids == NULL))
1388                 return NT_STATUS_NO_MEMORY;
1389
1390         total = 0;
1391
1392         for (i=0; i<r->in.num_rids; i++) {
1393                 struct ldb_message **res;
1394                 int count;
1395                 const char * const attrs[] = {  "sAMAccountType",
1396                                                 "sAMAccountName", NULL };
1397                 uint32_t atype;
1398                 struct dom_sid *sid;
1399
1400                 ids[i] = SID_NAME_UNKNOWN;
1401
1402                 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rids[i]);
1403                 if (sid == NULL) {
1404                         names[i].string = NULL;
1405                         status = STATUS_SOME_UNMAPPED;
1406                         continue;
1407                 }
1408                 
1409                 count = gendb_search(d_state->sam_ctx, mem_ctx,
1410                                      d_state->domain_dn, &res, attrs,
1411                                      "(objectSid=%s)", 
1412                                      ldap_encode_ndr_dom_sid(mem_ctx, sid));
1413                 if (count != 1) {
1414                         names[i].string = NULL;
1415                         status = STATUS_SOME_UNMAPPED;
1416                         continue;
1417                 }
1418
1419                 names[i].string = samdb_result_string(res[0], "sAMAccountName",
1420                                                       NULL);
1421
1422                 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1423                 if (atype == 0) {
1424                         status = STATUS_SOME_UNMAPPED;
1425                         continue;
1426                 }
1427
1428                 ids[i] = samdb_atype_map(atype);
1429                 
1430                 if (ids[i] == SID_NAME_UNKNOWN) {
1431                         status = STATUS_SOME_UNMAPPED;
1432                         continue;
1433                 }
1434         }
1435
1436         r->out.names.names = names;
1437         r->out.names.count = r->in.num_rids;
1438
1439         r->out.types.ids = ids;
1440         r->out.types.count = r->in.num_rids;
1441
1442         return status;
1443 }
1444
1445
1446 /* 
1447   samr_OpenGroup 
1448 */
1449 static NTSTATUS samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1450                        struct samr_OpenGroup *r)
1451 {
1452         struct samr_domain_state *d_state;
1453         struct samr_account_state *a_state;
1454         struct dcesrv_handle *h;
1455         const char *groupname;
1456         struct dom_sid *sid;
1457         struct ldb_message **msgs;
1458         struct dcesrv_handle *g_handle;
1459         const char * const attrs[2] = { "sAMAccountName", NULL };
1460         int ret;
1461
1462         ZERO_STRUCTP(r->out.group_handle);
1463
1464         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1465
1466         d_state = h->data;
1467
1468         /* form the group SID */
1469         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1470         if (!sid) {
1471                 return NT_STATUS_NO_MEMORY;
1472         }
1473
1474         /* search for the group record */
1475         ret = gendb_search(d_state->sam_ctx,
1476                            mem_ctx, d_state->domain_dn, &msgs, attrs,
1477                            "(&(objectSid=%s)(objectclass=group)"
1478                            "(grouptype=%s))",
1479                            ldap_encode_ndr_dom_sid(mem_ctx, sid),
1480                            ldb_hexstr(mem_ctx,
1481                                       GTYPE_SECURITY_GLOBAL_GROUP));
1482         if (ret == 0) {
1483                 return NT_STATUS_NO_SUCH_GROUP;
1484         }
1485         if (ret != 1) {
1486                 DEBUG(0,("Found %d records matching sid %s\n", 
1487                          ret, dom_sid_string(mem_ctx, sid)));
1488                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1489         }
1490
1491         groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
1492         if (groupname == NULL) {
1493                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
1494                          dom_sid_string(mem_ctx, sid)));
1495                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1496         }
1497
1498         a_state = talloc(d_state, struct samr_account_state);
1499         if (!a_state) {
1500                 return NT_STATUS_NO_MEMORY;
1501         }
1502         a_state->sam_ctx = d_state->sam_ctx;
1503         a_state->access_mask = r->in.access_mask;
1504         a_state->domain_state = talloc_reference(a_state, d_state);
1505         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1506         a_state->account_sid = talloc_steal(a_state, sid);
1507         a_state->account_name = talloc_strdup(a_state, groupname);
1508         if (!a_state->account_name) {
1509                 return NT_STATUS_NO_MEMORY;
1510         }
1511
1512         /* create the policy handle */
1513         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1514         if (!g_handle) {
1515                 return NT_STATUS_NO_MEMORY;
1516         }
1517
1518         g_handle->data = talloc_steal(g_handle, a_state);
1519
1520         *r->out.group_handle = g_handle->wire_handle;
1521
1522         return NT_STATUS_OK;
1523 }
1524
1525 /* these query macros make samr_Query[User|Group]Info a bit easier to read */
1526
1527 #define QUERY_STRING(msg, field, attr) \
1528         r->out.info->field = samdb_result_string(msg, attr, "");
1529 #define QUERY_UINT(msg, field, attr) \
1530         r->out.info->field = samdb_result_uint(msg, attr, 0);
1531 #define QUERY_RID(msg, field, attr) \
1532         r->out.info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
1533 #define QUERY_NTTIME(msg, field, attr) \
1534         r->out.info->field = samdb_result_nttime(msg, attr, 0);
1535 #define QUERY_APASSC(msg, field, attr) \
1536         r->out.info->field = samdb_result_allow_password_change(a_state->sam_ctx, mem_ctx, \
1537                                                            a_state->domain_state->domain_dn, msg, attr);
1538 #define QUERY_FPASSC(msg, field, attr) \
1539         r->out.info->field = samdb_result_force_password_change(a_state->sam_ctx, mem_ctx, \
1540                                                            a_state->domain_state->domain_dn, msg, attr);
1541 #define QUERY_LHOURS(msg, field, attr) \
1542         r->out.info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
1543 #define QUERY_AFLAGS(msg, field, attr) \
1544         r->out.info->field = samdb_result_acct_flags(msg, attr);
1545
1546
1547 /* these are used to make the Set[User|Group]Info code easier to follow */
1548
1549 #define SET_STRING(mod, field, attr) do { \
1550         if (r->in.info->field == NULL) return NT_STATUS_INVALID_PARAMETER; \
1551         if (samdb_msg_add_string(a_state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
1552                 return NT_STATUS_NO_MEMORY; \
1553         } \
1554 } while (0)
1555
1556 #define SET_UINT(mod, field, attr) do { \
1557         if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
1558                 return NT_STATUS_NO_MEMORY; \
1559         } \
1560 } while (0)
1561
1562 #define SET_AFLAGS(msg, field, attr) do { \
1563         if (samdb_msg_add_acct_flags(a_state->sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
1564                 return NT_STATUS_NO_MEMORY; \
1565         } \
1566 } while (0)
1567
1568 #define SET_LHOURS(msg, field, attr) do { \
1569         if (samdb_msg_add_logon_hours(a_state->sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
1570                 return NT_STATUS_NO_MEMORY; \
1571         } \
1572 } while (0)
1573
1574 /* 
1575   samr_QueryGroupInfo 
1576 */
1577 static NTSTATUS samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1578                        struct samr_QueryGroupInfo *r)
1579 {
1580         struct dcesrv_handle *h;
1581         struct samr_account_state *a_state;
1582         struct ldb_message *msg, **res;
1583         const char * const attrs[4] = { "sAMAccountName", "description",
1584                                         "numMembers", NULL };
1585         int ret;
1586
1587         r->out.info = NULL;
1588
1589         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1590
1591         a_state = h->data;
1592
1593         /* pull all the group attributes */
1594         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
1595                               a_state->account_dn, &res, attrs);
1596         if (ret != 1) {
1597                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1598         }
1599         msg = res[0];
1600
1601         /* allocate the info structure */
1602         r->out.info = talloc(mem_ctx, union samr_GroupInfo);
1603         if (r->out.info == NULL) {
1604                 return NT_STATUS_NO_MEMORY;
1605         }
1606         ZERO_STRUCTP(r->out.info);
1607
1608         /* Fill in the level */
1609         switch (r->in.level) {
1610         case GROUPINFOALL:
1611                 QUERY_STRING(msg, all.name.string,        "sAMAccountName");
1612                 r->out.info->all.attributes = 7; /* Do like w2k3 */
1613                 QUERY_UINT  (msg, all.num_members,      "numMembers")
1614                 QUERY_STRING(msg, all.description.string, "description");
1615                 break;
1616         case GROUPINFONAME:
1617                 QUERY_STRING(msg, name.string,            "sAMAccountName");
1618                 break;
1619         case GROUPINFOX:
1620                 r->out.info->unknown.unknown = 7;
1621                 break;
1622         case GROUPINFODESCRIPTION:
1623                 QUERY_STRING(msg, description.string, "description");
1624                 break;
1625         default:
1626                 r->out.info = NULL;
1627                 return NT_STATUS_INVALID_INFO_CLASS;
1628         }
1629         
1630         return NT_STATUS_OK;
1631 }
1632
1633
1634 /* 
1635   samr_SetGroupInfo 
1636 */
1637 static NTSTATUS samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1638                                   struct samr_SetGroupInfo *r)
1639 {
1640         struct dcesrv_handle *h;
1641         struct samr_account_state *a_state;
1642         struct ldb_message *msg;
1643         int ret;
1644
1645         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1646
1647         a_state = h->data;
1648
1649         msg = ldb_msg_new(mem_ctx);
1650         if (msg == NULL) {
1651                 return NT_STATUS_NO_MEMORY;
1652         }       
1653
1654         msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
1655         if (!msg->dn) {
1656                 return NT_STATUS_NO_MEMORY;
1657         }
1658
1659         switch (r->in.level) {
1660         case GROUPINFODESCRIPTION:
1661                 SET_STRING(msg, description.string,         "description");
1662                 break;
1663         case GROUPINFONAME:
1664                 /* On W2k3 this does not change the name, it changes the
1665                  * sAMAccountName attribute */
1666                 SET_STRING(msg, name.string,                "sAMAccountName");
1667                 break;
1668         case GROUPINFOX:
1669                 /* This does not do anything obviously visible in W2k3 LDAP */
1670                 break;
1671         default:
1672                 return NT_STATUS_INVALID_INFO_CLASS;
1673         }
1674
1675         /* modify the samdb record */
1676         ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
1677         if (ret != 0) {
1678                 /* we really need samdb.c to return NTSTATUS */
1679                 return NT_STATUS_UNSUCCESSFUL;
1680         }
1681
1682         return NT_STATUS_OK;
1683 }
1684
1685
1686 /* 
1687   samr_AddGroupMember 
1688 */
1689 static NTSTATUS samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1690                        struct samr_AddGroupMember *r)
1691 {
1692         struct dcesrv_handle *h;
1693         struct samr_account_state *a_state;
1694         struct samr_domain_state *d_state;
1695         struct ldb_message *mod;
1696         struct dom_sid *membersid;
1697         const char *memberdn;
1698         struct ldb_message **msgs;
1699         const char * const attrs[2] = { "distinguishedName", NULL };
1700         int ret;
1701
1702         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1703
1704         a_state = h->data;
1705         d_state = a_state->domain_state;
1706
1707         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1708         if (membersid == NULL)
1709                 return NT_STATUS_NO_MEMORY;
1710
1711         /* In native mode, AD can also nest domain groups. Not sure yet
1712          * whether this is also available via RPC. */
1713         ret = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn,
1714                            &msgs, attrs, "(&(objectSid=%s)(objectclass=user))",
1715                            ldap_encode_ndr_dom_sid(mem_ctx, membersid));
1716
1717         if (ret == 0)
1718                 return NT_STATUS_NO_SUCH_USER;
1719
1720         if (ret > 1)
1721                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1722
1723         memberdn = samdb_result_string(msgs[0], "distinguishedName", NULL);
1724
1725         if (memberdn == NULL)
1726                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1727
1728         mod = ldb_msg_new(mem_ctx);
1729         if (mod == NULL) {
1730                 return NT_STATUS_NO_MEMORY;
1731         }
1732
1733         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
1734
1735         if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
1736                                  memberdn) != 0)
1737                 return NT_STATUS_UNSUCCESSFUL;
1738
1739         if (samdb_modify(a_state->sam_ctx, mem_ctx, mod) != 0)
1740                 return NT_STATUS_UNSUCCESSFUL;
1741
1742         return NT_STATUS_OK;
1743 }
1744
1745
1746 /* 
1747   samr_DeleteDomainGroup 
1748 */
1749 static NTSTATUS samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1750                        struct samr_DeleteDomainGroup *r)
1751 {
1752         struct dcesrv_handle *h;
1753         struct samr_account_state *a_state;
1754         int ret;
1755
1756         *r->out.group_handle = *r->in.group_handle;
1757
1758         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1759
1760         a_state = h->data;
1761
1762         ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
1763         if (ret != 0) {
1764                 return NT_STATUS_UNSUCCESSFUL;
1765         }
1766
1767         ZERO_STRUCTP(r->out.group_handle);
1768
1769         return NT_STATUS_OK;
1770 }
1771
1772
1773 /* 
1774   samr_DeleteGroupMember 
1775 */
1776 static NTSTATUS samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1777                        struct samr_DeleteGroupMember *r)
1778 {
1779         struct dcesrv_handle *h;
1780         struct samr_account_state *a_state;
1781         struct samr_domain_state *d_state;
1782         struct ldb_message *mod;
1783         struct dom_sid *membersid;
1784         const char *memberdn;
1785         struct ldb_message **msgs;
1786         const char * const attrs[2] = { "distinguishedName", NULL };
1787         int ret;
1788
1789         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1790
1791         a_state = h->data;
1792         d_state = a_state->domain_state;
1793
1794         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1795         if (membersid == NULL)
1796                 return NT_STATUS_NO_MEMORY;
1797
1798         /* In native mode, AD can also nest domain groups. Not sure yet
1799          * whether this is also available via RPC. */
1800         ret = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn,
1801                            &msgs, attrs, "(&(objectSid=%s)(objectclass=user))",
1802                            ldap_encode_ndr_dom_sid(mem_ctx, membersid));
1803
1804         if (ret == 0)
1805                 return NT_STATUS_NO_SUCH_USER;
1806
1807         if (ret > 1)
1808                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1809
1810         memberdn = samdb_result_string(msgs[0], "distinguishedName", NULL);
1811
1812         if (memberdn == NULL)
1813                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1814
1815         mod = ldb_msg_new(mem_ctx);
1816         if (mod == NULL) {
1817                 return NT_STATUS_NO_MEMORY;
1818         }
1819
1820         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
1821
1822         if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
1823                                  memberdn) != 0)
1824                 return NT_STATUS_UNSUCCESSFUL;
1825
1826         if (samdb_modify(a_state->sam_ctx, mem_ctx, mod) != 0)
1827                 return NT_STATUS_UNSUCCESSFUL;
1828
1829         return NT_STATUS_OK;
1830 }
1831
1832
1833 /* 
1834   samr_QueryGroupMember 
1835 */
1836 static NTSTATUS samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1837                                       struct samr_QueryGroupMember *r)
1838 {
1839         struct dcesrv_handle *h;
1840         struct samr_account_state *a_state;
1841         struct ldb_message **res;
1842         struct ldb_message_element *el;
1843         struct samr_RidTypeArray *array;
1844         const char * const attrs[2] = { "member", NULL };
1845         int ret;
1846
1847         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1848
1849         a_state = h->data;
1850
1851         /* pull the member attribute */
1852         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
1853                               a_state->account_dn, &res, attrs);
1854
1855         if (ret != 1) {
1856                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1857         }
1858
1859         array = talloc(mem_ctx, struct samr_RidTypeArray);
1860
1861         if (array == NULL)
1862                 return NT_STATUS_NO_MEMORY;
1863
1864         ZERO_STRUCTP(array);
1865
1866         el = ldb_msg_find_element(res[0], "member");
1867
1868         if (el != NULL) {
1869                 int i;
1870
1871                 array->count = el->num_values;
1872
1873                 array->rids = talloc_array(mem_ctx, uint32_t,
1874                                              el->num_values);
1875                 if (array->rids == NULL)
1876                         return NT_STATUS_NO_MEMORY;
1877
1878                 array->types = talloc_array(mem_ctx, uint32_t,
1879                                             el->num_values);
1880                 if (array->types == NULL)
1881                         return NT_STATUS_NO_MEMORY;
1882
1883                 for (i=0; i<el->num_values; i++) {
1884                         struct ldb_message **res2;
1885                         const char * const attrs2[2] = { "objectSid", NULL };
1886                         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
1887                                            ldb_dn_explode(mem_ctx, el->values[i].data),
1888                                            &res2, attrs2);
1889                         if (ret != 1)
1890                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1891
1892                         array->rids[i] =
1893                                 samdb_result_rid_from_sid(mem_ctx, res2[0],
1894                                                           "objectSid", 0);
1895
1896                         if (array->rids[i] == 0)
1897                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1898
1899                         array->types[i] = 7; /* RID type of some kind, not sure what the value means. */
1900                 }
1901         }
1902
1903         r->out.rids = array;
1904
1905         return NT_STATUS_OK;
1906 }
1907
1908
1909 /* 
1910   samr_SetMemberAttributesOfGroup 
1911 */
1912 static NTSTATUS samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1913                        struct samr_SetMemberAttributesOfGroup *r)
1914 {
1915         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1916 }
1917
1918
1919 /* 
1920   samr_OpenAlias 
1921 */
1922 static NTSTATUS samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1923                        struct samr_OpenAlias *r)
1924 {
1925         struct samr_domain_state *d_state;
1926         struct samr_account_state *a_state;
1927         struct dcesrv_handle *h;
1928         const char *alias_name;
1929         struct dom_sid *sid;
1930         struct ldb_message **msgs;
1931         struct dcesrv_handle *g_handle;
1932         const char * const attrs[2] = { "sAMAccountName", NULL };
1933         int ret;
1934
1935         ZERO_STRUCTP(r->out.alias_handle);
1936
1937         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1938
1939         d_state = h->data;
1940
1941         /* form the alias SID */
1942         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1943         if (sid == NULL)
1944                 return NT_STATUS_NO_MEMORY;
1945
1946         /* search for the group record */
1947         ret = gendb_search(d_state->sam_ctx,
1948                            mem_ctx, d_state->domain_dn, &msgs, attrs,
1949                            "(&(objectSid=%s)(objectclass=group)"
1950                            "(|(grouptype=%s)(grouptype=%s)))",
1951                            ldap_encode_ndr_dom_sid(mem_ctx, sid),
1952                            ldb_hexstr(mem_ctx,
1953                                       GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
1954                            ldb_hexstr(mem_ctx,
1955                                       GTYPE_SECURITY_DOMAIN_LOCAL_GROUP));
1956         if (ret == 0) {
1957                 return NT_STATUS_NO_SUCH_ALIAS;
1958         }
1959         if (ret != 1) {
1960                 DEBUG(0,("Found %d records matching sid %s\n", 
1961                          ret, dom_sid_string(mem_ctx, sid)));
1962                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1963         }
1964
1965         alias_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
1966         if (alias_name == NULL) {
1967                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
1968                          dom_sid_string(mem_ctx, sid)));
1969                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1970         }
1971
1972         a_state = talloc(d_state, struct samr_account_state);
1973         if (!a_state) {
1974                 return NT_STATUS_NO_MEMORY;
1975         }
1976         a_state->sam_ctx = d_state->sam_ctx;
1977         a_state->access_mask = r->in.access_mask;
1978         a_state->domain_state = talloc_reference(a_state, d_state);
1979         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1980         a_state->account_sid = talloc_steal(a_state, sid);
1981         a_state->account_name = talloc_strdup(a_state, alias_name);
1982         if (!a_state->account_name) {
1983                 return NT_STATUS_NO_MEMORY;
1984         }
1985
1986         /* create the policy handle */
1987         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1988         if (!g_handle) {
1989                 return NT_STATUS_NO_MEMORY;
1990         }
1991
1992         g_handle->data = talloc_steal(g_handle, a_state);
1993
1994         *r->out.alias_handle = g_handle->wire_handle;
1995
1996         return NT_STATUS_OK;
1997 }
1998
1999
2000 /* 
2001   samr_QueryAliasInfo 
2002 */
2003 static NTSTATUS samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2004                        struct samr_QueryAliasInfo *r)
2005 {
2006         struct dcesrv_handle *h;
2007         struct samr_account_state *a_state;
2008         struct ldb_message *msg, **res;
2009         const char * const attrs[4] = { "sAMAccountName", "description",
2010                                         "numMembers", NULL };
2011         int ret;
2012
2013         r->out.info = NULL;
2014
2015         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2016
2017         a_state = h->data;
2018
2019         /* pull all the alias attributes */
2020         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2021                               a_state->account_dn ,&res, attrs);
2022         if (ret != 1) {
2023                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2024         }
2025         msg = res[0];
2026
2027         /* allocate the info structure */
2028         r->out.info = talloc(mem_ctx, union samr_AliasInfo);
2029         if (r->out.info == NULL) {
2030                 return NT_STATUS_NO_MEMORY;
2031         }
2032         ZERO_STRUCTP(r->out.info);
2033
2034         switch(r->in.level) {
2035         case ALIASINFOALL:
2036                 QUERY_STRING(msg, all.name.string, "sAMAccountName");
2037                 QUERY_UINT  (msg, all.num_members, "numMembers");
2038                 QUERY_STRING(msg, all.description.string, "description");
2039                 break;
2040         case ALIASINFONAME:
2041                 QUERY_STRING(msg, name.string, "sAMAccountName");
2042                 break;
2043         case ALIASINFODESCRIPTION:
2044                 QUERY_STRING(msg, description.string, "description");
2045                 break;
2046         default:
2047                 r->out.info = NULL;
2048                 return NT_STATUS_INVALID_INFO_CLASS;
2049         }
2050         
2051         return NT_STATUS_OK;
2052 }
2053
2054
2055 /* 
2056   samr_SetAliasInfo 
2057 */
2058 static NTSTATUS samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2059                        struct samr_SetAliasInfo *r)
2060 {
2061         struct dcesrv_handle *h;
2062         struct samr_account_state *a_state;
2063         struct ldb_message *msg;
2064         int ret;
2065
2066         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2067
2068         a_state = h->data;
2069
2070         msg = ldb_msg_new(mem_ctx);
2071         if (msg == NULL) {
2072                 return NT_STATUS_NO_MEMORY;
2073         }
2074
2075         msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2076         if (!msg->dn) {
2077                 return NT_STATUS_NO_MEMORY;
2078         }
2079
2080         switch (r->in.level) {
2081         case ALIASINFODESCRIPTION:
2082                 SET_STRING(msg, description.string,         "description");
2083                 break;
2084         case ALIASINFONAME:
2085                 /* On W2k3 this does not change the name, it changes the
2086                  * sAMAccountName attribute */
2087                 SET_STRING(msg, name.string,                "sAMAccountName");
2088                 break;
2089         default:
2090                 return NT_STATUS_INVALID_INFO_CLASS;
2091         }
2092
2093         /* modify the samdb record */
2094         ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
2095         if (ret != 0) {
2096                 /* we really need samdb.c to return NTSTATUS */
2097                 return NT_STATUS_UNSUCCESSFUL;
2098         }
2099
2100         return NT_STATUS_OK;
2101 }
2102
2103
2104 /* 
2105   samr_DeleteDomAlias 
2106 */
2107 static NTSTATUS samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2108                        struct samr_DeleteDomAlias *r)
2109 {
2110         struct dcesrv_handle *h;
2111         struct samr_account_state *a_state;
2112         int ret;
2113
2114         *r->out.alias_handle = *r->in.alias_handle;
2115
2116         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2117
2118         a_state = h->data;
2119
2120         ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
2121         if (ret != 0) {
2122                 return NT_STATUS_UNSUCCESSFUL;
2123         }
2124
2125         ZERO_STRUCTP(r->out.alias_handle);
2126
2127         return NT_STATUS_OK;
2128 }
2129
2130
2131 /* 
2132   samr_AddAliasMember 
2133 */
2134 static NTSTATUS samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2135                        struct samr_AddAliasMember *r)
2136 {
2137         struct dcesrv_handle *h;
2138         struct samr_account_state *a_state;
2139         struct samr_domain_state *d_state;
2140         struct ldb_message *mod;
2141         struct ldb_message **msgs;
2142         const char * const attrs[2] = { "distinguishedName", NULL };
2143         struct ldb_dn *memberdn = NULL;
2144         int ret;
2145
2146         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2147
2148         a_state = h->data;
2149         d_state = a_state->domain_state;
2150
2151         ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2152                            &msgs, attrs, "(objectsid=%s)", 
2153                            ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2154
2155         if (ret == 1) {
2156                 memberdn = ldb_dn_explode(mem_ctx, ldb_msg_find_string(msgs[0], "distinguishedName", NULL));
2157         } else  if (ret > 1) {
2158                 DEBUG(0,("Found %d records matching sid %s\n", 
2159                          ret, dom_sid_string(mem_ctx, r->in.sid)));
2160                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2161         } else if (ret == 0) {
2162                 struct ldb_message *msg;
2163                 struct ldb_dn *basedn;
2164                 const char *sidstr;
2165
2166                 sidstr = dom_sid_string(mem_ctx, r->in.sid);
2167                 NT_STATUS_HAVE_NO_MEMORY(sidstr);
2168
2169                 /* We might have to create a ForeignSecurityPrincipal, but
2170                  * only if it's not our own domain */
2171                 if (dom_sid_in_domain(d_state->domain_sid, r->in.sid))
2172                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2173
2174                 msg = ldb_msg_new(mem_ctx);
2175                 if (msg == NULL) {
2176                         return NT_STATUS_NO_MEMORY;
2177                 }
2178
2179                 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
2180                  * put the ForeignSecurityPrincipals? d_state->domain_dn does
2181                  * not work, this is wrong for the Builtin domain, there's no
2182                  * cn=For...,cn=Builtin,dc={BASEDN}.  -- vl
2183                  */
2184
2185                 basedn = samdb_search_dn(d_state->sam_ctx, mem_ctx, NULL,
2186                                          "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
2187
2188                 if (basedn == NULL) {
2189                         DEBUG(0, ("Failed to find DN for "
2190                                   "ForeignSecurityPrincipal container\n"));
2191                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
2192                 }
2193
2194                 /* add core elements to the ldb_message for the alias */
2195                 msg->dn = ldb_dn_build_child(mem_ctx, "CN", sidstr, basedn);
2196                 if (msg->dn == NULL)
2197                         return NT_STATUS_NO_MEMORY;
2198
2199                 memberdn = msg->dn;
2200
2201                 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg,
2202                                      "objectClass",
2203                                      "foreignSecurityPrincipal");
2204
2205                 /* create the alias */
2206                 ret = samdb_add(d_state->sam_ctx, mem_ctx, msg);
2207                 if (ret != 0) {
2208                         DEBUG(0,("Failed to create foreignSecurityPrincipal "
2209                                  "record %s\n", ldb_dn_linearize(mem_ctx, msg->dn)));
2210                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
2211                 }
2212         } else {
2213                 DEBUG(0, ("samdb_search returned %d\n", ret));
2214         }
2215
2216         if (memberdn == NULL) {
2217                 DEBUG(0, ("Could not find memberdn\n"));
2218                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2219         }
2220
2221         mod = ldb_msg_new(mem_ctx);
2222         if (mod == NULL) {
2223                 return NT_STATUS_NO_MEMORY;
2224         }
2225
2226         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2227
2228         if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2229                                  ldb_dn_linearize(mem_ctx, memberdn)) != 0)
2230                 return NT_STATUS_UNSUCCESSFUL;
2231
2232         if (samdb_modify(a_state->sam_ctx, mem_ctx, mod) != 0)
2233                 return NT_STATUS_UNSUCCESSFUL;
2234
2235         return NT_STATUS_OK;
2236 }
2237
2238
2239 /* 
2240   samr_DeleteAliasMember 
2241 */
2242 static NTSTATUS samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2243                        struct samr_DeleteAliasMember *r)
2244 {
2245         struct dcesrv_handle *h;
2246         struct samr_account_state *a_state;
2247         struct samr_domain_state *d_state;
2248         struct ldb_message *mod;
2249         const char *memberdn;
2250
2251         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2252
2253         a_state = h->data;
2254         d_state = a_state->domain_state;
2255
2256         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2257                                        "distinguishedName", "(objectSid=%s)", 
2258                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2259
2260         if (memberdn == NULL)
2261                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2262
2263         mod = ldb_msg_new(mem_ctx);
2264         if (mod == NULL) {
2265                 return NT_STATUS_NO_MEMORY;
2266         }
2267
2268         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2269
2270         if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2271                                  memberdn) != 0)
2272                 return NT_STATUS_UNSUCCESSFUL;
2273
2274         if (samdb_modify(a_state->sam_ctx, mem_ctx, mod) != 0)
2275                 return NT_STATUS_UNSUCCESSFUL;
2276
2277         return NT_STATUS_OK;
2278 }
2279
2280
2281 /* 
2282   samr_GetMembersInAlias 
2283 */
2284 static NTSTATUS samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2285                        struct samr_GetMembersInAlias *r)
2286 {
2287         struct dcesrv_handle *h;
2288         struct samr_account_state *a_state;
2289         struct samr_domain_state *d_state;
2290         struct ldb_message **msgs;
2291         struct lsa_SidPtr *sids;
2292         struct ldb_message_element *el;
2293         const char * const attrs[2] = { "member", NULL};
2294         int ret;
2295
2296         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2297
2298         a_state = h->data;
2299         d_state = a_state->domain_state;
2300
2301         ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
2302                               a_state->account_dn, &msgs, attrs);
2303
2304         if (ret != 1)
2305                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2306
2307         r->out.sids->num_sids = 0;
2308         r->out.sids->sids = NULL;
2309
2310         el = ldb_msg_find_element(msgs[0], "member");
2311
2312         if (el != NULL) {
2313                 int i;
2314
2315                 sids = talloc_array(mem_ctx, struct lsa_SidPtr,
2316                                       el->num_values);
2317
2318                 if (sids == NULL)
2319                         return NT_STATUS_NO_MEMORY;
2320
2321                 for (i=0; i<el->num_values; i++) {
2322                         struct ldb_message **msgs2;
2323                         const char * const attrs2[2] = { "objectSid", NULL };
2324                         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2325                                            ldb_dn_explode(mem_ctx, el->values[i].data),
2326                                            &msgs2, attrs2);
2327                         if (ret != 1)
2328                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2329
2330                         sids[i].sid = samdb_result_dom_sid(mem_ctx, msgs2[0],
2331                                                            "objectSid");
2332
2333                         if (sids[i].sid == NULL)
2334                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2335                 }
2336                 r->out.sids->num_sids = el->num_values;
2337                 r->out.sids->sids = sids;
2338         }
2339
2340         return NT_STATUS_OK;
2341 }
2342
2343 /* 
2344   samr_OpenUser 
2345 */
2346 static NTSTATUS samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2347                               struct samr_OpenUser *r)
2348 {
2349         struct samr_domain_state *d_state;
2350         struct samr_account_state *a_state;
2351         struct dcesrv_handle *h;
2352         const char *account_name;
2353         struct dom_sid *sid;
2354         struct ldb_message **msgs;
2355         struct dcesrv_handle *u_handle;
2356         const char * const attrs[2] = { "sAMAccountName", NULL };
2357         int ret;
2358
2359         ZERO_STRUCTP(r->out.user_handle);
2360
2361         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2362
2363         d_state = h->data;
2364
2365         /* form the users SID */
2366         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2367         if (!sid) {
2368                 return NT_STATUS_NO_MEMORY;
2369         }
2370
2371         /* search for the user record */
2372         ret = gendb_search(d_state->sam_ctx,
2373                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2374                            "(&(objectSid=%s)(objectclass=user))", 
2375                            ldap_encode_ndr_dom_sid(mem_ctx, sid));
2376         if (ret == 0) {
2377                 return NT_STATUS_NO_SUCH_USER;
2378         }
2379         if (ret != 1) {
2380                 DEBUG(0,("Found %d records matching sid %s\n", ret, 
2381                          dom_sid_string(mem_ctx, sid)));
2382                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2383         }
2384
2385         account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2386         if (account_name == NULL) {
2387                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2388                          dom_sid_string(mem_ctx, sid)));
2389                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2390         }
2391
2392         a_state = talloc(mem_ctx, struct samr_account_state);
2393         if (!a_state) {
2394                 return NT_STATUS_NO_MEMORY;
2395         }
2396         a_state->sam_ctx = d_state->sam_ctx;
2397         a_state->access_mask = r->in.access_mask;
2398         a_state->domain_state = talloc_reference(a_state, d_state);
2399         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2400         a_state->account_sid = talloc_steal(a_state, sid);
2401         a_state->account_name = talloc_strdup(a_state, account_name);
2402         if (!a_state->account_name) {
2403                 return NT_STATUS_NO_MEMORY;
2404         }
2405
2406         /* create the policy handle */
2407         u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2408         if (!u_handle) {
2409                 return NT_STATUS_NO_MEMORY;
2410         }
2411
2412         u_handle->data = talloc_steal(u_handle, a_state);
2413
2414         *r->out.user_handle = u_handle->wire_handle;
2415
2416         return NT_STATUS_OK;
2417
2418 }
2419
2420
2421 /* 
2422   samr_DeleteUser 
2423 */
2424 static NTSTATUS samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2425                                 struct samr_DeleteUser *r)
2426 {
2427         struct dcesrv_handle *h;
2428         struct samr_account_state *a_state;
2429         int ret;
2430
2431         *r->out.user_handle = *r->in.user_handle;
2432
2433         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2434
2435         a_state = h->data;
2436
2437         ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
2438         if (ret != 0) {
2439                 return NT_STATUS_UNSUCCESSFUL;
2440         }
2441
2442         ZERO_STRUCTP(r->out.user_handle);
2443
2444         return NT_STATUS_OK;
2445 }
2446
2447
2448 /* 
2449   samr_QueryUserInfo 
2450 */
2451 static NTSTATUS samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2452                                    struct samr_QueryUserInfo *r)
2453 {
2454         struct dcesrv_handle *h;
2455         struct samr_account_state *a_state;
2456         struct ldb_message *msg, **res;
2457         int ret;
2458
2459         r->out.info = NULL;
2460
2461         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2462
2463         a_state = h->data;
2464
2465         /* pull all the user attributes */
2466         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2467                               a_state->account_dn ,&res, NULL);
2468         if (ret != 1) {
2469                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2470         }
2471         msg = res[0];
2472
2473         /* allocate the info structure */
2474         r->out.info = talloc(mem_ctx, union samr_UserInfo);
2475         if (r->out.info == NULL) {
2476                 return NT_STATUS_NO_MEMORY;
2477         }
2478         ZERO_STRUCTP(r->out.info);
2479
2480         /* fill in the reply */
2481         switch (r->in.level) {
2482         case 1:
2483                 QUERY_STRING(msg, info1.account_name.string,   "sAMAccountName");
2484                 QUERY_STRING(msg, info1.full_name.string,      "displayName");
2485                 QUERY_UINT  (msg, info1.primary_gid,           "primaryGroupID");
2486                 QUERY_STRING(msg, info1.description.string,    "description");
2487                 QUERY_STRING(msg, info1.comment.string,        "comment");
2488                 break;
2489
2490         case 2:
2491                 QUERY_STRING(msg, info2.comment.string,        "comment");
2492                 QUERY_UINT  (msg, info2.country_code,          "countryCode");
2493                 QUERY_UINT  (msg, info2.code_page,             "codePage");
2494                 break;
2495
2496         case 3:
2497                 QUERY_STRING(msg, info3.account_name.string,   "sAMAccountName");
2498                 QUERY_STRING(msg, info3.full_name.string,      "displayName");
2499                 QUERY_RID   (msg, info3.rid,                   "objectSid");
2500                 QUERY_UINT  (msg, info3.primary_gid,           "primaryGroupID");
2501                 QUERY_STRING(msg, info3.home_directory.string, "homeDirectory");
2502                 QUERY_STRING(msg, info3.home_drive.string,     "homeDrive");
2503                 QUERY_STRING(msg, info3.logon_script.string,   "scriptPath");
2504                 QUERY_STRING(msg, info3.profile_path.string,   "profilePath");
2505                 QUERY_STRING(msg, info3.workstations.string,   "userWorkstations");
2506                 QUERY_NTTIME(msg, info3.last_logon,            "lastLogon");
2507                 QUERY_NTTIME(msg, info3.last_logoff,           "lastLogoff");
2508                 QUERY_NTTIME(msg, info3.last_password_change,  "pwdLastSet");
2509                 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
2510                 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
2511                 QUERY_LHOURS(msg, info3.logon_hours,           "logonHours");
2512                 QUERY_UINT  (msg, info3.bad_password_count,    "badPwdCount");
2513                 QUERY_UINT  (msg, info3.logon_count,           "logonCount");
2514                 QUERY_AFLAGS(msg, info3.acct_flags,            "userAccountControl");
2515                 break;
2516
2517         case 4:
2518                 QUERY_LHOURS(msg, info4.logon_hours,           "logonHours");
2519                 break;
2520
2521         case 5:
2522                 QUERY_STRING(msg, info5.account_name.string,   "sAMAccountName");
2523                 QUERY_STRING(msg, info5.full_name.string,      "displayName");
2524                 QUERY_RID   (msg, info5.rid,                   "objectSid");
2525                 QUERY_UINT  (msg, info5.primary_gid,           "primaryGroupID");
2526                 QUERY_STRING(msg, info5.home_directory.string, "homeDirectory");
2527                 QUERY_STRING(msg, info5.home_drive.string,     "homeDrive");
2528                 QUERY_STRING(msg, info5.logon_script.string,   "scriptPath");
2529                 QUERY_STRING(msg, info5.profile_path.string,   "profilePath");
2530                 QUERY_STRING(msg, info5.description.string,    "description");
2531                 QUERY_STRING(msg, info5.workstations.string,   "userWorkstations");
2532                 QUERY_NTTIME(msg, info5.last_logon,            "lastLogon");
2533                 QUERY_NTTIME(msg, info5.last_logoff,           "lastLogoff");
2534                 QUERY_LHOURS(msg, info5.logon_hours,           "logonHours");
2535                 QUERY_UINT  (msg, info5.bad_password_count,    "badPwdCount");
2536                 QUERY_UINT  (msg, info5.logon_count,           "logonCount");
2537                 QUERY_NTTIME(msg, info5.last_password_change,  "pwdLastSet");
2538                 QUERY_NTTIME(msg, info5.acct_expiry,           "accountExpires");
2539                 QUERY_AFLAGS(msg, info5.acct_flags,            "userAccountControl");
2540                 break;
2541
2542         case 6:
2543                 QUERY_STRING(msg, info6.account_name.string,   "sAMAccountName");
2544                 QUERY_STRING(msg, info6.full_name.string,      "displayName");
2545                 break;
2546
2547         case 7:
2548                 QUERY_STRING(msg, info7.account_name.string,   "sAMAccountName");
2549                 break;
2550
2551         case 8:
2552                 QUERY_STRING(msg, info8.full_name.string,      "displayName");
2553                 break;
2554
2555         case 9:
2556                 QUERY_UINT  (msg, info9.primary_gid,           "primaryGroupID");
2557                 break;
2558
2559         case 10:
2560                 QUERY_STRING(msg, info10.home_directory.string,"homeDirectory");
2561                 QUERY_STRING(msg, info10.home_drive.string,    "homeDrive");
2562                 break;
2563
2564         case 11:
2565                 QUERY_STRING(msg, info11.logon_script.string,  "scriptPath");
2566                 break;
2567
2568         case 12:
2569                 QUERY_STRING(msg, info12.profile_path.string,  "profilePath");
2570                 break;
2571
2572         case 13:
2573                 QUERY_STRING(msg, info13.description.string,   "description");
2574                 break;
2575
2576         case 14:
2577                 QUERY_STRING(msg, info14.workstations.string,  "userWorkstations");
2578                 break;
2579
2580         case 16:
2581                 QUERY_AFLAGS(msg, info16.acct_flags,           "userAccountControl");
2582                 break;
2583
2584         case 17:
2585                 QUERY_NTTIME(msg, info17.acct_expiry,          "accountExpires");
2586
2587         case 20:
2588                 QUERY_STRING(msg, info20.parameters.string,    "userParameters");
2589                 break;
2590
2591         case 21:
2592                 QUERY_NTTIME(msg, info21.last_logon,           "lastLogon");
2593                 QUERY_NTTIME(msg, info21.last_logoff,          "lastLogoff");
2594                 QUERY_NTTIME(msg, info21.last_password_change, "pwdLastSet");
2595                 QUERY_NTTIME(msg, info21.acct_expiry,          "accountExpires");
2596                 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
2597                 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
2598                 QUERY_STRING(msg, info21.account_name.string,  "sAMAccountName");
2599                 QUERY_STRING(msg, info21.full_name.string,     "displayName");
2600                 QUERY_STRING(msg, info21.home_directory.string,"homeDirectory");
2601                 QUERY_STRING(msg, info21.home_drive.string,    "homeDrive");
2602                 QUERY_STRING(msg, info21.logon_script.string,  "scriptPath");
2603                 QUERY_STRING(msg, info21.profile_path.string,  "profilePath");
2604                 QUERY_STRING(msg, info21.description.string,   "description");
2605                 QUERY_STRING(msg, info21.workstations.string,  "userWorkstations");
2606                 QUERY_STRING(msg, info21.comment.string,       "comment");
2607                 QUERY_STRING(msg, info21.parameters.string,    "userParameters");
2608                 QUERY_RID   (msg, info21.rid,                  "objectSid");
2609                 QUERY_UINT  (msg, info21.primary_gid,          "primaryGroupID");
2610                 QUERY_AFLAGS(msg, info21.acct_flags,           "userAccountControl");
2611                 r->out.info->info21.fields_present = 0x00FFFFFF;
2612                 QUERY_LHOURS(msg, info21.logon_hours,          "logonHours");
2613                 QUERY_UINT  (msg, info21.bad_password_count,   "badPwdCount");
2614                 QUERY_UINT  (msg, info21.logon_count,          "logonCount");
2615                 QUERY_UINT  (msg, info21.country_code,         "countryCode");
2616                 QUERY_UINT  (msg, info21.code_page,            "codePage");
2617                 break;
2618                 
2619
2620         default:
2621                 r->out.info = NULL;
2622                 return NT_STATUS_INVALID_INFO_CLASS;
2623         }
2624         
2625         return NT_STATUS_OK;
2626 }
2627
2628
2629 /* 
2630   samr_SetUserInfo 
2631 */
2632 static NTSTATUS samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2633                                  struct samr_SetUserInfo *r)
2634 {
2635         struct dcesrv_handle *h;
2636         struct samr_account_state *a_state;
2637         struct ldb_message *msg;
2638         int ret;
2639         NTSTATUS status = NT_STATUS_OK;
2640
2641         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2642
2643         a_state = h->data;
2644
2645         msg = ldb_msg_new(mem_ctx);
2646         if (msg == NULL) {
2647                 return NT_STATUS_NO_MEMORY;
2648         }
2649
2650         msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
2651         if (!msg->dn) {
2652                 return NT_STATUS_NO_MEMORY;
2653         }
2654
2655         switch (r->in.level) {
2656         case 2:
2657                 SET_STRING(msg, info2.comment.string,          "comment");
2658                 SET_UINT  (msg, info2.country_code,            "countryCode");
2659                 SET_UINT  (msg, info2.code_page,               "codePage");
2660                 break;
2661
2662         case 4:
2663                 SET_LHOURS(msg, info4.logon_hours,             "logonHours");
2664                 break;
2665
2666         case 6:
2667                 SET_STRING(msg, info6.full_name.string,        "displayName");
2668                 break;
2669
2670         case 7:
2671                 SET_STRING(msg, info7.account_name.string,     "samAccountName");
2672                 break;
2673
2674         case 8:
2675                 SET_STRING(msg, info8.full_name.string,        "displayName");
2676                 break;
2677
2678         case 9:
2679                 SET_UINT(msg, info9.primary_gid,               "primaryGroupID");
2680                 break;
2681
2682         case 10:
2683                 SET_STRING(msg, info10.home_directory.string,  "homeDirectory");
2684                 SET_STRING(msg, info10.home_drive.string,      "homeDrive");
2685                 break;
2686
2687         case 11:
2688                 SET_STRING(msg, info11.logon_script.string,    "scriptPath");
2689                 break;
2690
2691         case 12:
2692                 SET_STRING(msg, info12.profile_path.string,    "profilePath");
2693                 break;
2694
2695         case 13:
2696                 SET_STRING(msg, info13.description.string,     "description");
2697                 break;
2698
2699         case 14:
2700                 SET_STRING(msg, info14.workstations.string,    "userWorkstations");
2701                 break;
2702
2703         case 16:
2704                 SET_AFLAGS(msg, info16.acct_flags,             "userAccountControl");
2705                 break;
2706
2707         case 20:
2708                 SET_STRING(msg, info20.parameters.string,      "userParameters");
2709                 break;
2710
2711         case 21:
2712 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
2713                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
2714                         SET_STRING(msg, info21.account_name.string, "samAccountName");
2715                 IFSET(SAMR_FIELD_FULL_NAME)         
2716                         SET_STRING(msg, info21.full_name.string,    "displayName");
2717                 IFSET(SAMR_FIELD_DESCRIPTION)  
2718                         SET_STRING(msg, info21.description.string,  "description");
2719                 IFSET(SAMR_FIELD_COMMENT)      
2720                         SET_STRING(msg, info21.comment.string,      "comment");
2721                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
2722                         SET_STRING(msg, info21.logon_script.string, "scriptPath");
2723                 IFSET(SAMR_FIELD_PROFILE_PATH)      
2724                         SET_STRING(msg, info21.profile_path.string, "profilePath");
2725                 IFSET(SAMR_FIELD_WORKSTATIONS)  
2726                         SET_STRING(msg, info21.workstations.string, "userWorkstations");
2727                 IFSET(SAMR_FIELD_LOGON_HOURS)  
2728                         SET_LHOURS(msg, info21.logon_hours,         "logonHours");
2729                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
2730                         SET_AFLAGS(msg, info21.acct_flags,          "userAccountControl");
2731                 IFSET(SAMR_FIELD_PARAMETERS)     
2732                         SET_STRING(msg, info21.parameters.string,   "userParameters");
2733                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
2734                         SET_UINT  (msg, info21.country_code,        "countryCode");
2735                 IFSET(SAMR_FIELD_CODE_PAGE)    
2736                         SET_UINT  (msg, info21.code_page,           "codePage");
2737
2738
2739                 /* Any reason the rest of these can't be set? */
2740 #undef IFSET
2741                 break;
2742
2743         case 23:
2744 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
2745                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
2746                         SET_STRING(msg, info23.info.account_name.string, "samAccountName");
2747                 IFSET(SAMR_FIELD_FULL_NAME)         
2748                         SET_STRING(msg, info23.info.full_name.string,    "displayName");
2749                 IFSET(SAMR_FIELD_DESCRIPTION)  
2750                         SET_STRING(msg, info23.info.description.string,  "description");
2751                 IFSET(SAMR_FIELD_COMMENT)      
2752                         SET_STRING(msg, info23.info.comment.string,      "comment");
2753                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
2754                         SET_STRING(msg, info23.info.logon_script.string, "scriptPath");
2755                 IFSET(SAMR_FIELD_PROFILE_PATH)      
2756                         SET_STRING(msg, info23.info.profile_path.string, "profilePath");
2757                 IFSET(SAMR_FIELD_WORKSTATIONS)  
2758                         SET_STRING(msg, info23.info.workstations.string, "userWorkstations");
2759                 IFSET(SAMR_FIELD_LOGON_HOURS)  
2760                         SET_LHOURS(msg, info23.info.logon_hours,         "logonHours");
2761                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
2762                         SET_AFLAGS(msg, info23.info.acct_flags,          "userAccountControl");
2763                 IFSET(SAMR_FIELD_PARAMETERS)     
2764                         SET_STRING(msg, info23.info.parameters.string,   "userParameters");
2765                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
2766                         SET_UINT  (msg, info23.info.country_code,        "countryCode");
2767                 IFSET(SAMR_FIELD_CODE_PAGE)    
2768                         SET_UINT  (msg, info23.info.code_page,           "codePage");
2769                 IFSET(SAMR_FIELD_PASSWORD) {
2770                         status = samr_set_password(dce_call,
2771                                                    a_state->sam_ctx,
2772                                                    a_state->account_dn,
2773                                                    a_state->domain_state->domain_dn,
2774                                                    mem_ctx, msg, 
2775                                                    &r->in.info->info23.password);
2776                 } else IFSET(SAMR_FIELD_PASSWORD2) {
2777                         status = samr_set_password(dce_call,
2778                                                    a_state->sam_ctx,
2779                                                    a_state->account_dn,
2780                                                    a_state->domain_state->domain_dn,
2781                                                    mem_ctx, msg, 
2782                                                    &r->in.info->info23.password);
2783                 }
2784 #undef IFSET
2785                 break;
2786
2787                 /* the set password levels are handled separately */
2788         case 24:
2789                 status = samr_set_password(dce_call,
2790                                            a_state->sam_ctx,
2791                                            a_state->account_dn,
2792                                            a_state->domain_state->domain_dn,
2793                                            mem_ctx, msg, 
2794                                            &r->in.info->info24.password);
2795                 break;
2796
2797         case 25:
2798 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
2799                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
2800                         SET_STRING(msg, info25.info.account_name.string, "samAccountName");
2801                 IFSET(SAMR_FIELD_FULL_NAME)         
2802                         SET_STRING(msg, info25.info.full_name.string,    "displayName");
2803                 IFSET(SAMR_FIELD_DESCRIPTION)  
2804                         SET_STRING(msg, info25.info.description.string,  "description");
2805                 IFSET(SAMR_FIELD_COMMENT)      
2806                         SET_STRING(msg, info25.info.comment.string,      "comment");
2807                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
2808                         SET_STRING(msg, info25.info.logon_script.string, "scriptPath");
2809                 IFSET(SAMR_FIELD_PROFILE_PATH)      
2810                         SET_STRING(msg, info25.info.profile_path.string, "profilePath");
2811                 IFSET(SAMR_FIELD_WORKSTATIONS)  
2812                         SET_STRING(msg, info25.info.workstations.string, "userWorkstations");
2813                 IFSET(SAMR_FIELD_LOGON_HOURS)  
2814                         SET_LHOURS(msg, info25.info.logon_hours,         "logonHours");
2815                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
2816                         SET_AFLAGS(msg, info25.info.acct_flags,          "userAccountControl");
2817                 IFSET(SAMR_FIELD_PARAMETERS)     
2818                         SET_STRING(msg, info25.info.parameters.string,   "userParameters");
2819                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
2820                         SET_UINT  (msg, info25.info.country_code,        "countryCode");
2821                 IFSET(SAMR_FIELD_CODE_PAGE)    
2822                         SET_UINT  (msg, info25.info.code_page,           "codePage");
2823                 IFSET(SAMR_FIELD_PASSWORD) {
2824                         status = samr_set_password_ex(dce_call,
2825                                                       a_state->sam_ctx,
2826                                                       a_state->account_dn,
2827                                                       a_state->domain_state->domain_dn,
2828                                                       mem_ctx, msg, 
2829                                                       &r->in.info->info25.password);
2830                 } else IFSET(SAMR_FIELD_PASSWORD2) {
2831                         status = samr_set_password_ex(dce_call,
2832                                                       a_state->sam_ctx,
2833                                                       a_state->account_dn,
2834                                                       a_state->domain_state->domain_dn,
2835                                                       mem_ctx, msg, 
2836                                                       &r->in.info->info25.password);
2837                 }
2838 #undef IFSET
2839                 break;
2840
2841                 /* the set password levels are handled separately */
2842         case 26:
2843                 status = samr_set_password_ex(dce_call,
2844                                               a_state->sam_ctx,
2845                                               a_state->account_dn,
2846                                               a_state->domain_state->domain_dn,
2847                                               mem_ctx, msg, 
2848                                               &r->in.info->info26.password);
2849                 break;
2850                 
2851
2852         default:
2853                 /* many info classes are not valid for SetUserInfo */
2854                 return NT_STATUS_INVALID_INFO_CLASS;
2855         }
2856
2857         if (!NT_STATUS_IS_OK(status)) {
2858                 return status;
2859         }
2860
2861         /* modify the samdb record */
2862         ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
2863         if (ret != 0) {
2864                 /* we really need samdb.c to return NTSTATUS */
2865                 return NT_STATUS_UNSUCCESSFUL;
2866         }
2867
2868         return NT_STATUS_OK;
2869 }
2870
2871
2872 /* 
2873   samr_GetGroupsForUser 
2874 */
2875 static NTSTATUS samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2876                        struct samr_GetGroupsForUser *r)
2877 {
2878         struct dcesrv_handle *h;
2879         struct samr_account_state *a_state;
2880         struct samr_domain_state *d_state;
2881         struct ldb_message **res;
2882         const char * const attrs[2] = { "objectSid", NULL };
2883         struct samr_RidWithAttributeArray *array;
2884         int count;
2885
2886         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2887
2888         a_state = h->data;
2889         d_state = a_state->domain_state;
2890
2891         count = samdb_search_domain(a_state->sam_ctx, mem_ctx, NULL, &res,
2892                                     attrs, d_state->domain_sid,
2893                                     "(&(member=%s)(grouptype=%s)(objectclass=group))",
2894                                     ldb_dn_linearize(mem_ctx, a_state->account_dn),
2895                                     ldb_hexstr(mem_ctx,
2896                                                GTYPE_SECURITY_GLOBAL_GROUP));
2897         if (count < 0)
2898                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2899
2900         array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
2901         if (array == NULL)
2902                 return NT_STATUS_NO_MEMORY;
2903
2904         array->count = 0;
2905         array->rids = NULL;
2906
2907         if (count > 0) {
2908                 int i;
2909                 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
2910                                             count);
2911
2912                 if (array->rids == NULL)
2913                         return NT_STATUS_NO_MEMORY;
2914
2915                 for (i=0; i<count; i++) {
2916                         struct dom_sid *group_sid;
2917
2918                         group_sid = samdb_result_dom_sid(mem_ctx, res[i],
2919                                                          "objectSid");
2920                         if (group_sid == NULL) {
2921                                 DEBUG(0, ("Couldn't find objectSid attrib\n"));
2922                                 continue;
2923                         }
2924
2925                         array->rids[array->count].rid =
2926                                 group_sid->sub_auths[group_sid->num_auths-1];
2927                         array->rids[array->count].attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
2928                         array->count += 1;
2929                 }
2930         }
2931
2932         r->out.rids = array;
2933
2934         return NT_STATUS_OK;
2935 }
2936
2937
2938 /* 
2939   samr_QueryDisplayInfo 
2940 */
2941 static NTSTATUS samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2942                        struct samr_QueryDisplayInfo *r)
2943 {
2944         struct dcesrv_handle *h;
2945         struct samr_domain_state *d_state;
2946         struct ldb_message **res;
2947         int ldb_cnt, count, i;
2948         const char * const attrs[4] = { "objectSid", "sAMAccountName",
2949                                         "description", NULL };
2950         struct samr_DispEntryFull *entriesFull = NULL;
2951         struct samr_DispEntryAscii *entriesAscii = NULL;
2952         struct samr_DispEntryGeneral * entriesGeneral = NULL;
2953         const char *filter;
2954
2955         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2956
2957         d_state = h->data;
2958
2959         switch (r->in.level) {
2960         case 1:
2961         case 4:
2962                 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
2963                                          "(sAMAccountType=%s))",
2964                                          ldb_hexstr(mem_ctx,
2965                                                     ATYPE_NORMAL_ACCOUNT));
2966                 break;
2967         case 2:
2968                 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
2969                                          "(sAMAccountType=%s))",
2970                                          ldb_hexstr(mem_ctx,
2971                                                     ATYPE_WORKSTATION_TRUST));
2972                 break;
2973         case 3:
2974         case 5:
2975                 filter = talloc_asprintf(mem_ctx, "(&(grouptype=%s)"
2976                                          "(objectclass=group))",
2977                                          ldb_hexstr(mem_ctx, GTYPE_SECURITY_GLOBAL_GROUP));
2978                 break;
2979         default:
2980                 return NT_STATUS_INVALID_INFO_CLASS;
2981         }
2982
2983         /* search for all requested objects in this domain. This could
2984            possibly be cached and resumed based on resume_key */
2985         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
2986                                       d_state->domain_dn, &res, attrs,
2987                                       d_state->domain_sid, "%s", filter);
2988         if (ldb_cnt == -1) {
2989                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2990         }
2991         if (ldb_cnt == 0 || r->in.max_entries == 0) {
2992                 return NT_STATUS_OK;
2993         }
2994
2995         switch (r->in.level) {
2996         case 1:
2997                 entriesGeneral = talloc_array(mem_ctx,
2998                                                 struct samr_DispEntryGeneral,
2999                                                 ldb_cnt);
3000                 break;
3001         case 2:
3002         case 3:
3003                 entriesFull = talloc_array(mem_ctx,
3004                                              struct samr_DispEntryFull,
3005                                              ldb_cnt);
3006                 break;
3007         case 4:
3008         case 5:
3009                 entriesAscii = talloc_array(mem_ctx,
3010                                               struct samr_DispEntryAscii,
3011                                               ldb_cnt);
3012                 break;
3013         }
3014
3015         if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3016             (entriesAscii == NULL))
3017                 return NT_STATUS_NO_MEMORY;
3018
3019         count = 0;
3020
3021         for (i=0; i<ldb_cnt; i++) {
3022                 struct dom_sid *objectsid;
3023
3024                 objectsid = samdb_result_dom_sid(mem_ctx, res[i],
3025                                                  "objectSid");
3026                 if (objectsid == NULL)
3027                         continue;
3028
3029                 switch(r->in.level) {
3030                 case 1:
3031                         entriesGeneral[count].idx = count + 1;
3032                         entriesGeneral[count].rid = 
3033                                 objectsid->sub_auths[objectsid->num_auths-1];
3034                         entriesGeneral[count].acct_flags =
3035                                 samdb_result_acct_flags(res[i], 
3036                                                         "userAccountControl");
3037                         entriesGeneral[count].account_name.string =
3038                                 samdb_result_string(res[i],
3039                                                     "sAMAccountName", "");
3040                         entriesGeneral[count].full_name.string =
3041                                 samdb_result_string(res[i], "displayName", "");
3042                         entriesGeneral[count].description.string =
3043                                 samdb_result_string(res[i], "description", "");
3044                         break;
3045                 case 2:
3046                 case 3:
3047                         entriesFull[count].idx = count + 1;
3048                         entriesFull[count].rid =
3049                                 objectsid->sub_auths[objectsid->num_auths-1];
3050                         entriesFull[count].acct_flags =
3051                                 samdb_result_acct_flags(res[i], 
3052                                                         "userAccountControl");
3053                         if (r->in.level == 3) {
3054                                 /* We get a "7" here for groups */
3055                                 entriesFull[count].acct_flags = 7;
3056                         }
3057                         entriesFull[count].account_name.string =
3058                                 samdb_result_string(res[i], "sAMAccountName",
3059                                                     "");
3060                         entriesFull[count].description.string =
3061                                 samdb_result_string(res[i], "description", "");
3062                         break;
3063                 case 4:
3064                 case 5:
3065                         entriesAscii[count].idx = count + 1;
3066                         entriesAscii[count].account_name.string =
3067                                 samdb_result_string(res[i], "sAMAccountName",
3068                                                     "");
3069                         break;
3070                 }
3071
3072                 count += 1;
3073         }
3074
3075         r->out.total_size = count;
3076
3077         if (r->in.start_idx >= count) {
3078                 r->out.returned_size = 0;
3079                 switch(r->in.level) {
3080                 case 1:
3081                         r->out.info.info1.count = r->out.returned_size;
3082                         r->out.info.info1.entries = NULL;
3083                         break;
3084                 case 2:
3085                         r->out.info.info2.count = r->out.returned_size;
3086                         r->out.info.info2.entries = NULL;
3087                         break;
3088                 case 3:
3089                         r->out.info.info3.count = r->out.returned_size;
3090                         r->out.info.info3.entries = NULL;
3091                         break;
3092                 case 4:
3093                         r->out.info.info4.count = r->out.returned_size;
3094                         r->out.info.info4.entries = NULL;
3095                         break;
3096                 case 5:
3097                         r->out.info.info5.count = r->out.returned_size;
3098                         r->out.info.info5.entries = NULL;
3099                         break;
3100                 }
3101         } else {
3102                 r->out.returned_size = MIN(count - r->in.start_idx,
3103                                            r->in.max_entries);
3104                 switch(r->in.level) {
3105                 case 1:
3106                         r->out.info.info1.count = r->out.returned_size;
3107                         r->out.info.info1.entries =
3108                                 &(entriesGeneral[r->in.start_idx]);
3109                         break;
3110                 case 2:
3111                         r->out.info.info2.count = r->out.returned_size;
3112                         r->out.info.info2.entries =
3113                                 &(entriesFull[r->in.start_idx]);
3114                         break;
3115                 case 3:
3116                         r->out.info.info3.count = r->out.returned_size;
3117                         r->out.info.info3.entries =
3118                                 &(entriesFull[r->in.start_idx]);
3119                         break;
3120                 case 4:
3121                         r->out.info.info4.count = r->out.returned_size;
3122                         r->out.info.info4.entries =
3123                                 &(entriesAscii[r->in.start_idx]);
3124                         break;
3125                 case 5:
3126                         r->out.info.info5.count = r->out.returned_size;
3127                         r->out.info.info5.entries =
3128                                 &(entriesAscii[r->in.start_idx]);
3129                         break;
3130                 }
3131         }
3132
3133         return (r->out.returned_size < (count - r->in.start_idx)) ?
3134                 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3135 }
3136
3137
3138 /* 
3139   samr_GetDisplayEnumerationIndex 
3140 */
3141 static NTSTATUS samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3142                        struct samr_GetDisplayEnumerationIndex *r)
3143 {
3144         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3145 }
3146
3147
3148 /* 
3149   samr_TestPrivateFunctionsDomain 
3150 */
3151 static NTSTATUS samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3152                        struct samr_TestPrivateFunctionsDomain *r)
3153 {
3154         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3155 }
3156
3157
3158 /* 
3159   samr_TestPrivateFunctionsUser 
3160 */
3161 static NTSTATUS samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3162                        struct samr_TestPrivateFunctionsUser *r)
3163 {
3164         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3165 }
3166
3167
3168 /* 
3169   samr_GetUserPwInfo 
3170 */
3171 static NTSTATUS samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3172                                    struct samr_GetUserPwInfo *r)
3173 {
3174         struct dcesrv_handle *h;
3175         struct samr_account_state *a_state;
3176
3177         ZERO_STRUCT(r->out.info);
3178
3179         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3180
3181         a_state = h->data;
3182
3183         r->out.info.min_password_length = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0,
3184                                                             a_state->domain_state->domain_dn, "minPwdLength", 
3185                                                             NULL);
3186         r->out.info.password_properties = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0,
3187                                                             a_state->account_dn, 
3188                                                             "pwdProperties", NULL);
3189         return NT_STATUS_OK;
3190 }
3191
3192
3193 /* 
3194   samr_RemoveMemberFromForeignDomain 
3195 */
3196 static NTSTATUS samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3197                        struct samr_RemoveMemberFromForeignDomain *r)
3198 {
3199         struct dcesrv_handle *h;
3200         struct samr_domain_state *d_state;
3201         const char *memberdn;
3202         struct ldb_message **res;
3203         const char * const attrs[3] = { "distinguishedName", "objectSid", NULL };
3204         int i, count;
3205
3206         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3207
3208         d_state = h->data;
3209
3210         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3211                                        "distinguishedName", "(objectSid=%s)", 
3212                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3213         if (memberdn == NULL)
3214                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3215
3216         /* TODO: Does this call only remove alias members, or does it do this
3217          * for domain groups as well? */
3218
3219         count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3220                                     d_state->domain_dn, &res, attrs,
3221                                     d_state->domain_sid,
3222                                     "(&(member=%s)(objectClass=group)"
3223                                     "(|(groupType=%s)(groupType=%s)))",
3224                                     memberdn,
3225                                     ldb_hexstr(mem_ctx,
3226                                                GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
3227                                     ldb_hexstr(mem_ctx,
3228                                                GTYPE_SECURITY_DOMAIN_LOCAL_GROUP));
32