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