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