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