r4344: Unify memory handling in dcerpc_samr.c a bit
[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                 return NT_STATUS_NO_MEMORY;
514         }
515
516         /* create the policy handle */
517         g_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_GROUP);
518         if (!g_handle) {
519                 return NT_STATUS_NO_MEMORY;
520         }
521
522         g_handle->data = a_state;
523         g_handle->destroy = samr_handle_destroy;
524
525         *r->out.group_handle = g_handle->wire_handle;
526         *r->out.rid = rid;      
527
528         return NT_STATUS_OK;
529 }
530
531
532 /* 
533   samr_EnumDomainGroups 
534 */
535 static NTSTATUS samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
536                                       struct samr_EnumDomainGroups *r)
537 {
538         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
539 }
540
541
542 /* 
543   samr_CreateUser2 
544
545   TODO: This should do some form of locking, especially around the rid allocation
546 */
547 static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
548                                  struct samr_CreateUser2 *r)
549 {
550         struct samr_domain_state *d_state;
551         struct samr_account_state *a_state;
552         struct dcesrv_handle *h;
553         const char *name;
554         struct ldb_message msg;
555         uint32_t rid;
556         const char *account_name, *sidstr, *guidstr;
557         struct GUID guid;
558         time_t now = time(NULL);
559         struct dcesrv_handle *u_handle;
560         int ret;
561         NTSTATUS status;
562         const char *container, *additional_class=NULL;
563
564         ZERO_STRUCTP(r->out.user_handle);
565         *r->out.access_granted = 0;
566         *r->out.rid = 0;
567
568         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
569
570         d_state = h->data;
571
572         account_name = r->in.account_name->string;
573
574         if (account_name == NULL) {
575                 return NT_STATUS_INVALID_PARAMETER;
576         }
577
578         /* check if the user already exists */
579         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL, 
580                                    "sAMAccountName", 
581                                    "(&(sAMAccountName=%s)(objectclass=user))", account_name);
582         if (name != NULL) {
583                 return NT_STATUS_USER_EXISTS;
584         }
585
586         ZERO_STRUCT(msg);
587
588         /* This must be one of these values *only* */
589         if (r->in.acct_flags == ACB_NORMAL) {
590                 /* pull in all the template attributes */
591                 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg, 
592                                           "(&(name=TemplateUser)(objectclass=userTemplate))");
593                 if (ret != 0) {
594                         DEBUG(0,("Failed to load TemplateUser from samdb\n"));
595                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
596                 }
597
598                 container = "Users";
599
600         } else if (r->in.acct_flags == ACB_WSTRUST) {
601                 /* pull in all the template attributes */
602                 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg, 
603                                           "(&(name=TemplateMemberServer)(objectclass=userTemplate))");
604                 if (ret != 0) {
605                         DEBUG(0,("Failed to load TemplateMemberServer from samdb\n"));
606                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
607                 }
608
609                 container = "Computers";
610                 additional_class = "computer";
611
612         } else if (r->in.acct_flags == ACB_SVRTRUST) {
613                 /* pull in all the template attributes */
614                 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg, 
615                                           "(&(name=TemplateDomainController)(objectclass=userTemplate))");
616                 if (ret != 0) {
617                         DEBUG(0,("Failed to load TemplateDomainController from samdb\n"));
618                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
619                 }
620
621                 container = "Domain Controllers";
622                 additional_class = "computer";
623
624         } else if (r->in.acct_flags == ACB_DOMTRUST) {
625                 /* pull in all the template attributes */
626                 ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg, 
627                                           "(&(name=TemplateTrustingDomain)(objectclass=userTemplate))");
628                 if (ret != 0) {
629                         DEBUG(0,("Failed to load TemplateTrustingDomain from samdb\n"));
630                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
631                 }
632
633                 container = "Users";
634                 additional_class = "computer";
635
636         } else {
637                 return NT_STATUS_INVALID_PARAMETER;
638         }
639
640         /* allocate a rid */
641         status = samdb_allocate_next_id(d_state->sam_ctx, mem_ctx, 
642                                         d_state->domain_dn, "nextRid", &rid);
643         if (!NT_STATUS_IS_OK(status)) {
644                 return status;
645         }
646
647         /* and the users SID */
648         sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, rid);
649         if (!sidstr) {
650                 return NT_STATUS_NO_MEMORY;
651         }
652
653         /* a new GUID */
654         guid = GUID_random();
655         guidstr = GUID_string(mem_ctx, &guid);
656         if (!guidstr) {
657                 return NT_STATUS_NO_MEMORY;
658         }
659
660         /* add core elements to the ldb_message for the user */
661         msg.dn = talloc_asprintf(mem_ctx, "CN=%s,CN=%s,%s", account_name, container, d_state->domain_dn);
662         if (!msg.dn) {
663                 return NT_STATUS_NO_MEMORY;             
664         }
665         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "name", account_name);
666         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "cn", account_name);
667         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "sAMAccountName", account_name);
668         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectClass", "user");
669         if (additional_class) {
670                 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectClass", additional_class);
671         }
672         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectSid", sidstr);
673         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectGUID", guidstr);
674         samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenCreated", now);
675         samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenChanged", now);
676
677         /* create the user */
678         ret = samdb_add(d_state->sam_ctx, mem_ctx, &msg);
679         if (ret != 0) {
680                 DEBUG(0,("Failed to create user record %s\n", msg.dn));
681                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
682         }
683
684         a_state = talloc_p(d_state, struct samr_account_state);
685         if (!a_state) {
686                 return NT_STATUS_NO_MEMORY;
687         }
688         a_state->sam_ctx = d_state->sam_ctx;
689         a_state->access_mask = r->in.access_mask;
690         a_state->domain_state = talloc_reference(a_state, d_state);
691         a_state->account_dn = talloc_steal(a_state, msg.dn);
692         a_state->account_sid = talloc_steal(a_state, sidstr);
693         a_state->account_name = talloc_strdup(a_state, account_name);
694         if (!a_state->account_name) {
695                 return NT_STATUS_NO_MEMORY;
696         }
697
698         /* create the policy handle */
699         u_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_USER);
700         if (!u_handle) {
701                 return NT_STATUS_NO_MEMORY;
702         }
703
704         u_handle->data = a_state;
705         u_handle->destroy = samr_handle_destroy;
706
707         /* the domain state is in use one more time */
708         
709
710         *r->out.user_handle = u_handle->wire_handle;
711         *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
712         *r->out.rid = rid;      
713
714         return NT_STATUS_OK;
715 }
716
717
718 /* 
719   samr_CreateUser 
720 */
721 static NTSTATUS samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
722                                 struct samr_CreateUser *r)
723 {
724         struct samr_CreateUser2 r2;
725         uint32_t access_granted = 0;
726
727
728         /* a simple wrapper around samr_CreateUser2 works nicely */
729         r2.in.domain_handle = r->in.domain_handle;
730         r2.in.account_name = r->in.account_name;
731         r2.in.acct_flags = ACB_NORMAL;
732         r2.in.access_mask = r->in.access_mask;
733         r2.out.user_handle = r->out.user_handle;
734         r2.out.access_granted = &access_granted;
735         r2.out.rid = r->out.rid;
736
737         return samr_CreateUser2(dce_call, mem_ctx, &r2);
738 }
739
740 /*
741   comparison function for sorting SamEntry array
742 */
743 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
744 {
745         return e1->idx - e2->idx;
746 }
747
748 /* 
749   samr_EnumDomainUsers 
750 */
751 static NTSTATUS samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
752                                      struct samr_EnumDomainUsers *r)
753 {
754         struct dcesrv_handle *h;
755         struct samr_domain_state *d_state;
756         struct ldb_message **res;
757         int count, i, first;
758         struct samr_SamEntry *entries;
759         const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
760
761         *r->out.resume_handle = 0;
762         r->out.sam = NULL;
763         r->out.num_entries = 0;
764
765         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
766
767         d_state = h->data;
768         
769         /* search for all users in this domain. This could possibly be cached and 
770            resumed based on resume_key */
771         count = samdb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs, 
772                              "objectclass=user");
773         if (count == -1) {
774                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
775         }
776         if (count == 0 || r->in.max_size == 0) {
777                 return NT_STATUS_OK;
778         }
779
780         /* convert to SamEntry format */
781         entries = talloc_array_p(mem_ctx, struct samr_SamEntry, count);
782         if (!entries) {
783                 return NT_STATUS_NO_MEMORY;
784         }
785         for (i=0;i<count;i++) {
786                 entries[i].idx = samdb_result_rid_from_sid(mem_ctx, res[i], "objectSid", 0);
787                 entries[i].name.string = samdb_result_string(res[i], "sAMAccountName", "");
788         }
789
790         /* sort the results by rid */
791         qsort(entries, count, sizeof(struct samr_SamEntry), 
792               (comparison_fn_t)compare_SamEntry);
793
794         /* find the first entry to return */
795         for (first=0;
796              first<count && entries[first].idx <= *r->in.resume_handle;
797              first++) ;
798
799         if (first == count) {
800                 return NT_STATUS_OK;
801         }
802
803         /* return the rest, limit by max_size. Note that we 
804            use the w2k3 element size value of 54 */
805         r->out.num_entries = count - first;
806         r->out.num_entries = MIN(r->out.num_entries, 
807                                  1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
808
809         r->out.sam = talloc_p(mem_ctx, struct samr_SamArray);
810         if (!r->out.sam) {
811                 return NT_STATUS_NO_MEMORY;
812         }
813
814         r->out.sam->entries = entries+first;
815         r->out.sam->count = r->out.num_entries;
816
817         if (r->out.num_entries < count - first) {
818                 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
819                 return STATUS_MORE_ENTRIES;
820         }
821
822         return NT_STATUS_OK;
823 }
824
825
826 /* 
827   samr_CreateDomAlias 
828 */
829 static NTSTATUS samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
830                        struct samr_CreateDomAlias *r)
831 {
832         struct samr_domain_state *d_state;
833         struct samr_account_state *a_state;
834         struct dcesrv_handle *h;
835         const char *aliasname, *name, *sidstr, *guidstr;
836         struct GUID guid;
837         time_t now = time(NULL);
838         struct ldb_message msg;
839         uint32_t rid;
840         struct dcesrv_handle *a_handle;
841         int ret;
842         NTSTATUS status;
843
844         ZERO_STRUCTP(r->out.alias_handle);
845         *r->out.rid = 0;
846
847         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
848
849         d_state = h->data;
850
851         aliasname = r->in.aliasname->string;
852
853         if (aliasname == NULL) {
854                 return NT_STATUS_INVALID_PARAMETER;
855         }
856
857         /* Check if alias already exists */
858         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
859                                    "sAMAccountName",
860                                    "(&(sAMAccountName=%s)(objectclass=group))",
861                                    aliasname);
862
863         if (name != NULL) {
864                 return NT_STATUS_ALIAS_EXISTS;
865         }
866
867         ZERO_STRUCT(msg);
868
869         /* pull in all the template attributes */
870         ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg, 
871                                   "(&(name=TemplateAlias)"
872                                   "(objectclass=aliasTemplate))");
873         if (ret != 0) {
874                 DEBUG(0,("Failed to load TemplateAlias from samdb\n"));
875                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
876         }
877
878         /* allocate a rid */
879         status = samdb_allocate_next_id(d_state->sam_ctx, mem_ctx, 
880                                         d_state->domain_dn, "nextRid", &rid);
881         if (!NT_STATUS_IS_OK(status)) {
882                 return status;
883         }
884
885         /* and the group SID */
886         sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, rid);
887         if (!sidstr) {
888                 return NT_STATUS_NO_MEMORY;
889         }
890
891         /* a new GUID */
892         guid = GUID_random();
893         guidstr = GUID_string(mem_ctx, &guid);
894         if (!guidstr) {
895                 return NT_STATUS_NO_MEMORY;
896         }
897
898         /* add core elements to the ldb_message for the user */
899         msg.dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Users,%s", aliasname,
900                                  d_state->domain_dn);
901         if (!msg.dn) {
902                 return NT_STATUS_NO_MEMORY;
903         }
904
905         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "name", aliasname);
906         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "cn", aliasname);
907         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "sAMAccountName", aliasname);
908         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectClass", "group");
909         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectSid", sidstr);
910         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectGUID", guidstr);
911         samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenCreated", now);
912         samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenChanged", now);
913
914         /* create the alias */
915         ret = samdb_add(d_state->sam_ctx, mem_ctx, &msg);
916         if (ret != 0) {
917                 DEBUG(0,("Failed to create alias record %s\n", msg.dn));
918                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
919         }
920
921         a_state = talloc_p(d_state, struct samr_account_state);
922         if (!a_state) {
923                 return NT_STATUS_NO_MEMORY;
924         }
925
926         a_state->sam_ctx = d_state->sam_ctx;
927         a_state->access_mask = r->in.access_mask;
928         a_state->domain_state = talloc_reference(a_state, d_state);
929         a_state->account_dn = talloc_steal(a_state, msg.dn);
930         a_state->account_sid = talloc_steal(a_state, sidstr);
931         a_state->account_name = talloc_strdup(a_state, aliasname);
932         if (!a_state->account_name) {
933                 return NT_STATUS_NO_MEMORY;
934         }
935
936         /* create the policy handle */
937         a_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_ALIAS);
938         if (a_handle == NULL)
939                 return NT_STATUS_NO_MEMORY;
940
941         a_handle->data = a_state;
942         a_handle->destroy = samr_handle_destroy;
943
944         *r->out.alias_handle = a_handle->wire_handle;
945         *r->out.rid = rid;
946
947         return NT_STATUS_OK;
948 }
949
950
951 /* 
952   samr_EnumDomainAliases 
953 */
954 static NTSTATUS samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
955                        struct samr_EnumDomainAliases *r)
956 {
957         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
958 }
959
960
961 /* 
962   samr_GetAliasMembership 
963 */
964 static NTSTATUS samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
965                        struct samr_GetAliasMembership *r)
966 {
967         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
968 }
969
970
971 /* 
972   samr_LookupNames 
973 */
974 static NTSTATUS samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
975                                  struct samr_LookupNames *r)
976 {
977         struct dcesrv_handle *h;
978         struct samr_domain_state *d_state;
979         int i;
980         NTSTATUS status = NT_STATUS_OK;
981         const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
982         int count;
983
984         ZERO_STRUCT(r->out.rids);
985         ZERO_STRUCT(r->out.types);
986
987         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
988
989         d_state = h->data;
990
991         if (r->in.num_names == 0) {
992                 return NT_STATUS_OK;
993         }
994
995         r->out.rids.ids = talloc_array_p(mem_ctx, uint32_t, r->in.num_names);
996         r->out.types.ids = talloc_array_p(mem_ctx, uint32_t, r->in.num_names);
997         if (!r->out.rids.ids || !r->out.types.ids) {
998                 return NT_STATUS_NO_MEMORY;
999         }
1000         r->out.rids.count = r->in.num_names;
1001         r->out.types.count = r->in.num_names;
1002
1003         for (i=0;i<r->in.num_names;i++) {
1004                 struct ldb_message **res;
1005                 struct dom_sid2 *sid;
1006                 const char *sidstr;
1007                 uint32_t atype, rtype;
1008
1009                 r->out.rids.ids[i] = 0;
1010                 r->out.types.ids[i] = SID_NAME_UNKNOWN;
1011
1012                 count = samdb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs, 
1013                                      "sAMAccountName=%s", r->in.names[i].string);
1014                 if (count != 1) {
1015                         status = STATUS_SOME_UNMAPPED;
1016                         continue;
1017                 }
1018
1019                 sidstr = samdb_result_string(res[0], "objectSid", NULL);
1020                 if (sidstr == NULL) {
1021                         status = STATUS_SOME_UNMAPPED;
1022                         continue;
1023                 }
1024                 
1025                 sid = dom_sid_parse_talloc(mem_ctx, sidstr);
1026                 if (sid == NULL) {
1027                         status = STATUS_SOME_UNMAPPED;
1028                         continue;
1029                 }
1030
1031                 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1032                 if (atype == 0) {
1033                         status = STATUS_SOME_UNMAPPED;
1034                         continue;
1035                 }
1036
1037                 rtype = samdb_atype_map(atype);
1038                 
1039                 if (rtype == SID_NAME_UNKNOWN) {
1040                         status = STATUS_SOME_UNMAPPED;
1041                         continue;
1042                 }
1043
1044                 r->out.rids.ids[i] = sid->sub_auths[sid->num_auths-1];
1045                 r->out.types.ids[i] = rtype;
1046         }
1047         
1048
1049         return status;
1050 }
1051
1052
1053 /* 
1054   samr_LookupRids 
1055 */
1056 static NTSTATUS samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1057                        struct samr_LookupRids *r)
1058 {
1059         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1060 }
1061
1062
1063 /* 
1064   samr_OpenGroup 
1065 */
1066 static NTSTATUS samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1067                        struct samr_OpenGroup *r)
1068 {
1069         struct samr_domain_state *d_state;
1070         struct samr_account_state *a_state;
1071         struct dcesrv_handle *h;
1072         const char *groupname, *sidstr;
1073         struct ldb_message **msgs;
1074         struct dcesrv_handle *g_handle;
1075         const char * const attrs[2] = { "sAMAccountName", NULL };
1076         int ret;
1077
1078         ZERO_STRUCTP(r->out.group_handle);
1079
1080         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1081
1082         d_state = h->data;
1083
1084         /* form the group SID */
1085         sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, r->in.rid);
1086         if (!sidstr) {
1087                 return NT_STATUS_NO_MEMORY;
1088         }
1089
1090         /* search for the group record */
1091         ret = samdb_search(d_state->sam_ctx,
1092                            mem_ctx, d_state->domain_dn, &msgs, attrs,
1093                            "(&(objectSid=%s)(objectclass=group))", 
1094                            sidstr);
1095         if (ret == 0) {
1096                 return NT_STATUS_NO_SUCH_GROUP;
1097         }
1098         if (ret != 1) {
1099                 DEBUG(0,("Found %d records matching sid %s\n", ret, sidstr));
1100                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1101         }
1102
1103         groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
1104         if (groupname == NULL) {
1105                 DEBUG(0,("sAMAccountName field missing for sid %s\n", sidstr));
1106                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1107         }
1108
1109         a_state = talloc_p(d_state, struct samr_account_state);
1110         if (!a_state) {
1111                 return NT_STATUS_NO_MEMORY;
1112         }
1113         a_state->sam_ctx = d_state->sam_ctx;
1114         a_state->access_mask = r->in.access_mask;
1115         a_state->domain_state = talloc_reference(a_state, d_state);
1116         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1117         a_state->account_sid = talloc_steal(a_state, sidstr);
1118         a_state->account_name = talloc_strdup(a_state, groupname);
1119         if (!a_state->account_name) {
1120                 return NT_STATUS_NO_MEMORY;
1121         }
1122
1123         /* create the policy handle */
1124         g_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_GROUP);
1125         if (!g_handle) {
1126                 return NT_STATUS_NO_MEMORY;
1127         }
1128
1129         g_handle->data = a_state;
1130         g_handle->destroy = samr_handle_destroy;
1131
1132         *r->out.group_handle = g_handle->wire_handle;
1133
1134         return NT_STATUS_OK;
1135 }
1136
1137 /* these query macros make samr_Query[User|Group]Info a bit easier to read */
1138
1139 #define QUERY_STRING(msg, field, attr) \
1140         r->out.info->field = samdb_result_string(msg, attr, "");
1141 #define QUERY_UINT(msg, field, attr) \
1142         r->out.info->field = samdb_result_uint(msg, attr, 0);
1143 #define QUERY_RID(msg, field, attr) \
1144         r->out.info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
1145 #define QUERY_NTTIME(msg, field, attr) \
1146         r->out.info->field = samdb_result_nttime(msg, attr, 0);
1147 #define QUERY_APASSC(msg, field, attr) \
1148         r->out.info->field = samdb_result_allow_password_change(a_state->sam_ctx, mem_ctx, \
1149                                                            a_state->domain_state->domain_dn, msg, attr);
1150 #define QUERY_FPASSC(msg, field, attr) \
1151         r->out.info->field = samdb_result_force_password_change(a_state->sam_ctx, mem_ctx, \
1152                                                            a_state->domain_state->domain_dn, msg, attr);
1153 #define QUERY_LHOURS(msg, field, attr) \
1154         r->out.info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
1155 #define QUERY_AFLAGS(msg, field, attr) \
1156         r->out.info->field = samdb_result_acct_flags(msg, attr);
1157
1158
1159 /* these are used to make the Set[User|Group]Info code easier to follow */
1160
1161 #define SET_STRING(mod, field, attr) do { \
1162         if (r->in.info->field == NULL) return NT_STATUS_INVALID_PARAMETER; \
1163         if (samdb_msg_add_string(a_state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
1164                 return NT_STATUS_NO_MEMORY; \
1165         } \
1166 } while (0)
1167
1168 #define SET_UINT(mod, field, attr) do { \
1169         if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
1170                 return NT_STATUS_NO_MEMORY; \
1171         } \
1172 } while (0)
1173
1174 #define SET_AFLAGS(msg, field, attr) do { \
1175         if (samdb_msg_add_acct_flags(a_state->sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
1176                 return NT_STATUS_NO_MEMORY; \
1177         } \
1178 } while (0)
1179
1180 #define SET_LHOURS(msg, field, attr) do { \
1181         if (samdb_msg_add_logon_hours(a_state->sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
1182                 return NT_STATUS_NO_MEMORY; \
1183         } \
1184 } while (0)
1185
1186 /* 
1187   samr_QueryGroupInfo 
1188 */
1189 static NTSTATUS samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1190                        struct samr_QueryGroupInfo *r)
1191 {
1192         struct dcesrv_handle *h;
1193         struct samr_account_state *a_state;
1194         struct ldb_message *msg, **res;
1195         const char * const attrs[4] = { "sAMAccountName", "description",
1196                                         "numMembers", NULL };
1197         int ret;
1198
1199         r->out.info = NULL;
1200
1201         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1202
1203         a_state = h->data;
1204
1205         /* pull all the group attributes */
1206         ret = samdb_search(a_state->sam_ctx, mem_ctx, NULL, &res, attrs,
1207                            "dn=%s", a_state->account_dn);
1208         if (ret != 1) {
1209                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1210         }
1211         msg = res[0];
1212
1213         /* allocate the info structure */
1214         r->out.info = talloc_p(mem_ctx, union samr_GroupInfo);
1215         if (r->out.info == NULL) {
1216                 return NT_STATUS_NO_MEMORY;
1217         }
1218         ZERO_STRUCTP(r->out.info);
1219
1220         /* Fill in the level */
1221         switch (r->in.level) {
1222         case GroupInfoAll:
1223                 QUERY_STRING(msg, all.name.string,        "sAMAccountName");
1224                 r->out.info->all.attributes = 7; /* Do like w2k3 */
1225                 QUERY_UINT  (msg, all.num_members,      "numMembers")
1226                 QUERY_STRING(msg, all.description.string, "description");
1227                 break;
1228         case GroupInfoName:
1229                 QUERY_STRING(msg, name.string,            "sAMAccountName");
1230                 break;
1231         case GroupInfoX:
1232                 r->out.info->unknown.unknown = 7;
1233                 break;
1234         case GroupInfoDescription:
1235                 QUERY_STRING(msg, description.string, "description");
1236                 break;
1237         default:
1238                 r->out.info = NULL;
1239                 return NT_STATUS_INVALID_INFO_CLASS;
1240         }
1241         
1242         return NT_STATUS_OK;
1243 }
1244
1245
1246 /* 
1247   samr_SetGroupInfo 
1248 */
1249 static NTSTATUS samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1250                        struct samr_SetGroupInfo *r)
1251 {
1252         struct dcesrv_handle *h;
1253         struct samr_account_state *a_state;
1254         struct ldb_message mod, *msg = &mod;
1255         int ret;
1256
1257         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1258
1259         a_state = h->data;
1260
1261         ZERO_STRUCT(mod);
1262         mod.dn = talloc_strdup(mem_ctx, a_state->account_dn);
1263         if (!mod.dn) {
1264                 return NT_STATUS_NO_MEMORY;
1265         }
1266
1267         switch (r->in.level) {
1268         case GroupInfoDescription:
1269                 SET_STRING(msg, description.string,         "description");
1270                 break;
1271         case GroupInfoName:
1272                 /* On W2k3 this does not change the name, it changes the
1273                  * sAMAccountName attribute */
1274                 SET_STRING(msg, name.string,                "sAMAccountName");
1275                 break;
1276         case GroupInfoX:
1277                 /* This does not do anything obviously visible in W2k3 LDAP */
1278                 break;
1279         default:
1280                 return NT_STATUS_INVALID_INFO_CLASS;
1281         }
1282
1283         /* modify the samdb record */
1284         ret = samdb_replace(a_state->sam_ctx, mem_ctx, &mod);
1285         if (ret != 0) {
1286                 /* we really need samdb.c to return NTSTATUS */
1287                 return NT_STATUS_UNSUCCESSFUL;
1288         }
1289
1290         return NT_STATUS_OK;
1291 }
1292
1293
1294 /* 
1295   samr_AddGroupMember 
1296 */
1297 static NTSTATUS samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1298                        struct samr_AddGroupMember *r)
1299 {
1300         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1301 }
1302
1303
1304 /* 
1305   samr_DeleteDomainGroup 
1306 */
1307 static NTSTATUS samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1308                        struct samr_DeleteDomainGroup *r)
1309 {
1310         struct dcesrv_handle *h;
1311         struct samr_account_state *a_state;
1312         int ret;
1313
1314         *r->out.group_handle = *r->in.group_handle;
1315
1316         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1317
1318         a_state = h->data;
1319
1320         ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
1321         if (ret != 0) {
1322                 return NT_STATUS_UNSUCCESSFUL;
1323         }
1324
1325         ZERO_STRUCTP(r->out.group_handle);
1326
1327         return NT_STATUS_OK;
1328 }
1329
1330
1331 /* 
1332   samr_DeleteGroupMember 
1333 */
1334 static NTSTATUS samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1335                        struct samr_DeleteGroupMember *r)
1336 {
1337         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1338 }
1339
1340
1341 /* 
1342   samr_QueryGroupMember 
1343 */
1344 static NTSTATUS samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1345                        struct samr_QueryGroupMember *r)
1346 {
1347         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1348 }
1349
1350
1351 /* 
1352   samr_SetMemberAttributesOfGroup 
1353 */
1354 static NTSTATUS samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1355                        struct samr_SetMemberAttributesOfGroup *r)
1356 {
1357         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1358 }
1359
1360
1361 /* 
1362   samr_OpenAlias 
1363 */
1364 static NTSTATUS samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1365                        struct samr_OpenAlias *r)
1366 {
1367         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1368 }
1369
1370
1371 /* 
1372   samr_QueryAliasInfo 
1373 */
1374 static NTSTATUS samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1375                        struct samr_QueryAliasInfo *r)
1376 {
1377         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1378 }
1379
1380
1381 /* 
1382   samr_SetAliasInfo 
1383 */
1384 static NTSTATUS samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1385                        struct samr_SetAliasInfo *r)
1386 {
1387         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1388 }
1389
1390
1391 /* 
1392   samr_DeleteDomAlias 
1393 */
1394 static NTSTATUS samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1395                        struct samr_DeleteDomAlias *r)
1396 {
1397         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1398 }
1399
1400
1401 /* 
1402   samr_AddAliasMember 
1403 */
1404 static NTSTATUS samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1405                        struct samr_AddAliasMember *r)
1406 {
1407         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1408 }
1409
1410
1411 /* 
1412   samr_DeleteAliasMember 
1413 */
1414 static NTSTATUS samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1415                        struct samr_DeleteAliasMember *r)
1416 {
1417         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1418 }
1419
1420
1421 /* 
1422   samr_GetMembersInAlias 
1423 */
1424 static NTSTATUS samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1425                        struct samr_GetMembersInAlias *r)
1426 {
1427         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1428 }
1429
1430
1431 /* 
1432   samr_OpenUser 
1433 */
1434 static NTSTATUS samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1435                               struct samr_OpenUser *r)
1436 {
1437         struct samr_domain_state *d_state;
1438         struct samr_account_state *a_state;
1439         struct dcesrv_handle *h;
1440         const char *account_name, *sidstr;
1441         struct ldb_message **msgs;
1442         struct dcesrv_handle *u_handle;
1443         const char * const attrs[2] = { "sAMAccountName", NULL };
1444         int ret;
1445
1446         ZERO_STRUCTP(r->out.user_handle);
1447
1448         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1449
1450         d_state = h->data;
1451
1452         /* form the users SID */
1453         sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, r->in.rid);
1454         if (!sidstr) {
1455                 return NT_STATUS_NO_MEMORY;
1456         }
1457
1458         /* search for the user record */
1459         ret = samdb_search(d_state->sam_ctx,
1460                            mem_ctx, d_state->domain_dn, &msgs, attrs,
1461                            "(&(objectSid=%s)(objectclass=user))", 
1462                            sidstr);
1463         if (ret == 0) {
1464                 return NT_STATUS_NO_SUCH_USER;
1465         }
1466         if (ret != 1) {
1467                 DEBUG(0,("Found %d records matching sid %s\n", ret, sidstr));
1468                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1469         }
1470
1471         account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
1472         if (account_name == NULL) {
1473                 DEBUG(0,("sAMAccountName field missing for sid %s\n", sidstr));
1474                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1475         }
1476
1477         a_state = talloc_p(d_state, struct samr_account_state);
1478         if (!a_state) {
1479                 return NT_STATUS_NO_MEMORY;
1480         }
1481         a_state->sam_ctx = d_state->sam_ctx;
1482         a_state->access_mask = r->in.access_mask;
1483         a_state->domain_state = talloc_reference(a_state, d_state);
1484         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1485         a_state->account_sid = talloc_steal(a_state, sidstr);
1486         a_state->account_name = talloc_strdup(a_state, account_name);
1487         if (!a_state->account_name) {
1488                 return NT_STATUS_NO_MEMORY;
1489         }
1490
1491         /* create the policy handle */
1492         u_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_USER);
1493         if (!u_handle) {
1494                 return NT_STATUS_NO_MEMORY;
1495         }
1496
1497         u_handle->data = a_state;
1498         u_handle->destroy = samr_handle_destroy;
1499
1500         *r->out.user_handle = u_handle->wire_handle;
1501
1502         return NT_STATUS_OK;
1503
1504 }
1505
1506
1507 /* 
1508   samr_DeleteUser 
1509 */
1510 static NTSTATUS samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1511                                 struct samr_DeleteUser *r)
1512 {
1513         struct dcesrv_handle *h;
1514         struct samr_account_state *a_state;
1515         int ret;
1516
1517         *r->out.user_handle = *r->in.user_handle;
1518
1519         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
1520
1521         a_state = h->data;
1522
1523         ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
1524         if (ret != 0) {
1525                 return NT_STATUS_UNSUCCESSFUL;
1526         }
1527
1528         ZERO_STRUCTP(r->out.user_handle);
1529
1530         return NT_STATUS_OK;
1531 }
1532
1533
1534 /* 
1535   samr_QueryUserInfo 
1536 */
1537 static NTSTATUS samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1538                                    struct samr_QueryUserInfo *r)
1539 {
1540         struct dcesrv_handle *h;
1541         struct samr_account_state *a_state;
1542         struct ldb_message *msg, **res;
1543         int ret;
1544
1545         r->out.info = NULL;
1546
1547         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
1548
1549         a_state = h->data;
1550
1551         /* pull all the user attributes */
1552         ret = samdb_search(a_state->sam_ctx, mem_ctx, NULL, &res, NULL,
1553                            "dn=%s", a_state->account_dn);
1554         if (ret != 1) {
1555                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1556         }
1557         msg = res[0];
1558
1559         /* allocate the info structure */
1560         r->out.info = talloc_p(mem_ctx, union samr_UserInfo);
1561         if (r->out.info == NULL) {
1562                 return NT_STATUS_NO_MEMORY;
1563         }
1564         ZERO_STRUCTP(r->out.info);
1565
1566         /* fill in the reply */
1567         switch (r->in.level) {
1568         case 1:
1569                 QUERY_STRING(msg, info1.account_name.string,   "sAMAccountName");
1570                 QUERY_STRING(msg, info1.full_name.string,      "displayName");
1571                 QUERY_UINT  (msg, info1.primary_gid,           "primaryGroupID");
1572                 QUERY_STRING(msg, info1.description.string,    "description");
1573                 QUERY_STRING(msg, info1.comment.string,        "comment");
1574                 break;
1575
1576         case 2:
1577                 QUERY_STRING(msg, info2.comment.string,        "comment");
1578                 QUERY_UINT  (msg, info2.country_code,          "countryCode");
1579                 QUERY_UINT  (msg, info2.code_page,             "codePage");
1580                 break;
1581
1582         case 3:
1583                 QUERY_STRING(msg, info3.account_name.string,   "sAMAccountName");
1584                 QUERY_STRING(msg, info3.full_name.string,      "displayName");
1585                 QUERY_RID   (msg, info3.rid,                   "objectSid");
1586                 QUERY_UINT  (msg, info3.primary_gid,           "primaryGroupID");
1587                 QUERY_STRING(msg, info3.home_directory.string, "homeDirectory");
1588                 QUERY_STRING(msg, info3.home_drive.string,     "homeDrive");
1589                 QUERY_STRING(msg, info3.logon_script.string,   "scriptPath");
1590                 QUERY_STRING(msg, info3.profile_path.string,   "profilePath");
1591                 QUERY_STRING(msg, info3.workstations.string,   "userWorkstations");
1592                 QUERY_NTTIME(msg, info3.last_logon,            "lastLogon");
1593                 QUERY_NTTIME(msg, info3.last_logoff,           "lastLogoff");
1594                 QUERY_NTTIME(msg, info3.last_password_change,  "pwdLastSet");
1595                 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
1596                 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
1597                 QUERY_LHOURS(msg, info3.logon_hours,           "logonHours");
1598                 QUERY_UINT  (msg, info3.bad_password_count,    "badPwdCount");
1599                 QUERY_UINT  (msg, info3.logon_count,           "logonCount");
1600                 QUERY_AFLAGS(msg, info3.acct_flags,            "userAccountControl");
1601                 break;
1602
1603         case 4:
1604                 QUERY_LHOURS(msg, info4.logon_hours,           "logonHours");
1605                 break;
1606
1607         case 5:
1608                 QUERY_STRING(msg, info5.account_name.string,   "sAMAccountName");
1609                 QUERY_STRING(msg, info5.full_name.string,      "displayName");
1610                 QUERY_RID   (msg, info5.rid,                   "objectSid");
1611                 QUERY_UINT  (msg, info5.primary_gid,           "primaryGroupID");
1612                 QUERY_STRING(msg, info5.home_directory.string, "homeDirectory");
1613                 QUERY_STRING(msg, info5.home_drive.string,     "homeDrive");
1614                 QUERY_STRING(msg, info5.logon_script.string,   "scriptPath");
1615                 QUERY_STRING(msg, info5.profile_path.string,   "profilePath");
1616                 QUERY_STRING(msg, info5.description.string,    "description");
1617                 QUERY_STRING(msg, info5.workstations.string,   "userWorkstations");
1618                 QUERY_NTTIME(msg, info5.last_logon,            "lastLogon");
1619                 QUERY_NTTIME(msg, info5.last_logoff,           "lastLogoff");
1620                 QUERY_LHOURS(msg, info5.logon_hours,           "logonHours");
1621                 QUERY_UINT  (msg, info5.bad_password_count,    "badPwdCount");
1622                 QUERY_UINT  (msg, info5.logon_count,           "logonCount");
1623                 QUERY_NTTIME(msg, info5.last_password_change,  "pwdLastSet");
1624                 QUERY_NTTIME(msg, info5.acct_expiry,           "accountExpires");
1625                 QUERY_AFLAGS(msg, info5.acct_flags,            "userAccountControl");
1626                 break;
1627
1628         case 6:
1629                 QUERY_STRING(msg, info6.account_name.string,   "sAMAccountName");
1630                 QUERY_STRING(msg, info6.full_name.string,      "displayName");
1631                 break;
1632
1633         case 7:
1634                 QUERY_STRING(msg, info7.account_name.string,   "sAMAccountName");
1635                 break;
1636
1637         case 8:
1638                 QUERY_STRING(msg, info8.full_name.string,      "displayName");
1639                 break;
1640
1641         case 9:
1642                 QUERY_UINT  (msg, info9.primary_gid,           "primaryGroupID");
1643                 break;
1644
1645         case 10:
1646                 QUERY_STRING(msg, info10.home_directory.string,"homeDirectory");
1647                 QUERY_STRING(msg, info10.home_drive.string,    "homeDrive");
1648                 break;
1649
1650         case 11:
1651                 QUERY_STRING(msg, info11.logon_script.string,  "scriptPath");
1652                 break;
1653
1654         case 12:
1655                 QUERY_STRING(msg, info12.profile_path.string,  "profilePath");
1656                 break;
1657
1658         case 13:
1659                 QUERY_STRING(msg, info13.description.string,   "description");
1660                 break;
1661
1662         case 14:
1663                 QUERY_STRING(msg, info14.workstations.string,  "userWorkstations");
1664                 break;
1665
1666         case 16:
1667                 QUERY_AFLAGS(msg, info16.acct_flags,           "userAccountControl");
1668                 break;
1669
1670         case 17:
1671                 QUERY_NTTIME(msg, info17.acct_expiry,          "accountExpires");
1672
1673         case 20:
1674                 QUERY_STRING(msg, info20.parameters.string,    "userParameters");
1675                 break;
1676
1677         case 21:
1678                 QUERY_NTTIME(msg, info21.last_logon,           "lastLogon");
1679                 QUERY_NTTIME(msg, info21.last_logoff,          "lastLogoff");
1680                 QUERY_NTTIME(msg, info21.last_password_change, "pwdLastSet");
1681                 QUERY_NTTIME(msg, info21.acct_expiry,          "accountExpires");
1682                 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
1683                 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
1684                 QUERY_STRING(msg, info21.account_name.string,  "sAMAccountName");
1685                 QUERY_STRING(msg, info21.full_name.string,     "displayName");
1686                 QUERY_STRING(msg, info21.home_directory.string,"homeDirectory");
1687                 QUERY_STRING(msg, info21.home_drive.string,    "homeDrive");
1688                 QUERY_STRING(msg, info21.logon_script.string,  "scriptPath");
1689                 QUERY_STRING(msg, info21.profile_path.string,  "profilePath");
1690                 QUERY_STRING(msg, info21.description.string,   "description");
1691                 QUERY_STRING(msg, info21.workstations.string,  "userWorkstations");
1692                 QUERY_STRING(msg, info21.comment.string,       "comment");
1693                 QUERY_STRING(msg, info21.parameters.string,    "userParameters");
1694                 QUERY_RID   (msg, info21.rid,                  "objectSid");
1695                 QUERY_UINT  (msg, info21.primary_gid,          "primaryGroupID");
1696                 QUERY_AFLAGS(msg, info21.acct_flags,           "userAccountControl");
1697                 r->out.info->info21.fields_present = 0x00FFFFFF;
1698                 QUERY_LHOURS(msg, info21.logon_hours,          "logonHours");
1699                 QUERY_UINT  (msg, info21.bad_password_count,   "badPwdCount");
1700                 QUERY_UINT  (msg, info21.logon_count,          "logonCount");
1701                 QUERY_UINT  (msg, info21.country_code,         "countryCode");
1702                 QUERY_UINT  (msg, info21.code_page,            "codePage");
1703                 break;
1704                 
1705
1706         default:
1707                 r->out.info = NULL;
1708                 return NT_STATUS_INVALID_INFO_CLASS;
1709         }
1710         
1711         return NT_STATUS_OK;
1712 }
1713
1714
1715 /* 
1716   samr_SetUserInfo 
1717 */
1718 static NTSTATUS samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1719                                  struct samr_SetUserInfo *r)
1720 {
1721         struct dcesrv_handle *h;
1722         struct samr_account_state *a_state;
1723         struct ldb_message mod, *msg = &mod;
1724         int ret;
1725         NTSTATUS status = NT_STATUS_OK;
1726
1727         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
1728
1729         a_state = h->data;
1730
1731         ZERO_STRUCT(mod);
1732         mod.dn = talloc_strdup(mem_ctx, a_state->account_dn);
1733         if (!mod.dn) {
1734                 return NT_STATUS_NO_MEMORY;
1735         }
1736
1737         switch (r->in.level) {
1738         case 2:
1739                 SET_STRING(msg, info2.comment.string,          "comment");
1740                 SET_UINT  (msg, info2.country_code,            "countryCode");
1741                 SET_UINT  (msg, info2.code_page,               "codePage");
1742                 break;
1743
1744         case 4:
1745                 SET_LHOURS(msg, info4.logon_hours,             "logonHours");
1746                 break;
1747
1748         case 6:
1749                 SET_STRING(msg, info6.full_name.string,        "displayName");
1750                 break;
1751
1752         case 8:
1753                 SET_STRING(msg, info8.full_name.string,        "displayName");
1754                 break;
1755
1756         case 9:
1757                 SET_UINT(msg, info9.primary_gid,               "primaryGroupID");
1758                 break;
1759
1760         case 10:
1761                 SET_STRING(msg, info10.home_directory.string,  "homeDirectory");
1762                 SET_STRING(msg, info10.home_drive.string,      "homeDrive");
1763                 break;
1764
1765         case 11:
1766                 SET_STRING(msg, info11.logon_script.string,    "scriptPath");
1767                 break;
1768
1769         case 12:
1770                 SET_STRING(msg, info12.profile_path.string,    "profilePath");
1771                 break;
1772
1773         case 13:
1774                 SET_STRING(msg, info13.description.string,     "description");
1775                 break;
1776
1777         case 14:
1778                 SET_STRING(msg, info14.workstations.string,    "userWorkstations");
1779                 break;
1780
1781         case 16:
1782                 SET_AFLAGS(msg, info16.acct_flags,             "userAccountControl");
1783                 break;
1784
1785         case 20:
1786                 SET_STRING(msg, info20.parameters.string,      "userParameters");
1787                 break;
1788
1789         case 21:
1790 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
1791                 IFSET(SAMR_FIELD_NAME)         
1792                         SET_STRING(msg, info21.full_name.string,    "displayName");
1793                 IFSET(SAMR_FIELD_DESCRIPTION)  
1794                         SET_STRING(msg, info21.description.string,  "description");
1795                 IFSET(SAMR_FIELD_COMMENT)      
1796                         SET_STRING(msg, info21.comment.string,      "comment");
1797                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
1798                         SET_STRING(msg, info21.logon_script.string, "scriptPath");
1799                 IFSET(SAMR_FIELD_PROFILE_PATH)      
1800                         SET_STRING(msg, info21.profile_path.string, "profilePath");
1801                 IFSET(SAMR_FIELD_WORKSTATION)  
1802                         SET_STRING(msg, info21.workstations.string, "userWorkstations");
1803                 IFSET(SAMR_FIELD_LOGON_HOURS)  
1804                         SET_LHOURS(msg, info21.logon_hours,         "logonHours");
1805                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
1806                         SET_AFLAGS(msg, info21.acct_flags,          "userAccountControl");
1807                 IFSET(SAMR_FIELD_PARAMETERS)     
1808                         SET_STRING(msg, info21.parameters.string,   "userParameters");
1809                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
1810                         SET_UINT  (msg, info21.country_code,        "countryCode");
1811                 IFSET(SAMR_FIELD_CODE_PAGE)    
1812                         SET_UINT  (msg, info21.code_page,           "codePage");
1813
1814
1815                 /* Any reason the rest of these can't be set? */
1816 #undef IFSET
1817                 break;
1818
1819         case 23:
1820 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
1821                 IFSET(SAMR_FIELD_NAME)         
1822                         SET_STRING(msg, info23.info.full_name.string,    "displayName");
1823                 IFSET(SAMR_FIELD_DESCRIPTION)  
1824                         SET_STRING(msg, info23.info.description.string,  "description");
1825                 IFSET(SAMR_FIELD_COMMENT)      
1826                         SET_STRING(msg, info23.info.comment.string,      "comment");
1827                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
1828                         SET_STRING(msg, info23.info.logon_script.string, "scriptPath");
1829                 IFSET(SAMR_FIELD_PROFILE_PATH)      
1830                         SET_STRING(msg, info23.info.profile_path.string, "profilePath");
1831                 IFSET(SAMR_FIELD_WORKSTATION)  
1832                         SET_STRING(msg, info23.info.workstations.string, "userWorkstations");
1833                 IFSET(SAMR_FIELD_LOGON_HOURS)  
1834                         SET_LHOURS(msg, info23.info.logon_hours,         "logonHours");
1835                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
1836                         SET_AFLAGS(msg, info23.info.acct_flags,          "userAccountControl");
1837                 IFSET(SAMR_FIELD_PARAMETERS)     
1838                         SET_STRING(msg, info23.info.parameters.string,   "userParameters");
1839                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
1840                         SET_UINT  (msg, info23.info.country_code,        "countryCode");
1841                 IFSET(SAMR_FIELD_CODE_PAGE)    
1842                         SET_UINT  (msg, info23.info.code_page,           "codePage");
1843                 IFSET(SAMR_FIELD_PASSWORD) {
1844                         status = samr_set_password(dce_call,
1845                                                    a_state->sam_ctx,
1846                                                    a_state->account_dn,
1847                                                    a_state->domain_state->domain_dn,
1848                                                    mem_ctx, msg, 
1849                                                    &r->in.info->info23.password);
1850                 } else IFSET(SAMR_FIELD_PASSWORD2) {
1851                         status = samr_set_password(dce_call,
1852                                                    a_state->sam_ctx,
1853                                                    a_state->account_dn,
1854                                                    a_state->domain_state->domain_dn,
1855                                                    mem_ctx, msg, 
1856                                                    &r->in.info->info23.password);
1857                 }
1858 #undef IFSET
1859                 break;
1860
1861                 /* the set password levels are handled separately */
1862         case 24:
1863                 status = samr_set_password(dce_call,
1864                                            a_state->sam_ctx,
1865                                            a_state->account_dn,
1866                                            a_state->domain_state->domain_dn,
1867                                            mem_ctx, msg, 
1868                                            &r->in.info->info24.password);
1869                 break;
1870
1871         case 25:
1872 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
1873                 IFSET(SAMR_FIELD_NAME)         
1874                         SET_STRING(msg, info25.info.full_name.string,    "displayName");
1875                 IFSET(SAMR_FIELD_DESCRIPTION)  
1876                         SET_STRING(msg, info25.info.description.string,  "description");
1877                 IFSET(SAMR_FIELD_COMMENT)      
1878                         SET_STRING(msg, info25.info.comment.string,      "comment");
1879                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
1880                         SET_STRING(msg, info25.info.logon_script.string, "scriptPath");
1881                 IFSET(SAMR_FIELD_PROFILE_PATH)      
1882                         SET_STRING(msg, info25.info.profile_path.string, "profilePath");
1883                 IFSET(SAMR_FIELD_WORKSTATION)  
1884                         SET_STRING(msg, info25.info.workstations.string, "userWorkstations");
1885                 IFSET(SAMR_FIELD_LOGON_HOURS)  
1886                         SET_LHOURS(msg, info25.info.logon_hours,         "logonHours");
1887                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
1888                         SET_AFLAGS(msg, info25.info.acct_flags,          "userAccountControl");
1889                 IFSET(SAMR_FIELD_PARAMETERS)     
1890                         SET_STRING(msg, info25.info.parameters.string,   "userParameters");
1891                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
1892                         SET_UINT  (msg, info25.info.country_code,        "countryCode");
1893                 IFSET(SAMR_FIELD_CODE_PAGE)    
1894                         SET_UINT  (msg, info25.info.code_page,           "codePage");
1895                 IFSET(SAMR_FIELD_PASSWORD) {
1896                         status = samr_set_password_ex(dce_call,
1897                                                       a_state->sam_ctx,
1898                                                       a_state->account_dn,
1899                                                       a_state->domain_state->domain_dn,
1900                                                       mem_ctx, msg, 
1901                                                       &r->in.info->info25.password);
1902                 } else IFSET(SAMR_FIELD_PASSWORD2) {
1903                         status = samr_set_password_ex(dce_call,
1904                                                       a_state->sam_ctx,
1905                                                       a_state->account_dn,
1906                                                       a_state->domain_state->domain_dn,
1907                                                       mem_ctx, msg, 
1908                                                       &r->in.info->info25.password);
1909                 }
1910 #undef IFSET
1911                 break;
1912
1913                 /* the set password levels are handled separately */
1914         case 26:
1915                 status = samr_set_password_ex(dce_call,
1916                                               a_state->sam_ctx,
1917                                               a_state->account_dn,
1918                                               a_state->domain_state->domain_dn,
1919                                               mem_ctx, msg, 
1920                                               &r->in.info->info26.password);
1921                 break;
1922                 
1923
1924         default:
1925                 /* many info classes are not valid for SetUserInfo */
1926                 return NT_STATUS_INVALID_INFO_CLASS;
1927         }
1928
1929         if (!NT_STATUS_IS_OK(status)) {
1930                 return status;
1931         }
1932
1933         /* modify the samdb record */
1934         ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
1935         if (ret != 0) {
1936                 /* we really need samdb.c to return NTSTATUS */
1937                 return NT_STATUS_UNSUCCESSFUL;
1938         }
1939
1940         return NT_STATUS_OK;
1941 }
1942
1943
1944 /* 
1945   samr_GetGroupsForUser 
1946 */
1947 static NTSTATUS samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1948                        struct samr_GetGroupsForUser *r)
1949 {
1950         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1951 }
1952
1953
1954 /* 
1955   samr_QueryDisplayInfo 
1956 */
1957 static NTSTATUS samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1958                        struct samr_QueryDisplayInfo *r)
1959 {
1960         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1961 }
1962
1963
1964 /* 
1965   samr_GetDisplayEnumerationIndex 
1966 */
1967 static NTSTATUS samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1968                        struct samr_GetDisplayEnumerationIndex *r)
1969 {
1970         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1971 }
1972
1973
1974 /* 
1975   samr_TestPrivateFunctionsDomain 
1976 */
1977 static NTSTATUS samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1978                        struct samr_TestPrivateFunctionsDomain *r)
1979 {
1980         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1981 }
1982
1983
1984 /* 
1985   samr_TestPrivateFunctionsUser 
1986 */
1987 static NTSTATUS samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1988                        struct samr_TestPrivateFunctionsUser *r)
1989 {
1990         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1991 }
1992
1993
1994 /* 
1995   samr_GetUserPwInfo 
1996 */
1997 static NTSTATUS samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1998                                    struct samr_GetUserPwInfo *r)
1999 {
2000         struct dcesrv_handle *h;
2001         struct samr_account_state *a_state;
2002
2003         ZERO_STRUCT(r->out.info);
2004
2005         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2006
2007         a_state = h->data;
2008
2009         r->out.info.min_password_length = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0, NULL, "minPwdLength", 
2010                                                             "dn=%s", a_state->domain_state->domain_dn);
2011         r->out.info.password_properties = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0, NULL, "pwdProperties", 
2012                                                             "dn=%s", a_state->account_dn);
2013         return NT_STATUS_OK;
2014 }
2015
2016
2017 /* 
2018   samr_RemoveMemberFromForeignDomain 
2019 */
2020 static NTSTATUS samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2021                        struct samr_RemoveMemberFromForeignDomain *r)
2022 {
2023         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2024 }
2025
2026
2027 /* 
2028   samr_QueryDomainInfo2 
2029 */
2030 static NTSTATUS samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2031                        struct samr_QueryDomainInfo2 *r)
2032 {
2033         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2034 }
2035
2036
2037 /* 
2038   samr_QueryUserInfo2 
2039
2040   just an alias for samr_QueryUserInfo
2041 */
2042 static NTSTATUS samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2043                                     struct samr_QueryUserInfo2 *r)
2044 {
2045         struct samr_QueryUserInfo r1;
2046         NTSTATUS status;
2047
2048         r1.in.user_handle = r->in.user_handle;
2049         r1.in.level  = r->in.level;
2050         
2051         status = samr_QueryUserInfo(dce_call, mem_ctx, &r1);
2052         
2053         r->out.info = r1.out.info;
2054
2055         return status;
2056 }
2057
2058
2059 /* 
2060   samr_QueryDisplayInfo2 
2061 */
2062 static NTSTATUS samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2063                        struct samr_QueryDisplayInfo2 *r)
2064 {
2065         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2066 }
2067
2068
2069 /* 
2070   samr_GetDisplayEnumerationIndex2 
2071 */
2072 static NTSTATUS samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2073                        struct samr_GetDisplayEnumerationIndex2 *r)
2074 {
2075         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2076 }
2077
2078
2079 /* 
2080   samr_QueryDisplayInfo3 
2081 */
2082 static NTSTATUS samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2083                        struct samr_QueryDisplayInfo3 *r)
2084 {
2085         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2086 }
2087
2088
2089 /* 
2090   samr_AddMultipleMembersToAlias 
2091 */
2092 static NTSTATUS samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2093                        struct samr_AddMultipleMembersToAlias *r)
2094 {
2095         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2096 }
2097
2098
2099 /* 
2100   samr_RemoveMultipleMembersFromAlias 
2101 */
2102 static NTSTATUS samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2103                        struct samr_RemoveMultipleMembersFromAlias *r)
2104 {
2105         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2106 }
2107
2108
2109 /* 
2110   samr_GetDomPwInfo 
2111
2112   this fetches the default password properties for a domain
2113
2114   note that w2k3 completely ignores the domain name in this call, and 
2115   always returns the information for the servers primary domain
2116 */
2117 static NTSTATUS samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2118                                   struct samr_GetDomPwInfo *r)
2119 {
2120         struct ldb_message **msgs;
2121         int ret;
2122         const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
2123         void *sam_ctx;
2124
2125         ZERO_STRUCT(r->out.info);
2126
2127         sam_ctx = samdb_connect(mem_ctx);
2128         if (sam_ctx == NULL) {
2129                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
2130         }
2131
2132         ret = samdb_search(sam_ctx, 
2133                            mem_ctx, NULL, &msgs, attrs, 
2134                            "(&(name=%s)(objectclass=domain))",
2135                            lp_workgroup());
2136         if (ret <= 0) {
2137                 return NT_STATUS_NO_SUCH_DOMAIN;
2138         }
2139         if (ret > 1) {
2140                 samdb_search_free(sam_ctx, mem_ctx, msgs);
2141                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2142         }
2143
2144         r->out.info.min_password_length = samdb_result_uint(msgs[0], "minPwdLength", 0);
2145         r->out.info.password_properties = samdb_result_uint(msgs[0], "pwdProperties", 1);
2146
2147         samdb_search_free(sam_ctx, mem_ctx, msgs);
2148
2149         talloc_free(sam_ctx);
2150         return NT_STATUS_OK;
2151 }
2152
2153
2154 /* 
2155   samr_Connect2 
2156 */
2157 static NTSTATUS samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2158                               struct samr_Connect2 *r)
2159 {
2160         struct samr_Connect c;
2161
2162         c.in.system_name = NULL;
2163         c.in.access_mask = r->in.access_mask;
2164         c.out.connect_handle = r->out.connect_handle;
2165
2166         return samr_Connect(dce_call, mem_ctx, &c);
2167 }
2168
2169
2170 /* 
2171   samr_SetUserInfo2 
2172
2173   just an alias for samr_SetUserInfo
2174 */
2175 static NTSTATUS samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2176                                   struct samr_SetUserInfo2 *r)
2177 {
2178         struct samr_SetUserInfo r2;
2179
2180         r2.in.user_handle = r->in.user_handle;
2181         r2.in.level = r->in.level;
2182         r2.in.info = r->in.info;
2183
2184         return samr_SetUserInfo(dce_call, mem_ctx, &r2);
2185 }
2186
2187
2188 /* 
2189   samr_SetBootKeyInformation 
2190 */
2191 static NTSTATUS samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2192                        struct samr_SetBootKeyInformation *r)
2193 {
2194         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2195 }
2196
2197
2198 /* 
2199   samr_GetBootKeyInformation 
2200 */
2201 static NTSTATUS samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2202                        struct samr_GetBootKeyInformation *r)
2203 {
2204         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2205 }
2206
2207
2208 /* 
2209   samr_Connect3 
2210 */
2211 static NTSTATUS samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2212                        struct samr_Connect3 *r)
2213 {
2214         struct samr_Connect c;
2215
2216         c.in.system_name = NULL;
2217         c.in.access_mask = r->in.access_mask;
2218         c.out.connect_handle = r->out.connect_handle;
2219
2220         return samr_Connect(dce_call, mem_ctx, &c);
2221 }
2222
2223
2224 /* 
2225   samr_Connect4 
2226 */
2227 static NTSTATUS samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2228                        struct samr_Connect4 *r)
2229 {
2230         struct samr_Connect c;
2231
2232         c.in.system_name = NULL;
2233         c.in.access_mask = r->in.access_mask;
2234         c.out.connect_handle = r->out.connect_handle;
2235
2236         return samr_Connect(dce_call, mem_ctx, &c);
2237 }
2238
2239
2240 /* 
2241   samr_Connect5 
2242 */
2243 static NTSTATUS samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2244                               struct samr_Connect5 *r)
2245 {
2246         struct samr_Connect c;
2247         NTSTATUS status;
2248
2249         c.in.system_name = NULL;
2250         c.in.access_mask = r->in.access_mask;
2251         c.out.connect_handle = r->out.connect_handle;
2252
2253         status = samr_Connect(dce_call, mem_ctx, &c);
2254
2255         r->out.info->info1.unknown1 = 3;
2256         r->out.info->info1.unknown2 = 0;
2257         r->out.level = r->in.level;
2258
2259         return status;
2260 }
2261
2262
2263 /* 
2264   samr_RidToSid 
2265 */
2266 static NTSTATUS samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2267                        struct samr_RidToSid *r)
2268 {
2269         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2270 }
2271
2272
2273 /* 
2274   samr_SetDsrmPassword 
2275 */
2276 static NTSTATUS samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2277                        struct samr_SetDsrmPassword *r)
2278 {
2279         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2280 }
2281
2282
2283 /* 
2284   samr_ValidatePassword 
2285 */
2286 static NTSTATUS samr_ValidatePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2287                                       struct samr_ValidatePassword *r)
2288 {
2289         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2290 }
2291
2292
2293 /* include the generated boilerplate */
2294 #include "librpc/gen_ndr/ndr_samr_s.c"