r4367: Implement samr_AddGroupMember, samr_DeleteGroupMember and
[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   samr_EnumDomainGroups 
543 */
544 static NTSTATUS samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
545                                       struct samr_EnumDomainGroups *r)
546 {
547         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
548 }
549
550
551 /* 
552   samr_CreateUser2 
553
554   TODO: This should do some form of locking, especially around the rid allocation
555 */
556 static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
557                                  struct samr_CreateUser2 *r)
558 {
559         struct samr_domain_state *d_state;
560         struct samr_account_state *a_state;
561         struct dcesrv_handle *h;
562         const char *name;
563         struct ldb_message msg;
564         uint32_t rid;
565         const char *account_name, *sidstr, *guidstr;
566         struct GUID guid;
567         time_t now = time(NULL);
568         struct dcesrv_handle *u_handle;
569         int ret;
570         NTSTATUS status;
571         const char *container, *additional_class=NULL;
572
573         ZERO_STRUCTP(r->out.user_handle);
574         *r->out.access_granted = 0;
575         *r->out.rid = 0;
576
577         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
578
579         d_state = h->data;
580
581         account_name = r->in.account_name->string;
582
583         if (account_name == NULL) {
584                 return NT_STATUS_INVALID_PARAMETER;
585         }
586
587         /* check if the user already exists */
588         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL, 
589                                    "sAMAccountName", 
590                                    "(&(sAMAccountName=%s)(objectclass=user))", account_name);
591         if (name != NULL) {
592                 return NT_STATUS_USER_EXISTS;
593         }
594
595         ZERO_STRUCT(msg);
596
597         /* This must be one of these values *only* */
598         if (r->in.acct_flags == ACB_NORMAL) {
599                 /* pull in all the template attributes */
600                 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg, 
601                                           "(&(name=TemplateUser)(objectclass=userTemplate))");
602                 if (ret != 0) {
603                         DEBUG(0,("Failed to load TemplateUser from samdb\n"));
604                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
605                 }
606
607                 container = "Users";
608
609         } else if (r->in.acct_flags == ACB_WSTRUST) {
610                 /* pull in all the template attributes */
611                 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg, 
612                                           "(&(name=TemplateMemberServer)(objectclass=userTemplate))");
613                 if (ret != 0) {
614                         DEBUG(0,("Failed to load TemplateMemberServer from samdb\n"));
615                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
616                 }
617
618                 container = "Computers";
619                 additional_class = "computer";
620
621         } else if (r->in.acct_flags == ACB_SVRTRUST) {
622                 /* pull in all the template attributes */
623                 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg, 
624                                           "(&(name=TemplateDomainController)(objectclass=userTemplate))");
625                 if (ret != 0) {
626                         DEBUG(0,("Failed to load TemplateDomainController from samdb\n"));
627                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
628                 }
629
630                 container = "Domain Controllers";
631                 additional_class = "computer";
632
633         } else if (r->in.acct_flags == ACB_DOMTRUST) {
634                 /* pull in all the template attributes */
635                 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg, 
636                                           "(&(name=TemplateTrustingDomain)(objectclass=userTemplate))");
637                 if (ret != 0) {
638                         DEBUG(0,("Failed to load TemplateTrustingDomain from samdb\n"));
639                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
640                 }
641
642                 container = "Users";
643                 additional_class = "computer";
644
645         } else {
646                 return NT_STATUS_INVALID_PARAMETER;
647         }
648
649         /* allocate a rid */
650         status = samdb_allocate_next_id(d_state->sam_ctx, mem_ctx, 
651                                         d_state->domain_dn, "nextRid", &rid);
652         if (!NT_STATUS_IS_OK(status)) {
653                 return status;
654         }
655
656         /* and the users SID */
657         sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, rid);
658         if (!sidstr) {
659                 return NT_STATUS_NO_MEMORY;
660         }
661
662         /* a new GUID */
663         guid = GUID_random();
664         guidstr = GUID_string(mem_ctx, &guid);
665         if (!guidstr) {
666                 return NT_STATUS_NO_MEMORY;
667         }
668
669         /* add core elements to the ldb_message for the user */
670         msg.dn = talloc_asprintf(mem_ctx, "CN=%s,CN=%s,%s", account_name, container, d_state->domain_dn);
671         if (!msg.dn) {
672                 return NT_STATUS_NO_MEMORY;             
673         }
674         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "name", account_name);
675         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "cn", account_name);
676         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "sAMAccountName", account_name);
677         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectClass", "user");
678         if (additional_class) {
679                 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectClass", additional_class);
680         }
681         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectSid", sidstr);
682         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectGUID", guidstr);
683         samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenCreated", now);
684         samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenChanged", now);
685
686         /* create the user */
687         ret = samdb_add(d_state->sam_ctx, mem_ctx, &msg);
688         if (ret != 0) {
689                 DEBUG(0,("Failed to create user record %s\n", msg.dn));
690                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
691         }
692
693         a_state = talloc_p(d_state, struct samr_account_state);
694         if (!a_state) {
695                 return NT_STATUS_NO_MEMORY;
696         }
697         a_state->sam_ctx = d_state->sam_ctx;
698         a_state->access_mask = r->in.access_mask;
699         a_state->domain_state = talloc_reference(a_state, d_state);
700         a_state->account_dn = talloc_steal(a_state, msg.dn);
701         a_state->account_sid = talloc_steal(a_state, sidstr);
702         a_state->account_name = talloc_strdup(a_state, account_name);
703         if (!a_state->account_name) {
704                 return NT_STATUS_NO_MEMORY;
705         }
706
707         /* create the policy handle */
708         u_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_USER);
709         if (!u_handle) {
710                 return NT_STATUS_NO_MEMORY;
711         }
712
713         u_handle->data = a_state;
714         u_handle->destroy = samr_handle_destroy;
715
716         /* the domain state is in use one more time */
717         
718
719         *r->out.user_handle = u_handle->wire_handle;
720         *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
721         *r->out.rid = rid;      
722
723         return NT_STATUS_OK;
724 }
725
726
727 /* 
728   samr_CreateUser 
729 */
730 static NTSTATUS samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
731                                 struct samr_CreateUser *r)
732 {
733         struct samr_CreateUser2 r2;
734         uint32_t access_granted = 0;
735
736
737         /* a simple wrapper around samr_CreateUser2 works nicely */
738         r2.in.domain_handle = r->in.domain_handle;
739         r2.in.account_name = r->in.account_name;
740         r2.in.acct_flags = ACB_NORMAL;
741         r2.in.access_mask = r->in.access_mask;
742         r2.out.user_handle = r->out.user_handle;
743         r2.out.access_granted = &access_granted;
744         r2.out.rid = r->out.rid;
745
746         return samr_CreateUser2(dce_call, mem_ctx, &r2);
747 }
748
749 /*
750   comparison function for sorting SamEntry array
751 */
752 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
753 {
754         return e1->idx - e2->idx;
755 }
756
757 /* 
758   samr_EnumDomainUsers 
759 */
760 static NTSTATUS samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
761                                      struct samr_EnumDomainUsers *r)
762 {
763         struct dcesrv_handle *h;
764         struct samr_domain_state *d_state;
765         struct ldb_message **res;
766         int count, i, first;
767         struct samr_SamEntry *entries;
768         const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
769
770         *r->out.resume_handle = 0;
771         r->out.sam = NULL;
772         r->out.num_entries = 0;
773
774         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
775
776         d_state = h->data;
777         
778         /* search for all users in this domain. This could possibly be cached and 
779            resumed based on resume_key */
780         count = samdb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs, 
781                              "objectclass=user");
782         if (count == -1) {
783                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
784         }
785         if (count == 0 || r->in.max_size == 0) {
786                 return NT_STATUS_OK;
787         }
788
789         /* convert to SamEntry format */
790         entries = talloc_array_p(mem_ctx, struct samr_SamEntry, count);
791         if (!entries) {
792                 return NT_STATUS_NO_MEMORY;
793         }
794         for (i=0;i<count;i++) {
795                 entries[i].idx = samdb_result_rid_from_sid(mem_ctx, res[i], "objectSid", 0);
796                 entries[i].name.string = samdb_result_string(res[i], "sAMAccountName", "");
797         }
798
799         /* sort the results by rid */
800         qsort(entries, count, sizeof(struct samr_SamEntry), 
801               (comparison_fn_t)compare_SamEntry);
802
803         /* find the first entry to return */
804         for (first=0;
805              first<count && entries[first].idx <= *r->in.resume_handle;
806              first++) ;
807
808         if (first == count) {
809                 return NT_STATUS_OK;
810         }
811
812         /* return the rest, limit by max_size. Note that we 
813            use the w2k3 element size value of 54 */
814         r->out.num_entries = count - first;
815         r->out.num_entries = MIN(r->out.num_entries, 
816                                  1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
817
818         r->out.sam = talloc_p(mem_ctx, struct samr_SamArray);
819         if (!r->out.sam) {
820                 return NT_STATUS_NO_MEMORY;
821         }
822
823         r->out.sam->entries = entries+first;
824         r->out.sam->count = r->out.num_entries;
825
826         if (r->out.num_entries < count - first) {
827                 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
828                 return STATUS_MORE_ENTRIES;
829         }
830
831         return NT_STATUS_OK;
832 }
833
834
835 /* 
836   samr_CreateDomAlias 
837 */
838 static NTSTATUS samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
839                        struct samr_CreateDomAlias *r)
840 {
841         struct samr_domain_state *d_state;
842         struct samr_account_state *a_state;
843         struct dcesrv_handle *h;
844         const char *aliasname, *name, *sidstr, *guidstr;
845         struct GUID guid;
846         time_t now = time(NULL);
847         struct ldb_message msg;
848         uint32_t rid;
849         struct dcesrv_handle *a_handle;
850         int ret;
851         NTSTATUS status;
852
853         ZERO_STRUCTP(r->out.alias_handle);
854         *r->out.rid = 0;
855
856         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
857
858         d_state = h->data;
859
860         aliasname = r->in.aliasname->string;
861
862         if (aliasname == NULL) {
863                 return NT_STATUS_INVALID_PARAMETER;
864         }
865
866         /* Check if alias already exists */
867         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
868                                    "sAMAccountName",
869                                    "(&(sAMAccountName=%s)(objectclass=group))",
870                                    aliasname);
871
872         if (name != NULL) {
873                 return NT_STATUS_ALIAS_EXISTS;
874         }
875
876         ZERO_STRUCT(msg);
877
878         /* pull in all the template attributes */
879         ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg, 
880                                   "(&(name=TemplateAlias)"
881                                   "(objectclass=aliasTemplate))");
882         if (ret != 0) {
883                 DEBUG(0,("Failed to load TemplateAlias from samdb\n"));
884                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
885         }
886
887         /* allocate a rid */
888         status = samdb_allocate_next_id(d_state->sam_ctx, mem_ctx, 
889                                         d_state->domain_dn, "nextRid", &rid);
890         if (!NT_STATUS_IS_OK(status)) {
891                 return status;
892         }
893
894         /* and the group SID */
895         sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, rid);
896         if (!sidstr) {
897                 return NT_STATUS_NO_MEMORY;
898         }
899
900         /* a new GUID */
901         guid = GUID_random();
902         guidstr = GUID_string(mem_ctx, &guid);
903         if (!guidstr) {
904                 return NT_STATUS_NO_MEMORY;
905         }
906
907         /* add core elements to the ldb_message for the user */
908         msg.dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Users,%s", aliasname,
909                                  d_state->domain_dn);
910         if (!msg.dn) {
911                 return NT_STATUS_NO_MEMORY;
912         }
913
914         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "name", aliasname);
915         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "cn", aliasname);
916         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "sAMAccountName", aliasname);
917         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectClass", "group");
918         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectSid", sidstr);
919         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectGUID", guidstr);
920         samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenCreated", now);
921         samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenChanged", now);
922
923         /* create the alias */
924         ret = samdb_add(d_state->sam_ctx, mem_ctx, &msg);
925         if (ret != 0) {
926                 DEBUG(0,("Failed to create alias record %s\n", msg.dn));
927                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
928         }
929
930         a_state = talloc_p(d_state, struct samr_account_state);
931         if (!a_state) {
932                 return NT_STATUS_NO_MEMORY;
933         }
934
935         a_state->sam_ctx = d_state->sam_ctx;
936         a_state->access_mask = r->in.access_mask;
937         a_state->domain_state = talloc_reference(a_state, d_state);
938         a_state->account_dn = talloc_steal(a_state, msg.dn);
939         a_state->account_sid = talloc_steal(a_state, sidstr);
940         a_state->account_name = talloc_strdup(a_state, aliasname);
941         if (!a_state->account_name) {
942                 return NT_STATUS_NO_MEMORY;
943         }
944
945         /* create the policy handle */
946         a_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_ALIAS);
947         if (a_handle == NULL)
948                 return NT_STATUS_NO_MEMORY;
949
950         a_handle->data = a_state;
951         a_handle->destroy = samr_handle_destroy;
952
953         *r->out.alias_handle = a_handle->wire_handle;
954         *r->out.rid = rid;
955
956         return NT_STATUS_OK;
957 }
958
959
960 /* 
961   samr_EnumDomainAliases 
962 */
963 static NTSTATUS samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
964                        struct samr_EnumDomainAliases *r)
965 {
966         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
967 }
968
969
970 /* 
971   samr_GetAliasMembership 
972 */
973 static NTSTATUS samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
974                        struct samr_GetAliasMembership *r)
975 {
976         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
977 }
978
979
980 /* 
981   samr_LookupNames 
982 */
983 static NTSTATUS samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
984                                  struct samr_LookupNames *r)
985 {
986         struct dcesrv_handle *h;
987         struct samr_domain_state *d_state;
988         int i;
989         NTSTATUS status = NT_STATUS_OK;
990         const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
991         int count;
992
993         ZERO_STRUCT(r->out.rids);
994         ZERO_STRUCT(r->out.types);
995
996         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
997
998         d_state = h->data;
999
1000         if (r->in.num_names == 0) {
1001                 return NT_STATUS_OK;
1002         }
1003
1004         r->out.rids.ids = talloc_array_p(mem_ctx, uint32_t, r->in.num_names);
1005         r->out.types.ids = talloc_array_p(mem_ctx, uint32_t, r->in.num_names);
1006         if (!r->out.rids.ids || !r->out.types.ids) {
1007                 return NT_STATUS_NO_MEMORY;
1008         }
1009         r->out.rids.count = r->in.num_names;
1010         r->out.types.count = r->in.num_names;
1011
1012         for (i=0;i<r->in.num_names;i++) {
1013                 struct ldb_message **res;
1014                 struct dom_sid2 *sid;
1015                 const char *sidstr;
1016                 uint32_t atype, rtype;
1017
1018                 r->out.rids.ids[i] = 0;
1019                 r->out.types.ids[i] = SID_NAME_UNKNOWN;
1020
1021                 count = samdb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs, 
1022                                      "sAMAccountName=%s", r->in.names[i].string);
1023                 if (count != 1) {
1024                         status = STATUS_SOME_UNMAPPED;
1025                         continue;
1026                 }
1027
1028                 sidstr = samdb_result_string(res[0], "objectSid", NULL);
1029                 if (sidstr == NULL) {
1030                         status = STATUS_SOME_UNMAPPED;
1031                         continue;
1032                 }
1033                 
1034                 sid = dom_sid_parse_talloc(mem_ctx, sidstr);
1035                 if (sid == NULL) {
1036                         status = STATUS_SOME_UNMAPPED;
1037                         continue;
1038                 }
1039
1040                 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1041                 if (atype == 0) {
1042                         status = STATUS_SOME_UNMAPPED;
1043                         continue;
1044                 }
1045
1046                 rtype = samdb_atype_map(atype);
1047                 
1048                 if (rtype == SID_NAME_UNKNOWN) {
1049                         status = STATUS_SOME_UNMAPPED;
1050                         continue;
1051                 }
1052
1053                 r->out.rids.ids[i] = sid->sub_auths[sid->num_auths-1];
1054                 r->out.types.ids[i] = rtype;
1055         }
1056         
1057
1058         return status;
1059 }
1060
1061
1062 /* 
1063   samr_LookupRids 
1064 */
1065 static NTSTATUS samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1066                        struct samr_LookupRids *r)
1067 {
1068         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1069 }
1070
1071
1072 /* 
1073   samr_OpenGroup 
1074 */
1075 static NTSTATUS samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1076                        struct samr_OpenGroup *r)
1077 {
1078         struct samr_domain_state *d_state;
1079         struct samr_account_state *a_state;
1080         struct dcesrv_handle *h;
1081         const char *groupname, *sidstr;
1082         struct ldb_message **msgs;
1083         struct dcesrv_handle *g_handle;
1084         const char * const attrs[2] = { "sAMAccountName", NULL };
1085         int ret;
1086
1087         ZERO_STRUCTP(r->out.group_handle);
1088
1089         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1090
1091         d_state = h->data;
1092
1093         /* form the group SID */
1094         sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, r->in.rid);
1095         if (!sidstr) {
1096                 return NT_STATUS_NO_MEMORY;
1097         }
1098
1099         /* search for the group record */
1100         ret = samdb_search(d_state->sam_ctx,
1101                            mem_ctx, d_state->domain_dn, &msgs, attrs,
1102                            "(&(objectSid=%s)(objectclass=group)"
1103                            "(grouptype=%s))",
1104                            sidstr, ldb_hexstr(mem_ctx,
1105                                               GTYPE_SECURITY_GLOBAL_GROUP));
1106         if (ret == 0) {
1107                 return NT_STATUS_NO_SUCH_GROUP;
1108         }
1109         if (ret != 1) {
1110                 DEBUG(0,("Found %d records matching sid %s\n", ret, sidstr));
1111                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1112         }
1113
1114         groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
1115         if (groupname == NULL) {
1116                 DEBUG(0,("sAMAccountName field missing for sid %s\n", sidstr));
1117                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1118         }
1119
1120         a_state = talloc_p(d_state, struct samr_account_state);
1121         if (!a_state) {
1122                 return NT_STATUS_NO_MEMORY;
1123         }
1124         a_state->sam_ctx = d_state->sam_ctx;
1125         a_state->access_mask = r->in.access_mask;
1126         a_state->domain_state = talloc_reference(a_state, d_state);
1127         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1128         a_state->account_sid = talloc_steal(a_state, sidstr);
1129         a_state->account_name = talloc_strdup(a_state, groupname);
1130         if (!a_state->account_name) {
1131                 return NT_STATUS_NO_MEMORY;
1132         }
1133
1134         /* create the policy handle */
1135         g_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_GROUP);
1136         if (!g_handle) {
1137                 return NT_STATUS_NO_MEMORY;
1138         }
1139
1140         g_handle->data = a_state;
1141         g_handle->destroy = samr_handle_destroy;
1142
1143         *r->out.group_handle = g_handle->wire_handle;
1144
1145         return NT_STATUS_OK;
1146 }
1147
1148 /* these query macros make samr_Query[User|Group]Info a bit easier to read */
1149
1150 #define QUERY_STRING(msg, field, attr) \
1151         r->out.info->field = samdb_result_string(msg, attr, "");
1152 #define QUERY_UINT(msg, field, attr) \
1153         r->out.info->field = samdb_result_uint(msg, attr, 0);
1154 #define QUERY_RID(msg, field, attr) \
1155         r->out.info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
1156 #define QUERY_NTTIME(msg, field, attr) \
1157         r->out.info->field = samdb_result_nttime(msg, attr, 0);
1158 #define QUERY_APASSC(msg, field, attr) \
1159         r->out.info->field = samdb_result_allow_password_change(a_state->sam_ctx, mem_ctx, \
1160                                                            a_state->domain_state->domain_dn, msg, attr);
1161 #define QUERY_FPASSC(msg, field, attr) \
1162         r->out.info->field = samdb_result_force_password_change(a_state->sam_ctx, mem_ctx, \
1163                                                            a_state->domain_state->domain_dn, msg, attr);
1164 #define QUERY_LHOURS(msg, field, attr) \
1165         r->out.info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
1166 #define QUERY_AFLAGS(msg, field, attr) \
1167         r->out.info->field = samdb_result_acct_flags(msg, attr);
1168
1169
1170 /* these are used to make the Set[User|Group]Info code easier to follow */
1171
1172 #define SET_STRING(mod, field, attr) do { \
1173         if (r->in.info->field == NULL) return NT_STATUS_INVALID_PARAMETER; \
1174         if (samdb_msg_add_string(a_state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
1175                 return NT_STATUS_NO_MEMORY; \
1176         } \
1177 } while (0)
1178
1179 #define SET_UINT(mod, field, attr) do { \
1180         if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
1181                 return NT_STATUS_NO_MEMORY; \
1182         } \
1183 } while (0)
1184
1185 #define SET_AFLAGS(msg, field, attr) do { \
1186         if (samdb_msg_add_acct_flags(a_state->sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
1187                 return NT_STATUS_NO_MEMORY; \
1188         } \
1189 } while (0)
1190
1191 #define SET_LHOURS(msg, field, attr) do { \
1192         if (samdb_msg_add_logon_hours(a_state->sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
1193                 return NT_STATUS_NO_MEMORY; \
1194         } \
1195 } while (0)
1196
1197 /* 
1198   samr_QueryGroupInfo 
1199 */
1200 static NTSTATUS samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1201                        struct samr_QueryGroupInfo *r)
1202 {
1203         struct dcesrv_handle *h;
1204         struct samr_account_state *a_state;
1205         struct ldb_message *msg, **res;
1206         const char * const attrs[4] = { "sAMAccountName", "description",
1207                                         "numMembers", NULL };
1208         int ret;
1209
1210         r->out.info = NULL;
1211
1212         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1213
1214         a_state = h->data;
1215
1216         /* pull all the group attributes */
1217         ret = samdb_search(a_state->sam_ctx, mem_ctx, NULL, &res, attrs,
1218                            "dn=%s", a_state->account_dn);
1219         if (ret != 1) {
1220                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1221         }
1222         msg = res[0];
1223
1224         /* allocate the info structure */
1225         r->out.info = talloc_p(mem_ctx, union samr_GroupInfo);
1226         if (r->out.info == NULL) {
1227                 return NT_STATUS_NO_MEMORY;
1228         }
1229         ZERO_STRUCTP(r->out.info);
1230
1231         /* Fill in the level */
1232         switch (r->in.level) {
1233         case GroupInfoAll:
1234                 QUERY_STRING(msg, all.name.string,        "sAMAccountName");
1235                 r->out.info->all.attributes = 7; /* Do like w2k3 */
1236                 QUERY_UINT  (msg, all.num_members,      "numMembers")
1237                 QUERY_STRING(msg, all.description.string, "description");
1238                 break;
1239         case GroupInfoName:
1240                 QUERY_STRING(msg, name.string,            "sAMAccountName");
1241                 break;
1242         case GroupInfoX:
1243                 r->out.info->unknown.unknown = 7;
1244                 break;
1245         case GroupInfoDescription:
1246                 QUERY_STRING(msg, description.string, "description");
1247                 break;
1248         default:
1249                 r->out.info = NULL;
1250                 return NT_STATUS_INVALID_INFO_CLASS;
1251         }
1252         
1253         return NT_STATUS_OK;
1254 }
1255
1256
1257 /* 
1258   samr_SetGroupInfo 
1259 */
1260 static NTSTATUS samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1261                        struct samr_SetGroupInfo *r)
1262 {
1263         struct dcesrv_handle *h;
1264         struct samr_account_state *a_state;
1265         struct ldb_message mod, *msg = &mod;
1266         int ret;
1267
1268         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1269
1270         a_state = h->data;
1271
1272         ZERO_STRUCT(mod);
1273         mod.dn = talloc_strdup(mem_ctx, a_state->account_dn);
1274         if (!mod.dn) {
1275                 return NT_STATUS_NO_MEMORY;
1276         }
1277
1278         switch (r->in.level) {
1279         case GroupInfoDescription:
1280                 SET_STRING(msg, description.string,         "description");
1281                 break;
1282         case GroupInfoName:
1283                 /* On W2k3 this does not change the name, it changes the
1284                  * sAMAccountName attribute */
1285                 SET_STRING(msg, name.string,                "sAMAccountName");
1286                 break;
1287         case GroupInfoX:
1288                 /* This does not do anything obviously visible in W2k3 LDAP */
1289                 break;
1290         default:
1291                 return NT_STATUS_INVALID_INFO_CLASS;
1292         }
1293
1294         /* modify the samdb record */
1295         ret = samdb_replace(a_state->sam_ctx, mem_ctx, &mod);
1296         if (ret != 0) {
1297                 /* we really need samdb.c to return NTSTATUS */
1298                 return NT_STATUS_UNSUCCESSFUL;
1299         }
1300
1301         return NT_STATUS_OK;
1302 }
1303
1304
1305 /* 
1306   samr_AddGroupMember 
1307 */
1308 static NTSTATUS samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1309                        struct samr_AddGroupMember *r)
1310 {
1311         struct dcesrv_handle *h;
1312         struct samr_account_state *a_state;
1313         struct samr_domain_state *d_state;
1314         struct ldb_message mod;
1315         char *membersidstr;
1316         const char *memberdn;
1317         struct ldb_message **msgs;
1318         const char * const attrs[2] = { "dn", NULL };
1319         int ret;
1320
1321         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1322
1323         a_state = h->data;
1324         d_state = a_state->domain_state;
1325
1326         membersidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid,
1327                                        r->in.rid);
1328         if (membersidstr == NULL)
1329                 return NT_STATUS_NO_MEMORY;
1330
1331         /* In native mode, AD can also nest domain groups. Not sure yet
1332          * whether this is also available via RPC. */
1333         ret = samdb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn,
1334                            &msgs, attrs, "(&(objectSid=%s)(objectclass=user))",
1335                            membersidstr);
1336
1337         if (ret == 0)
1338                 return NT_STATUS_NO_SUCH_USER;
1339
1340         if (ret > 1)
1341                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1342
1343         memberdn = samdb_result_string(msgs[0], "dn", NULL);
1344
1345         if (memberdn == NULL)
1346                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1347
1348         ZERO_STRUCT(mod);
1349         mod.dn = talloc_reference(mem_ctx, a_state->account_dn);
1350
1351         if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, &mod, "member",
1352                                  memberdn) != 0)
1353                 return NT_STATUS_UNSUCCESSFUL;
1354
1355         if (samdb_modify(a_state->sam_ctx, mem_ctx, &mod) != 0)
1356                 return NT_STATUS_UNSUCCESSFUL;
1357
1358         return NT_STATUS_OK;
1359 }
1360
1361
1362 /* 
1363   samr_DeleteDomainGroup 
1364 */
1365 static NTSTATUS samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1366                        struct samr_DeleteDomainGroup *r)
1367 {
1368         struct dcesrv_handle *h;
1369         struct samr_account_state *a_state;
1370         int ret;
1371
1372         *r->out.group_handle = *r->in.group_handle;
1373
1374         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1375
1376         a_state = h->data;
1377
1378         ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
1379         if (ret != 0) {
1380                 return NT_STATUS_UNSUCCESSFUL;
1381         }
1382
1383         ZERO_STRUCTP(r->out.group_handle);
1384
1385         return NT_STATUS_OK;
1386 }
1387
1388
1389 /* 
1390   samr_DeleteGroupMember 
1391 */
1392 static NTSTATUS samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1393                        struct samr_DeleteGroupMember *r)
1394 {
1395         struct dcesrv_handle *h;
1396         struct samr_account_state *a_state;
1397         struct samr_domain_state *d_state;
1398         struct ldb_message mod;
1399         char *membersidstr;
1400         const char *memberdn;
1401         struct ldb_message **msgs;
1402         const char * const attrs[2] = { "dn", NULL };
1403         int ret;
1404
1405         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1406
1407         a_state = h->data;
1408         d_state = a_state->domain_state;
1409
1410         membersidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid,
1411                                        r->in.rid);
1412         if (membersidstr == NULL)
1413                 return NT_STATUS_NO_MEMORY;
1414
1415         /* In native mode, AD can also nest domain groups. Not sure yet
1416          * whether this is also available via RPC. */
1417         ret = samdb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn,
1418                            &msgs, attrs, "(&(objectSid=%s)(objectclass=user))",
1419                            membersidstr);
1420
1421         if (ret == 0)
1422                 return NT_STATUS_NO_SUCH_USER;
1423
1424         if (ret > 1)
1425                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1426
1427         memberdn = samdb_result_string(msgs[0], "dn", NULL);
1428
1429         if (memberdn == NULL)
1430                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1431
1432         ZERO_STRUCT(mod);
1433         mod.dn = talloc_reference(mem_ctx, a_state->account_dn);
1434
1435         if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, &mod, "member",
1436                                  memberdn) != 0)
1437                 return NT_STATUS_UNSUCCESSFUL;
1438
1439         if (samdb_modify(a_state->sam_ctx, mem_ctx, &mod) != 0)
1440                 return NT_STATUS_UNSUCCESSFUL;
1441
1442         return NT_STATUS_OK;
1443 }
1444
1445
1446 /* 
1447   samr_QueryGroupMember 
1448 */
1449 static NTSTATUS samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1450                        struct samr_QueryGroupMember *r)
1451 {
1452         struct dcesrv_handle *h;
1453         struct samr_account_state *a_state;
1454         struct ldb_message **res;
1455         struct ldb_message_element *el;
1456         struct samr_ridArray *array;
1457         const char * const attrs[2] = { "member", NULL };
1458         int ret;
1459
1460         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1461
1462         a_state = h->data;
1463
1464         /* pull the member attribute */
1465         ret = samdb_search(a_state->sam_ctx, mem_ctx, NULL, &res, attrs,
1466                            "dn=%s", a_state->account_dn);
1467
1468         if (ret != 1) {
1469                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1470         }
1471
1472         array = talloc_p(mem_ctx, struct samr_ridArray);
1473
1474         if (array == NULL)
1475                 return NT_STATUS_NO_MEMORY;
1476
1477         ZERO_STRUCTP(array);
1478
1479         el = ldb_msg_find_element(res[0], "member");
1480
1481         if (el != NULL) {
1482                 int i;
1483
1484                 array->count = el->num_values;
1485
1486                 array->rids = talloc_array_p(mem_ctx, uint32,
1487                                              el->num_values);
1488                 if (array->rids == NULL)
1489                         return NT_STATUS_NO_MEMORY;
1490
1491                 array->unknown = talloc_array_p(mem_ctx, uint32,
1492                                                 el->num_values);
1493                 if (array->unknown == NULL)
1494                         return NT_STATUS_NO_MEMORY;
1495
1496                 for (i=0; i<el->num_values; i++) {
1497                         struct ldb_message **res2;
1498                         const char * const attrs2[2] = { "objectSid", NULL };
1499                         ret = samdb_search(a_state->sam_ctx, mem_ctx, NULL,
1500                                            &res2, attrs2, "dn=%s",
1501                                            (char *)el->values[i].data);
1502                         if (ret != 1)
1503                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1504
1505                         array->rids[i] =
1506                                 samdb_result_rid_from_sid(mem_ctx, res2[0],
1507                                                           "objectSid", 0);
1508
1509                         if (array->rids[i] == 0)
1510                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1511
1512                         array->unknown[i] = 7; /* Not sure what this is.. */
1513                 }
1514         }
1515
1516         r->out.rids = array;
1517
1518         return NT_STATUS_OK;
1519 }
1520
1521
1522 /* 
1523   samr_SetMemberAttributesOfGroup 
1524 */
1525 static NTSTATUS samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1526                        struct samr_SetMemberAttributesOfGroup *r)
1527 {
1528         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1529 }
1530
1531
1532 /* 
1533   samr_OpenAlias 
1534 */
1535 static NTSTATUS samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1536                        struct samr_OpenAlias *r)
1537 {
1538         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1539 }
1540
1541
1542 /* 
1543   samr_QueryAliasInfo 
1544 */
1545 static NTSTATUS samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1546                        struct samr_QueryAliasInfo *r)
1547 {
1548         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1549 }
1550
1551
1552 /* 
1553   samr_SetAliasInfo 
1554 */
1555 static NTSTATUS samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1556                        struct samr_SetAliasInfo *r)
1557 {
1558         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1559 }
1560
1561
1562 /* 
1563   samr_DeleteDomAlias 
1564 */
1565 static NTSTATUS samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1566                        struct samr_DeleteDomAlias *r)
1567 {
1568         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1569 }
1570
1571
1572 /* 
1573   samr_AddAliasMember 
1574 */
1575 static NTSTATUS samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1576                        struct samr_AddAliasMember *r)
1577 {
1578         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1579 }
1580
1581
1582 /* 
1583   samr_DeleteAliasMember 
1584 */
1585 static NTSTATUS samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1586                        struct samr_DeleteAliasMember *r)
1587 {
1588         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1589 }
1590
1591
1592 /* 
1593   samr_GetMembersInAlias 
1594 */
1595 static NTSTATUS samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1596                        struct samr_GetMembersInAlias *r)
1597 {
1598         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1599 }
1600
1601
1602 /* 
1603   samr_OpenUser 
1604 */
1605 static NTSTATUS samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1606                               struct samr_OpenUser *r)
1607 {
1608         struct samr_domain_state *d_state;
1609         struct samr_account_state *a_state;
1610         struct dcesrv_handle *h;
1611         const char *account_name, *sidstr;
1612         struct ldb_message **msgs;
1613         struct dcesrv_handle *u_handle;
1614         const char * const attrs[2] = { "sAMAccountName", NULL };
1615         int ret;
1616
1617         ZERO_STRUCTP(r->out.user_handle);
1618
1619         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1620
1621         d_state = h->data;
1622
1623         /* form the users SID */
1624         sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, r->in.rid);
1625         if (!sidstr) {
1626                 return NT_STATUS_NO_MEMORY;
1627         }
1628
1629         /* search for the user record */
1630         ret = samdb_search(d_state->sam_ctx,
1631                            mem_ctx, d_state->domain_dn, &msgs, attrs,
1632                            "(&(objectSid=%s)(objectclass=user))", 
1633                            sidstr);
1634         if (ret == 0) {
1635                 return NT_STATUS_NO_SUCH_USER;
1636         }
1637         if (ret != 1) {
1638                 DEBUG(0,("Found %d records matching sid %s\n", ret, sidstr));
1639                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1640         }
1641
1642         account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
1643         if (account_name == NULL) {
1644                 DEBUG(0,("sAMAccountName field missing for sid %s\n", sidstr));
1645                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1646         }
1647
1648         a_state = talloc_p(d_state, struct samr_account_state);
1649         if (!a_state) {
1650                 return NT_STATUS_NO_MEMORY;
1651         }
1652         a_state->sam_ctx = d_state->sam_ctx;
1653         a_state->access_mask = r->in.access_mask;
1654         a_state->domain_state = talloc_reference(a_state, d_state);
1655         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1656         a_state->account_sid = talloc_steal(a_state, sidstr);
1657         a_state->account_name = talloc_strdup(a_state, account_name);
1658         if (!a_state->account_name) {
1659                 return NT_STATUS_NO_MEMORY;
1660         }
1661
1662         /* create the policy handle */
1663         u_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_USER);
1664         if (!u_handle) {
1665                 return NT_STATUS_NO_MEMORY;
1666         }
1667
1668         u_handle->data = a_state;
1669         u_handle->destroy = samr_handle_destroy;
1670
1671         *r->out.user_handle = u_handle->wire_handle;
1672
1673         return NT_STATUS_OK;
1674
1675 }
1676
1677
1678 /* 
1679   samr_DeleteUser 
1680 */
1681 static NTSTATUS samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1682                                 struct samr_DeleteUser *r)
1683 {
1684         struct dcesrv_handle *h;
1685         struct samr_account_state *a_state;
1686         int ret;
1687
1688         *r->out.user_handle = *r->in.user_handle;
1689
1690         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
1691
1692         a_state = h->data;
1693
1694         ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
1695         if (ret != 0) {
1696                 return NT_STATUS_UNSUCCESSFUL;
1697         }
1698
1699         ZERO_STRUCTP(r->out.user_handle);
1700
1701         return NT_STATUS_OK;
1702 }
1703
1704
1705 /* 
1706   samr_QueryUserInfo 
1707 */
1708 static NTSTATUS samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1709                                    struct samr_QueryUserInfo *r)
1710 {
1711         struct dcesrv_handle *h;
1712         struct samr_account_state *a_state;
1713         struct ldb_message *msg, **res;
1714         int ret;
1715
1716         r->out.info = NULL;
1717
1718         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
1719
1720         a_state = h->data;
1721
1722         /* pull all the user attributes */
1723         ret = samdb_search(a_state->sam_ctx, mem_ctx, NULL, &res, NULL,
1724                            "dn=%s", a_state->account_dn);
1725         if (ret != 1) {
1726                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1727         }
1728         msg = res[0];
1729
1730         /* allocate the info structure */
1731         r->out.info = talloc_p(mem_ctx, union samr_UserInfo);
1732         if (r->out.info == NULL) {
1733                 return NT_STATUS_NO_MEMORY;
1734         }
1735         ZERO_STRUCTP(r->out.info);
1736
1737         /* fill in the reply */
1738         switch (r->in.level) {
1739         case 1:
1740                 QUERY_STRING(msg, info1.account_name.string,   "sAMAccountName");
1741                 QUERY_STRING(msg, info1.full_name.string,      "displayName");
1742                 QUERY_UINT  (msg, info1.primary_gid,           "primaryGroupID");
1743                 QUERY_STRING(msg, info1.description.string,    "description");
1744                 QUERY_STRING(msg, info1.comment.string,        "comment");
1745                 break;
1746
1747         case 2:
1748                 QUERY_STRING(msg, info2.comment.string,        "comment");
1749                 QUERY_UINT  (msg, info2.country_code,          "countryCode");
1750                 QUERY_UINT  (msg, info2.code_page,             "codePage");
1751                 break;
1752
1753         case 3:
1754                 QUERY_STRING(msg, info3.account_name.string,   "sAMAccountName");
1755                 QUERY_STRING(msg, info3.full_name.string,      "displayName");
1756                 QUERY_RID   (msg, info3.rid,                   "objectSid");
1757                 QUERY_UINT  (msg, info3.primary_gid,           "primaryGroupID");
1758                 QUERY_STRING(msg, info3.home_directory.string, "homeDirectory");
1759                 QUERY_STRING(msg, info3.home_drive.string,     "homeDrive");
1760                 QUERY_STRING(msg, info3.logon_script.string,   "scriptPath");
1761                 QUERY_STRING(msg, info3.profile_path.string,   "profilePath");
1762                 QUERY_STRING(msg, info3.workstations.string,   "userWorkstations");
1763                 QUERY_NTTIME(msg, info3.last_logon,            "lastLogon");
1764                 QUERY_NTTIME(msg, info3.last_logoff,           "lastLogoff");
1765                 QUERY_NTTIME(msg, info3.last_password_change,  "pwdLastSet");
1766                 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
1767                 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
1768                 QUERY_LHOURS(msg, info3.logon_hours,           "logonHours");
1769                 QUERY_UINT  (msg, info3.bad_password_count,    "badPwdCount");
1770                 QUERY_UINT  (msg, info3.logon_count,           "logonCount");
1771                 QUERY_AFLAGS(msg, info3.acct_flags,            "userAccountControl");
1772                 break;
1773
1774         case 4:
1775                 QUERY_LHOURS(msg, info4.logon_hours,           "logonHours");
1776                 break;
1777
1778         case 5:
1779                 QUERY_STRING(msg, info5.account_name.string,   "sAMAccountName");
1780                 QUERY_STRING(msg, info5.full_name.string,      "displayName");
1781                 QUERY_RID   (msg, info5.rid,                   "objectSid");
1782                 QUERY_UINT  (msg, info5.primary_gid,           "primaryGroupID");
1783                 QUERY_STRING(msg, info5.home_directory.string, "homeDirectory");
1784                 QUERY_STRING(msg, info5.home_drive.string,     "homeDrive");
1785                 QUERY_STRING(msg, info5.logon_script.string,   "scriptPath");
1786                 QUERY_STRING(msg, info5.profile_path.string,   "profilePath");
1787                 QUERY_STRING(msg, info5.description.string,    "description");
1788                 QUERY_STRING(msg, info5.workstations.string,   "userWorkstations");
1789                 QUERY_NTTIME(msg, info5.last_logon,            "lastLogon");
1790                 QUERY_NTTIME(msg, info5.last_logoff,           "lastLogoff");
1791                 QUERY_LHOURS(msg, info5.logon_hours,           "logonHours");
1792                 QUERY_UINT  (msg, info5.bad_password_count,    "badPwdCount");
1793                 QUERY_UINT  (msg, info5.logon_count,           "logonCount");
1794                 QUERY_NTTIME(msg, info5.last_password_change,  "pwdLastSet");
1795                 QUERY_NTTIME(msg, info5.acct_expiry,           "accountExpires");
1796                 QUERY_AFLAGS(msg, info5.acct_flags,            "userAccountControl");
1797                 break;
1798
1799         case 6:
1800                 QUERY_STRING(msg, info6.account_name.string,   "sAMAccountName");
1801                 QUERY_STRING(msg, info6.full_name.string,      "displayName");
1802                 break;
1803
1804         case 7:
1805                 QUERY_STRING(msg, info7.account_name.string,   "sAMAccountName");
1806                 break;
1807
1808         case 8:
1809                 QUERY_STRING(msg, info8.full_name.string,      "displayName");
1810                 break;
1811
1812         case 9:
1813                 QUERY_UINT  (msg, info9.primary_gid,           "primaryGroupID");
1814                 break;
1815
1816         case 10:
1817                 QUERY_STRING(msg, info10.home_directory.string,"homeDirectory");
1818                 QUERY_STRING(msg, info10.home_drive.string,    "homeDrive");
1819                 break;
1820
1821         case 11:
1822                 QUERY_STRING(msg, info11.logon_script.string,  "scriptPath");
1823                 break;
1824
1825         case 12:
1826                 QUERY_STRING(msg, info12.profile_path.string,  "profilePath");
1827                 break;
1828
1829         case 13:
1830                 QUERY_STRING(msg, info13.description.string,   "description");
1831                 break;
1832
1833         case 14:
1834                 QUERY_STRING(msg, info14.workstations.string,  "userWorkstations");
1835                 break;
1836
1837         case 16:
1838                 QUERY_AFLAGS(msg, info16.acct_flags,           "userAccountControl");
1839                 break;
1840
1841         case 17:
1842                 QUERY_NTTIME(msg, info17.acct_expiry,          "accountExpires");
1843
1844         case 20:
1845                 QUERY_STRING(msg, info20.parameters.string,    "userParameters");
1846                 break;
1847
1848         case 21:
1849                 QUERY_NTTIME(msg, info21.last_logon,           "lastLogon");
1850                 QUERY_NTTIME(msg, info21.last_logoff,          "lastLogoff");
1851                 QUERY_NTTIME(msg, info21.last_password_change, "pwdLastSet");
1852                 QUERY_NTTIME(msg, info21.acct_expiry,          "accountExpires");
1853                 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
1854                 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
1855                 QUERY_STRING(msg, info21.account_name.string,  "sAMAccountName");
1856                 QUERY_STRING(msg, info21.full_name.string,     "displayName");
1857                 QUERY_STRING(msg, info21.home_directory.string,"homeDirectory");
1858                 QUERY_STRING(msg, info21.home_drive.string,    "homeDrive");
1859                 QUERY_STRING(msg, info21.logon_script.string,  "scriptPath");
1860                 QUERY_STRING(msg, info21.profile_path.string,  "profilePath");
1861                 QUERY_STRING(msg, info21.description.string,   "description");
1862                 QUERY_STRING(msg, info21.workstations.string,  "userWorkstations");
1863                 QUERY_STRING(msg, info21.comment.string,       "comment");
1864                 QUERY_STRING(msg, info21.parameters.string,    "userParameters");
1865                 QUERY_RID   (msg, info21.rid,                  "objectSid");
1866                 QUERY_UINT  (msg, info21.primary_gid,          "primaryGroupID");
1867                 QUERY_AFLAGS(msg, info21.acct_flags,           "userAccountControl");
1868                 r->out.info->info21.fields_present = 0x00FFFFFF;
1869                 QUERY_LHOURS(msg, info21.logon_hours,          "logonHours");
1870                 QUERY_UINT  (msg, info21.bad_password_count,   "badPwdCount");
1871                 QUERY_UINT  (msg, info21.logon_count,          "logonCount");
1872                 QUERY_UINT  (msg, info21.country_code,         "countryCode");
1873                 QUERY_UINT  (msg, info21.code_page,            "codePage");
1874                 break;
1875                 
1876
1877         default:
1878                 r->out.info = NULL;
1879                 return NT_STATUS_INVALID_INFO_CLASS;
1880         }
1881         
1882         return NT_STATUS_OK;
1883 }
1884
1885
1886 /* 
1887   samr_SetUserInfo 
1888 */
1889 static NTSTATUS samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1890                                  struct samr_SetUserInfo *r)
1891 {
1892         struct dcesrv_handle *h;
1893         struct samr_account_state *a_state;
1894         struct ldb_message mod, *msg = &mod;
1895         int ret;
1896         NTSTATUS status = NT_STATUS_OK;
1897
1898         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
1899
1900         a_state = h->data;
1901
1902         ZERO_STRUCT(mod);
1903         mod.dn = talloc_strdup(mem_ctx, a_state->account_dn);
1904         if (!mod.dn) {
1905                 return NT_STATUS_NO_MEMORY;
1906         }
1907
1908         switch (r->in.level) {
1909         case 2:
1910                 SET_STRING(msg, info2.comment.string,          "comment");
1911                 SET_UINT  (msg, info2.country_code,            "countryCode");
1912                 SET_UINT  (msg, info2.code_page,               "codePage");
1913                 break;
1914
1915         case 4:
1916                 SET_LHOURS(msg, info4.logon_hours,             "logonHours");
1917                 break;
1918
1919         case 6:
1920                 SET_STRING(msg, info6.full_name.string,        "displayName");
1921                 break;
1922
1923         case 8:
1924                 SET_STRING(msg, info8.full_name.string,        "displayName");
1925                 break;
1926
1927         case 9:
1928                 SET_UINT(msg, info9.primary_gid,               "primaryGroupID");
1929                 break;
1930
1931         case 10:
1932                 SET_STRING(msg, info10.home_directory.string,  "homeDirectory");
1933                 SET_STRING(msg, info10.home_drive.string,      "homeDrive");
1934                 break;
1935
1936         case 11:
1937                 SET_STRING(msg, info11.logon_script.string,    "scriptPath");
1938                 break;
1939
1940         case 12:
1941                 SET_STRING(msg, info12.profile_path.string,    "profilePath");
1942                 break;
1943
1944         case 13:
1945                 SET_STRING(msg, info13.description.string,     "description");
1946                 break;
1947
1948         case 14:
1949                 SET_STRING(msg, info14.workstations.string,    "userWorkstations");
1950                 break;
1951
1952         case 16:
1953                 SET_AFLAGS(msg, info16.acct_flags,             "userAccountControl");
1954                 break;
1955
1956         case 20:
1957                 SET_STRING(msg, info20.parameters.string,      "userParameters");
1958                 break;
1959
1960         case 21:
1961 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
1962                 IFSET(SAMR_FIELD_NAME)         
1963                         SET_STRING(msg, info21.full_name.string,    "displayName");
1964                 IFSET(SAMR_FIELD_DESCRIPTION)  
1965                         SET_STRING(msg, info21.description.string,  "description");
1966                 IFSET(SAMR_FIELD_COMMENT)      
1967                         SET_STRING(msg, info21.comment.string,      "comment");
1968                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
1969                         SET_STRING(msg, info21.logon_script.string, "scriptPath");
1970                 IFSET(SAMR_FIELD_PROFILE_PATH)      
1971                         SET_STRING(msg, info21.profile_path.string, "profilePath");
1972                 IFSET(SAMR_FIELD_WORKSTATION)  
1973                         SET_STRING(msg, info21.workstations.string, "userWorkstations");
1974                 IFSET(SAMR_FIELD_LOGON_HOURS)  
1975                         SET_LHOURS(msg, info21.logon_hours,         "logonHours");
1976                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
1977                         SET_AFLAGS(msg, info21.acct_flags,          "userAccountControl");
1978                 IFSET(SAMR_FIELD_PARAMETERS)     
1979                         SET_STRING(msg, info21.parameters.string,   "userParameters");
1980                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
1981                         SET_UINT  (msg, info21.country_code,        "countryCode");
1982                 IFSET(SAMR_FIELD_CODE_PAGE)    
1983                         SET_UINT  (msg, info21.code_page,           "codePage");
1984
1985
1986                 /* Any reason the rest of these can't be set? */
1987 #undef IFSET
1988                 break;
1989
1990         case 23:
1991 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
1992                 IFSET(SAMR_FIELD_NAME)         
1993                         SET_STRING(msg, info23.info.full_name.string,    "displayName");
1994                 IFSET(SAMR_FIELD_DESCRIPTION)  
1995                         SET_STRING(msg, info23.info.description.string,  "description");
1996                 IFSET(SAMR_FIELD_COMMENT)      
1997                         SET_STRING(msg, info23.info.comment.string,      "comment");
1998                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
1999                         SET_STRING(msg, info23.info.logon_script.string, "scriptPath");
2000                 IFSET(SAMR_FIELD_PROFILE_PATH)      
2001                         SET_STRING(msg, info23.info.profile_path.string, "profilePath");
2002                 IFSET(SAMR_FIELD_WORKSTATION)  
2003                         SET_STRING(msg, info23.info.workstations.string, "userWorkstations");
2004                 IFSET(SAMR_FIELD_LOGON_HOURS)  
2005                         SET_LHOURS(msg, info23.info.logon_hours,         "logonHours");
2006                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
2007                         SET_AFLAGS(msg, info23.info.acct_flags,          "userAccountControl");
2008                 IFSET(SAMR_FIELD_PARAMETERS)     
2009                         SET_STRING(msg, info23.info.parameters.string,   "userParameters");
2010                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
2011                         SET_UINT  (msg, info23.info.country_code,        "countryCode");
2012                 IFSET(SAMR_FIELD_CODE_PAGE)    
2013                         SET_UINT  (msg, info23.info.code_page,           "codePage");
2014                 IFSET(SAMR_FIELD_PASSWORD) {
2015                         status = samr_set_password(dce_call,
2016                                                    a_state->sam_ctx,
2017                                                    a_state->account_dn,
2018                                                    a_state->domain_state->domain_dn,
2019                                                    mem_ctx, msg, 
2020                                                    &r->in.info->info23.password);
2021                 } else IFSET(SAMR_FIELD_PASSWORD2) {
2022                         status = samr_set_password(dce_call,
2023                                                    a_state->sam_ctx,
2024                                                    a_state->account_dn,
2025                                                    a_state->domain_state->domain_dn,
2026                                                    mem_ctx, msg, 
2027                                                    &r->in.info->info23.password);
2028                 }
2029 #undef IFSET
2030                 break;
2031
2032                 /* the set password levels are handled separately */
2033         case 24:
2034                 status = samr_set_password(dce_call,
2035                                            a_state->sam_ctx,
2036                                            a_state->account_dn,
2037                                            a_state->domain_state->domain_dn,
2038                                            mem_ctx, msg, 
2039                                            &r->in.info->info24.password);
2040                 break;
2041
2042         case 25:
2043 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
2044                 IFSET(SAMR_FIELD_NAME)         
2045                         SET_STRING(msg, info25.info.full_name.string,    "displayName");
2046                 IFSET(SAMR_FIELD_DESCRIPTION)  
2047                         SET_STRING(msg, info25.info.description.string,  "description");
2048                 IFSET(SAMR_FIELD_COMMENT)      
2049                         SET_STRING(msg, info25.info.comment.string,      "comment");
2050                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
2051                         SET_STRING(msg, info25.info.logon_script.string, "scriptPath");
2052                 IFSET(SAMR_FIELD_PROFILE_PATH)      
2053                         SET_STRING(msg, info25.info.profile_path.string, "profilePath");
2054                 IFSET(SAMR_FIELD_WORKSTATION)  
2055                         SET_STRING(msg, info25.info.workstations.string, "userWorkstations");
2056                 IFSET(SAMR_FIELD_LOGON_HOURS)  
2057                         SET_LHOURS(msg, info25.info.logon_hours,         "logonHours");
2058                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
2059                         SET_AFLAGS(msg, info25.info.acct_flags,          "userAccountControl");
2060                 IFSET(SAMR_FIELD_PARAMETERS)     
2061                         SET_STRING(msg, info25.info.parameters.string,   "userParameters");
2062                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
2063                         SET_UINT  (msg, info25.info.country_code,        "countryCode");
2064                 IFSET(SAMR_FIELD_CODE_PAGE)    
2065                         SET_UINT  (msg, info25.info.code_page,           "codePage");
2066                 IFSET(SAMR_FIELD_PASSWORD) {
2067                         status = samr_set_password_ex(dce_call,
2068                                                       a_state->sam_ctx,
2069                                                       a_state->account_dn,
2070                                                       a_state->domain_state->domain_dn,
2071                                                       mem_ctx, msg, 
2072                                                       &r->in.info->info25.password);
2073                 } else IFSET(SAMR_FIELD_PASSWORD2) {
2074                         status = samr_set_password_ex(dce_call,
2075                                                       a_state->sam_ctx,
2076                                                       a_state->account_dn,
2077                                                       a_state->domain_state->domain_dn,
2078                                                       mem_ctx, msg, 
2079                                                       &r->in.info->info25.password);
2080                 }
2081 #undef IFSET
2082                 break;
2083
2084                 /* the set password levels are handled separately */
2085         case 26:
2086                 status = samr_set_password_ex(dce_call,
2087                                               a_state->sam_ctx,
2088                                               a_state->account_dn,
2089                                               a_state->domain_state->domain_dn,
2090                                               mem_ctx, msg, 
2091                                               &r->in.info->info26.password);
2092                 break;
2093                 
2094
2095         default:
2096                 /* many info classes are not valid for SetUserInfo */
2097                 return NT_STATUS_INVALID_INFO_CLASS;
2098         }
2099
2100         if (!NT_STATUS_IS_OK(status)) {
2101                 return status;
2102         }
2103
2104         /* modify the samdb record */
2105         ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
2106         if (ret != 0) {
2107                 /* we really need samdb.c to return NTSTATUS */
2108                 return NT_STATUS_UNSUCCESSFUL;
2109         }
2110
2111         return NT_STATUS_OK;
2112 }
2113
2114
2115 /* 
2116   samr_GetGroupsForUser 
2117 */
2118 static NTSTATUS samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2119                        struct samr_GetGroupsForUser *r)
2120 {
2121         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2122 }
2123
2124
2125 /* 
2126   samr_QueryDisplayInfo 
2127 */
2128 static NTSTATUS samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2129                        struct samr_QueryDisplayInfo *r)
2130 {
2131         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2132 }
2133
2134
2135 /* 
2136   samr_GetDisplayEnumerationIndex 
2137 */
2138 static NTSTATUS samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2139                        struct samr_GetDisplayEnumerationIndex *r)
2140 {
2141         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2142 }
2143
2144
2145 /* 
2146   samr_TestPrivateFunctionsDomain 
2147 */
2148 static NTSTATUS samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2149                        struct samr_TestPrivateFunctionsDomain *r)
2150 {
2151         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2152 }
2153
2154
2155 /* 
2156   samr_TestPrivateFunctionsUser 
2157 */
2158 static NTSTATUS samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2159                        struct samr_TestPrivateFunctionsUser *r)
2160 {
2161         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2162 }
2163
2164
2165 /* 
2166   samr_GetUserPwInfo 
2167 */
2168 static NTSTATUS samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2169                                    struct samr_GetUserPwInfo *r)
2170 {
2171         struct dcesrv_handle *h;
2172         struct samr_account_state *a_state;
2173
2174         ZERO_STRUCT(r->out.info);
2175
2176         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2177
2178         a_state = h->data;
2179
2180         r->out.info.min_password_length = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0, NULL, "minPwdLength", 
2181                                                             "dn=%s", a_state->domain_state->domain_dn);
2182         r->out.info.password_properties = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0, NULL, "pwdProperties", 
2183                                                             "dn=%s", a_state->account_dn);
2184         return NT_STATUS_OK;
2185 }
2186
2187
2188 /* 
2189   samr_RemoveMemberFromForeignDomain 
2190 */
2191 static NTSTATUS samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2192                        struct samr_RemoveMemberFromForeignDomain *r)
2193 {
2194         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2195 }
2196
2197
2198 /* 
2199   samr_QueryDomainInfo2 
2200 */
2201 static NTSTATUS samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2202                        struct samr_QueryDomainInfo2 *r)
2203 {
2204         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2205 }
2206
2207
2208 /* 
2209   samr_QueryUserInfo2 
2210
2211   just an alias for samr_QueryUserInfo
2212 */
2213 static NTSTATUS samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2214                                     struct samr_QueryUserInfo2 *r)
2215 {
2216         struct samr_QueryUserInfo r1;
2217         NTSTATUS status;
2218
2219         r1.in.user_handle = r->in.user_handle;
2220         r1.in.level  = r->in.level;
2221         
2222         status = samr_QueryUserInfo(dce_call, mem_ctx, &r1);
2223         
2224         r->out.info = r1.out.info;
2225
2226         return status;
2227 }
2228
2229
2230 /* 
2231   samr_QueryDisplayInfo2 
2232 */
2233 static NTSTATUS samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2234                        struct samr_QueryDisplayInfo2 *r)
2235 {
2236         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2237 }
2238
2239
2240 /* 
2241   samr_GetDisplayEnumerationIndex2 
2242 */
2243 static NTSTATUS samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2244                        struct samr_GetDisplayEnumerationIndex2 *r)
2245 {
2246         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2247 }
2248
2249
2250 /* 
2251   samr_QueryDisplayInfo3 
2252 */
2253 static NTSTATUS samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2254                        struct samr_QueryDisplayInfo3 *r)
2255 {
2256         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2257 }
2258
2259
2260 /* 
2261   samr_AddMultipleMembersToAlias 
2262 */
2263 static NTSTATUS samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2264                        struct samr_AddMultipleMembersToAlias *r)
2265 {
2266         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2267 }
2268
2269
2270 /* 
2271   samr_RemoveMultipleMembersFromAlias 
2272 */
2273 static NTSTATUS samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2274                        struct samr_RemoveMultipleMembersFromAlias *r)
2275 {
2276         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2277 }
2278
2279
2280 /* 
2281   samr_GetDomPwInfo 
2282
2283   this fetches the default password properties for a domain
2284
2285   note that w2k3 completely ignores the domain name in this call, and 
2286   always returns the information for the servers primary domain
2287 */
2288 static NTSTATUS samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2289                                   struct samr_GetDomPwInfo *r)
2290 {
2291         struct ldb_message **msgs;
2292         int ret;
2293         const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
2294         void *sam_ctx;
2295
2296         ZERO_STRUCT(r->out.info);
2297
2298         sam_ctx = samdb_connect(mem_ctx);
2299         if (sam_ctx == NULL) {
2300                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
2301         }
2302
2303         ret = samdb_search(sam_ctx, 
2304                            mem_ctx, NULL, &msgs, attrs, 
2305                            "(&(name=%s)(objectclass=domain))",
2306                            lp_workgroup());
2307         if (ret <= 0) {
2308                 return NT_STATUS_NO_SUCH_DOMAIN;
2309         }
2310         if (ret > 1) {
2311                 samdb_search_free(sam_ctx, mem_ctx, msgs);
2312                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2313         }
2314
2315         r->out.info.min_password_length = samdb_result_uint(msgs[0], "minPwdLength", 0);
2316         r->out.info.password_properties = samdb_result_uint(msgs[0], "pwdProperties", 1);
2317
2318         samdb_search_free(sam_ctx, mem_ctx, msgs);
2319
2320         talloc_free(sam_ctx);
2321         return NT_STATUS_OK;
2322 }
2323
2324
2325 /* 
2326   samr_Connect2 
2327 */
2328 static NTSTATUS samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2329                               struct samr_Connect2 *r)
2330 {
2331         struct samr_Connect c;
2332
2333         c.in.system_name = NULL;
2334         c.in.access_mask = r->in.access_mask;
2335         c.out.connect_handle = r->out.connect_handle;
2336
2337         return samr_Connect(dce_call, mem_ctx, &c);
2338 }
2339
2340
2341 /* 
2342   samr_SetUserInfo2 
2343
2344   just an alias for samr_SetUserInfo
2345 */
2346 static NTSTATUS samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2347                                   struct samr_SetUserInfo2 *r)
2348 {
2349         struct samr_SetUserInfo r2;
2350
2351         r2.in.user_handle = r->in.user_handle;
2352         r2.in.level = r->in.level;
2353         r2.in.info = r->in.info;
2354
2355         return samr_SetUserInfo(dce_call, mem_ctx, &r2);
2356 }
2357
2358
2359 /* 
2360   samr_SetBootKeyInformation 
2361 */
2362 static NTSTATUS samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2363                        struct samr_SetBootKeyInformation *r)
2364 {
2365         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2366 }
2367
2368
2369 /* 
2370   samr_GetBootKeyInformation 
2371 */
2372 static NTSTATUS samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2373                        struct samr_GetBootKeyInformation *r)
2374 {
2375         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2376 }
2377
2378
2379 /* 
2380   samr_Connect3 
2381 */
2382 static NTSTATUS samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2383                        struct samr_Connect3 *r)
2384 {
2385         struct samr_Connect c;
2386
2387         c.in.system_name = NULL;
2388         c.in.access_mask = r->in.access_mask;
2389         c.out.connect_handle = r->out.connect_handle;
2390
2391         return samr_Connect(dce_call, mem_ctx, &c);
2392 }
2393
2394
2395 /* 
2396   samr_Connect4 
2397 */
2398 static NTSTATUS samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2399                        struct samr_Connect4 *r)
2400 {
2401         struct samr_Connect c;
2402
2403         c.in.system_name = NULL;
2404         c.in.access_mask = r->in.access_mask;
2405         c.out.connect_handle = r->out.connect_handle;
2406
2407         return samr_Connect(dce_call, mem_ctx, &c);
2408 }
2409
2410
2411 /* 
2412   samr_Connect5 
2413 */
2414 static NTSTATUS samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2415                               struct samr_Connect5 *r)
2416 {
2417         struct samr_Connect c;
2418         NTSTATUS status;
2419
2420         c.in.system_name = NULL;
2421         c.in.access_mask = r->in.access_mask;
2422         c.out.connect_handle = r->out.connect_handle;
2423
2424         status = samr_Connect(dce_call, mem_ctx, &c);
2425
2426         r->out.info->info1.unknown1 = 3;
2427         r->out.info->info1.unknown2 = 0;
2428         r->out.level = r->in.level;
2429
2430         return status;
2431 }
2432
2433
2434 /* 
2435   samr_RidToSid 
2436 */
2437 static NTSTATUS samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2438                        struct samr_RidToSid *r)
2439 {
2440         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2441 }
2442
2443
2444 /* 
2445   samr_SetDsrmPassword 
2446 */
2447 static NTSTATUS samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2448                        struct samr_SetDsrmPassword *r)
2449 {
2450         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2451 }
2452
2453
2454 /* 
2455   samr_ValidatePassword 
2456 */
2457 static NTSTATUS samr_ValidatePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2458                                       struct samr_ValidatePassword *r)
2459 {
2460         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2461 }
2462
2463
2464 /* include the generated boilerplate */
2465 #include "librpc/gen_ndr/ndr_samr_s.c"