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