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