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