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