239dd58b60bfae4e121736b288b6916c50c828bc
[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   samr_Connect 
42
43   create a connection to the SAM database
44 */
45 static NTSTATUS samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
46                              struct samr_Connect *r)
47 {
48         struct samr_connect_state *c_state;
49         struct dcesrv_handle *handle;
50
51         ZERO_STRUCTP(r->out.connect_handle);
52
53         c_state = talloc_p(dce_call->conn, struct samr_connect_state);
54         if (!c_state) {
55                 return NT_STATUS_NO_MEMORY;
56         }
57
58         /* make sure the sam database is accessible */
59         c_state->sam_ctx = samdb_connect(c_state);
60         if (c_state->sam_ctx == NULL) {
61                 talloc_free(c_state);
62                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
63         }
64
65         handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_CONNECT);
66         if (!handle) {
67                 talloc_free(c_state);
68                 return NT_STATUS_NO_MEMORY;
69         }
70
71         handle->data = c_state;
72         handle->destroy = samr_handle_destroy;
73
74         c_state->access_mask = r->in.access_mask;
75         *r->out.connect_handle = handle->wire_handle;
76
77         return NT_STATUS_OK;
78 }
79
80
81 /* 
82   samr_Close 
83 */
84 static NTSTATUS samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
85                            struct samr_Close *r)
86 {
87         struct dcesrv_handle *h;
88
89         *r->out.handle = *r->in.handle;
90
91         DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
92
93         /* this causes the parameters samr_XXX_destroy() to be called by
94            the handle destroy code which destroys the state associated
95            with the handle */
96         dcesrv_handle_destroy(dce_call->conn, h);
97
98         ZERO_STRUCTP(r->out.handle);
99
100         return NT_STATUS_OK;
101 }
102
103
104 /* 
105   samr_SetSecurity 
106 */
107 static NTSTATUS samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
108                                  struct samr_SetSecurity *r)
109 {
110         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
111 }
112
113
114 /* 
115   samr_QuerySecurity 
116 */
117 static NTSTATUS samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
118                                    struct samr_QuerySecurity *r)
119 {
120         struct dcesrv_handle *h;
121         struct sec_desc_buf *sd;
122
123         r->out.sdbuf = NULL;
124
125         DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
126
127         sd = talloc_p(mem_ctx, struct sec_desc_buf);
128         if (sd == NULL) {
129                 return NT_STATUS_NO_MEMORY;
130         }
131
132         sd->sd = samdb_default_security_descriptor(mem_ctx);
133
134         r->out.sdbuf = sd;
135
136         return NT_STATUS_OK;
137 }
138
139
140 /* 
141   samr_Shutdown 
142
143   we refuse this operation completely. If a admin wants to shutdown samr
144   in Samba then they should use the samba admin tools to disable the samr pipe
145 */
146 static NTSTATUS samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
147                               struct samr_Shutdown *r)
148 {
149         return NT_STATUS_ACCESS_DENIED;
150 }
151
152
153 /* 
154   samr_LookupDomain 
155
156   this maps from a domain name to a SID
157 */
158 static NTSTATUS samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
159                                   struct samr_LookupDomain *r)
160 {
161         struct samr_connect_state *c_state;
162         struct dcesrv_handle *h;
163         struct dom_sid2 *sid;
164         const char *sidstr;
165                 
166         r->out.sid = NULL;
167
168         DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
169
170         c_state = h->data;
171
172         if (r->in.domain->string == NULL) {
173                 return NT_STATUS_INVALID_PARAMETER;
174         }
175
176         sidstr = samdb_search_string(c_state->sam_ctx,
177                                      mem_ctx, NULL, "objectSid",
178                                      "(&(name=%s)(objectclass=domain))",
179                                      r->in.domain->string);
180         if (sidstr == NULL) {
181                 return NT_STATUS_NO_SUCH_DOMAIN;
182         }
183
184         sid = dom_sid_parse_talloc(mem_ctx, sidstr);
185         if (sid == NULL) {
186                 DEBUG(0,("samdb: Invalid sid '%s' for domain %s\n",
187                          sidstr, r->in.domain->string));
188                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
189         }
190
191         r->out.sid = sid;
192
193         return NT_STATUS_OK;
194 }
195
196
197 /* 
198   samr_EnumDomains 
199
200   list the domains in the SAM
201 */
202 static NTSTATUS samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
203                                  struct samr_EnumDomains *r)
204 {
205         struct samr_connect_state *c_state;
206         struct dcesrv_handle *h;
207         struct samr_SamArray *array;
208         const char **domains;
209         int count, i, start_i;
210
211         *r->out.resume_handle = 0;
212         r->out.sam = NULL;
213         r->out.num_entries = 0;
214
215         DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
216
217         c_state = h->data;
218
219         count = samdb_search_string_multiple(c_state->sam_ctx,
220                                              mem_ctx, NULL, &domains, 
221                                              "name", "(objectclass=domain)");
222         if (count == -1) {
223                 DEBUG(0,("samdb: no domains found in EnumDomains\n"));
224                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
225         }
226
227         *r->out.resume_handle = count;
228
229         start_i = *r->in.resume_handle;
230
231         if (start_i >= count) {
232                 /* search past end of list is not an error for this call */
233                 return NT_STATUS_OK;
234         }
235
236         array = talloc_p(mem_ctx, struct samr_SamArray);
237         if (array == NULL) {
238                 return NT_STATUS_NO_MEMORY;
239         }
240                 
241         array->count = 0;
242         array->entries = NULL;
243
244         array->entries = talloc_array_p(mem_ctx, struct samr_SamEntry, count - start_i);
245         if (array->entries == NULL) {
246                 return NT_STATUS_NO_MEMORY;
247         }
248
249         for (i=0;i<count-start_i;i++) {
250                 array->entries[i].idx = start_i + i;
251                 array->entries[i].name.string = domains[start_i+i];
252         }
253
254         r->out.sam = array;
255         r->out.num_entries = i;
256         array->count = r->out.num_entries;
257
258         return NT_STATUS_OK;
259 }
260
261
262 /* 
263   samr_OpenDomain 
264 */
265 static NTSTATUS samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
266                                 struct samr_OpenDomain *r)
267 {
268         struct dcesrv_handle *h_conn, *h_domain;
269         const char *sidstr, *domain_name;
270         struct samr_connect_state *c_state;
271         struct samr_domain_state *d_state;
272         const char * const attrs[2] = { "name", NULL};
273         struct ldb_message **msgs;
274         int ret;
275
276         ZERO_STRUCTP(r->out.domain_handle);
277
278         DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
279
280         c_state = h_conn->data;
281
282         if (r->in.sid == NULL) {
283                 return NT_STATUS_INVALID_PARAMETER;
284         }
285
286         sidstr = dom_sid_string(mem_ctx, r->in.sid);
287         if (sidstr == NULL) {
288                 return NT_STATUS_INVALID_PARAMETER;
289         }
290
291         ret = samdb_search(c_state->sam_ctx,
292                            mem_ctx, NULL, &msgs, attrs,
293                            "(&(objectSid=%s)(objectclass=domain))", 
294                            sidstr);
295         if (ret != 1) {
296                 return NT_STATUS_NO_SUCH_DOMAIN;
297         }
298
299         domain_name = ldb_msg_find_string(msgs[0], "name", NULL);
300         if (domain_name == NULL) {
301                 return NT_STATUS_NO_SUCH_DOMAIN;
302         }
303
304         d_state = talloc_p(c_state, struct samr_domain_state);
305         if (!d_state) {
306                 return NT_STATUS_NO_MEMORY;
307         }
308
309         d_state->connect_state = talloc_reference(d_state, c_state);
310         d_state->sam_ctx = c_state->sam_ctx;
311         d_state->domain_sid = talloc_strdup(d_state, sidstr);
312         d_state->domain_name = talloc_strdup(d_state, domain_name);
313         d_state->domain_dn = talloc_strdup(d_state, msgs[0]->dn);
314         if (!d_state->domain_sid || !d_state->domain_name || !d_state->domain_dn) {
315                 talloc_free(d_state);
316                 return NT_STATUS_NO_MEMORY;             
317         }
318         d_state->access_mask = r->in.access_mask;
319
320         h_domain = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_DOMAIN);
321         if (!h_domain) {
322                 talloc_free(d_state);
323                 return NT_STATUS_NO_MEMORY;
324         }
325         
326         h_domain->data = d_state;
327         h_domain->destroy = samr_handle_destroy;
328         *r->out.domain_handle = h_domain->wire_handle;
329
330         return NT_STATUS_OK;
331 }
332
333 /*
334   return DomInfo2
335 */
336 static NTSTATUS samr_info_DomInfo2(struct samr_domain_state *state, TALLOC_CTX *mem_ctx,
337                                    struct samr_DomInfo2 *info)
338 {
339         const char * const attrs[] = { "comment", "name", NULL };
340         int ret;
341         struct ldb_message **res;
342
343         ret = samdb_search(state->sam_ctx, mem_ctx, NULL, &res, attrs, 
344                            "dn=%s", state->domain_dn);
345         if (ret != 1) {
346                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
347         }
348
349         /* where is this supposed to come from? is it settable? */
350         info->force_logoff_time = 0x8000000000000000LL;
351
352         info->comment.string = samdb_result_string(res[0], "comment", NULL);
353         info->domain.string  = samdb_result_string(res[0], "name", NULL);
354
355         info->primary.string = lp_netbios_name();
356         info->sequence_num = 0;
357         info->role = ROLE_DOMAIN_PDC;
358         info->num_users = samdb_search_count(state->sam_ctx, mem_ctx, NULL, "(objectClass=user)");
359         info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx, NULL,
360                                               "(&(objectClass=group)(sAMAccountType=%u))",
361                                               ATYPE_GLOBAL_GROUP);
362         info->num_aliases = samdb_search_count(state->sam_ctx, mem_ctx, NULL,
363                                                "(&(objectClass=group)(sAMAccountType=%u))",
364                                                ATYPE_LOCAL_GROUP);
365
366         return NT_STATUS_OK;
367 }
368
369 /* 
370   samr_QueryDomainInfo 
371 */
372 static NTSTATUS samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
373                                      struct samr_QueryDomainInfo *r)
374 {
375         struct dcesrv_handle *h;
376         struct samr_domain_state *d_state;
377
378         r->out.info = NULL;
379
380         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
381
382         d_state = h->data;
383
384         r->out.info = talloc_p(mem_ctx, union samr_DomainInfo);
385         if (!r->out.info) {
386                 return NT_STATUS_NO_MEMORY;
387         }
388
389         ZERO_STRUCTP(r->out.info);
390
391         switch (r->in.level) {
392         case 2:
393                 return samr_info_DomInfo2(d_state, mem_ctx, &r->out.info->info2);
394         }
395
396         return NT_STATUS_INVALID_INFO_CLASS;
397 }
398
399
400 /* 
401   samr_SetDomainInfo 
402 */
403 static NTSTATUS samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
404                        struct samr_SetDomainInfo *r)
405 {
406         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
407 }
408
409 /* 
410   samr_CreateDomainGroup 
411 */
412 static NTSTATUS samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
413                                        struct samr_CreateDomainGroup *r)
414 {
415         struct samr_domain_state *d_state;
416         struct samr_account_state *a_state;
417         struct dcesrv_handle *h;
418         const char *name;
419         struct ldb_message msg;
420         uint32_t rid;
421         const char *groupname, *sidstr, *guidstr;
422         struct GUID guid;
423         time_t now = time(NULL);
424         struct dcesrv_handle *g_handle;
425         int ret;
426         NTSTATUS status;
427
428         ZERO_STRUCTP(r->out.group_handle);
429         *r->out.rid = 0;
430
431         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
432
433         d_state = h->data;
434
435         groupname = r->in.name->string;
436
437         if (groupname == NULL) {
438                 return NT_STATUS_INVALID_PARAMETER;
439         }
440
441         /* check if the group already exists */
442         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL, 
443                                    "sAMAccountName",
444                                    "(&(sAMAccountName=%s)(objectclass=group))",
445                                    groupname);
446         if (name != NULL) {
447                 return NT_STATUS_GROUP_EXISTS;
448         }
449
450         ZERO_STRUCT(msg);
451
452         /* pull in all the template attributes */
453         ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg, 
454                                   "(&(name=TemplateGroup)(objectclass=groupTemplate))");
455         if (ret != 0) {
456                 DEBUG(0,("Failed to load TemplateGroup from samdb\n"));
457                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
458         }
459
460         /* allocate a rid */
461         status = samdb_allocate_next_id(d_state->sam_ctx, mem_ctx, 
462                                         d_state->domain_dn, "nextRid", &rid);
463         if (!NT_STATUS_IS_OK(status)) {
464                 return status;
465         }
466
467         /* and the group SID */
468         sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, rid);
469         if (!sidstr) {
470                 return NT_STATUS_NO_MEMORY;
471         }
472
473         /* a new GUID */
474         guid = GUID_random();
475         guidstr = GUID_string(mem_ctx, &guid);
476         if (!guidstr) {
477                 return NT_STATUS_NO_MEMORY;
478         }
479
480         /* add core elements to the ldb_message for the user */
481         msg.dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Users,%s", groupname,
482                                  d_state->domain_dn);
483         if (!msg.dn) {
484                 return NT_STATUS_NO_MEMORY;
485         }
486         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "name", groupname);
487         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "cn", groupname);
488         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "sAMAccountName", groupname);
489         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectClass", "group");
490         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectSid", sidstr);
491         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectGUID", guidstr);
492         samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenCreated", now);
493         samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenChanged", now);
494                              
495         /* create the group */
496         ret = samdb_add(d_state->sam_ctx, mem_ctx, &msg);
497         if (ret != 0) {
498                 DEBUG(0,("Failed to create group record %s\n", msg.dn));
499                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
500         }
501
502         a_state = talloc_p(d_state, struct samr_account_state);
503         if (!a_state) {
504                 return NT_STATUS_NO_MEMORY;
505         }
506         a_state->sam_ctx = d_state->sam_ctx;
507         a_state->access_mask = r->in.access_mask;
508         a_state->domain_state = talloc_reference(a_state, d_state);
509         a_state->account_dn = talloc_steal(a_state, msg.dn);
510         a_state->account_sid = talloc_strdup(a_state, sidstr);
511         a_state->account_name = talloc_strdup(a_state, groupname);
512         if (!a_state->account_name || !a_state->account_sid) {
513                 talloc_free(a_state);
514                 return NT_STATUS_NO_MEMORY;
515         }
516
517         /* create the policy handle */
518         g_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_GROUP);
519         if (!g_handle) {
520                 return NT_STATUS_NO_MEMORY;
521         }
522
523         g_handle->data = a_state;
524         g_handle->destroy = samr_handle_destroy;
525
526         *r->out.group_handle = g_handle->wire_handle;
527         *r->out.rid = rid;      
528
529         return NT_STATUS_OK;
530 }
531
532
533 /* 
534   samr_EnumDomainGroups 
535 */
536 static NTSTATUS samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
537                                       struct samr_EnumDomainGroups *r)
538 {
539         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
540 }
541
542
543 /* 
544   samr_CreateUser2 
545
546   TODO: This should do some form of locking, especially around the rid allocation
547 */
548 static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
549                                  struct samr_CreateUser2 *r)
550 {
551         struct samr_domain_state *d_state;
552         struct samr_account_state *a_state;
553         struct dcesrv_handle *h;
554         const char *name;
555         struct ldb_message msg;
556         uint32_t rid;
557         const char *account_name, *sidstr, *guidstr;
558         struct GUID guid;
559         time_t now = time(NULL);
560         struct dcesrv_handle *u_handle;
561         int ret;
562         NTSTATUS status;
563         const char *container, *additional_class=NULL;
564
565         ZERO_STRUCTP(r->out.user_handle);
566         *r->out.access_granted = 0;
567         *r->out.rid = 0;
568
569         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
570
571         d_state = h->data;
572
573         account_name = r->in.account_name->string;
574
575         if (account_name == NULL) {
576                 return NT_STATUS_INVALID_PARAMETER;
577         }
578
579         /* check if the user already exists */
580         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL, 
581                                    "sAMAccountName", 
582                                    "(&(sAMAccountName=%s)(objectclass=user))", account_name);
583         if (name != NULL) {
584                 return NT_STATUS_USER_EXISTS;
585         }
586
587         ZERO_STRUCT(msg);
588
589         /* This must be one of these values *only* */
590         if (r->in.acct_flags == ACB_NORMAL) {
591                 /* pull in all the template attributes */
592                 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg, 
593                                           "(&(name=TemplateUser)(objectclass=userTemplate))");
594                 if (ret != 0) {
595                         DEBUG(0,("Failed to load TemplateUser from samdb\n"));
596                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
597                 }
598
599                 container = "Users";
600
601         } else if (r->in.acct_flags == ACB_WSTRUST) {
602                 /* pull in all the template attributes */
603                 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg, 
604                                           "(&(name=TemplateMemberServer)(objectclass=userTemplate))");
605                 if (ret != 0) {
606                         DEBUG(0,("Failed to load TemplateMemberServer from samdb\n"));
607                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
608                 }
609
610                 container = "Computers";
611                 additional_class = "computer";
612
613         } else if (r->in.acct_flags == ACB_SVRTRUST) {
614                 /* pull in all the template attributes */
615                 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg, 
616                                           "(&(name=TemplateDomainController)(objectclass=userTemplate))");
617                 if (ret != 0) {
618                         DEBUG(0,("Failed to load TemplateDomainController from samdb\n"));
619                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
620                 }
621
622                 container = "Domain Controllers";
623                 additional_class = "computer";
624
625         } else if (r->in.acct_flags == ACB_DOMTRUST) {
626                 /* pull in all the template attributes */
627                 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg, 
628                                           "(&(name=TemplateTrustingDomain)(objectclass=userTemplate))");
629                 if (ret != 0) {
630                         DEBUG(0,("Failed to load TemplateTrustingDomain from samdb\n"));
631                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
632                 }
633
634                 container = "Users";
635                 additional_class = "computer";
636
637         } else {
638                 return NT_STATUS_INVALID_PARAMETER;
639         }
640
641         /* allocate a rid */
642         status = samdb_allocate_next_id(d_state->sam_ctx, mem_ctx, 
643                                         d_state->domain_dn, "nextRid", &rid);
644         if (!NT_STATUS_IS_OK(status)) {
645                 return status;
646         }
647
648         /* and the users SID */
649         sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, rid);
650         if (!sidstr) {
651                 return NT_STATUS_NO_MEMORY;
652         }
653
654         /* a new GUID */
655         guid = GUID_random();
656         guidstr = GUID_string(mem_ctx, &guid);
657         if (!guidstr) {
658                 return NT_STATUS_NO_MEMORY;
659         }
660
661         /* add core elements to the ldb_message for the user */
662         msg.dn = talloc_asprintf(mem_ctx, "CN=%s,CN=%s,%s", account_name, container, d_state->domain_dn);
663         if (!msg.dn) {
664                 return NT_STATUS_NO_MEMORY;             
665         }
666         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "name", account_name);
667         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "cn", account_name);
668         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "sAMAccountName", account_name);
669         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectClass", "user");
670         if (additional_class) {
671                 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectClass", additional_class);
672         }
673         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectSid", sidstr);
674         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectGUID", guidstr);
675         samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenCreated", now);
676         samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenChanged", now);
677
678         /* create the user */
679         ret = samdb_add(d_state->sam_ctx, mem_ctx, &msg);
680         if (ret != 0) {
681                 DEBUG(0,("Failed to create user record %s\n", msg.dn));
682                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
683         }
684
685         a_state = talloc_p(d_state, struct samr_account_state);
686         if (!a_state) {
687                 return NT_STATUS_NO_MEMORY;
688         }
689         a_state->sam_ctx = d_state->sam_ctx;
690         a_state->access_mask = r->in.access_mask;
691         a_state->domain_state = talloc_reference(a_state, d_state);
692         a_state->account_dn = talloc_steal(d_state, msg.dn);
693         a_state->account_sid = talloc_strdup(d_state, sidstr);
694         a_state->account_name = talloc_strdup(d_state, account_name);
695         if (!a_state->account_name || !a_state->account_sid) {
696                 talloc_free(a_state);
697                 return NT_STATUS_NO_MEMORY;
698         }
699
700         /* create the policy handle */
701         u_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_USER);
702         if (!u_handle) {
703                 talloc_free(a_state);
704                 return NT_STATUS_NO_MEMORY;
705         }
706
707         u_handle->data = a_state;
708         u_handle->destroy = samr_handle_destroy;
709
710         /* the domain state is in use one more time */
711         
712
713         *r->out.user_handle = u_handle->wire_handle;
714         *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
715         *r->out.rid = rid;      
716
717         return NT_STATUS_OK;
718 }
719
720
721 /* 
722   samr_CreateUser 
723 */
724 static NTSTATUS samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
725                                 struct samr_CreateUser *r)
726 {
727         struct samr_CreateUser2 r2;
728         uint32_t access_granted = 0;
729
730
731         /* a simple wrapper around samr_CreateUser2 works nicely */
732         r2.in.domain_handle = r->in.domain_handle;
733         r2.in.account_name = r->in.account_name;
734         r2.in.acct_flags = ACB_NORMAL;
735         r2.in.access_mask = r->in.access_mask;
736         r2.out.user_handle = r->out.user_handle;
737         r2.out.access_granted = &access_granted;
738         r2.out.rid = r->out.rid;
739
740         return samr_CreateUser2(dce_call, mem_ctx, &r2);
741 }
742
743 /*
744   comparison function for sorting SamEntry array
745 */
746 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
747 {
748         return e1->idx - e2->idx;
749 }
750
751 /* 
752   samr_EnumDomainUsers 
753 */
754 static NTSTATUS samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
755                                      struct samr_EnumDomainUsers *r)
756 {
757         struct dcesrv_handle *h;
758         struct samr_domain_state *d_state;
759         struct ldb_message **res;
760         int count, i, first;
761         struct samr_SamEntry *entries;
762         const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
763
764         *r->out.resume_handle = 0;
765         r->out.sam = NULL;
766         r->out.num_entries = 0;
767
768         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
769
770         d_state = h->data;
771         
772         /* search for all users in this domain. This could possibly be cached and 
773            resumed based on resume_key */
774         count = samdb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs, 
775                              "objectclass=user");
776         if (count == -1) {
777                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
778         }
779         if (count == 0 || r->in.max_size == 0) {
780                 return NT_STATUS_OK;
781         }
782
783         /* convert to SamEntry format */
784         entries = talloc_array_p(mem_ctx, struct samr_SamEntry, count);
785         if (!entries) {
786                 return NT_STATUS_NO_MEMORY;
787         }
788         for (i=0;i<count;i++) {
789                 entries[i].idx = samdb_result_rid_from_sid(mem_ctx, res[i], "objectSid", 0);
790                 entries[i].name.string = samdb_result_string(res[i], "sAMAccountName", "");
791         }
792
793         /* sort the results by rid */
794         qsort(entries, count, sizeof(struct samr_SamEntry), 
795               (comparison_fn_t)compare_SamEntry);
796
797         /* find the first entry to return */
798         for (first=0;
799              first<count && entries[first].idx <= *r->in.resume_handle;
800              first++) ;
801
802         if (first == count) {
803                 return NT_STATUS_OK;
804         }
805
806         /* return the rest, limit by max_size. Note that we 
807            use the w2k3 element size value of 54 */
808         r->out.num_entries = count - first;
809         r->out.num_entries = MIN(r->out.num_entries, 
810                                  1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
811
812         r->out.sam = talloc_p(mem_ctx, struct samr_SamArray);
813         if (!r->out.sam) {
814                 return NT_STATUS_NO_MEMORY;
815         }
816
817         r->out.sam->entries = entries+first;
818         r->out.sam->count = r->out.num_entries;
819
820         if (r->out.num_entries < count - first) {
821                 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
822                 return STATUS_MORE_ENTRIES;
823         }
824
825         return NT_STATUS_OK;
826 }
827
828
829 /* 
830   samr_CreateDomAlias 
831 */
832 static NTSTATUS samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
833                        struct samr_CreateDomAlias *r)
834 {
835         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
836 }
837
838
839 /* 
840   samr_EnumDomainAliases 
841 */
842 static NTSTATUS samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
843                        struct samr_EnumDomainAliases *r)
844 {
845         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
846 }
847
848
849 /* 
850   samr_GetAliasMembership 
851 */
852 static NTSTATUS samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
853                        struct samr_GetAliasMembership *r)
854 {
855         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
856 }
857
858
859 /* 
860   samr_LookupNames 
861 */
862 static NTSTATUS samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
863                                  struct samr_LookupNames *r)
864 {
865         struct dcesrv_handle *h;
866         struct samr_domain_state *d_state;
867         int i;
868         NTSTATUS status = NT_STATUS_OK;
869         const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
870         int count;
871
872         ZERO_STRUCT(r->out.rids);
873         ZERO_STRUCT(r->out.types);
874
875         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
876
877         d_state = h->data;
878
879         if (r->in.num_names == 0) {
880                 return NT_STATUS_OK;
881         }
882
883         r->out.rids.ids = talloc_array_p(mem_ctx, uint32_t, r->in.num_names);
884         r->out.types.ids = talloc_array_p(mem_ctx, uint32_t, r->in.num_names);
885         if (!r->out.rids.ids || !r->out.types.ids) {
886                 return NT_STATUS_NO_MEMORY;
887         }
888         r->out.rids.count = r->in.num_names;
889         r->out.types.count = r->in.num_names;
890
891         for (i=0;i<r->in.num_names;i++) {
892                 struct ldb_message **res;
893                 struct dom_sid2 *sid;
894                 const char *sidstr;
895                 uint32_t atype, rtype;
896
897                 r->out.rids.ids[i] = 0;
898                 r->out.types.ids[i] = SID_NAME_UNKNOWN;
899
900                 count = samdb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs, 
901                                      "sAMAccountName=%s", r->in.names[i].string);
902                 if (count != 1) {
903                         status = STATUS_SOME_UNMAPPED;
904                         continue;
905                 }
906
907                 sidstr = samdb_result_string(res[0], "objectSid", NULL);
908                 if (sidstr == NULL) {
909                         status = STATUS_SOME_UNMAPPED;
910                         continue;
911                 }
912                 
913                 sid = dom_sid_parse_talloc(mem_ctx, sidstr);
914                 if (sid == NULL) {
915                         status = STATUS_SOME_UNMAPPED;
916                         continue;
917                 }
918
919                 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
920                 if (atype == 0) {
921                         status = STATUS_SOME_UNMAPPED;
922                         continue;
923                 }
924
925                 rtype = samdb_atype_map(atype);
926                 
927                 if (rtype == SID_NAME_UNKNOWN) {
928                         status = STATUS_SOME_UNMAPPED;
929                         continue;
930                 }
931
932                 r->out.rids.ids[i] = sid->sub_auths[sid->num_auths-1];
933                 r->out.types.ids[i] = rtype;
934         }
935         
936
937         return status;
938 }
939
940
941 /* 
942   samr_LookupRids 
943 */
944 static NTSTATUS samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
945                        struct samr_LookupRids *r)
946 {
947         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
948 }
949
950
951 /* 
952   samr_OpenGroup 
953 */
954 static NTSTATUS samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
955                        struct samr_OpenGroup *r)
956 {
957         struct samr_domain_state *d_state;
958         struct samr_account_state *a_state;
959         struct dcesrv_handle *h;
960         const char *groupname, *sidstr;
961         struct ldb_message **msgs;
962         struct dcesrv_handle *g_handle;
963         const char * const attrs[2] = { "sAMAccountName", NULL };
964         int ret;
965
966         ZERO_STRUCTP(r->out.group_handle);
967
968         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
969
970         d_state = h->data;
971
972         /* form the group SID */
973         sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, r->in.rid);
974         if (!sidstr) {
975                 return NT_STATUS_NO_MEMORY;
976         }
977
978         /* search for the group record */
979         ret = samdb_search(d_state->sam_ctx,
980                            mem_ctx, d_state->domain_dn, &msgs, attrs,
981                            "(&(objectSid=%s)(objectclass=group))", 
982                            sidstr);
983         if (ret == 0) {
984                 return NT_STATUS_NO_SUCH_GROUP;
985         }
986         if (ret != 1) {
987                 DEBUG(0,("Found %d records matching sid %s\n", ret, sidstr));
988                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
989         }
990
991         groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
992         if (groupname == NULL) {
993                 DEBUG(0,("sAMAccountName field missing for sid %s\n", sidstr));
994                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
995         }
996
997         a_state = talloc_p(d_state, struct samr_account_state);
998         if (!a_state) {
999                 return NT_STATUS_NO_MEMORY;
1000         }
1001         a_state->sam_ctx = d_state->sam_ctx;
1002         a_state->access_mask = r->in.access_mask;
1003         a_state->domain_state = talloc_reference(a_state, d_state);
1004         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1005         a_state->account_sid = talloc_strdup(a_state, sidstr);
1006         a_state->account_name = talloc_strdup(a_state, groupname);
1007         if (!a_state->account_name || !a_state->account_sid) {
1008                 return NT_STATUS_NO_MEMORY;
1009         }
1010
1011         /* create the policy handle */
1012         g_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_GROUP);
1013         if (!g_handle) {
1014                 return NT_STATUS_NO_MEMORY;
1015         }
1016
1017         g_handle->data = a_state;
1018         g_handle->destroy = samr_handle_destroy;
1019
1020         *r->out.group_handle = g_handle->wire_handle;
1021
1022         return NT_STATUS_OK;
1023 }
1024
1025 /* these query macros make samr_Query[User|Group]Info a bit easier to read */
1026
1027 #define QUERY_STRING(msg, field, attr) \
1028         r->out.info->field = samdb_result_string(msg, attr, "");
1029 #define QUERY_UINT(msg, field, attr) \
1030         r->out.info->field = samdb_result_uint(msg, attr, 0);
1031 #define QUERY_RID(msg, field, attr) \
1032         r->out.info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
1033 #define QUERY_NTTIME(msg, field, attr) \
1034         r->out.info->field = samdb_result_nttime(msg, attr, 0);
1035 #define QUERY_APASSC(msg, field, attr) \
1036         r->out.info->field = samdb_result_allow_password_change(a_state->sam_ctx, mem_ctx, \
1037                                                            a_state->domain_state->domain_dn, msg, attr);
1038 #define QUERY_FPASSC(msg, field, attr) \
1039         r->out.info->field = samdb_result_force_password_change(a_state->sam_ctx, mem_ctx, \
1040                                                            a_state->domain_state->domain_dn, msg, attr);
1041 #define QUERY_LHOURS(msg, field, attr) \
1042         r->out.info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
1043 #define QUERY_AFLAGS(msg, field, attr) \
1044         r->out.info->field = samdb_result_acct_flags(msg, attr);
1045
1046
1047 /* these are used to make the Set[User|Group]Info code easier to follow */
1048
1049 #define SET_STRING(mod, field, attr) do { \
1050         if (r->in.info->field == NULL) return NT_STATUS_INVALID_PARAMETER; \
1051         if (samdb_msg_add_string(a_state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
1052                 return NT_STATUS_NO_MEMORY; \
1053         } \
1054 } while (0)
1055
1056 #define SET_UINT(mod, field, attr) do { \
1057         if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
1058                 return NT_STATUS_NO_MEMORY; \
1059         } \
1060 } while (0)
1061
1062 #define SET_AFLAGS(msg, field, attr) do { \
1063         if (samdb_msg_add_acct_flags(a_state->sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
1064                 return NT_STATUS_NO_MEMORY; \
1065         } \
1066 } while (0)
1067
1068 #define SET_LHOURS(msg, field, attr) do { \
1069         if (samdb_msg_add_logon_hours(a_state->sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
1070                 return NT_STATUS_NO_MEMORY; \
1071         } \
1072 } while (0)
1073
1074 /* 
1075   samr_QueryGroupInfo 
1076 */
1077 static NTSTATUS samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1078                        struct samr_QueryGroupInfo *r)
1079 {
1080         struct dcesrv_handle *h;
1081         struct samr_account_state *a_state;
1082         struct ldb_message *msg, **res;
1083         const char * const attrs[4] = { "sAMAccountName", "description",
1084                                         "numMembers", NULL };
1085         int ret;
1086
1087         r->out.info = NULL;
1088
1089         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1090
1091         a_state = h->data;
1092
1093         /* pull all the group attributes */
1094         ret = samdb_search(a_state->sam_ctx, mem_ctx, NULL, &res, attrs,
1095                            "dn=%s", a_state->account_dn);
1096         if (ret != 1) {
1097                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1098         }
1099         msg = res[0];
1100
1101         /* allocate the info structure */
1102         r->out.info = talloc_p(mem_ctx, union samr_GroupInfo);
1103         if (r->out.info == NULL) {
1104                 return NT_STATUS_NO_MEMORY;
1105         }
1106         ZERO_STRUCTP(r->out.info);
1107
1108         /* Fill in the level */
1109         switch (r->in.level) {
1110         case GroupInfoAll:
1111                 QUERY_STRING(msg, all.name.string,        "sAMAccountName");
1112                 r->out.info->all.attributes = 7; /* Do like w2k3 */
1113                 QUERY_UINT  (msg, all.num_members,      "numMembers")
1114                 QUERY_STRING(msg, all.description.string, "description");
1115                 break;
1116         case GroupInfoName:
1117                 QUERY_STRING(msg, name.string,            "sAMAccountName");
1118                 break;
1119         case GroupInfoX:
1120                 r->out.info->unknown.unknown = 7;
1121                 break;
1122         case GroupInfoDescription:
1123                 QUERY_STRING(msg, description.string, "description");
1124                 break;
1125         default:
1126                 r->out.info = NULL;
1127                 return NT_STATUS_INVALID_INFO_CLASS;
1128         }
1129         
1130         return NT_STATUS_OK;
1131 }
1132
1133
1134 /* 
1135   samr_SetGroupInfo 
1136 */
1137 static NTSTATUS samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1138                        struct samr_SetGroupInfo *r)
1139 {
1140         struct dcesrv_handle *h;
1141         struct samr_account_state *a_state;
1142         struct ldb_message mod, *msg = &mod;
1143         int ret;
1144
1145         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1146
1147         a_state = h->data;
1148
1149         ZERO_STRUCT(mod);
1150         mod.dn = talloc_strdup(mem_ctx, a_state->account_dn);
1151         if (!mod.dn) {
1152                 return NT_STATUS_NO_MEMORY;
1153         }
1154
1155         switch (r->in.level) {
1156         case GroupInfoDescription:
1157                 SET_STRING(msg, description.string,         "description");
1158                 break;
1159         case GroupInfoName:
1160                 /* On W2k3 this does not change the name, it changes the
1161                  * sAMAccountName attribute */
1162                 SET_STRING(msg, name.string,                "sAMAccountName");
1163                 break;
1164         case GroupInfoX:
1165                 /* This does not do anything obviously visible in W2k3 LDAP */
1166                 break;
1167         default:
1168                 return NT_STATUS_INVALID_INFO_CLASS;
1169         }
1170
1171         /* modify the samdb record */
1172         ret = samdb_replace(a_state->sam_ctx, mem_ctx, &mod);
1173         if (ret != 0) {
1174                 /* we really need samdb.c to return NTSTATUS */
1175                 return NT_STATUS_UNSUCCESSFUL;
1176         }
1177
1178         return NT_STATUS_OK;
1179 }
1180
1181
1182 /* 
1183   samr_AddGroupMember 
1184 */
1185 static NTSTATUS samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1186                        struct samr_AddGroupMember *r)
1187 {
1188         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1189 }
1190
1191
1192 /* 
1193   samr_DeleteDomainGroup 
1194 */
1195 static NTSTATUS samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1196                        struct samr_DeleteDomainGroup *r)
1197 {
1198         struct dcesrv_handle *h;
1199         struct samr_account_state *a_state;
1200         int ret;
1201
1202         *r->out.group_handle = *r->in.group_handle;
1203
1204         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1205
1206         a_state = h->data;
1207
1208         ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
1209         if (ret != 0) {
1210                 return NT_STATUS_UNSUCCESSFUL;
1211         }
1212
1213         ZERO_STRUCTP(r->out.group_handle);
1214
1215         return NT_STATUS_OK;
1216 }
1217
1218
1219 /* 
1220   samr_DeleteGroupMember 
1221 */
1222 static NTSTATUS samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1223                        struct samr_DeleteGroupMember *r)
1224 {
1225         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1226 }
1227
1228
1229 /* 
1230   samr_QueryGroupMember 
1231 */
1232 static NTSTATUS samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1233                        struct samr_QueryGroupMember *r)
1234 {
1235         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1236 }
1237
1238
1239 /* 
1240   samr_SetMemberAttributesOfGroup 
1241 */
1242 static NTSTATUS samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1243                        struct samr_SetMemberAttributesOfGroup *r)
1244 {
1245         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1246 }
1247
1248
1249 /* 
1250   samr_OpenAlias 
1251 */
1252 static NTSTATUS samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1253                        struct samr_OpenAlias *r)
1254 {
1255         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1256 }
1257
1258
1259 /* 
1260   samr_QueryAliasInfo 
1261 */
1262 static NTSTATUS samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1263                        struct samr_QueryAliasInfo *r)
1264 {
1265         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1266 }
1267
1268
1269 /* 
1270   samr_SetAliasInfo 
1271 */
1272 static NTSTATUS samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1273                        struct samr_SetAliasInfo *r)
1274 {
1275         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1276 }
1277
1278
1279 /* 
1280   samr_DeleteDomAlias 
1281 */
1282 static NTSTATUS samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1283                        struct samr_DeleteDomAlias *r)
1284 {
1285         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1286 }
1287
1288
1289 /* 
1290   samr_AddAliasMember 
1291 */
1292 static NTSTATUS samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1293                        struct samr_AddAliasMember *r)
1294 {
1295         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1296 }
1297
1298
1299 /* 
1300   samr_DeleteAliasMember 
1301 */
1302 static NTSTATUS samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1303                        struct samr_DeleteAliasMember *r)
1304 {
1305         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1306 }
1307
1308
1309 /* 
1310   samr_GetMembersInAlias 
1311 */
1312 static NTSTATUS samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1313                        struct samr_GetMembersInAlias *r)
1314 {
1315         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1316 }
1317
1318
1319 /* 
1320   samr_OpenUser 
1321 */
1322 static NTSTATUS samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1323                               struct samr_OpenUser *r)
1324 {
1325         struct samr_domain_state *d_state;
1326         struct samr_account_state *a_state;
1327         struct dcesrv_handle *h;
1328         const char *account_name, *sidstr;
1329         struct ldb_message **msgs;
1330         struct dcesrv_handle *u_handle;
1331         const char * const attrs[2] = { "sAMAccountName", NULL };
1332         int ret;
1333
1334         ZERO_STRUCTP(r->out.user_handle);
1335
1336         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1337
1338         d_state = h->data;
1339
1340         /* form the users SID */
1341         sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, r->in.rid);
1342         if (!sidstr) {
1343                 return NT_STATUS_NO_MEMORY;
1344         }
1345
1346         /* search for the user record */
1347         ret = samdb_search(d_state->sam_ctx,
1348                            mem_ctx, d_state->domain_dn, &msgs, attrs,
1349                            "(&(objectSid=%s)(objectclass=user))", 
1350                            sidstr);
1351         if (ret == 0) {
1352                 return NT_STATUS_NO_SUCH_USER;
1353         }
1354         if (ret != 1) {
1355                 DEBUG(0,("Found %d records matching sid %s\n", ret, sidstr));
1356                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1357         }
1358
1359         account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
1360         if (account_name == NULL) {
1361                 DEBUG(0,("sAMAccountName field missing for sid %s\n", sidstr));
1362                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1363         }
1364
1365         a_state = talloc_p(d_state, struct samr_account_state);
1366         if (!a_state) {
1367                 return NT_STATUS_NO_MEMORY;
1368         }
1369         a_state->sam_ctx = d_state->sam_ctx;
1370         a_state->access_mask = r->in.access_mask;
1371         a_state->domain_state = talloc_reference(a_state, d_state);
1372         a_state->account_dn = talloc_steal(d_state, msgs[0]->dn);
1373         a_state->account_sid = talloc_strdup(d_state, sidstr);
1374         a_state->account_name = talloc_strdup(d_state, account_name);
1375         if (!a_state->account_name || !a_state->account_sid) {
1376                 return NT_STATUS_NO_MEMORY;
1377         }
1378
1379         /* create the policy handle */
1380         u_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_USER);
1381         if (!u_handle) {
1382                 return NT_STATUS_NO_MEMORY;
1383         }
1384
1385         u_handle->data = a_state;
1386         u_handle->destroy = samr_handle_destroy;
1387
1388         *r->out.user_handle = u_handle->wire_handle;
1389
1390         return NT_STATUS_OK;
1391
1392 }
1393
1394
1395 /* 
1396   samr_DeleteUser 
1397 */
1398 static NTSTATUS samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1399                                 struct samr_DeleteUser *r)
1400 {
1401         struct dcesrv_handle *h;
1402         struct samr_account_state *a_state;
1403         int ret;
1404
1405         *r->out.user_handle = *r->in.user_handle;
1406
1407         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
1408
1409         a_state = h->data;
1410
1411         ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
1412         if (ret != 0) {
1413                 return NT_STATUS_UNSUCCESSFUL;
1414         }
1415
1416         ZERO_STRUCTP(r->out.user_handle);
1417
1418         return NT_STATUS_OK;
1419 }
1420
1421
1422 /* 
1423   samr_QueryUserInfo 
1424 */
1425 static NTSTATUS samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1426                                    struct samr_QueryUserInfo *r)
1427 {
1428         struct dcesrv_handle *h;
1429         struct samr_account_state *a_state;
1430         struct ldb_message *msg, **res;
1431         int ret;
1432
1433         r->out.info = NULL;
1434
1435         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
1436
1437         a_state = h->data;
1438
1439         /* pull all the user attributes */
1440         ret = samdb_search(a_state->sam_ctx, mem_ctx, NULL, &res, NULL,
1441                            "dn=%s", a_state->account_dn);
1442         if (ret != 1) {
1443                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1444         }
1445         msg = res[0];
1446
1447         /* allocate the info structure */
1448         r->out.info = talloc_p(mem_ctx, union samr_UserInfo);
1449         if (r->out.info == NULL) {
1450                 return NT_STATUS_NO_MEMORY;
1451         }
1452         ZERO_STRUCTP(r->out.info);
1453
1454         /* fill in the reply */
1455         switch (r->in.level) {
1456         case 1:
1457                 QUERY_STRING(msg, info1.account_name.string,   "sAMAccountName");
1458                 QUERY_STRING(msg, info1.full_name.string,      "displayName");
1459                 QUERY_UINT  (msg, info1.primary_gid,           "primaryGroupID");
1460                 QUERY_STRING(msg, info1.description.string,    "description");
1461                 QUERY_STRING(msg, info1.comment.string,        "comment");
1462                 break;
1463
1464         case 2:
1465                 QUERY_STRING(msg, info2.comment.string,        "comment");
1466                 QUERY_UINT  (msg, info2.country_code,          "countryCode");
1467                 QUERY_UINT  (msg, info2.code_page,             "codePage");
1468                 break;
1469
1470         case 3:
1471                 QUERY_STRING(msg, info3.account_name.string,   "sAMAccountName");
1472                 QUERY_STRING(msg, info3.full_name.string,      "displayName");
1473                 QUERY_RID   (msg, info3.rid,                   "objectSid");
1474                 QUERY_UINT  (msg, info3.primary_gid,           "primaryGroupID");
1475                 QUERY_STRING(msg, info3.home_directory.string, "homeDirectory");
1476                 QUERY_STRING(msg, info3.home_drive.string,     "homeDrive");
1477                 QUERY_STRING(msg, info3.logon_script.string,   "scriptPath");
1478                 QUERY_STRING(msg, info3.profile_path.string,   "profilePath");
1479                 QUERY_STRING(msg, info3.workstations.string,   "userWorkstations");
1480                 QUERY_NTTIME(msg, info3.last_logon,            "lastLogon");
1481                 QUERY_NTTIME(msg, info3.last_logoff,           "lastLogoff");
1482                 QUERY_NTTIME(msg, info3.last_password_change,  "pwdLastSet");
1483                 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
1484                 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
1485                 QUERY_LHOURS(msg, info3.logon_hours,           "logonHours");
1486                 QUERY_UINT  (msg, info3.bad_password_count,    "badPwdCount");
1487                 QUERY_UINT  (msg, info3.logon_count,           "logonCount");
1488                 QUERY_AFLAGS(msg, info3.acct_flags,            "userAccountControl");
1489                 break;
1490
1491         case 4:
1492                 QUERY_LHOURS(msg, info4.logon_hours,           "logonHours");
1493                 break;
1494
1495         case 5:
1496                 QUERY_STRING(msg, info5.account_name.string,   "sAMAccountName");
1497                 QUERY_STRING(msg, info5.full_name.string,      "displayName");
1498                 QUERY_RID   (msg, info5.rid,                   "objectSid");
1499                 QUERY_UINT  (msg, info5.primary_gid,           "primaryGroupID");
1500                 QUERY_STRING(msg, info5.home_directory.string, "homeDirectory");
1501                 QUERY_STRING(msg, info5.home_drive.string,     "homeDrive");
1502                 QUERY_STRING(msg, info5.logon_script.string,   "scriptPath");
1503                 QUERY_STRING(msg, info5.profile_path.string,   "profilePath");
1504                 QUERY_STRING(msg, info5.description.string,    "description");
1505                 QUERY_STRING(msg, info5.workstations.string,   "userWorkstations");
1506                 QUERY_NTTIME(msg, info5.last_logon,            "lastLogon");
1507                 QUERY_NTTIME(msg, info5.last_logoff,           "lastLogoff");
1508                 QUERY_LHOURS(msg, info5.logon_hours,           "logonHours");
1509                 QUERY_UINT  (msg, info5.bad_password_count,    "badPwdCount");
1510                 QUERY_UINT  (msg, info5.logon_count,           "logonCount");
1511                 QUERY_NTTIME(msg, info5.last_password_change,  "pwdLastSet");
1512                 QUERY_NTTIME(msg, info5.acct_expiry,           "accountExpires");
1513                 QUERY_AFLAGS(msg, info5.acct_flags,            "userAccountControl");
1514                 break;
1515
1516         case 6:
1517                 QUERY_STRING(msg, info6.account_name.string,   "sAMAccountName");
1518                 QUERY_STRING(msg, info6.full_name.string,      "displayName");
1519                 break;
1520
1521         case 7:
1522                 QUERY_STRING(msg, info7.account_name.string,   "sAMAccountName");
1523                 break;
1524
1525         case 8:
1526                 QUERY_STRING(msg, info8.full_name.string,      "displayName");
1527                 break;
1528
1529         case 9:
1530                 QUERY_UINT  (msg, info9.primary_gid,           "primaryGroupID");
1531                 break;
1532
1533         case 10:
1534                 QUERY_STRING(msg, info10.home_directory.string,"homeDirectory");
1535                 QUERY_STRING(msg, info10.home_drive.string,    "homeDrive");
1536                 break;
1537
1538         case 11:
1539                 QUERY_STRING(msg, info11.logon_script.string,  "scriptPath");
1540                 break;
1541
1542         case 12:
1543                 QUERY_STRING(msg, info12.profile_path.string,  "profilePath");
1544                 break;
1545
1546         case 13:
1547                 QUERY_STRING(msg, info13.description.string,   "description");
1548                 break;
1549
1550         case 14:
1551                 QUERY_STRING(msg, info14.workstations.string,  "userWorkstations");
1552                 break;
1553
1554         case 16:
1555                 QUERY_AFLAGS(msg, info16.acct_flags,           "userAccountControl");
1556                 break;
1557
1558         case 17:
1559                 QUERY_NTTIME(msg, info17.acct_expiry,          "accountExpires");
1560
1561         case 20:
1562                 QUERY_STRING(msg, info20.parameters.string,    "userParameters");
1563                 break;
1564
1565         case 21:
1566                 QUERY_NTTIME(msg, info21.last_logon,           "lastLogon");
1567                 QUERY_NTTIME(msg, info21.last_logoff,          "lastLogoff");
1568                 QUERY_NTTIME(msg, info21.last_password_change, "pwdLastSet");
1569                 QUERY_NTTIME(msg, info21.acct_expiry,          "accountExpires");
1570                 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
1571                 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
1572                 QUERY_STRING(msg, info21.account_name.string,  "sAMAccountName");
1573                 QUERY_STRING(msg, info21.full_name.string,     "displayName");
1574                 QUERY_STRING(msg, info21.home_directory.string,"homeDirectory");
1575                 QUERY_STRING(msg, info21.home_drive.string,    "homeDrive");
1576                 QUERY_STRING(msg, info21.logon_script.string,  "scriptPath");
1577                 QUERY_STRING(msg, info21.profile_path.string,  "profilePath");
1578                 QUERY_STRING(msg, info21.description.string,   "description");
1579                 QUERY_STRING(msg, info21.workstations.string,  "userWorkstations");
1580                 QUERY_STRING(msg, info21.comment.string,       "comment");
1581                 QUERY_STRING(msg, info21.parameters.string,    "userParameters");
1582                 QUERY_RID   (msg, info21.rid,                  "objectSid");
1583                 QUERY_UINT  (msg, info21.primary_gid,          "primaryGroupID");
1584                 QUERY_AFLAGS(msg, info21.acct_flags,           "userAccountControl");
1585                 r->out.info->info21.fields_present = 0x00FFFFFF;
1586                 QUERY_LHOURS(msg, info21.logon_hours,          "logonHours");
1587                 QUERY_UINT  (msg, info21.bad_password_count,   "badPwdCount");
1588                 QUERY_UINT  (msg, info21.logon_count,          "logonCount");
1589                 QUERY_UINT  (msg, info21.country_code,         "countryCode");
1590                 QUERY_UINT  (msg, info21.code_page,            "codePage");
1591                 break;
1592                 
1593
1594         default:
1595                 r->out.info = NULL;
1596                 return NT_STATUS_INVALID_INFO_CLASS;
1597         }
1598         
1599         return NT_STATUS_OK;
1600 }
1601
1602
1603 /* 
1604   samr_SetUserInfo 
1605 */
1606 static NTSTATUS samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1607                                  struct samr_SetUserInfo *r)
1608 {
1609         struct dcesrv_handle *h;
1610         struct samr_account_state *a_state;
1611         struct ldb_message mod, *msg = &mod;
1612         int ret;
1613         NTSTATUS status = NT_STATUS_OK;
1614
1615         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
1616
1617         a_state = h->data;
1618
1619         ZERO_STRUCT(mod);
1620         mod.dn = talloc_strdup(mem_ctx, a_state->account_dn);
1621         if (!mod.dn) {
1622                 return NT_STATUS_NO_MEMORY;
1623         }
1624
1625         switch (r->in.level) {
1626         case 2:
1627                 SET_STRING(msg, info2.comment.string,          "comment");
1628                 SET_UINT  (msg, info2.country_code,            "countryCode");
1629                 SET_UINT  (msg, info2.code_page,               "codePage");
1630                 break;
1631
1632         case 4:
1633                 SET_LHOURS(msg, info4.logon_hours,             "logonHours");
1634                 break;
1635
1636         case 6:
1637                 SET_STRING(msg, info6.full_name.string,        "displayName");
1638                 break;
1639
1640         case 8:
1641                 SET_STRING(msg, info8.full_name.string,        "displayName");
1642                 break;
1643
1644         case 9:
1645                 SET_UINT(msg, info9.primary_gid,               "primaryGroupID");
1646                 break;
1647
1648         case 10:
1649                 SET_STRING(msg, info10.home_directory.string,  "homeDirectory");
1650                 SET_STRING(msg, info10.home_drive.string,      "homeDrive");
1651                 break;
1652
1653         case 11:
1654                 SET_STRING(msg, info11.logon_script.string,    "scriptPath");
1655                 break;
1656
1657         case 12:
1658                 SET_STRING(msg, info12.profile_path.string,    "profilePath");
1659                 break;
1660
1661         case 13:
1662                 SET_STRING(msg, info13.description.string,     "description");
1663                 break;
1664
1665         case 14:
1666                 SET_STRING(msg, info14.workstations.string,    "userWorkstations");
1667                 break;
1668
1669         case 16:
1670                 SET_AFLAGS(msg, info16.acct_flags,             "userAccountControl");
1671                 break;
1672
1673         case 20:
1674                 SET_STRING(msg, info20.parameters.string,      "userParameters");
1675                 break;
1676
1677         case 21:
1678 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
1679                 IFSET(SAMR_FIELD_NAME)         
1680                         SET_STRING(msg, info21.full_name.string,    "displayName");
1681                 IFSET(SAMR_FIELD_DESCRIPTION)  
1682                         SET_STRING(msg, info21.description.string,  "description");
1683                 IFSET(SAMR_FIELD_COMMENT)      
1684                         SET_STRING(msg, info21.comment.string,      "comment");
1685                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
1686                         SET_STRING(msg, info21.logon_script.string, "scriptPath");
1687                 IFSET(SAMR_FIELD_PROFILE_PATH)      
1688                         SET_STRING(msg, info21.profile_path.string, "profilePath");
1689                 IFSET(SAMR_FIELD_WORKSTATION)  
1690                         SET_STRING(msg, info21.workstations.string, "userWorkstations");
1691                 IFSET(SAMR_FIELD_LOGON_HOURS)  
1692                         SET_LHOURS(msg, info21.logon_hours,         "logonHours");
1693                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
1694                         SET_AFLAGS(msg, info21.acct_flags,          "userAccountControl");
1695                 IFSET(SAMR_FIELD_PARAMETERS)     
1696                         SET_STRING(msg, info21.parameters.string,   "userParameters");
1697                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
1698                         SET_UINT  (msg, info21.country_code,        "countryCode");
1699                 IFSET(SAMR_FIELD_CODE_PAGE)    
1700                         SET_UINT  (msg, info21.code_page,           "codePage");
1701
1702
1703                 /* Any reason the rest of these can't be set? */
1704 #undef IFSET
1705                 break;
1706
1707         case 23:
1708 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
1709                 IFSET(SAMR_FIELD_NAME)         
1710                         SET_STRING(msg, info23.info.full_name.string,    "displayName");
1711                 IFSET(SAMR_FIELD_DESCRIPTION)  
1712                         SET_STRING(msg, info23.info.description.string,  "description");
1713                 IFSET(SAMR_FIELD_COMMENT)      
1714                         SET_STRING(msg, info23.info.comment.string,      "comment");
1715                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
1716                         SET_STRING(msg, info23.info.logon_script.string, "scriptPath");
1717                 IFSET(SAMR_FIELD_PROFILE_PATH)      
1718                         SET_STRING(msg, info23.info.profile_path.string, "profilePath");
1719                 IFSET(SAMR_FIELD_WORKSTATION)  
1720                         SET_STRING(msg, info23.info.workstations.string, "userWorkstations");
1721                 IFSET(SAMR_FIELD_LOGON_HOURS)  
1722                         SET_LHOURS(msg, info23.info.logon_hours,         "logonHours");
1723                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
1724                         SET_AFLAGS(msg, info23.info.acct_flags,          "userAccountControl");
1725                 IFSET(SAMR_FIELD_PARAMETERS)     
1726                         SET_STRING(msg, info23.info.parameters.string,   "userParameters");
1727                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
1728                         SET_UINT  (msg, info23.info.country_code,        "countryCode");
1729                 IFSET(SAMR_FIELD_CODE_PAGE)    
1730                         SET_UINT  (msg, info23.info.code_page,           "codePage");
1731                 IFSET(SAMR_FIELD_PASSWORD) {
1732                         status = samr_set_password(dce_call,
1733                                                    a_state->sam_ctx,
1734                                                    a_state->account_dn,
1735                                                    a_state->domain_state->domain_dn,
1736                                                    mem_ctx, msg, 
1737                                                    &r->in.info->info23.password);
1738                 } else IFSET(SAMR_FIELD_PASSWORD2) {
1739                         status = samr_set_password(dce_call,
1740                                                    a_state->sam_ctx,
1741                                                    a_state->account_dn,
1742                                                    a_state->domain_state->domain_dn,
1743                                                    mem_ctx, msg, 
1744                                                    &r->in.info->info23.password);
1745                 }
1746 #undef IFSET
1747                 break;
1748
1749                 /* the set password levels are handled separately */
1750         case 24:
1751                 status = samr_set_password(dce_call,
1752                                            a_state->sam_ctx,
1753                                            a_state->account_dn,
1754                                            a_state->domain_state->domain_dn,
1755                                            mem_ctx, msg, 
1756                                            &r->in.info->info24.password);
1757                 break;
1758
1759         case 25:
1760 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
1761                 IFSET(SAMR_FIELD_NAME)         
1762                         SET_STRING(msg, info25.info.full_name.string,    "displayName");
1763                 IFSET(SAMR_FIELD_DESCRIPTION)  
1764                         SET_STRING(msg, info25.info.description.string,  "description");
1765                 IFSET(SAMR_FIELD_COMMENT)      
1766                         SET_STRING(msg, info25.info.comment.string,      "comment");
1767                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
1768                         SET_STRING(msg, info25.info.logon_script.string, "scriptPath");
1769                 IFSET(SAMR_FIELD_PROFILE_PATH)      
1770                         SET_STRING(msg, info25.info.profile_path.string, "profilePath");
1771                 IFSET(SAMR_FIELD_WORKSTATION)  
1772                         SET_STRING(msg, info25.info.workstations.string, "userWorkstations");
1773                 IFSET(SAMR_FIELD_LOGON_HOURS)  
1774                         SET_LHOURS(msg, info25.info.logon_hours,         "logonHours");
1775                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
1776                         SET_AFLAGS(msg, info25.info.acct_flags,          "userAccountControl");
1777                 IFSET(SAMR_FIELD_PARAMETERS)     
1778                         SET_STRING(msg, info25.info.parameters.string,   "userParameters");
1779                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
1780                         SET_UINT  (msg, info25.info.country_code,        "countryCode");
1781                 IFSET(SAMR_FIELD_CODE_PAGE)    
1782                         SET_UINT  (msg, info25.info.code_page,           "codePage");
1783                 IFSET(SAMR_FIELD_PASSWORD) {
1784                         status = samr_set_password_ex(dce_call,
1785                                                       a_state->sam_ctx,
1786                                                       a_state->account_dn,
1787                                                       a_state->domain_state->domain_dn,
1788                                                       mem_ctx, msg, 
1789                                                       &r->in.info->info25.password);
1790                 } else IFSET(SAMR_FIELD_PASSWORD2) {
1791                         status = samr_set_password_ex(dce_call,
1792                                                       a_state->sam_ctx,
1793                                                       a_state->account_dn,
1794                                                       a_state->domain_state->domain_dn,
1795                                                       mem_ctx, msg, 
1796                                                       &r->in.info->info25.password);
1797                 }
1798 #undef IFSET
1799                 break;
1800
1801                 /* the set password levels are handled separately */
1802         case 26:
1803                 status = samr_set_password_ex(dce_call,
1804                                               a_state->sam_ctx,
1805                                               a_state->account_dn,
1806                                               a_state->domain_state->domain_dn,
1807                                               mem_ctx, msg, 
1808                                               &r->in.info->info26.password);
1809                 break;
1810                 
1811
1812         default:
1813                 /* many info classes are not valid for SetUserInfo */
1814                 return NT_STATUS_INVALID_INFO_CLASS;
1815         }
1816
1817         if (!NT_STATUS_IS_OK(status)) {
1818                 return status;
1819         }
1820
1821         /* modify the samdb record */
1822         ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
1823         if (ret != 0) {
1824                 /* we really need samdb.c to return NTSTATUS */
1825                 return NT_STATUS_UNSUCCESSFUL;
1826         }
1827
1828         return NT_STATUS_OK;
1829 }
1830
1831
1832 /* 
1833   samr_GetGroupsForUser 
1834 */
1835 static NTSTATUS samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1836                        struct samr_GetGroupsForUser *r)
1837 {
1838         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1839 }
1840
1841
1842 /* 
1843   samr_QueryDisplayInfo 
1844 */
1845 static NTSTATUS samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1846                        struct samr_QueryDisplayInfo *r)
1847 {
1848         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1849 }
1850
1851
1852 /* 
1853   samr_GetDisplayEnumerationIndex 
1854 */
1855 static NTSTATUS samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1856                        struct samr_GetDisplayEnumerationIndex *r)
1857 {
1858         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1859 }
1860
1861
1862 /* 
1863   samr_TestPrivateFunctionsDomain 
1864 */
1865 static NTSTATUS samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1866                        struct samr_TestPrivateFunctionsDomain *r)
1867 {
1868         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1869 }
1870
1871
1872 /* 
1873   samr_TestPrivateFunctionsUser 
1874 */
1875 static NTSTATUS samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1876                        struct samr_TestPrivateFunctionsUser *r)
1877 {
1878         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1879 }
1880
1881
1882 /* 
1883   samr_GetUserPwInfo 
1884 */
1885 static NTSTATUS samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1886                                    struct samr_GetUserPwInfo *r)
1887 {
1888         struct dcesrv_handle *h;
1889         struct samr_account_state *a_state;
1890
1891         ZERO_STRUCT(r->out.info);
1892
1893         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
1894
1895         a_state = h->data;
1896
1897         r->out.info.min_password_length = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0, NULL, "minPwdLength", 
1898                                                             "dn=%s", a_state->domain_state->domain_dn);
1899         r->out.info.password_properties = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0, NULL, "pwdProperties", 
1900                                                             "dn=%s", a_state->account_dn);
1901         return NT_STATUS_OK;
1902 }
1903
1904
1905 /* 
1906   samr_RemoveMemberFromForeignDomain 
1907 */
1908 static NTSTATUS samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1909                        struct samr_RemoveMemberFromForeignDomain *r)
1910 {
1911         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1912 }
1913
1914
1915 /* 
1916   samr_QueryDomainInfo2 
1917 */
1918 static NTSTATUS samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1919                        struct samr_QueryDomainInfo2 *r)
1920 {
1921         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1922 }
1923
1924
1925 /* 
1926   samr_QueryUserInfo2 
1927
1928   just an alias for samr_QueryUserInfo
1929 */
1930 static NTSTATUS samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1931                                     struct samr_QueryUserInfo2 *r)
1932 {
1933         struct samr_QueryUserInfo r1;
1934         NTSTATUS status;
1935
1936         r1.in.user_handle = r->in.user_handle;
1937         r1.in.level  = r->in.level;
1938         
1939         status = samr_QueryUserInfo(dce_call, mem_ctx, &r1);
1940         
1941         r->out.info = r1.out.info;
1942
1943         return status;
1944 }
1945
1946
1947 /* 
1948   samr_QueryDisplayInfo2 
1949 */
1950 static NTSTATUS samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1951                        struct samr_QueryDisplayInfo2 *r)
1952 {
1953         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1954 }
1955
1956
1957 /* 
1958   samr_GetDisplayEnumerationIndex2 
1959 */
1960 static NTSTATUS samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1961                        struct samr_GetDisplayEnumerationIndex2 *r)
1962 {
1963         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1964 }
1965
1966
1967 /* 
1968   samr_QueryDisplayInfo3 
1969 */
1970 static NTSTATUS samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1971                        struct samr_QueryDisplayInfo3 *r)
1972 {
1973         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1974 }
1975
1976
1977 /* 
1978   samr_AddMultipleMembersToAlias 
1979 */
1980 static NTSTATUS samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1981                        struct samr_AddMultipleMembersToAlias *r)
1982 {
1983         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1984 }
1985
1986
1987 /* 
1988   samr_RemoveMultipleMembersFromAlias 
1989 */
1990 static NTSTATUS samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1991                        struct samr_RemoveMultipleMembersFromAlias *r)
1992 {
1993         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1994 }
1995
1996
1997 /* 
1998   samr_GetDomPwInfo 
1999
2000   this fetches the default password properties for a domain
2001
2002   note that w2k3 completely ignores the domain name in this call, and 
2003   always returns the information for the servers primary domain
2004 */
2005 static NTSTATUS samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2006                                   struct samr_GetDomPwInfo *r)
2007 {
2008         struct ldb_message **msgs;
2009         int ret;
2010         const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
2011         void *sam_ctx;
2012
2013         ZERO_STRUCT(r->out.info);
2014
2015         sam_ctx = samdb_connect(mem_ctx);
2016         if (sam_ctx == NULL) {
2017                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
2018         }
2019
2020         ret = samdb_search(sam_ctx, 
2021                            mem_ctx, NULL, &msgs, attrs, 
2022                            "(&(name=%s)(objectclass=domain))",
2023                            lp_workgroup());
2024         if (ret <= 0) {
2025                 return NT_STATUS_NO_SUCH_DOMAIN;
2026         }
2027         if (ret > 1) {
2028                 samdb_search_free(sam_ctx, mem_ctx, msgs);
2029                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2030         }
2031
2032         r->out.info.min_password_length = samdb_result_uint(msgs[0], "minPwdLength", 0);
2033         r->out.info.password_properties = samdb_result_uint(msgs[0], "pwdProperties", 1);
2034
2035         samdb_search_free(sam_ctx, mem_ctx, msgs);
2036
2037         talloc_free(sam_ctx);
2038         return NT_STATUS_OK;
2039 }
2040
2041
2042 /* 
2043   samr_Connect2 
2044 */
2045 static NTSTATUS samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2046                               struct samr_Connect2 *r)
2047 {
2048         struct samr_Connect c;
2049
2050         c.in.system_name = NULL;
2051         c.in.access_mask = r->in.access_mask;
2052         c.out.connect_handle = r->out.connect_handle;
2053
2054         return samr_Connect(dce_call, mem_ctx, &c);
2055 }
2056
2057
2058 /* 
2059   samr_SetUserInfo2 
2060
2061   just an alias for samr_SetUserInfo
2062 */
2063 static NTSTATUS samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2064                                   struct samr_SetUserInfo2 *r)
2065 {
2066         struct samr_SetUserInfo r2;
2067
2068         r2.in.user_handle = r->in.user_handle;
2069         r2.in.level = r->in.level;
2070         r2.in.info = r->in.info;
2071
2072         return samr_SetUserInfo(dce_call, mem_ctx, &r2);
2073 }
2074
2075
2076 /* 
2077   samr_SetBootKeyInformation 
2078 */
2079 static NTSTATUS samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2080                        struct samr_SetBootKeyInformation *r)
2081 {
2082         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2083 }
2084
2085
2086 /* 
2087   samr_GetBootKeyInformation 
2088 */
2089 static NTSTATUS samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2090                        struct samr_GetBootKeyInformation *r)
2091 {
2092         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2093 }
2094
2095
2096 /* 
2097   samr_Connect3 
2098 */
2099 static NTSTATUS samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2100                        struct samr_Connect3 *r)
2101 {
2102         struct samr_Connect c;
2103
2104         c.in.system_name = NULL;
2105         c.in.access_mask = r->in.access_mask;
2106         c.out.connect_handle = r->out.connect_handle;
2107
2108         return samr_Connect(dce_call, mem_ctx, &c);
2109 }
2110
2111
2112 /* 
2113   samr_Connect4 
2114 */
2115 static NTSTATUS samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2116                        struct samr_Connect4 *r)
2117 {
2118         struct samr_Connect c;
2119
2120         c.in.system_name = NULL;
2121         c.in.access_mask = r->in.access_mask;
2122         c.out.connect_handle = r->out.connect_handle;
2123
2124         return samr_Connect(dce_call, mem_ctx, &c);
2125 }
2126
2127
2128 /* 
2129   samr_Connect5 
2130 */
2131 static NTSTATUS samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2132                               struct samr_Connect5 *r)
2133 {
2134         struct samr_Connect c;
2135         NTSTATUS status;
2136
2137         c.in.system_name = NULL;
2138         c.in.access_mask = r->in.access_mask;
2139         c.out.connect_handle = r->out.connect_handle;
2140
2141         status = samr_Connect(dce_call, mem_ctx, &c);
2142
2143         r->out.info->info1.unknown1 = 3;
2144         r->out.info->info1.unknown2 = 0;
2145         r->out.level = r->in.level;
2146
2147         return status;
2148 }
2149
2150
2151 /* 
2152   samr_RidToSid 
2153 */
2154 static NTSTATUS samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2155                        struct samr_RidToSid *r)
2156 {
2157         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2158 }
2159
2160
2161 /* 
2162   samr_SetDsrmPassword 
2163 */
2164 static NTSTATUS samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2165                        struct samr_SetDsrmPassword *r)
2166 {
2167         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2168 }
2169
2170
2171 /* 
2172   samr_ValidatePassword 
2173 */
2174 static NTSTATUS samr_ValidatePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2175                                       struct samr_ValidatePassword *r)
2176 {
2177         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2178 }
2179
2180
2181 /* include the generated boilerplate */
2182 #include "librpc/gen_ndr/ndr_samr_s.c"