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