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