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