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