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