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