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