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