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