r9391: Convert all the code to use struct ldb_dn to ohandle ldap like distinguished...
[kai/samba.git] / source4 / rpc_server / samr / dcesrv_samr.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    endpoint server for the samr pipe
5
6    Copyright (C) Andrew Tridgell 2004
7    Copyright (C) Volker Lendecke 2004
8    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26 #include "librpc/gen_ndr/ndr_samr.h"
27 #include "rpc_server/dcerpc_server.h"
28 #include "rpc_server/common/common.h"
29 #include "rpc_server/samr/dcesrv_samr.h"
30 #include "system/time.h"
31 #include "lib/ldb/include/ldb.h"
32 #include "ads.h"
33
34
35 /*
36   This is a bad temporary hack until we have at least some kind of schema
37   support
38 */
39 static char *ldb_hexstr(TALLOC_CTX *mem_ctx, uint32_t val)
40 {
41         return talloc_asprintf(mem_ctx, "0x%.8x", val);
42 }
43
44 /* 
45   samr_Connect 
46
47   create a connection to the SAM database
48 */
49 static NTSTATUS samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
50                              struct samr_Connect *r)
51 {
52         struct samr_connect_state *c_state;
53         struct dcesrv_handle *handle;
54
55         ZERO_STRUCTP(r->out.connect_handle);
56
57         c_state = talloc(dce_call->conn, struct samr_connect_state);
58         if (!c_state) {
59                 return NT_STATUS_NO_MEMORY;
60         }
61
62         /* make sure the sam database is accessible */
63         c_state->sam_ctx = samdb_connect(c_state);
64         if (c_state->sam_ctx == NULL) {
65                 talloc_free(c_state);
66                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
67         }
68
69         handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_CONNECT);
70         if (!handle) {
71                 talloc_free(c_state);
72                 return NT_STATUS_NO_MEMORY;
73         }
74
75         handle->data = talloc_steal(handle, c_state);
76
77         c_state->access_mask = r->in.access_mask;
78         *r->out.connect_handle = handle->wire_handle;
79
80         return NT_STATUS_OK;
81 }
82
83
84 /* 
85   samr_Close 
86 */
87 static NTSTATUS samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
88                            struct samr_Close *r)
89 {
90         struct dcesrv_handle *h;
91
92         *r->out.handle = *r->in.handle;
93
94         DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
95
96         talloc_free(h);
97
98         ZERO_STRUCTP(r->out.handle);
99
100         return NT_STATUS_OK;
101 }
102
103
104 /* 
105   samr_SetSecurity 
106 */
107 static NTSTATUS samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
108                                  struct samr_SetSecurity *r)
109 {
110         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
111 }
112
113
114 /* 
115   samr_QuerySecurity 
116 */
117 static NTSTATUS samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
118                                    struct samr_QuerySecurity *r)
119 {
120         struct dcesrv_handle *h;
121         struct sec_desc_buf *sd;
122
123         r->out.sdbuf = NULL;
124
125         DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
126
127         sd = talloc(mem_ctx, struct sec_desc_buf);
128         if (sd == NULL) {
129                 return NT_STATUS_NO_MEMORY;
130         }
131
132         sd->sd = samdb_default_security_descriptor(mem_ctx);
133
134         r->out.sdbuf = sd;
135
136         return NT_STATUS_OK;
137 }
138
139
140 /* 
141   samr_Shutdown 
142
143   we refuse this operation completely. If a admin wants to shutdown samr
144   in Samba then they should use the samba admin tools to disable the samr pipe
145 */
146 static NTSTATUS samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
147                               struct samr_Shutdown *r)
148 {
149         return NT_STATUS_ACCESS_DENIED;
150 }
151
152
153 /* 
154   samr_LookupDomain 
155
156   this maps from a domain name to a SID
157 */
158 static NTSTATUS samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
159                                   struct samr_LookupDomain *r)
160 {
161         struct samr_connect_state *c_state;
162         struct dcesrv_handle *h;
163         struct dom_sid *sid;
164         const char * const dom_attrs[] = { "objectSid", NULL};
165         const char * const ref_attrs[] = { "ncName", NULL};
166         struct ldb_message **dom_msgs;
167         struct ldb_message **ref_msgs;
168         int ret;
169
170         r->out.sid = NULL;
171
172         DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
173
174         c_state = h->data;
175
176         if (r->in.domain_name->string == NULL) {
177                 return NT_STATUS_INVALID_PARAMETER;
178         }
179
180         if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
181                 ret = gendb_search(c_state->sam_ctx,
182                                    mem_ctx, NULL, &dom_msgs, dom_attrs,
183                                    "(objectClass=builtinDomain)");
184         } else {
185                 ret = gendb_search(c_state->sam_ctx,
186                                    mem_ctx, NULL, &ref_msgs, ref_attrs,
187                                    "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))", 
188                                    r->in.domain_name->string);
189                 if (ret != 1) {
190                         return NT_STATUS_NO_SUCH_DOMAIN;
191                 }
192                 
193                 ret = gendb_search_dn(c_state->sam_ctx, mem_ctx, 
194                                       samdb_result_dn(mem_ctx,
195                                         ref_msgs[0], "ncName", NULL), 
196                                       &dom_msgs, dom_attrs);
197         }
198
199         if (ret != 1) {
200                 return NT_STATUS_NO_SUCH_DOMAIN;
201         }
202         
203         sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
204                                    "objectSid");
205                 
206         if (sid == NULL) {
207                 return NT_STATUS_NO_SUCH_DOMAIN;
208         }
209
210         r->out.sid = sid;
211
212         return NT_STATUS_OK;
213 }
214
215
216 /* 
217   samr_EnumDomains 
218
219   list the domains in the SAM
220 */
221 static NTSTATUS samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
222                                  struct samr_EnumDomains *r)
223 {
224         struct samr_connect_state *c_state;
225         struct dcesrv_handle *h;
226         struct samr_SamArray *array;
227         int count, i, start_i;
228         const char * const dom_attrs[] = { "cn", NULL};
229         const char * const ref_attrs[] = { "nETBIOSName", NULL};
230         struct ldb_message **dom_msgs;
231         struct ldb_message **ref_msgs;
232
233         *r->out.resume_handle = 0;
234         r->out.sam = NULL;
235         r->out.num_entries = 0;
236
237         DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
238
239         c_state = h->data;
240
241         count = gendb_search(c_state->sam_ctx,
242                            mem_ctx, NULL, &dom_msgs, dom_attrs,
243                            "(objectClass=domain)");
244         if (count == -1) {
245                 DEBUG(0,("samdb: no domains found in EnumDomains\n"));
246                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
247         }
248
249         *r->out.resume_handle = count;
250
251         start_i = *r->in.resume_handle;
252
253         if (start_i >= count) {
254                 /* search past end of list is not an error for this call */
255                 return NT_STATUS_OK;
256         }
257
258         array = talloc(mem_ctx, struct samr_SamArray);
259         if (array == NULL) {
260                 return NT_STATUS_NO_MEMORY;
261         }
262                 
263         array->count = 0;
264         array->entries = NULL;
265
266         array->entries = talloc_array(mem_ctx, struct samr_SamEntry, count - start_i);
267         if (array->entries == NULL) {
268                 return NT_STATUS_NO_MEMORY;
269         }
270
271         for (i=0;i<count-start_i;i++) {
272                 int ret;
273                 array->entries[i].idx = start_i + i;
274                 /* try and find the domain */
275                 ret = gendb_search(c_state->sam_ctx, mem_ctx, NULL, 
276                                    &ref_msgs, ref_attrs, 
277                                    "(&(objectClass=crossRef)(ncName=%s))", 
278                                    ldb_dn_linearize(mem_ctx, dom_msgs[i]->dn));
279                 if (ret == 1) {
280                         array->entries[i].name.string = samdb_result_string(ref_msgs[0], "nETBIOSName", NULL);
281                 } else {
282                         array->entries[i].name.string = samdb_result_string(dom_msgs[i], "cn", NULL);
283                 }
284         }
285
286         r->out.sam = array;
287         r->out.num_entries = i;
288         array->count = r->out.num_entries;
289
290         return NT_STATUS_OK;
291 }
292
293
294 /* 
295   samr_OpenDomain 
296 */
297 static NTSTATUS samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
298                                 struct samr_OpenDomain *r)
299 {
300         struct dcesrv_handle *h_conn, *h_domain;
301         const char *domain_name;
302         struct samr_connect_state *c_state;
303         struct samr_domain_state *d_state;
304         const char * const dom_attrs[] = { "cn", NULL};
305         const char * const ref_attrs[] = { "nETBIOSName", NULL};
306         struct ldb_message **dom_msgs;
307         struct ldb_message **ref_msgs;
308         int ret;
309
310         ZERO_STRUCTP(r->out.domain_handle);
311
312         DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
313
314         c_state = h_conn->data;
315
316         if (r->in.sid == NULL) {
317                 return NT_STATUS_INVALID_PARAMETER;
318         }
319
320         ret = gendb_search(c_state->sam_ctx,
321                            mem_ctx, NULL, &dom_msgs, dom_attrs,
322                            "(&(objectSid=%s)(&(objectclass=domain)(!(objectClass=builtinDomain))))",
323                            ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
324         if (ret == -1) {
325                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
326         } else if (ret == 0) {
327                 ret = gendb_search(c_state->sam_ctx,
328                                    mem_ctx, NULL, &dom_msgs, dom_attrs,
329                                    "(&(objectSid=%s)(objectClass=builtinDomain))", 
330                                    ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
331                 if (ret != 1) {
332                         return NT_STATUS_NO_SUCH_DOMAIN;
333                 }
334
335                 domain_name = ldb_msg_find_string(dom_msgs[0], "cn", NULL);
336                 if (domain_name == NULL) {
337                         return NT_STATUS_NO_SUCH_DOMAIN;
338                 }
339         } else {
340                 ret = gendb_search(c_state->sam_ctx,
341                                    mem_ctx, NULL, &ref_msgs, ref_attrs,
342                                    "(&(&(nETBIOSName=*)(objectclass=crossRef))(ncName=%s))", 
343                                    ldb_dn_linearize(mem_ctx, dom_msgs[0]->dn));
344                 if (ret != 1) {
345                         return NT_STATUS_NO_SUCH_DOMAIN;
346                 }
347                 
348                 domain_name = ldb_msg_find_string(ref_msgs[0], "nETBIOSName", NULL);
349                 if (domain_name == NULL) {
350                         return NT_STATUS_NO_SUCH_DOMAIN;
351                 }
352         }
353
354         d_state = talloc(c_state, struct samr_domain_state);
355         if (!d_state) {
356                 return NT_STATUS_NO_MEMORY;
357         }
358
359         d_state->connect_state = talloc_reference(d_state, c_state);
360         d_state->sam_ctx = c_state->sam_ctx;
361         d_state->domain_sid = dom_sid_dup(d_state, r->in.sid);
362         d_state->domain_name = talloc_strdup(d_state, domain_name);
363         d_state->domain_dn = ldb_dn_copy(d_state, dom_msgs[0]->dn);
364         if (!d_state->domain_sid || !d_state->domain_name || !d_state->domain_dn) {
365                 talloc_free(d_state);
366                 return NT_STATUS_NO_MEMORY;             
367         }
368         d_state->access_mask = r->in.access_mask;
369
370         h_domain = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_DOMAIN);
371         if (!h_domain) {
372                 talloc_free(d_state);
373                 return NT_STATUS_NO_MEMORY;
374         }
375         
376         h_domain->data = talloc_steal(h_domain, d_state);
377
378         *r->out.domain_handle = h_domain->wire_handle;
379
380         return NT_STATUS_OK;
381 }
382
383 /*
384   return DomInfo1
385 */
386 static NTSTATUS samr_info_DomInfo1(struct samr_domain_state *state,
387                                    TALLOC_CTX *mem_ctx,
388                                    struct samr_DomInfo1 *info)
389 {
390         const char * const attrs[] = { "minPwdLength", "pwdHistoryLength",
391                                        "pwdProperties", "maxPwdAge",
392                                        "minPwdAge", NULL };
393         int ret;
394         struct ldb_message **res;
395
396         ret = gendb_search_dn(state->sam_ctx, mem_ctx,
397                               state->domain_dn , &res, attrs);
398         if (ret != 1) {
399                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
400         }
401
402         info->min_password_length =
403                 samdb_result_uint(res[0], "minPwdLength", 0);
404         info->password_history_length =
405                 samdb_result_uint(res[0], "pwdHistoryLength", 0);
406         info->password_properties = 
407                 samdb_result_uint(res[0], "pwdProperties", 0);
408         info->max_password_age = 
409                 samdb_result_int64(res[0], "maxPwdAge", 0);
410         info->min_password_age = 
411                 samdb_result_int64(res[0], "minPwdAge", 0);
412
413         return NT_STATUS_OK;
414 }
415
416 /*
417   return DomInfo2
418 */
419 static NTSTATUS samr_info_DomInfo2(struct samr_domain_state *state, TALLOC_CTX *mem_ctx,
420                                    struct samr_DomInfo2 *info)
421 {
422         const char * const dom_attrs[] = { "comment", NULL };
423         int ret;
424         struct ldb_message **dom_msgs;
425         const char *domain_name;
426         
427         ret = gendb_search_dn(state->sam_ctx, mem_ctx,
428                               state->domain_dn, &dom_msgs, dom_attrs);
429         if (ret != 1) {
430                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
431         }
432
433         domain_name = state->domain_name;
434         /* where is this supposed to come from? is it settable? */
435         info->force_logoff_time = 0x8000000000000000LL;
436
437         info->comment.string = samdb_result_string(dom_msgs[0], "comment", NULL);
438         info->domain_name.string  = domain_name;
439
440         info->primary.string = lp_netbios_name();
441         info->sequence_num = 0;
442         info->role = ROLE_DOMAIN_PDC;
443         info->num_users = samdb_search_count(state->sam_ctx, mem_ctx, NULL, "(objectClass=user)");
444         info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx, NULL,
445                                               "(&(objectClass=group)(sAMAccountType=%u))",
446                                               ATYPE_GLOBAL_GROUP);
447         info->num_aliases = samdb_search_count(state->sam_ctx, mem_ctx, NULL,
448                                                "(&(objectClass=group)(sAMAccountType=%u))",
449                                                ATYPE_LOCAL_GROUP);
450
451         return NT_STATUS_OK;
452 }
453
454 /*
455   return DomInfo3
456 */
457 static NTSTATUS samr_info_DomInfo3(struct samr_domain_state *state,
458                                    TALLOC_CTX *mem_ctx,
459                                    struct samr_DomInfo3 *info)
460 {
461         /* where is this supposed to come from? is it settable? */
462         info->force_logoff_time = 0x8000000000000000LL;
463
464         return NT_STATUS_OK;
465 }
466
467 /* 
468   samr_QueryDomainInfo 
469 */
470 static NTSTATUS samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
471                                      struct samr_QueryDomainInfo *r)
472 {
473         struct dcesrv_handle *h;
474         struct samr_domain_state *d_state;
475
476         r->out.info = NULL;
477
478         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
479
480         d_state = h->data;
481
482         r->out.info = talloc(mem_ctx, union samr_DomainInfo);
483         if (!r->out.info) {
484                 return NT_STATUS_NO_MEMORY;
485         }
486
487         ZERO_STRUCTP(r->out.info);
488
489         switch (r->in.level) {
490         case 1:
491                 return samr_info_DomInfo1(d_state, mem_ctx,
492                                           &r->out.info->info1);
493         case 2:
494                 return samr_info_DomInfo2(d_state, mem_ctx, &r->out.info->info2);
495         case 3:
496                 return samr_info_DomInfo3(d_state, mem_ctx,
497                                           &r->out.info->info3);
498         }
499
500         return NT_STATUS_INVALID_INFO_CLASS;
501 }
502
503
504 /* 
505   samr_SetDomainInfo 
506 */
507 static NTSTATUS samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
508                        struct samr_SetDomainInfo *r)
509 {
510         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
511 }
512
513 /* 
514   samr_CreateDomainGroup 
515 */
516 static NTSTATUS samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
517                                        struct samr_CreateDomainGroup *r)
518 {
519         struct samr_domain_state *d_state;
520         struct samr_account_state *a_state;
521         struct dcesrv_handle *h;
522         const char *name;
523         struct ldb_message *msg;
524         struct dom_sid *sid;
525         const char *groupname;
526         struct dcesrv_handle *g_handle;
527         int ret;
528
529         ZERO_STRUCTP(r->out.group_handle);
530         *r->out.rid = 0;
531
532         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
533
534         d_state = h->data;
535
536         groupname = r->in.name->string;
537
538         if (groupname == NULL) {
539                 return NT_STATUS_INVALID_PARAMETER;
540         }
541
542         /* check if the group already exists */
543         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL, 
544                                    "sAMAccountName",
545                                    "(&(sAMAccountName=%s)(objectclass=group))",
546                                    groupname);
547         if (name != NULL) {
548                 return NT_STATUS_GROUP_EXISTS;
549         }
550
551         msg = ldb_msg_new(mem_ctx);
552         if (msg == NULL) {
553                 return NT_STATUS_NO_MEMORY;
554         }
555
556         /* add core elements to the ldb_message for the user */
557         msg->dn = ldb_dn_build_child(mem_ctx,
558                                      "CN", groupname,
559                                      ldb_dn_build_child(mem_ctx,
560                                                         "CN", "Users",
561                                                         d_state->domain_dn));
562         if (!msg->dn) {
563                 return NT_STATUS_NO_MEMORY;
564         }
565         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", groupname);
566         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
567                              
568         /* create the group */
569         ret = samdb_add(d_state->sam_ctx, mem_ctx, msg);
570         if (ret != 0) {
571                 DEBUG(0,("Failed to create group record %s\n",
572                          ldb_dn_linearize(mem_ctx, msg->dn)));
573                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
574         }
575
576         a_state = talloc(d_state, struct samr_account_state);
577         if (!a_state) {
578                 return NT_STATUS_NO_MEMORY;
579         }
580         a_state->sam_ctx = d_state->sam_ctx;
581         a_state->access_mask = r->in.access_mask;
582         a_state->domain_state = talloc_reference(a_state, d_state);
583         a_state->account_dn = talloc_steal(a_state, msg->dn);
584
585         /* retrieve the sid for the group just created */
586         sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
587                                    msg->dn, "objectSid", "dn=%s",
588                                    ldb_dn_linearize(mem_ctx, msg->dn));
589         if (sid == NULL) {
590                 return NT_STATUS_UNSUCCESSFUL;
591         }
592
593         a_state->account_name = talloc_strdup(a_state, groupname);
594         if (!a_state->account_name) {
595                 return NT_STATUS_NO_MEMORY;
596         }
597
598         /* create the policy handle */
599         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
600         if (!g_handle) {
601                 return NT_STATUS_NO_MEMORY;
602         }
603
604         g_handle->data = talloc_steal(g_handle, a_state);
605
606         *r->out.group_handle = g_handle->wire_handle;
607         *r->out.rid = sid->sub_auths[sid->num_auths-1];
608
609         return NT_STATUS_OK;
610 }
611
612
613 /*
614   comparison function for sorting SamEntry array
615 */
616 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
617 {
618         return e1->idx - e2->idx;
619 }
620
621 /* 
622   samr_EnumDomainGroups 
623 */
624 static NTSTATUS samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
625                                       struct samr_EnumDomainGroups *r)
626 {
627         struct dcesrv_handle *h;
628         struct samr_domain_state *d_state;
629         struct ldb_message **res;
630         int ldb_cnt, count, i, first;
631         struct samr_SamEntry *entries;
632         const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
633
634         *r->out.resume_handle = 0;
635         r->out.sam = NULL;
636         r->out.num_entries = 0;
637
638         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
639
640         d_state = h->data;
641
642         /* search for all domain groups in this domain. This could possibly be
643            cached and resumed based on resume_key */
644         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
645                                       d_state->domain_dn, &res, attrs,
646                                       d_state->domain_sid,
647                                       "(&(grouptype=%s)(objectclass=group))",
648                                       ldb_hexstr(mem_ctx,
649                                                  GTYPE_SECURITY_GLOBAL_GROUP));
650         if (ldb_cnt == -1) {
651                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
652         }
653         if (ldb_cnt == 0 || r->in.max_size == 0) {
654                 return NT_STATUS_OK;
655         }
656
657         /* convert to SamEntry format */
658         entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
659         if (!entries) {
660                 return NT_STATUS_NO_MEMORY;
661         }
662
663         count = 0;
664
665         for (i=0;i<ldb_cnt;i++) {
666                 struct dom_sid *group_sid;
667
668                 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
669                                                  "objectSid");
670                 if (group_sid == NULL)
671                         continue;
672
673                 entries[count].idx =
674                         group_sid->sub_auths[group_sid->num_auths-1];
675                 entries[count].name.string =
676                         samdb_result_string(res[i], "sAMAccountName", "");
677                 count += 1;
678         }
679
680         /* sort the results by rid */
681         qsort(entries, count, sizeof(struct samr_SamEntry), 
682               (comparison_fn_t)compare_SamEntry);
683
684         /* find the first entry to return */
685         for (first=0;
686              first<count && entries[first].idx <= *r->in.resume_handle;
687              first++) ;
688
689         if (first == count) {
690                 return NT_STATUS_OK;
691         }
692
693         /* return the rest, limit by max_size. Note that we 
694            use the w2k3 element size value of 54 */
695         r->out.num_entries = count - first;
696         r->out.num_entries = MIN(r->out.num_entries, 
697                                  1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
698
699         r->out.sam = talloc(mem_ctx, struct samr_SamArray);
700         if (!r->out.sam) {
701                 return NT_STATUS_NO_MEMORY;
702         }
703
704         r->out.sam->entries = entries+first;
705         r->out.sam->count = r->out.num_entries;
706
707         if (r->out.num_entries < count - first) {
708                 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
709                 return STATUS_MORE_ENTRIES;
710         }
711
712         return NT_STATUS_OK;
713 }
714
715
716 /* 
717   samr_CreateUser2 
718
719   TODO: This should do some form of locking, especially around the rid allocation
720 */
721 static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
722                                  struct samr_CreateUser2 *r)
723 {
724         struct samr_domain_state *d_state;
725         struct samr_account_state *a_state;
726         struct dcesrv_handle *h;
727         const char *name;
728         struct ldb_message *msg;
729         struct dom_sid *sid;
730         const char *account_name;
731         struct dcesrv_handle *u_handle;
732         int ret;
733         const char *container, *obj_class=NULL;
734         char *cn_name;
735         int cn_name_len;
736
737         ZERO_STRUCTP(r->out.user_handle);
738         *r->out.access_granted = 0;
739         *r->out.rid = 0;
740
741         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
742
743         d_state = h->data;
744
745         account_name = r->in.account_name->string;
746
747         if (account_name == NULL) {
748                 return NT_STATUS_INVALID_PARAMETER;
749         }
750
751         /* check if the user already exists */
752         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL, 
753                                    "sAMAccountName", 
754                                    "(&(sAMAccountName=%s)(objectclass=user))", account_name);
755         if (name != NULL) {
756                 return NT_STATUS_USER_EXISTS;
757         }
758
759         msg = ldb_msg_new(mem_ctx);
760         if (msg == NULL) {
761                 return NT_STATUS_NO_MEMORY;
762         }
763
764         cn_name   = talloc_strdup(mem_ctx, account_name);
765         NT_STATUS_HAVE_NO_MEMORY(cn_name);
766         cn_name_len = strlen(cn_name);
767
768         /* This must be one of these values *only* */
769         if (r->in.acct_flags == ACB_NORMAL) {
770                 container = "Users";
771                 obj_class = "user";
772
773         } else if (r->in.acct_flags == ACB_WSTRUST) {
774                 if (cn_name[cn_name_len - 1] != '$') {
775                         return NT_STATUS_FOOBAR;
776                 }
777                 cn_name[cn_name_len - 1] = '\0';
778                 container = "Computers";
779                 obj_class = "computer";
780
781         } else if (r->in.acct_flags == ACB_SVRTRUST) {
782                 if (cn_name[cn_name_len - 1] != '$') {
783                         return NT_STATUS_FOOBAR;                
784                 }
785                 cn_name[cn_name_len - 1] = '\0';
786                 container = "Domain Controllers";
787                 obj_class = "computer";
788
789         } else if (r->in.acct_flags == ACB_DOMTRUST) {
790                 container = "Users";
791                 obj_class = "user";
792
793         } else {
794                 return NT_STATUS_INVALID_PARAMETER;
795         }
796
797         /* add core elements to the ldb_message for the user */
798         msg->dn = ldb_dn_build_child(mem_ctx, "CN", cn_name, ldb_dn_build_child(mem_ctx, "CN", container, d_state->domain_dn));
799         if (!msg->dn) {
800                 return NT_STATUS_NO_MEMORY;             
801         }
802         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", account_name);
803         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", obj_class);
804         /* create the user */
805         ret = samdb_add(d_state->sam_ctx, mem_ctx, msg);
806         if (ret != 0) {
807                 DEBUG(0,("Failed to create user record %s\n",
808                          ldb_dn_linearize(mem_ctx, msg->dn)));
809                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
810         }
811
812         a_state = talloc(d_state, struct samr_account_state);
813         if (!a_state) {
814                 return NT_STATUS_NO_MEMORY;
815         }
816         a_state->sam_ctx = d_state->sam_ctx;
817         a_state->access_mask = r->in.access_mask;
818         a_state->domain_state = talloc_reference(a_state, d_state);
819         a_state->account_dn = talloc_steal(a_state, msg->dn);
820
821         /* retrieve the sid for the user just created */
822         sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
823                                    msg->dn, "objectSid", "dn=%s", ldb_dn_linearize(mem_ctx, msg->dn));
824         if (sid == NULL) {
825                 return NT_STATUS_UNSUCCESSFUL;
826         }
827
828         a_state->account_name = talloc_strdup(a_state, account_name);
829         if (!a_state->account_name) {
830                 return NT_STATUS_NO_MEMORY;
831         }
832
833         /* create the policy handle */
834         u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
835         if (!u_handle) {
836                 return NT_STATUS_NO_MEMORY;
837         }
838
839         u_handle->data = talloc_steal(u_handle, a_state);
840
841         *r->out.user_handle = u_handle->wire_handle;
842         *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
843
844         *r->out.rid = sid->sub_auths[sid->num_auths-1];
845
846         return NT_STATUS_OK;
847 }
848
849
850 /* 
851   samr_CreateUser 
852 */
853 static NTSTATUS samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
854                                 struct samr_CreateUser *r)
855 {
856         struct samr_CreateUser2 r2;
857         uint32_t access_granted = 0;
858
859
860         /* a simple wrapper around samr_CreateUser2 works nicely */
861         r2.in.domain_handle = r->in.domain_handle;
862         r2.in.account_name = r->in.account_name;
863         r2.in.acct_flags = ACB_NORMAL;
864         r2.in.access_mask = r->in.access_mask;
865         r2.out.user_handle = r->out.user_handle;
866         r2.out.access_granted = &access_granted;
867         r2.out.rid = r->out.rid;
868
869         return samr_CreateUser2(dce_call, mem_ctx, &r2);
870 }
871
872 /* 
873   samr_EnumDomainUsers 
874 */
875 static NTSTATUS samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
876                                      struct samr_EnumDomainUsers *r)
877 {
878         struct dcesrv_handle *h;
879         struct samr_domain_state *d_state;
880         struct ldb_message **res;
881         int count, i, first;
882         struct samr_SamEntry *entries;
883         const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
884
885         *r->out.resume_handle = 0;
886         r->out.sam = NULL;
887         r->out.num_entries = 0;
888
889         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
890
891         d_state = h->data;
892         
893         /* search for all users in this domain. This could possibly be cached and 
894            resumed based on resume_key */
895         count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs, 
896                              "objectclass=user");
897         if (count == -1) {
898                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
899         }
900         if (count == 0 || r->in.max_size == 0) {
901                 return NT_STATUS_OK;
902         }
903
904         /* convert to SamEntry format */
905         entries = talloc_array(mem_ctx, struct samr_SamEntry, count);
906         if (!entries) {
907                 return NT_STATUS_NO_MEMORY;
908         }
909         for (i=0;i<count;i++) {
910                 entries[i].idx = samdb_result_rid_from_sid(mem_ctx, res[i], "objectSid", 0);
911                 entries[i].name.string = samdb_result_string(res[i], "sAMAccountName", "");
912         }
913
914         /* sort the results by rid */
915         qsort(entries, count, sizeof(struct samr_SamEntry), 
916               (comparison_fn_t)compare_SamEntry);
917
918         /* find the first entry to return */
919         for (first=0;
920              first<count && entries[first].idx <= *r->in.resume_handle;
921              first++) ;
922
923         if (first == count) {
924                 return NT_STATUS_OK;
925         }
926
927         /* return the rest, limit by max_size. Note that we 
928            use the w2k3 element size value of 54 */
929         r->out.num_entries = count - first;
930         r->out.num_entries = MIN(r->out.num_entries, 
931                                  1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
932
933         r->out.sam = talloc(mem_ctx, struct samr_SamArray);
934         if (!r->out.sam) {
935                 return NT_STATUS_NO_MEMORY;
936         }
937
938         r->out.sam->entries = entries+first;
939         r->out.sam->count = r->out.num_entries;
940
941         if (r->out.num_entries < count - first) {
942                 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
943                 return STATUS_MORE_ENTRIES;
944         }
945
946         return NT_STATUS_OK;
947 }
948
949
950 /* 
951   samr_CreateDomAlias 
952 */
953 static NTSTATUS samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
954                        struct samr_CreateDomAlias *r)
955 {
956         struct samr_domain_state *d_state;
957         struct samr_account_state *a_state;
958         struct dcesrv_handle *h;
959         const char *alias_name, *name;
960         struct ldb_message *msg;
961         struct dom_sid *sid;
962         struct dcesrv_handle *a_handle;
963         int ret;
964
965         ZERO_STRUCTP(r->out.alias_handle);
966         *r->out.rid = 0;
967
968         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
969
970         d_state = h->data;
971
972         alias_name = r->in.alias_name->string;
973
974         if (alias_name == NULL) {
975                 return NT_STATUS_INVALID_PARAMETER;
976         }
977
978         /* Check if alias already exists */
979         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
980                                    "sAMAccountName",
981                                    "(sAMAccountName=%s)(objectclass=group))",
982                                    alias_name);
983
984         if (name != NULL) {
985                 return NT_STATUS_ALIAS_EXISTS;
986         }
987
988         msg = ldb_msg_new(mem_ctx);
989         if (msg == NULL) {
990                 return NT_STATUS_NO_MEMORY;
991         }
992
993         /* add core elements to the ldb_message for the alias */
994         msg->dn = ldb_dn_build_child(mem_ctx,
995                                      "CN", alias_name,
996                                      ldb_dn_build_child(mem_ctx,
997                                                         "CN", "Users",
998                                                         d_state->domain_dn));
999         if (!msg->dn) {
1000                 return NT_STATUS_NO_MEMORY;
1001         }
1002
1003         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", alias_name);
1004         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1005         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "groupType", "0x80000004");
1006
1007         /* create the alias */
1008         ret = samdb_add(d_state->sam_ctx, mem_ctx, msg);
1009         if (ret != 0) {
1010                 DEBUG(0,("Failed to create alias record %s\n",
1011                          ldb_dn_linearize(mem_ctx, msg->dn)));
1012                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1013         }
1014
1015         a_state = talloc(d_state, struct samr_account_state);
1016         if (!a_state) {
1017                 return NT_STATUS_NO_MEMORY;
1018         }
1019
1020         a_state->sam_ctx = d_state->sam_ctx;
1021         a_state->access_mask = r->in.access_mask;
1022         a_state->domain_state = talloc_reference(a_state, d_state);
1023         a_state->account_dn = talloc_steal(a_state, msg->dn);
1024
1025         /* retrieve the sid for the alias just created */
1026         sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1027                                    msg->dn, "objectSid", "dn=%s",
1028                                    ldb_dn_linearize(mem_ctx, msg->dn));
1029
1030         a_state->account_name = talloc_strdup(a_state, alias_name);
1031         if (!a_state->account_name) {
1032                 return NT_STATUS_NO_MEMORY;
1033         }
1034
1035         /* create the policy handle */
1036         a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1037         if (a_handle == NULL)
1038                 return NT_STATUS_NO_MEMORY;
1039
1040         a_handle->data = talloc_steal(a_handle, a_state);
1041
1042         *r->out.alias_handle = a_handle->wire_handle;
1043
1044         *r->out.rid = sid->sub_auths[sid->num_auths-1];
1045
1046         return NT_STATUS_OK;
1047 }
1048
1049
1050 /* 
1051   samr_EnumDomainAliases 
1052 */
1053 static NTSTATUS samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1054                        struct samr_EnumDomainAliases *r)
1055 {
1056         struct dcesrv_handle *h;
1057         struct samr_domain_state *d_state;
1058         struct ldb_message **res;
1059         int ldb_cnt, count, i, first;
1060         struct samr_SamEntry *entries;
1061         const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1062
1063         *r->out.resume_handle = 0;
1064         r->out.sam = NULL;
1065         r->out.num_entries = 0;
1066
1067         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1068
1069         d_state = h->data;
1070
1071         /* search for all domain groups in this domain. This could possibly be
1072            cached and resumed based on resume_key */
1073         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1074                                       d_state->domain_dn,
1075                                       &res, attrs, 
1076                                       d_state->domain_sid,
1077                                       "(&(|(grouptype=%s)(grouptype=%s)))"
1078                                       "(objectclass=group))",
1079                                       ldb_hexstr(mem_ctx,
1080                                                  GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
1081                                       ldb_hexstr(mem_ctx,
1082                                                  GTYPE_SECURITY_DOMAIN_LOCAL_GROUP));
1083         if (ldb_cnt == -1) {
1084                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1085         }
1086         if (ldb_cnt == 0) {
1087                 return NT_STATUS_OK;
1088         }
1089
1090         /* convert to SamEntry format */
1091         entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1092         if (!entries) {
1093                 return NT_STATUS_NO_MEMORY;
1094         }
1095
1096         count = 0;
1097
1098         for (i=0;i<ldb_cnt;i++) {
1099                 struct dom_sid *alias_sid;
1100
1101                 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1102                                                  "objectSid");
1103
1104                 if (alias_sid == NULL)
1105                         continue;
1106
1107                 entries[count].idx =
1108                         alias_sid->sub_auths[alias_sid->num_auths-1];
1109                 entries[count].name.string =
1110                         samdb_result_string(res[i], "sAMAccountName", "");
1111                 count += 1;
1112         }
1113
1114         /* sort the results by rid */
1115         qsort(entries, count, sizeof(struct samr_SamEntry), 
1116               (comparison_fn_t)compare_SamEntry);
1117
1118         /* find the first entry to return */
1119         for (first=0;
1120              first<count && entries[first].idx <= *r->in.resume_handle;
1121              first++) ;
1122
1123         if (first == count) {
1124                 return NT_STATUS_OK;
1125         }
1126
1127         r->out.num_entries = count - first;
1128         r->out.num_entries = MIN(r->out.num_entries, 1000);
1129
1130         r->out.sam = talloc(mem_ctx, struct samr_SamArray);
1131         if (!r->out.sam) {
1132                 return NT_STATUS_NO_MEMORY;
1133         }
1134
1135         r->out.sam->entries = entries+first;
1136         r->out.sam->count = r->out.num_entries;
1137
1138         if (r->out.num_entries < count - first) {
1139                 *r->out.resume_handle =
1140                         entries[first+r->out.num_entries-1].idx;
1141                 return STATUS_MORE_ENTRIES;
1142         }
1143
1144         return NT_STATUS_OK;
1145 }
1146
1147
1148 /* 
1149   samr_GetAliasMembership 
1150 */
1151 static NTSTATUS samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1152                        struct samr_GetAliasMembership *r)
1153 {
1154         struct dcesrv_handle *h;
1155         struct samr_domain_state *d_state;
1156         struct ldb_message **res;
1157         int i, count = 0;
1158
1159         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1160
1161         d_state = h->data;
1162
1163         if (r->in.sids->num_sids > 0) {
1164                 const char *filter;
1165                 const char * const attrs[2] = { "objectSid", NULL };
1166
1167                 filter = talloc_asprintf(mem_ctx,
1168                                          "(&(|(grouptype=%s)(grouptype=%s))"
1169                                          "(objectclass=group)(|",
1170                                          ldb_hexstr(mem_ctx,
1171                                                     GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
1172                                          ldb_hexstr(mem_ctx,
1173                                                     GTYPE_SECURITY_DOMAIN_LOCAL_GROUP));
1174                 if (filter == NULL)
1175                         return NT_STATUS_NO_MEMORY;
1176
1177                 for (i=0; i<r->in.sids->num_sids; i++) {
1178                         const char *memberdn;
1179
1180                         memberdn = 
1181                                 samdb_search_string(d_state->sam_ctx,
1182                                                     mem_ctx, NULL, "dn",
1183                                                     "(objectSid=%s)",
1184                                                     ldap_encode_ndr_dom_sid(mem_ctx, 
1185                                                                             r->in.sids->sids[i].sid));
1186
1187                         if (memberdn == NULL)
1188                                 continue;
1189
1190                         filter = talloc_asprintf(mem_ctx, "%s(member=%s)",
1191                                                  filter, memberdn);
1192                         if (filter == NULL)
1193                                 return NT_STATUS_NO_MEMORY;
1194                 }
1195
1196                 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1197                                             d_state->domain_dn, &res, attrs,
1198                                             d_state->domain_sid, "%s))", filter);
1199                 if (count < 0)
1200                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1201         }
1202
1203         r->out.rids->count = 0;
1204         r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1205         if (r->out.rids->ids == NULL)
1206                 return NT_STATUS_NO_MEMORY;
1207
1208         for (i=0; i<count; i++) {
1209                 struct dom_sid *alias_sid;
1210
1211                 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1212
1213                 if (alias_sid == NULL) {
1214                         DEBUG(0, ("Could not find objectSid\n"));
1215                         continue;
1216                 }
1217
1218                 r->out.rids->ids[r->out.rids->count] =
1219                         alias_sid->sub_auths[alias_sid->num_auths-1];
1220                 r->out.rids->count += 1;
1221         }
1222
1223         return NT_STATUS_OK;
1224 }
1225
1226
1227 /* 
1228   samr_LookupNames 
1229 */
1230 static NTSTATUS samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1231                                  struct samr_LookupNames *r)
1232 {
1233         struct dcesrv_handle *h;
1234         struct samr_domain_state *d_state;
1235         int i;
1236         NTSTATUS status = NT_STATUS_OK;
1237         const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1238         int count;
1239
1240         ZERO_STRUCT(r->out.rids);
1241         ZERO_STRUCT(r->out.types);
1242
1243         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1244
1245         d_state = h->data;
1246
1247         if (r->in.num_names == 0) {
1248                 return NT_STATUS_OK;
1249         }
1250
1251         r->out.rids.ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1252         r->out.types.ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1253         if (!r->out.rids.ids || !r->out.types.ids) {
1254                 return NT_STATUS_NO_MEMORY;
1255         }
1256         r->out.rids.count = r->in.num_names;
1257         r->out.types.count = r->in.num_names;
1258
1259         for (i=0;i<r->in.num_names;i++) {
1260                 struct ldb_message **res;
1261                 struct dom_sid *sid;
1262                 uint32_t atype, rtype;
1263
1264                 r->out.rids.ids[i] = 0;
1265                 r->out.types.ids[i] = SID_NAME_UNKNOWN;
1266
1267                 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs, 
1268                                      "sAMAccountName=%s", r->in.names[i].string);
1269                 if (count != 1) {
1270                         status = STATUS_SOME_UNMAPPED;
1271                         continue;
1272                 }
1273
1274                 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1275                 if (sid == NULL) {
1276                         status = STATUS_SOME_UNMAPPED;
1277                         continue;
1278                 }
1279                 
1280                 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1281                 if (atype == 0) {
1282                         status = STATUS_SOME_UNMAPPED;
1283                         continue;
1284                 }
1285
1286                 rtype = samdb_atype_map(atype);
1287                 
1288                 if (rtype == SID_NAME_UNKNOWN) {
1289                         status = STATUS_SOME_UNMAPPED;
1290                         continue;
1291                 }
1292
1293                 r->out.rids.ids[i] = sid->sub_auths[sid->num_auths-1];
1294                 r->out.types.ids[i] = rtype;
1295         }
1296         
1297
1298         return status;
1299 }
1300
1301
1302 /* 
1303   samr_LookupRids 
1304 */
1305 static NTSTATUS samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1306                        struct samr_LookupRids *r)
1307 {
1308         struct dcesrv_handle *h;
1309         struct samr_domain_state *d_state;
1310         int i, total;
1311         NTSTATUS status = NT_STATUS_OK;
1312         struct lsa_String *names;
1313         uint32_t *ids;
1314
1315         ZERO_STRUCT(r->out.names);
1316         ZERO_STRUCT(r->out.types);
1317
1318         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1319
1320         d_state = h->data;
1321
1322         if (r->in.num_rids == 0)
1323                 return NT_STATUS_OK;
1324
1325         names = talloc_array(mem_ctx, struct lsa_String, r->in.num_rids);
1326         ids = talloc_array(mem_ctx, uint32_t, r->in.num_rids);
1327
1328         if ((names == NULL) || (ids == NULL))
1329                 return NT_STATUS_NO_MEMORY;
1330
1331         total = 0;
1332
1333         for (i=0; i<r->in.num_rids; i++) {
1334                 struct ldb_message **res;
1335                 int count;
1336                 const char * const attrs[] = {  "sAMAccountType",
1337                                                 "sAMAccountName", NULL };
1338                 uint32_t atype;
1339                 struct dom_sid *sid;
1340
1341                 ids[i] = SID_NAME_UNKNOWN;
1342
1343                 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rids[i]);
1344                 if (sid == NULL) {
1345                         names[i].string = NULL;
1346                         status = STATUS_SOME_UNMAPPED;
1347                         continue;
1348                 }
1349                 
1350                 count = gendb_search(d_state->sam_ctx, mem_ctx,
1351                                      d_state->domain_dn, &res, attrs,
1352                                      "(objectSid=%s)", 
1353                                      ldap_encode_ndr_dom_sid(mem_ctx, sid));
1354                 if (count != 1) {
1355                         names[i].string = NULL;
1356                         status = STATUS_SOME_UNMAPPED;
1357                         continue;
1358                 }
1359
1360                 names[i].string = samdb_result_string(res[0], "sAMAccountName",
1361                                                       NULL);
1362
1363                 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1364                 if (atype == 0) {
1365                         status = STATUS_SOME_UNMAPPED;
1366                         continue;
1367                 }
1368
1369                 ids[i] = samdb_atype_map(atype);
1370                 
1371                 if (ids[i] == SID_NAME_UNKNOWN) {
1372                         status = STATUS_SOME_UNMAPPED;
1373                         continue;
1374                 }
1375         }
1376
1377         r->out.names.names = names;
1378         r->out.names.count = r->in.num_rids;
1379
1380         r->out.types.ids = ids;
1381         r->out.types.count = r->in.num_rids;
1382
1383         return status;
1384 }
1385
1386
1387 /* 
1388   samr_OpenGroup 
1389 */
1390 static NTSTATUS samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1391                        struct samr_OpenGroup *r)
1392 {
1393         struct samr_domain_state *d_state;
1394         struct samr_account_state *a_state;
1395         struct dcesrv_handle *h;
1396         const char *groupname;
1397         struct dom_sid *sid;
1398         struct ldb_message **msgs;
1399         struct dcesrv_handle *g_handle;
1400         const char * const attrs[2] = { "sAMAccountName", NULL };
1401         int ret;
1402
1403         ZERO_STRUCTP(r->out.group_handle);
1404
1405         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1406
1407         d_state = h->data;
1408
1409         /* form the group SID */
1410         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1411         if (!sid) {
1412                 return NT_STATUS_NO_MEMORY;
1413         }
1414
1415         /* search for the group record */
1416         ret = gendb_search(d_state->sam_ctx,
1417                            mem_ctx, d_state->domain_dn, &msgs, attrs,
1418                            "(&(objectSid=%s)(objectclass=group)"
1419                            "(grouptype=%s))",
1420                            ldap_encode_ndr_dom_sid(mem_ctx, sid),
1421                            ldb_hexstr(mem_ctx,
1422                                       GTYPE_SECURITY_GLOBAL_GROUP));
1423         if (ret == 0) {
1424                 return NT_STATUS_NO_SUCH_GROUP;
1425         }
1426         if (ret != 1) {
1427                 DEBUG(0,("Found %d records matching sid %s\n", 
1428                          ret, dom_sid_string(mem_ctx, sid)));
1429                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1430         }
1431
1432         groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
1433         if (groupname == NULL) {
1434                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
1435                          dom_sid_string(mem_ctx, sid)));
1436                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1437         }
1438
1439         a_state = talloc(d_state, struct samr_account_state);
1440         if (!a_state) {
1441                 return NT_STATUS_NO_MEMORY;
1442         }
1443         a_state->sam_ctx = d_state->sam_ctx;
1444         a_state->access_mask = r->in.access_mask;
1445         a_state->domain_state = talloc_reference(a_state, d_state);
1446         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1447         a_state->account_sid = talloc_steal(a_state, sid);
1448         a_state->account_name = talloc_strdup(a_state, groupname);
1449         if (!a_state->account_name) {
1450                 return NT_STATUS_NO_MEMORY;
1451         }
1452
1453         /* create the policy handle */
1454         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1455         if (!g_handle) {
1456                 return NT_STATUS_NO_MEMORY;
1457         }
1458
1459         g_handle->data = talloc_steal(g_handle, a_state);
1460
1461         *r->out.group_handle = g_handle->wire_handle;
1462
1463         return NT_STATUS_OK;
1464 }
1465
1466 /* these query macros make samr_Query[User|Group]Info a bit easier to read */
1467
1468 #define QUERY_STRING(msg, field, attr) \
1469         r->out.info->field = samdb_result_string(msg, attr, "");
1470 #define QUERY_UINT(msg, field, attr) \
1471         r->out.info->field = samdb_result_uint(msg, attr, 0);
1472 #define QUERY_RID(msg, field, attr) \
1473         r->out.info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
1474 #define QUERY_NTTIME(msg, field, attr) \
1475         r->out.info->field = samdb_result_nttime(msg, attr, 0);
1476 #define QUERY_APASSC(msg, field, attr) \
1477         r->out.info->field = samdb_result_allow_password_change(a_state->sam_ctx, mem_ctx, \
1478                                                            a_state->domain_state->domain_dn, msg, attr);
1479 #define QUERY_FPASSC(msg, field, attr) \
1480         r->out.info->field = samdb_result_force_password_change(a_state->sam_ctx, mem_ctx, \
1481                                                            a_state->domain_state->domain_dn, msg, attr);
1482 #define QUERY_LHOURS(msg, field, attr) \
1483         r->out.info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
1484 #define QUERY_AFLAGS(msg, field, attr) \
1485         r->out.info->field = samdb_result_acct_flags(msg, attr);
1486
1487
1488 /* these are used to make the Set[User|Group]Info code easier to follow */
1489
1490 #define SET_STRING(mod, field, attr) do { \
1491         if (r->in.info->field == NULL) return NT_STATUS_INVALID_PARAMETER; \
1492         if (samdb_msg_add_string(a_state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
1493                 return NT_STATUS_NO_MEMORY; \
1494         } \
1495 } while (0)
1496
1497 #define SET_UINT(mod, field, attr) do { \
1498         if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
1499                 return NT_STATUS_NO_MEMORY; \
1500         } \
1501 } while (0)
1502
1503 #define SET_AFLAGS(msg, field, attr) do { \
1504         if (samdb_msg_add_acct_flags(a_state->sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
1505                 return NT_STATUS_NO_MEMORY; \
1506         } \
1507 } while (0)
1508
1509 #define SET_LHOURS(msg, field, attr) do { \
1510         if (samdb_msg_add_logon_hours(a_state->sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
1511                 return NT_STATUS_NO_MEMORY; \
1512         } \
1513 } while (0)
1514
1515 /* 
1516   samr_QueryGroupInfo 
1517 */
1518 static NTSTATUS samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1519                        struct samr_QueryGroupInfo *r)
1520 {
1521         struct dcesrv_handle *h;
1522         struct samr_account_state *a_state;
1523         struct ldb_message *msg, **res;
1524         const char * const attrs[4] = { "sAMAccountName", "description",
1525                                         "numMembers", NULL };
1526         int ret;
1527
1528         r->out.info = NULL;
1529
1530         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1531
1532         a_state = h->data;
1533
1534         /* pull all the group attributes */
1535         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
1536                               a_state->account_dn, &res, attrs);
1537         if (ret != 1) {
1538                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1539         }
1540         msg = res[0];
1541
1542         /* allocate the info structure */
1543         r->out.info = talloc(mem_ctx, union samr_GroupInfo);
1544         if (r->out.info == NULL) {
1545                 return NT_STATUS_NO_MEMORY;
1546         }
1547         ZERO_STRUCTP(r->out.info);
1548
1549         /* Fill in the level */
1550         switch (r->in.level) {
1551         case GROUPINFOALL:
1552                 QUERY_STRING(msg, all.name.string,        "sAMAccountName");
1553                 r->out.info->all.attributes = 7; /* Do like w2k3 */
1554                 QUERY_UINT  (msg, all.num_members,      "numMembers")
1555                 QUERY_STRING(msg, all.description.string, "description");
1556                 break;
1557         case GROUPINFONAME:
1558                 QUERY_STRING(msg, name.string,            "sAMAccountName");
1559                 break;
1560         case GROUPINFOX:
1561                 r->out.info->unknown.unknown = 7;
1562                 break;
1563         case GROUPINFODESCRIPTION:
1564                 QUERY_STRING(msg, description.string, "description");
1565                 break;
1566         default:
1567                 r->out.info = NULL;
1568                 return NT_STATUS_INVALID_INFO_CLASS;
1569         }
1570         
1571         return NT_STATUS_OK;
1572 }
1573
1574
1575 /* 
1576   samr_SetGroupInfo 
1577 */
1578 static NTSTATUS samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1579                                   struct samr_SetGroupInfo *r)
1580 {
1581         struct dcesrv_handle *h;
1582         struct samr_account_state *a_state;
1583         struct ldb_message *msg;
1584         int ret;
1585
1586         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1587
1588         a_state = h->data;
1589
1590         msg = ldb_msg_new(mem_ctx);
1591         if (msg == NULL) {
1592                 return NT_STATUS_NO_MEMORY;
1593         }       
1594
1595         msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
1596         if (!msg->dn) {
1597                 return NT_STATUS_NO_MEMORY;
1598         }
1599
1600         switch (r->in.level) {
1601         case GROUPINFODESCRIPTION:
1602                 SET_STRING(msg, description.string,         "description");
1603                 break;
1604         case GROUPINFONAME:
1605                 /* On W2k3 this does not change the name, it changes the
1606                  * sAMAccountName attribute */
1607                 SET_STRING(msg, name.string,                "sAMAccountName");
1608                 break;
1609         case GROUPINFOX:
1610                 /* This does not do anything obviously visible in W2k3 LDAP */
1611                 break;
1612         default:
1613                 return NT_STATUS_INVALID_INFO_CLASS;
1614         }
1615
1616         /* modify the samdb record */
1617         ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
1618         if (ret != 0) {
1619                 /* we really need samdb.c to return NTSTATUS */
1620                 return NT_STATUS_UNSUCCESSFUL;
1621         }
1622
1623         return NT_STATUS_OK;
1624 }
1625
1626
1627 /* 
1628   samr_AddGroupMember 
1629 */
1630 static NTSTATUS samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1631                        struct samr_AddGroupMember *r)
1632 {
1633         struct dcesrv_handle *h;
1634         struct samr_account_state *a_state;
1635         struct samr_domain_state *d_state;
1636         struct ldb_message *mod;
1637         struct dom_sid *membersid;
1638         const char *memberdn;
1639         struct ldb_message **msgs;
1640         const char * const attrs[2] = { "dn", NULL };
1641         int ret;
1642
1643         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1644
1645         a_state = h->data;
1646         d_state = a_state->domain_state;
1647
1648         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1649         if (membersid == NULL)
1650                 return NT_STATUS_NO_MEMORY;
1651
1652         /* In native mode, AD can also nest domain groups. Not sure yet
1653          * whether this is also available via RPC. */
1654         ret = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn,
1655                            &msgs, attrs, "(&(objectSid=%s)(objectclass=user))",
1656                            ldap_encode_ndr_dom_sid(mem_ctx, membersid));
1657
1658         if (ret == 0)
1659                 return NT_STATUS_NO_SUCH_USER;
1660
1661         if (ret > 1)
1662                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1663
1664         memberdn = samdb_result_string(msgs[0], "dn", NULL);
1665
1666         if (memberdn == NULL)
1667                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1668
1669         mod = ldb_msg_new(mem_ctx);
1670         if (mod == NULL) {
1671                 return NT_STATUS_NO_MEMORY;
1672         }
1673
1674         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
1675
1676         if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
1677                                  memberdn) != 0)
1678                 return NT_STATUS_UNSUCCESSFUL;
1679
1680         if (samdb_modify(a_state->sam_ctx, mem_ctx, mod) != 0)
1681                 return NT_STATUS_UNSUCCESSFUL;
1682
1683         return NT_STATUS_OK;
1684 }
1685
1686
1687 /* 
1688   samr_DeleteDomainGroup 
1689 */
1690 static NTSTATUS samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1691                        struct samr_DeleteDomainGroup *r)
1692 {
1693         struct dcesrv_handle *h;
1694         struct samr_account_state *a_state;
1695         int ret;
1696
1697         *r->out.group_handle = *r->in.group_handle;
1698
1699         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1700
1701         a_state = h->data;
1702
1703         ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
1704         if (ret != 0) {
1705                 return NT_STATUS_UNSUCCESSFUL;
1706         }
1707
1708         ZERO_STRUCTP(r->out.group_handle);
1709
1710         return NT_STATUS_OK;
1711 }
1712
1713
1714 /* 
1715   samr_DeleteGroupMember 
1716 */
1717 static NTSTATUS samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1718                        struct samr_DeleteGroupMember *r)
1719 {
1720         struct dcesrv_handle *h;
1721         struct samr_account_state *a_state;
1722         struct samr_domain_state *d_state;
1723         struct ldb_message *mod;
1724         struct dom_sid *membersid;
1725         const char *memberdn;
1726         struct ldb_message **msgs;
1727         const char * const attrs[2] = { "dn", NULL };
1728         int ret;
1729
1730         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1731
1732         a_state = h->data;
1733         d_state = a_state->domain_state;
1734
1735         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1736         if (membersid == NULL)
1737                 return NT_STATUS_NO_MEMORY;
1738
1739         /* In native mode, AD can also nest domain groups. Not sure yet
1740          * whether this is also available via RPC. */
1741         ret = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn,
1742                            &msgs, attrs, "(&(objectSid=%s)(objectclass=user))",
1743                            ldap_encode_ndr_dom_sid(mem_ctx, membersid));
1744
1745         if (ret == 0)
1746                 return NT_STATUS_NO_SUCH_USER;
1747
1748         if (ret > 1)
1749                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1750
1751         memberdn = samdb_result_string(msgs[0], "dn", NULL);
1752
1753         if (memberdn == NULL)
1754                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1755
1756         mod = ldb_msg_new(mem_ctx);
1757         if (mod == NULL) {
1758                 return NT_STATUS_NO_MEMORY;
1759         }
1760
1761         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
1762
1763         if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
1764                                  memberdn) != 0)
1765                 return NT_STATUS_UNSUCCESSFUL;
1766
1767         if (samdb_modify(a_state->sam_ctx, mem_ctx, mod) != 0)
1768                 return NT_STATUS_UNSUCCESSFUL;
1769
1770         return NT_STATUS_OK;
1771 }
1772
1773
1774 /* 
1775   samr_QueryGroupMember 
1776 */
1777 static NTSTATUS samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1778                        struct samr_QueryGroupMember *r)
1779 {
1780         struct dcesrv_handle *h;
1781         struct samr_account_state *a_state;
1782         struct ldb_message **res;
1783         struct ldb_message_element *el;
1784         struct samr_RidTypeArray *array;
1785         const char * const attrs[2] = { "member", NULL };
1786         int ret;
1787
1788         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1789
1790         a_state = h->data;
1791
1792         /* pull the member attribute */
1793         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
1794                               a_state->account_dn, &res, attrs);
1795
1796         if (ret != 1) {
1797                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1798         }
1799
1800         array = talloc(mem_ctx, struct samr_RidTypeArray);
1801
1802         if (array == NULL)
1803                 return NT_STATUS_NO_MEMORY;
1804
1805         ZERO_STRUCTP(array);
1806
1807         el = ldb_msg_find_element(res[0], "member");
1808
1809         if (el != NULL) {
1810                 int i;
1811
1812                 array->count = el->num_values;
1813
1814                 array->rids = talloc_array(mem_ctx, uint32_t,
1815                                              el->num_values);
1816                 if (array->rids == NULL)
1817                         return NT_STATUS_NO_MEMORY;
1818
1819                 array->types = talloc_array(mem_ctx, uint32_t,
1820                                             el->num_values);
1821                 if (array->types == NULL)
1822                         return NT_STATUS_NO_MEMORY;
1823
1824                 for (i=0; i<el->num_values; i++) {
1825                         struct ldb_message **res2;
1826                         const char * const attrs2[2] = { "objectSid", NULL };
1827                         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
1828                                            ldb_dn_explode(mem_ctx, el->values[i].data),
1829                                            &res2, attrs2);
1830                         if (ret != 1)
1831                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1832
1833                         array->rids[i] =
1834                                 samdb_result_rid_from_sid(mem_ctx, res2[0],
1835                                                           "objectSid", 0);
1836
1837                         if (array->rids[i] == 0)
1838                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1839
1840                         array->types[i] = 7; /* RID type of some kind, not sure what the value means. */
1841                 }
1842         }
1843
1844         r->out.rids = array;
1845
1846         return NT_STATUS_OK;
1847 }
1848
1849
1850 /* 
1851   samr_SetMemberAttributesOfGroup 
1852 */
1853 static NTSTATUS samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1854                        struct samr_SetMemberAttributesOfGroup *r)
1855 {
1856         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1857 }
1858
1859
1860 /* 
1861   samr_OpenAlias 
1862 */
1863 static NTSTATUS samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1864                        struct samr_OpenAlias *r)
1865 {
1866         struct samr_domain_state *d_state;
1867         struct samr_account_state *a_state;
1868         struct dcesrv_handle *h;
1869         const char *alias_name;
1870         struct dom_sid *sid;
1871         struct ldb_message **msgs;
1872         struct dcesrv_handle *g_handle;
1873         const char * const attrs[2] = { "sAMAccountName", NULL };
1874         int ret;
1875
1876         ZERO_STRUCTP(r->out.alias_handle);
1877
1878         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1879
1880         d_state = h->data;
1881
1882         /* form the alias SID */
1883         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1884         if (sid == NULL)
1885                 return NT_STATUS_NO_MEMORY;
1886
1887         /* search for the group record */
1888         ret = gendb_search(d_state->sam_ctx,
1889                            mem_ctx, d_state->domain_dn, &msgs, attrs,
1890                            "(&(objectSid=%s)(objectclass=group)"
1891                            "(|(grouptype=%s)(grouptype=%s)))",
1892                            ldap_encode_ndr_dom_sid(mem_ctx, sid),
1893                            ldb_hexstr(mem_ctx,
1894                                       GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
1895                            ldb_hexstr(mem_ctx,
1896                                       GTYPE_SECURITY_DOMAIN_LOCAL_GROUP));
1897         if (ret == 0) {
1898                 return NT_STATUS_NO_SUCH_ALIAS;
1899         }
1900         if (ret != 1) {
1901                 DEBUG(0,("Found %d records matching sid %s\n", 
1902                          ret, dom_sid_string(mem_ctx, sid)));
1903                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1904         }
1905
1906         alias_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
1907         if (alias_name == NULL) {
1908                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
1909                          dom_sid_string(mem_ctx, sid)));
1910                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1911         }
1912
1913         a_state = talloc(d_state, struct samr_account_state);
1914         if (!a_state) {
1915                 return NT_STATUS_NO_MEMORY;
1916         }
1917         a_state->sam_ctx = d_state->sam_ctx;
1918         a_state->access_mask = r->in.access_mask;
1919         a_state->domain_state = talloc_reference(a_state, d_state);
1920         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1921         a_state->account_sid = talloc_steal(a_state, sid);
1922         a_state->account_name = talloc_strdup(a_state, alias_name);
1923         if (!a_state->account_name) {
1924                 return NT_STATUS_NO_MEMORY;
1925         }
1926
1927         /* create the policy handle */
1928         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1929         if (!g_handle) {
1930                 return NT_STATUS_NO_MEMORY;
1931         }
1932
1933         g_handle->data = talloc_steal(g_handle, a_state);
1934
1935         *r->out.alias_handle = g_handle->wire_handle;
1936
1937         return NT_STATUS_OK;
1938 }
1939
1940
1941 /* 
1942   samr_QueryAliasInfo 
1943 */
1944 static NTSTATUS samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1945                        struct samr_QueryAliasInfo *r)
1946 {
1947         struct dcesrv_handle *h;
1948         struct samr_account_state *a_state;
1949         struct ldb_message *msg, **res;
1950         const char * const attrs[4] = { "sAMAccountName", "description",
1951                                         "numMembers", NULL };
1952         int ret;
1953
1954         r->out.info = NULL;
1955
1956         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
1957
1958         a_state = h->data;
1959
1960         /* pull all the alias attributes */
1961         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
1962                               a_state->account_dn ,&res, attrs);
1963         if (ret != 1) {
1964                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1965         }
1966         msg = res[0];
1967
1968         /* allocate the info structure */
1969         r->out.info = talloc(mem_ctx, union samr_AliasInfo);
1970         if (r->out.info == NULL) {
1971                 return NT_STATUS_NO_MEMORY;
1972         }
1973         ZERO_STRUCTP(r->out.info);
1974
1975         switch(r->in.level) {
1976         case ALIASINFOALL:
1977                 QUERY_STRING(msg, all.name.string, "sAMAccountName");
1978                 QUERY_UINT  (msg, all.num_members, "numMembers");
1979                 QUERY_STRING(msg, all.description.string, "description");
1980                 break;
1981         case ALIASINFONAME:
1982                 QUERY_STRING(msg, name.string, "sAMAccountName");
1983                 break;
1984         case ALIASINFODESCRIPTION:
1985                 QUERY_STRING(msg, description.string, "description");
1986                 break;
1987         default:
1988                 r->out.info = NULL;
1989                 return NT_STATUS_INVALID_INFO_CLASS;
1990         }
1991         
1992         return NT_STATUS_OK;
1993 }
1994
1995
1996 /* 
1997   samr_SetAliasInfo 
1998 */
1999 static NTSTATUS samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2000                        struct samr_SetAliasInfo *r)
2001 {
2002         struct dcesrv_handle *h;
2003         struct samr_account_state *a_state;
2004         struct ldb_message *msg;
2005         int ret;
2006
2007         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2008
2009         a_state = h->data;
2010
2011         msg = ldb_msg_new(mem_ctx);
2012         if (msg == NULL) {
2013                 return NT_STATUS_NO_MEMORY;
2014         }
2015
2016         msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2017         if (!msg->dn) {
2018                 return NT_STATUS_NO_MEMORY;
2019         }
2020
2021         switch (r->in.level) {
2022         case ALIASINFODESCRIPTION:
2023                 SET_STRING(msg, description.string,         "description");
2024                 break;
2025         case ALIASINFONAME:
2026                 /* On W2k3 this does not change the name, it changes the
2027                  * sAMAccountName attribute */
2028                 SET_STRING(msg, name.string,                "sAMAccountName");
2029                 break;
2030         default:
2031                 return NT_STATUS_INVALID_INFO_CLASS;
2032         }
2033
2034         /* modify the samdb record */
2035         ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
2036         if (ret != 0) {
2037                 /* we really need samdb.c to return NTSTATUS */
2038                 return NT_STATUS_UNSUCCESSFUL;
2039         }
2040
2041         return NT_STATUS_OK;
2042 }
2043
2044
2045 /* 
2046   samr_DeleteDomAlias 
2047 */
2048 static NTSTATUS samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2049                        struct samr_DeleteDomAlias *r)
2050 {
2051         struct dcesrv_handle *h;
2052         struct samr_account_state *a_state;
2053         int ret;
2054
2055         *r->out.alias_handle = *r->in.alias_handle;
2056
2057         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2058
2059         a_state = h->data;
2060
2061         ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
2062         if (ret != 0) {
2063                 return NT_STATUS_UNSUCCESSFUL;
2064         }
2065
2066         ZERO_STRUCTP(r->out.alias_handle);
2067
2068         return NT_STATUS_OK;
2069 }
2070
2071
2072 /* 
2073   samr_AddAliasMember 
2074 */
2075 static NTSTATUS samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2076                        struct samr_AddAliasMember *r)
2077 {
2078         struct dcesrv_handle *h;
2079         struct samr_account_state *a_state;
2080         struct samr_domain_state *d_state;
2081         struct ldb_message *mod;
2082         struct ldb_message **msgs;
2083         const char * const attrs[2] = { "dn", NULL };
2084         struct ldb_dn *memberdn = NULL;
2085         int ret;
2086
2087         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2088
2089         a_state = h->data;
2090         d_state = a_state->domain_state;
2091
2092         ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2093                            &msgs, attrs, "(objectsid=%s)", 
2094                            ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2095
2096         if (ret == 1) {
2097                 memberdn = ldb_dn_explode(mem_ctx, ldb_msg_find_string(msgs[0], "dn", NULL));
2098         } else  if (ret > 1) {
2099                 DEBUG(0,("Found %d records matching sid %s\n", 
2100                          ret, dom_sid_string(mem_ctx, r->in.sid)));
2101                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2102         } else if (ret == 0) {
2103                 struct ldb_message *msg;
2104                 struct ldb_dn *basedn;
2105                 const char *sidstr;
2106
2107                 sidstr = dom_sid_string(mem_ctx, r->in.sid);
2108                 NT_STATUS_HAVE_NO_MEMORY(sidstr);
2109
2110                 /* We might have to create a ForeignSecurityPrincipal, but
2111                  * only if it's not our own domain */
2112                 if (dom_sid_in_domain(d_state->domain_sid, r->in.sid))
2113                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2114
2115                 msg = ldb_msg_new(mem_ctx);
2116                 if (msg == NULL) {
2117                         return NT_STATUS_NO_MEMORY;
2118                 }
2119
2120                 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
2121                  * put the ForeignSecurityPrincipals? d_state->domain_dn does
2122                  * not work, this is wrong for the Builtin domain, there's no
2123                  * cn=For...,cn=Builtin,dc={BASEDN}.  -- vl
2124                  */
2125
2126                 basedn = ldb_dn_explode(mem_ctx,
2127                                         samdb_search_string(d_state->sam_ctx,
2128                                                             mem_ctx, NULL, "dn",
2129                                                             "(&(objectClass=container)"
2130                                                             "(cn=ForeignSecurityPrincipals))"));
2131
2132                 if (basedn == NULL) {
2133                         DEBUG(0, ("Failed to find DN for "
2134                                   "ForeignSecurityPrincipal container\n"));
2135                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
2136                 }
2137
2138                 /* add core elements to the ldb_message for the alias */
2139                 msg->dn = ldb_dn_build_child(mem_ctx, "CN", sidstr, basedn);
2140                 if (msg->dn == NULL)
2141                         return NT_STATUS_NO_MEMORY;
2142
2143                 memberdn = msg->dn;
2144
2145                 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg,
2146                                      "objectClass",
2147                                      "foreignSecurityPrincipal");
2148
2149                 /* create the alias */
2150                 ret = samdb_add(d_state->sam_ctx, mem_ctx, msg);
2151                 if (ret != 0) {
2152                         DEBUG(0,("Failed to create foreignSecurityPrincipal "
2153                                  "record %s\n", ldb_dn_linearize(mem_ctx, msg->dn)));
2154                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
2155                 }
2156         } else {
2157                 DEBUG(0, ("samdb_search returned %d\n", ret));
2158         }
2159
2160         if (memberdn == NULL) {
2161                 DEBUG(0, ("Could not find memberdn\n"));
2162                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2163         }
2164
2165         mod = ldb_msg_new(mem_ctx);
2166         if (mod == NULL) {
2167                 return NT_STATUS_NO_MEMORY;
2168         }
2169
2170         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2171
2172         if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2173                                  ldb_dn_linearize(mem_ctx, memberdn)) != 0)
2174                 return NT_STATUS_UNSUCCESSFUL;
2175
2176         if (samdb_modify(a_state->sam_ctx, mem_ctx, mod) != 0)
2177                 return NT_STATUS_UNSUCCESSFUL;
2178
2179         return NT_STATUS_OK;
2180 }
2181
2182
2183 /* 
2184   samr_DeleteAliasMember 
2185 */
2186 static NTSTATUS samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2187                        struct samr_DeleteAliasMember *r)
2188 {
2189         struct dcesrv_handle *h;
2190         struct samr_account_state *a_state;
2191         struct samr_domain_state *d_state;
2192         struct ldb_message *mod;
2193         const char *memberdn;
2194
2195         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2196
2197         a_state = h->data;
2198         d_state = a_state->domain_state;
2199
2200         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2201                                        "dn", "(objectSid=%s)", 
2202                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2203
2204         if (memberdn == NULL)
2205                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2206
2207         mod = ldb_msg_new(mem_ctx);
2208         if (mod == NULL) {
2209                 return NT_STATUS_NO_MEMORY;
2210         }
2211
2212         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2213
2214         if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2215                                  memberdn) != 0)
2216                 return NT_STATUS_UNSUCCESSFUL;
2217
2218         if (samdb_modify(a_state->sam_ctx, mem_ctx, mod) != 0)
2219                 return NT_STATUS_UNSUCCESSFUL;
2220
2221         return NT_STATUS_OK;
2222 }
2223
2224
2225 /* 
2226   samr_GetMembersInAlias 
2227 */
2228 static NTSTATUS samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2229                        struct samr_GetMembersInAlias *r)
2230 {
2231         struct dcesrv_handle *h;
2232         struct samr_account_state *a_state;
2233         struct samr_domain_state *d_state;
2234         struct ldb_message **msgs;
2235         struct lsa_SidPtr *sids;
2236         struct ldb_message_element *el;
2237         const char * const attrs[2] = { "member", NULL};
2238         int ret;
2239
2240         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2241
2242         a_state = h->data;
2243         d_state = a_state->domain_state;
2244
2245         ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
2246                               a_state->account_dn, &msgs, attrs);
2247
2248         if (ret != 1)
2249                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2250
2251         r->out.sids->num_sids = 0;
2252         r->out.sids->sids = NULL;
2253
2254         el = ldb_msg_find_element(msgs[0], "member");
2255
2256         if (el != NULL) {
2257                 int i;
2258
2259                 sids = talloc_array(mem_ctx, struct lsa_SidPtr,
2260                                       el->num_values);
2261
2262                 if (sids == NULL)
2263                         return NT_STATUS_NO_MEMORY;
2264
2265                 for (i=0; i<el->num_values; i++) {
2266                         struct ldb_message **msgs2;
2267                         const char * const attrs2[2] = { "objectSid", NULL };
2268                         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2269                                            ldb_dn_explode(mem_ctx, el->values[i].data),
2270                                            &msgs2, attrs2);
2271                         if (ret != 1)
2272                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2273
2274                         sids[i].sid = samdb_result_dom_sid(mem_ctx, msgs2[0],
2275                                                            "objectSid");
2276
2277                         if (sids[i].sid == NULL)
2278                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2279                 }
2280                 r->out.sids->num_sids = el->num_values;
2281                 r->out.sids->sids = sids;
2282         }
2283
2284         return NT_STATUS_OK;
2285 }
2286
2287 /* 
2288   samr_OpenUser 
2289 */
2290 static NTSTATUS samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2291                               struct samr_OpenUser *r)
2292 {
2293         struct samr_domain_state *d_state;
2294         struct samr_account_state *a_state;
2295         struct dcesrv_handle *h;
2296         const char *account_name;
2297         struct dom_sid *sid;
2298         struct ldb_message **msgs;
2299         struct dcesrv_handle *u_handle;
2300         const char * const attrs[2] = { "sAMAccountName", NULL };
2301         int ret;
2302
2303         ZERO_STRUCTP(r->out.user_handle);
2304
2305         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2306
2307         d_state = h->data;
2308
2309         /* form the users SID */
2310         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2311         if (!sid) {
2312                 return NT_STATUS_NO_MEMORY;
2313         }
2314
2315         /* search for the user record */
2316         ret = gendb_search(d_state->sam_ctx,
2317                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2318                            "(&(objectSid=%s)(objectclass=user))", 
2319                            ldap_encode_ndr_dom_sid(mem_ctx, sid));
2320         if (ret == 0) {
2321                 return NT_STATUS_NO_SUCH_USER;
2322         }
2323         if (ret != 1) {
2324                 DEBUG(0,("Found %d records matching sid %s\n", ret, 
2325                          dom_sid_string(mem_ctx, sid)));
2326                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2327         }
2328
2329         account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2330         if (account_name == NULL) {
2331                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2332                          dom_sid_string(mem_ctx, sid)));
2333                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2334         }
2335
2336         a_state = talloc(mem_ctx, struct samr_account_state);
2337         if (!a_state) {
2338                 return NT_STATUS_NO_MEMORY;
2339         }
2340         a_state->sam_ctx = d_state->sam_ctx;
2341         a_state->access_mask = r->in.access_mask;
2342         a_state->domain_state = talloc_reference(a_state, d_state);
2343         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2344         a_state->account_sid = talloc_steal(a_state, sid);
2345         a_state->account_name = talloc_strdup(a_state, account_name);
2346         if (!a_state->account_name) {
2347                 return NT_STATUS_NO_MEMORY;
2348         }
2349
2350         /* create the policy handle */
2351         u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2352         if (!u_handle) {
2353                 return NT_STATUS_NO_MEMORY;
2354         }
2355
2356         u_handle->data = talloc_steal(u_handle, a_state);
2357
2358         *r->out.user_handle = u_handle->wire_handle;
2359
2360         return NT_STATUS_OK;
2361
2362 }
2363
2364
2365 /* 
2366   samr_DeleteUser 
2367 */
2368 static NTSTATUS samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2369                                 struct samr_DeleteUser *r)
2370 {
2371         struct dcesrv_handle *h;
2372         struct samr_account_state *a_state;
2373         int ret;
2374
2375         *r->out.user_handle = *r->in.user_handle;
2376
2377         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2378
2379         a_state = h->data;
2380
2381         ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
2382         if (ret != 0) {
2383                 return NT_STATUS_UNSUCCESSFUL;
2384         }
2385
2386         ZERO_STRUCTP(r->out.user_handle);
2387
2388         return NT_STATUS_OK;
2389 }
2390
2391
2392 /* 
2393   samr_QueryUserInfo 
2394 */
2395 static NTSTATUS samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2396                                    struct samr_QueryUserInfo *r)
2397 {
2398         struct dcesrv_handle *h;
2399         struct samr_account_state *a_state;
2400         struct ldb_message *msg, **res;
2401         int ret;
2402
2403         r->out.info = NULL;
2404
2405         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2406
2407         a_state = h->data;
2408
2409         /* pull all the user attributes */
2410         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2411                               a_state->account_dn ,&res, NULL);
2412         if (ret != 1) {
2413                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2414         }
2415         msg = res[0];
2416
2417         /* allocate the info structure */
2418         r->out.info = talloc(mem_ctx, union samr_UserInfo);
2419         if (r->out.info == NULL) {
2420                 return NT_STATUS_NO_MEMORY;
2421         }
2422         ZERO_STRUCTP(r->out.info);
2423
2424         /* fill in the reply */
2425         switch (r->in.level) {
2426         case 1:
2427                 QUERY_STRING(msg, info1.account_name.string,   "sAMAccountName");
2428                 QUERY_STRING(msg, info1.full_name.string,      "displayName");
2429                 QUERY_UINT  (msg, info1.primary_gid,           "primaryGroupID");
2430                 QUERY_STRING(msg, info1.description.string,    "description");
2431                 QUERY_STRING(msg, info1.comment.string,        "comment");
2432                 break;
2433
2434         case 2:
2435                 QUERY_STRING(msg, info2.comment.string,        "comment");
2436                 QUERY_UINT  (msg, info2.country_code,          "countryCode");
2437                 QUERY_UINT  (msg, info2.code_page,             "codePage");
2438                 break;
2439
2440         case 3:
2441                 QUERY_STRING(msg, info3.account_name.string,   "sAMAccountName");
2442                 QUERY_STRING(msg, info3.full_name.string,      "displayName");
2443                 QUERY_RID   (msg, info3.rid,                   "objectSid");
2444                 QUERY_UINT  (msg, info3.primary_gid,           "primaryGroupID");
2445                 QUERY_STRING(msg, info3.home_directory.string, "homeDirectory");
2446                 QUERY_STRING(msg, info3.home_drive.string,     "homeDrive");
2447                 QUERY_STRING(msg, info3.logon_script.string,   "scriptPath");
2448                 QUERY_STRING(msg, info3.profile_path.string,   "profilePath");
2449                 QUERY_STRING(msg, info3.workstations.string,   "userWorkstations");
2450                 QUERY_NTTIME(msg, info3.last_logon,            "lastLogon");
2451                 QUERY_NTTIME(msg, info3.last_logoff,           "lastLogoff");
2452                 QUERY_NTTIME(msg, info3.last_password_change,  "pwdLastSet");
2453                 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
2454                 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
2455                 QUERY_LHOURS(msg, info3.logon_hours,           "logonHours");
2456                 QUERY_UINT  (msg, info3.bad_password_count,    "badPwdCount");
2457                 QUERY_UINT  (msg, info3.logon_count,           "logonCount");
2458                 QUERY_AFLAGS(msg, info3.acct_flags,            "userAccountControl");
2459                 break;
2460
2461         case 4:
2462                 QUERY_LHOURS(msg, info4.logon_hours,           "logonHours");
2463                 break;
2464
2465         case 5:
2466                 QUERY_STRING(msg, info5.account_name.string,   "sAMAccountName");
2467                 QUERY_STRING(msg, info5.full_name.string,      "displayName");
2468                 QUERY_RID   (msg, info5.rid,                   "objectSid");
2469                 QUERY_UINT  (msg, info5.primary_gid,           "primaryGroupID");
2470                 QUERY_STRING(msg, info5.home_directory.string, "homeDirectory");
2471                 QUERY_STRING(msg, info5.home_drive.string,     "homeDrive");
2472                 QUERY_STRING(msg, info5.logon_script.string,   "scriptPath");
2473                 QUERY_STRING(msg, info5.profile_path.string,   "profilePath");
2474                 QUERY_STRING(msg, info5.description.string,    "description");
2475                 QUERY_STRING(msg, info5.workstations.string,   "userWorkstations");
2476                 QUERY_NTTIME(msg, info5.last_logon,            "lastLogon");
2477                 QUERY_NTTIME(msg, info5.last_logoff,           "lastLogoff");
2478                 QUERY_LHOURS(msg, info5.logon_hours,           "logonHours");
2479                 QUERY_UINT  (msg, info5.bad_password_count,    "badPwdCount");
2480                 QUERY_UINT  (msg, info5.logon_count,           "logonCount");
2481                 QUERY_NTTIME(msg, info5.last_password_change,  "pwdLastSet");
2482                 QUERY_NTTIME(msg, info5.acct_expiry,           "accountExpires");
2483                 QUERY_AFLAGS(msg, info5.acct_flags,            "userAccountControl");
2484                 break;
2485
2486         case 6:
2487                 QUERY_STRING(msg, info6.account_name.string,   "sAMAccountName");
2488                 QUERY_STRING(msg, info6.full_name.string,      "displayName");
2489                 break;
2490
2491         case 7:
2492                 QUERY_STRING(msg, info7.account_name.string,   "sAMAccountName");
2493                 break;
2494
2495         case 8:
2496                 QUERY_STRING(msg, info8.full_name.string,      "displayName");
2497                 break;
2498
2499         case 9:
2500                 QUERY_UINT  (msg, info9.primary_gid,           "primaryGroupID");
2501                 break;
2502
2503         case 10:
2504                 QUERY_STRING(msg, info10.home_directory.string,"homeDirectory");
2505                 QUERY_STRING(msg, info10.home_drive.string,    "homeDrive");
2506                 break;
2507
2508         case 11:
2509                 QUERY_STRING(msg, info11.logon_script.string,  "scriptPath");
2510                 break;
2511
2512         case 12:
2513                 QUERY_STRING(msg, info12.profile_path.string,  "profilePath");
2514                 break;
2515
2516         case 13:
2517                 QUERY_STRING(msg, info13.description.string,   "description");
2518                 break;
2519
2520         case 14:
2521                 QUERY_STRING(msg, info14.workstations.string,  "userWorkstations");
2522                 break;
2523
2524         case 16:
2525                 QUERY_AFLAGS(msg, info16.acct_flags,           "userAccountControl");
2526                 break;
2527
2528         case 17:
2529                 QUERY_NTTIME(msg, info17.acct_expiry,          "accountExpires");
2530
2531         case 20:
2532                 QUERY_STRING(msg, info20.parameters.string,    "userParameters");
2533                 break;
2534
2535         case 21:
2536                 QUERY_NTTIME(msg, info21.last_logon,           "lastLogon");
2537                 QUERY_NTTIME(msg, info21.last_logoff,          "lastLogoff");
2538                 QUERY_NTTIME(msg, info21.last_password_change, "pwdLastSet");
2539                 QUERY_NTTIME(msg, info21.acct_expiry,          "accountExpires");
2540                 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
2541                 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
2542                 QUERY_STRING(msg, info21.account_name.string,  "sAMAccountName");
2543                 QUERY_STRING(msg, info21.full_name.string,     "displayName");
2544                 QUERY_STRING(msg, info21.home_directory.string,"homeDirectory");
2545                 QUERY_STRING(msg, info21.home_drive.string,    "homeDrive");
2546                 QUERY_STRING(msg, info21.logon_script.string,  "scriptPath");
2547                 QUERY_STRING(msg, info21.profile_path.string,  "profilePath");
2548                 QUERY_STRING(msg, info21.description.string,   "description");
2549                 QUERY_STRING(msg, info21.workstations.string,  "userWorkstations");
2550                 QUERY_STRING(msg, info21.comment.string,       "comment");
2551                 QUERY_STRING(msg, info21.parameters.string,    "userParameters");
2552                 QUERY_RID   (msg, info21.rid,                  "objectSid");
2553                 QUERY_UINT  (msg, info21.primary_gid,          "primaryGroupID");
2554                 QUERY_AFLAGS(msg, info21.acct_flags,           "userAccountControl");
2555                 r->out.info->info21.fields_present = 0x00FFFFFF;
2556                 QUERY_LHOURS(msg, info21.logon_hours,          "logonHours");
2557                 QUERY_UINT  (msg, info21.bad_password_count,   "badPwdCount");
2558                 QUERY_UINT  (msg, info21.logon_count,          "logonCount");
2559                 QUERY_UINT  (msg, info21.country_code,         "countryCode");
2560                 QUERY_UINT  (msg, info21.code_page,            "codePage");
2561                 break;
2562                 
2563
2564         default:
2565                 r->out.info = NULL;
2566                 return NT_STATUS_INVALID_INFO_CLASS;
2567         }
2568         
2569         return NT_STATUS_OK;
2570 }
2571
2572
2573 /* 
2574   samr_SetUserInfo 
2575 */
2576 static NTSTATUS samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2577                                  struct samr_SetUserInfo *r)
2578 {
2579         struct dcesrv_handle *h;
2580         struct samr_account_state *a_state;
2581         struct ldb_message *msg;
2582         int ret;
2583         NTSTATUS status = NT_STATUS_OK;
2584
2585         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2586
2587         a_state = h->data;
2588
2589         msg = ldb_msg_new(mem_ctx);
2590         if (msg == NULL) {
2591                 return NT_STATUS_NO_MEMORY;
2592         }
2593
2594         msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
2595         if (!msg->dn) {
2596                 return NT_STATUS_NO_MEMORY;
2597         }
2598
2599         switch (r->in.level) {
2600         case 2:
2601                 SET_STRING(msg, info2.comment.string,          "comment");
2602                 SET_UINT  (msg, info2.country_code,            "countryCode");
2603                 SET_UINT  (msg, info2.code_page,               "codePage");
2604                 break;
2605
2606         case 4:
2607                 SET_LHOURS(msg, info4.logon_hours,             "logonHours");
2608                 break;
2609
2610         case 6:
2611                 SET_STRING(msg, info6.full_name.string,        "displayName");
2612                 break;
2613
2614         case 7:
2615                 SET_STRING(msg, info7.account_name.string,     "samAccountName");
2616                 break;
2617
2618         case 8:
2619                 SET_STRING(msg, info8.full_name.string,        "displayName");
2620                 break;
2621
2622         case 9:
2623                 SET_UINT(msg, info9.primary_gid,               "primaryGroupID");
2624                 break;
2625
2626         case 10:
2627                 SET_STRING(msg, info10.home_directory.string,  "homeDirectory");
2628                 SET_STRING(msg, info10.home_drive.string,      "homeDrive");
2629                 break;
2630
2631         case 11:
2632                 SET_STRING(msg, info11.logon_script.string,    "scriptPath");
2633                 break;
2634
2635         case 12:
2636                 SET_STRING(msg, info12.profile_path.string,    "profilePath");
2637                 break;
2638
2639         case 13:
2640                 SET_STRING(msg, info13.description.string,     "description");
2641                 break;
2642
2643         case 14:
2644                 SET_STRING(msg, info14.workstations.string,    "userWorkstations");
2645                 break;
2646
2647         case 16:
2648                 SET_AFLAGS(msg, info16.acct_flags,             "userAccountControl");
2649                 break;
2650
2651         case 20:
2652                 SET_STRING(msg, info20.parameters.string,      "userParameters");
2653                 break;
2654
2655         case 21:
2656 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
2657                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
2658                         SET_STRING(msg, info21.account_name.string, "samAccountName");
2659                 IFSET(SAMR_FIELD_FULL_NAME)         
2660                         SET_STRING(msg, info21.full_name.string,    "displayName");
2661                 IFSET(SAMR_FIELD_DESCRIPTION)  
2662                         SET_STRING(msg, info21.description.string,  "description");
2663                 IFSET(SAMR_FIELD_COMMENT)      
2664                         SET_STRING(msg, info21.comment.string,      "comment");
2665                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
2666                         SET_STRING(msg, info21.logon_script.string, "scriptPath");
2667                 IFSET(SAMR_FIELD_PROFILE_PATH)      
2668                         SET_STRING(msg, info21.profile_path.string, "profilePath");
2669                 IFSET(SAMR_FIELD_WORKSTATIONS)  
2670                         SET_STRING(msg, info21.workstations.string, "userWorkstations");
2671                 IFSET(SAMR_FIELD_LOGON_HOURS)  
2672                         SET_LHOURS(msg, info21.logon_hours,         "logonHours");
2673                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
2674                         SET_AFLAGS(msg, info21.acct_flags,          "userAccountControl");
2675                 IFSET(SAMR_FIELD_PARAMETERS)     
2676                         SET_STRING(msg, info21.parameters.string,   "userParameters");
2677                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
2678                         SET_UINT  (msg, info21.country_code,        "countryCode");
2679                 IFSET(SAMR_FIELD_CODE_PAGE)    
2680                         SET_UINT  (msg, info21.code_page,           "codePage");
2681
2682
2683                 /* Any reason the rest of these can't be set? */
2684 #undef IFSET
2685                 break;
2686
2687         case 23:
2688 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
2689                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
2690                         SET_STRING(msg, info23.info.account_name.string, "samAccountName");
2691                 IFSET(SAMR_FIELD_FULL_NAME)         
2692                         SET_STRING(msg, info23.info.full_name.string,    "displayName");
2693                 IFSET(SAMR_FIELD_DESCRIPTION)  
2694                         SET_STRING(msg, info23.info.description.string,  "description");
2695                 IFSET(SAMR_FIELD_COMMENT)      
2696                         SET_STRING(msg, info23.info.comment.string,      "comment");
2697                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
2698                         SET_STRING(msg, info23.info.logon_script.string, "scriptPath");
2699                 IFSET(SAMR_FIELD_PROFILE_PATH)      
2700                         SET_STRING(msg, info23.info.profile_path.string, "profilePath");
2701                 IFSET(SAMR_FIELD_WORKSTATIONS)  
2702                         SET_STRING(msg, info23.info.workstations.string, "userWorkstations");
2703                 IFSET(SAMR_FIELD_LOGON_HOURS)  
2704                         SET_LHOURS(msg, info23.info.logon_hours,         "logonHours");
2705                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
2706                         SET_AFLAGS(msg, info23.info.acct_flags,          "userAccountControl");
2707                 IFSET(SAMR_FIELD_PARAMETERS)     
2708                         SET_STRING(msg, info23.info.parameters.string,   "userParameters");
2709                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
2710                         SET_UINT  (msg, info23.info.country_code,        "countryCode");
2711                 IFSET(SAMR_FIELD_CODE_PAGE)    
2712                         SET_UINT  (msg, info23.info.code_page,           "codePage");
2713                 IFSET(SAMR_FIELD_PASSWORD) {
2714                         status = samr_set_password(dce_call,
2715                                                    a_state->sam_ctx,
2716                                                    a_state->account_dn,
2717                                                    a_state->domain_state->domain_dn,
2718                                                    mem_ctx, msg, 
2719                                                    &r->in.info->info23.password);
2720                 } else IFSET(SAMR_FIELD_PASSWORD2) {
2721                         status = samr_set_password(dce_call,
2722                                                    a_state->sam_ctx,
2723                                                    a_state->account_dn,
2724                                                    a_state->domain_state->domain_dn,
2725                                                    mem_ctx, msg, 
2726                                                    &r->in.info->info23.password);
2727                 }
2728 #undef IFSET
2729                 break;
2730
2731                 /* the set password levels are handled separately */
2732         case 24:
2733                 status = samr_set_password(dce_call,
2734                                            a_state->sam_ctx,
2735                                            a_state->account_dn,
2736                                            a_state->domain_state->domain_dn,
2737                                            mem_ctx, msg, 
2738                                            &r->in.info->info24.password);
2739                 break;
2740
2741         case 25:
2742 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
2743                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
2744                         SET_STRING(msg, info25.info.account_name.string, "samAccountName");
2745                 IFSET(SAMR_FIELD_FULL_NAME)         
2746                         SET_STRING(msg, info25.info.full_name.string,    "displayName");
2747                 IFSET(SAMR_FIELD_DESCRIPTION)  
2748                         SET_STRING(msg, info25.info.description.string,  "description");
2749                 IFSET(SAMR_FIELD_COMMENT)      
2750                         SET_STRING(msg, info25.info.comment.string,      "comment");
2751                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
2752                         SET_STRING(msg, info25.info.logon_script.string, "scriptPath");
2753                 IFSET(SAMR_FIELD_PROFILE_PATH)      
2754                         SET_STRING(msg, info25.info.profile_path.string, "profilePath");
2755                 IFSET(SAMR_FIELD_WORKSTATIONS)  
2756                         SET_STRING(msg, info25.info.workstations.string, "userWorkstations");
2757                 IFSET(SAMR_FIELD_LOGON_HOURS)  
2758                         SET_LHOURS(msg, info25.info.logon_hours,         "logonHours");
2759                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
2760                         SET_AFLAGS(msg, info25.info.acct_flags,          "userAccountControl");
2761                 IFSET(SAMR_FIELD_PARAMETERS)     
2762                         SET_STRING(msg, info25.info.parameters.string,   "userParameters");
2763                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
2764                         SET_UINT  (msg, info25.info.country_code,        "countryCode");
2765                 IFSET(SAMR_FIELD_CODE_PAGE)    
2766                         SET_UINT  (msg, info25.info.code_page,           "codePage");
2767                 IFSET(SAMR_FIELD_PASSWORD) {
2768                         status = samr_set_password_ex(dce_call,
2769                                                       a_state->sam_ctx,
2770                                                       a_state->account_dn,
2771                                                       a_state->domain_state->domain_dn,
2772                                                       mem_ctx, msg, 
2773                                                       &r->in.info->info25.password);
2774                 } else IFSET(SAMR_FIELD_PASSWORD2) {
2775                         status = samr_set_password_ex(dce_call,
2776                                                       a_state->sam_ctx,
2777                                                       a_state->account_dn,
2778                                                       a_state->domain_state->domain_dn,
2779                                                       mem_ctx, msg, 
2780                                                       &r->in.info->info25.password);
2781                 }
2782 #undef IFSET
2783                 break;
2784
2785                 /* the set password levels are handled separately */
2786         case 26:
2787                 status = samr_set_password_ex(dce_call,
2788                                               a_state->sam_ctx,
2789                                               a_state->account_dn,
2790                                               a_state->domain_state->domain_dn,
2791                                               mem_ctx, msg, 
2792                                               &r->in.info->info26.password);
2793                 break;
2794                 
2795
2796         default:
2797                 /* many info classes are not valid for SetUserInfo */
2798                 return NT_STATUS_INVALID_INFO_CLASS;
2799         }
2800
2801         if (!NT_STATUS_IS_OK(status)) {
2802                 return status;
2803         }
2804
2805         /* modify the samdb record */
2806         ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
2807         if (ret != 0) {
2808                 /* we really need samdb.c to return NTSTATUS */
2809                 return NT_STATUS_UNSUCCESSFUL;
2810         }
2811
2812         return NT_STATUS_OK;
2813 }
2814
2815
2816 /* 
2817   samr_GetGroupsForUser 
2818 */
2819 static NTSTATUS samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2820                        struct samr_GetGroupsForUser *r)
2821 {
2822         struct dcesrv_handle *h;
2823         struct samr_account_state *a_state;
2824         struct samr_domain_state *d_state;
2825         struct ldb_message **res;
2826         const char * const attrs[2] = { "objectSid", NULL };
2827         struct samr_RidWithAttributeArray *array;
2828         int count;
2829
2830         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2831
2832         a_state = h->data;
2833         d_state = a_state->domain_state;
2834
2835         count = samdb_search_domain(a_state->sam_ctx, mem_ctx, NULL, &res,
2836                                     attrs, d_state->domain_sid,
2837                                     "(&(member=%s)(grouptype=%s)(objectclass=group))",
2838                                     ldb_dn_linearize(mem_ctx, a_state->account_dn),
2839                                     ldb_hexstr(mem_ctx,
2840                                                GTYPE_SECURITY_GLOBAL_GROUP));
2841         if (count < 0)
2842                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2843
2844         array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
2845         if (array == NULL)
2846                 return NT_STATUS_NO_MEMORY;
2847
2848         array->count = 0;
2849         array->rids = NULL;
2850
2851         if (count > 0) {
2852                 int i;
2853                 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
2854                                             count);
2855
2856                 if (array->rids == NULL)
2857                         return NT_STATUS_NO_MEMORY;
2858
2859                 for (i=0; i<count; i++) {
2860                         struct dom_sid *group_sid;
2861
2862                         group_sid = samdb_result_dom_sid(mem_ctx, res[i],
2863                                                          "objectSid");
2864                         if (group_sid == NULL) {
2865                                 DEBUG(0, ("Couldn't find objectSid attrib\n"));
2866                                 continue;
2867                         }
2868
2869                         array->rids[array->count].rid =
2870                                 group_sid->sub_auths[group_sid->num_auths-1];
2871                         array->rids[array->count].attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
2872                         array->count += 1;
2873                 }
2874         }
2875
2876         r->out.rids = array;
2877
2878         return NT_STATUS_OK;
2879 }
2880
2881
2882 /* 
2883   samr_QueryDisplayInfo 
2884 */
2885 static NTSTATUS samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2886                        struct samr_QueryDisplayInfo *r)
2887 {
2888         struct dcesrv_handle *h;
2889         struct samr_domain_state *d_state;
2890         struct ldb_message **res;
2891         int ldb_cnt, count, i;
2892         const char * const attrs[4] = { "objectSid", "sAMAccountName",
2893                                         "description", NULL };
2894         struct samr_DispEntryFull *entriesFull = NULL;
2895         struct samr_DispEntryAscii *entriesAscii = NULL;
2896         struct samr_DispEntryGeneral * entriesGeneral = NULL;
2897         const char *filter;
2898
2899         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2900
2901         d_state = h->data;
2902
2903         switch (r->in.level) {
2904         case 1:
2905         case 4:
2906                 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
2907                                          "(sAMAccountType=%s))",
2908                                          ldb_hexstr(mem_ctx,
2909                                                     ATYPE_NORMAL_ACCOUNT));
2910                 break;
2911         case 2:
2912                 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
2913                                          "(sAMAccountType=%s))",
2914                                          ldb_hexstr(mem_ctx,
2915                                                     ATYPE_WORKSTATION_TRUST));
2916                 break;
2917         case 3:
2918         case 5:
2919                 filter = talloc_asprintf(mem_ctx, "(&(grouptype=%s)"
2920                                          "(objectclass=group))",
2921                                          ldb_hexstr(mem_ctx, GTYPE_SECURITY_GLOBAL_GROUP));
2922                 break;
2923         default:
2924                 return NT_STATUS_INVALID_INFO_CLASS;
2925         }
2926
2927         /* search for all requested objects in this domain. This could
2928            possibly be cached and resumed based on resume_key */
2929         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
2930                                       d_state->domain_dn, &res, attrs,
2931                                       d_state->domain_sid, "%s", filter);
2932         if (ldb_cnt == -1) {
2933                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2934         }
2935         if (ldb_cnt == 0 || r->in.max_entries == 0) {
2936                 return NT_STATUS_OK;
2937         }
2938
2939         switch (r->in.level) {
2940         case 1:
2941                 entriesGeneral = talloc_array(mem_ctx,
2942                                                 struct samr_DispEntryGeneral,
2943                                                 ldb_cnt);
2944                 break;
2945         case 2:
2946         case 3:
2947                 entriesFull = talloc_array(mem_ctx,
2948                                              struct samr_DispEntryFull,
2949                                              ldb_cnt);
2950                 break;
2951         case 4:
2952         case 5:
2953                 entriesAscii = talloc_array(mem_ctx,
2954                                               struct samr_DispEntryAscii,
2955                                               ldb_cnt);
2956                 break;
2957         }
2958
2959         if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
2960             (entriesAscii == NULL))
2961                 return NT_STATUS_NO_MEMORY;
2962
2963         count = 0;
2964
2965         for (i=0; i<ldb_cnt; i++) {
2966                 struct dom_sid *objectsid;
2967
2968                 objectsid = samdb_result_dom_sid(mem_ctx, res[i],
2969                                                  "objectSid");
2970                 if (objectsid == NULL)
2971                         continue;
2972
2973                 switch(r->in.level) {
2974                 case 1:
2975                         entriesGeneral[count].idx = count + 1;
2976                         entriesGeneral[count].rid = 
2977                                 objectsid->sub_auths[objectsid->num_auths-1];
2978                         entriesGeneral[count].acct_flags =
2979                                 samdb_result_acct_flags(res[i], 
2980                                                         "userAccountControl");
2981                         entriesGeneral[count].account_name.string =
2982                                 samdb_result_string(res[i],
2983                                                     "sAMAccountName", "");
2984                         entriesGeneral[count].full_name.string =
2985                                 samdb_result_string(res[i], "displayName", "");
2986                         entriesGeneral[count].description.string =
2987                                 samdb_result_string(res[i], "description", "");
2988                         break;
2989                 case 2:
2990                 case 3:
2991                         entriesFull[count].idx = count + 1;
2992                         entriesFull[count].rid =
2993                                 objectsid->sub_auths[objectsid->num_auths-1];
2994                         entriesFull[count].acct_flags =
2995                                 samdb_result_acct_flags(res[i], 
2996                                                         "userAccountControl");
2997                         if (r->in.level == 3) {
2998                                 /* We get a "7" here for groups */
2999                                 entriesFull[count].acct_flags = 7;
3000                         }
3001                         entriesFull[count].account_name.string =
3002                                 samdb_result_string(res[i], "sAMAccountName",
3003                                                     "");
3004                         entriesFull[count].description.string =
3005                                 samdb_result_string(res[i], "description", "");
3006                         break;
3007                 case 4:
3008                 case 5:
3009                         entriesAscii[count].idx = count + 1;
3010                         entriesAscii[count].account_name.string =
3011                                 samdb_result_string(res[i], "sAMAccountName",
3012                                                     "");
3013                         break;
3014                 }
3015
3016                 count += 1;
3017         }
3018
3019         r->out.total_size = count;
3020
3021         if (r->in.start_idx >= count) {
3022                 r->out.returned_size = 0;
3023                 switch(r->in.level) {
3024                 case 1:
3025                         r->out.info.info1.count = r->out.returned_size;
3026                         r->out.info.info1.entries = NULL;
3027                         break;
3028                 case 2:
3029                         r->out.info.info2.count = r->out.returned_size;
3030                         r->out.info.info2.entries = NULL;
3031                         break;
3032                 case 3:
3033                         r->out.info.info3.count = r->out.returned_size;
3034                         r->out.info.info3.entries = NULL;
3035                         break;
3036                 case 4:
3037                         r->out.info.info4.count = r->out.returned_size;
3038                         r->out.info.info4.entries = NULL;
3039                         break;
3040                 case 5:
3041                         r->out.info.info5.count = r->out.returned_size;
3042                         r->out.info.info5.entries = NULL;
3043                         break;
3044                 }
3045         } else {
3046                 r->out.returned_size = MIN(count - r->in.start_idx,
3047                                            r->in.max_entries);
3048                 switch(r->in.level) {
3049                 case 1:
3050                         r->out.info.info1.count = r->out.returned_size;
3051                         r->out.info.info1.entries =
3052                                 &(entriesGeneral[r->in.start_idx]);
3053                         break;
3054                 case 2:
3055                         r->out.info.info2.count = r->out.returned_size;
3056                         r->out.info.info2.entries =
3057                                 &(entriesFull[r->in.start_idx]);
3058                         break;
3059                 case 3:
3060                         r->out.info.info3.count = r->out.returned_size;
3061                         r->out.info.info3.entries =
3062                                 &(entriesFull[r->in.start_idx]);
3063                         break;
3064                 case 4:
3065                         r->out.info.info4.count = r->out.returned_size;
3066                         r->out.info.info4.entries =
3067                                 &(entriesAscii[r->in.start_idx]);
3068                         break;
3069                 case 5:
3070                         r->out.info.info5.count = r->out.returned_size;
3071                         r->out.info.info5.entries =
3072                                 &(entriesAscii[r->in.start_idx]);
3073                         break;
3074                 }
3075         }
3076
3077         return (r->out.returned_size < (count - r->in.start_idx)) ?
3078                 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3079 }
3080
3081
3082 /* 
3083   samr_GetDisplayEnumerationIndex 
3084 */
3085 static NTSTATUS samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3086                        struct samr_GetDisplayEnumerationIndex *r)
3087 {
3088         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3089 }
3090
3091
3092 /* 
3093   samr_TestPrivateFunctionsDomain 
3094 */
3095 static NTSTATUS samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3096                        struct samr_TestPrivateFunctionsDomain *r)
3097 {
3098         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3099 }
3100
3101
3102 /* 
3103   samr_TestPrivateFunctionsUser 
3104 */
3105 static NTSTATUS samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3106                        struct samr_TestPrivateFunctionsUser *r)
3107 {
3108         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3109 }
3110
3111
3112 /* 
3113   samr_GetUserPwInfo 
3114 */
3115 static NTSTATUS samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3116                                    struct samr_GetUserPwInfo *r)
3117 {
3118         struct dcesrv_handle *h;
3119         struct samr_account_state *a_state;
3120
3121         ZERO_STRUCT(r->out.info);
3122
3123         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3124
3125         a_state = h->data;
3126
3127         r->out.info.min_password_length = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0,
3128                                                             a_state->domain_state->domain_dn, "minPwdLength", 
3129                                                             "dn=%s", 
3130                                                             ldb_dn_linearize(mem_ctx, a_state->domain_state->domain_dn));
3131         r->out.info.password_properties = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0,
3132                                                             a_state->account_dn, 
3133                                                             "pwdProperties", "dn=%s",
3134                                                             ldb_dn_linearize(mem_ctx, a_state->account_dn));
3135         return NT_STATUS_OK;
3136 }
3137
3138
3139 /* 
3140   samr_RemoveMemberFromForeignDomain 
3141 */
3142 static NTSTATUS samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3143                        struct samr_RemoveMemberFromForeignDomain *r)
3144 {
3145         struct dcesrv_handle *h;
3146         struct samr_domain_state *d_state;
3147         const char *memberdn;
3148         struct ldb_message **res;
3149         const char * const attrs[3] = { "dn", "objectSid", NULL };
3150         int i, count;
3151
3152         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3153
3154         d_state = h->data;
3155
3156         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3157                                        "dn", "(objectSid=%s)", 
3158                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3159         if (memberdn == NULL)
3160                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3161
3162         /* TODO: Does this call only remove alias members, or does it do this
3163          * for domain groups as well? */
3164
3165         count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3166                                     d_state->domain_dn, &res, attrs,
3167                                     d_state->domain_sid,
3168                                     "(&(member=%s)(objectClass=group)"
3169                                     "(|(groupType=%s)(groupType=%s)))",
3170                                     memberdn,
3171                                     ldb_hexstr(mem_ctx,
3172                                                GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
3173                                     ldb_hexstr(mem_ctx,
3174                                                GTYPE_SECURITY_DOMAIN_LOCAL_GROUP));
3175
3176         if (count < 0)
3177                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3178
3179         for (i=0; i<count; i++) {
3180                 struct ldb_message *mod;
3181
3182                 mod = ldb_msg_new(mem_ctx);
3183                 if (mod == NULL) {
3184                         return NT_STATUS_NO_MEMORY;
3185                 }
3186
3187                 mod->dn = samdb_result_dn(mod, res[i], "dn", NULL);
3188                 if (mod->dn == NULL) {
3189                         talloc_free(mod);
3190                         continue;
3191                 }
3192
3193                 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
3194                                          "member", memberdn) != 0)
3195                         return NT_STATUS_NO_MEMORY;
3196
3197                 if (samdb_modify(d_state->sam_ctx, mem_ctx, mod) != 0)
3198                         return NT_STATUS_UNSUCCESSFUL;
3199
3200                 talloc_free(mod);
3201         }
3202
3203         return NT_STATUS_OK;
3204 }
3205
3206
3207 /* 
3208   samr_QueryDomainInfo2 
3209 */
3210 static NTSTATUS samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3211                        struct samr_QueryDomainInfo2 *r)
3212 {
3213         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3214 }
3215
3216
3217 /* 
3218   samr_QueryUserInfo2 
3219
3220   just an alias for samr_QueryUserInfo
3221 */
3222 static NTSTATUS samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3223                                     struct samr_QueryUserInfo2 *r)
3224 {
3225         struct samr_QueryUserInfo r1;
3226         NTSTATUS status;
3227
3228         ZERO_STRUCT(r1.out);
3229         r1.in.user_handle = r->in.user_handle;
3230         r1.in.level  = r->in.level;
3231         
3232         status = samr_QueryUserInfo(dce_call, mem_ctx, &r1);
3233         
3234         r->out.info = r1.out.info;
3235
3236         return status;
3237 }
3238
3239
3240 /* 
3241   samr_QueryDisplayInfo2 
3242 */
3243 static NTSTATUS samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3244                                        struct samr_QueryDisplayInfo2 *r)
3245 {
3246         struct samr_QueryDisplayInfo q;
3247         NTSTATUS result;
3248
3249         q.in.domain_handle = r->in.domain_handle;
3250         q.in.level = r->in.level;
3251         q.in.start_idx = r->in.start_idx;
3252         q.in.max_entries = r->in.max_entries;
3253         q.in.buf_size = r->in.buf_size;
3254         ZERO_STRUCT(q.out);
3255
3256         result = samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
3257
3258         r->out.total_size = q.out.total_size;
3259         r->out.returned_size = q.out.returned_size;
3260         r->out.info = q.out.info;
3261
3262         return result;
3263 }
3264
3265
3266 /* 
3267   samr_GetDisplayEnumerationIndex2 
3268 */
3269 static NTSTATUS samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3270                        struct samr_GetDisplayEnumerationIndex2 *r)
3271 {
3272         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3273 }
3274
3275
3276 /* 
3277   samr_QueryDisplayInfo3 
3278 */
3279 static NTSTATUS samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3280                        struct samr_QueryDisplayInfo3 *r)
3281 {
3282         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3283 }
3284
3285
3286 /* 
3287   samr_AddMultipleMembersToAlias 
3288 */
3289 static NTSTATUS samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3290                        struct samr_AddMultipleMembersToAlias *r)
3291 {
3292         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3293 }
3294
3295
3296 /* 
3297   samr_RemoveMultipleMembersFromAlias 
3298 */
3299 static NTSTATUS samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3300                        struct samr_RemoveMultipleMembersFromAlias *r)
3301 {
3302         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3303 }
3304
3305
3306 /* 
3307   samr_GetDomPwInfo 
3308
3309   this fetches the default password properties for a domain
3310
3311   note that w2k3 completely ignores the domain name in this call, and 
3312   always returns the information for the servers primary domain
3313 */
3314 static NTSTATUS samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3315                                   struct samr_GetDomPwInfo *r)
3316 {
3317         struct ldb_message **msgs;
3318         int ret;
3319         const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
3320         struct ldb_context *sam_ctx;
3321
3322         ZERO_STRUCT(r->out.info);
3323
3324         sam_ctx = samdb_connect(mem_ctx);
3325         if (sam_ctx == NULL) {
3326                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
3327         }
3328
3329         ret = gendb_search(sam_ctx, 
3330                            mem_ctx, NULL, &msgs, attrs, 
3331                            "(&(!(objectClass=builtinDomain))(objectclass=domain))");
3332         if (ret <= 0) {
3333                 return NT_STATUS_NO_SUCH_DOMAIN;
3334         }
3335         if (ret > 1) {
3336                 talloc_free(msgs);
3337                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3338         }
3339
3340         r->out.info.min_password_length = samdb_result_uint(msgs[0], "minPwdLength", 0);
3341         r->out.info.password_properties = samdb_result_uint(msgs[0], "pwdProperties", 1);
3342
3343         talloc_free(msgs);
3344
3345         talloc_free(sam_ctx);
3346         return NT_STATUS_OK;
3347 }
3348
3349
3350 /* 
3351   samr_Connect2 
3352 */
3353 static NTSTATUS samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3354                               struct samr_Connect2 *r)
3355 {
3356         struct samr_Connect c;
3357
3358         c.in.system_name = NULL;
3359         c.in.access_mask = r->in.access_mask;
3360         c.out.connect_handle = r->out.connect_handle;
3361
3362         return samr_Connect(dce_call, mem_ctx, &c);
3363 }
3364
3365
3366 /* 
3367   samr_SetUserInfo2 
3368
3369   just an alias for samr_SetUserInfo
3370 */
3371 static NTSTATUS samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3372                                   struct samr_SetUserInfo2 *r)
3373 {
3374         struct samr_SetUserInfo r2;
3375
3376         r2.in.user_handle = r->in.user_handle;
3377         r2.in.level = r->in.level;
3378         r2.in.info = r->in.info;
3379
3380         return samr_SetUserInfo(dce_call, mem_ctx, &r2);
3381 }
3382
3383
3384 /* 
3385   samr_SetBootKeyInformation 
3386 */
3387 static NTSTATUS samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3388                        struct samr_SetBootKeyInformation *r)
3389 {
3390         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3391 }
3392
3393
3394 /* 
3395   samr_GetBootKeyInformation 
3396 */
3397 static NTSTATUS samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3398                        struct samr_GetBootKeyInformation *r)
3399 {
3400         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3401 }
3402
3403
3404 /* 
3405   samr_Connect3 
3406 */
3407 static NTSTATUS samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3408                        struct samr_Connect3 *r)
3409 {
3410         struct samr_Connect c;
3411
3412         c.in.system_name = NULL;
3413         c.in.access_mask = r->in.access_mask;
3414         c.out.connect_handle = r->out.connect_handle;
3415
3416         return samr_Connect(dce_call, mem_ctx, &c);
3417 }
3418
3419
3420 /* 
3421   samr_Connect4 
3422 */
3423 static NTSTATUS samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3424                        struct samr_Connect4 *r)
3425 {
3426         struct samr_Connect c;
3427
3428         c.in.system_name = NULL;
3429         c.in.access_mask = r->in.access_mask;
3430         c.out.connect_handle = r->out.connect_handle;
3431
3432         return samr_Connect(dce_call, mem_ctx, &c);
3433 }
3434
3435
3436 /* 
3437   samr_Connect5 
3438 */
3439 static NTSTATUS samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3440                               struct samr_Connect5 *r)
3441 {
3442         struct samr_Connect c;
3443         NTSTATUS status;
3444
3445         c.in.system_name = NULL;
3446         c.in.access_mask = r->in.access_mask;
3447         c.out.connect_handle = r->out.connect_handle;
3448
3449         status = samr_Connect(dce_call, mem_ctx, &c);
3450
3451         r->out.info->info1.unknown1 = 3;
3452         r->out.info->info1.unknown2 = 0;
3453         r->out.level = r->in.level;
3454
3455         return status;
3456 }
3457
3458
3459 /* 
3460   samr_RidToSid 
3461 */
3462 static NTSTATUS samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3463                        struct samr_RidToSid *r)
3464 {
3465         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3466 }
3467
3468
3469 /* 
3470   samr_SetDsrmPassword 
3471 */
3472 static NTSTATUS samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3473                        struct samr_SetDsrmPassword *r)
3474 {
3475         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3476 }
3477
3478
3479 /* 
3480   samr_ValidatePassword 
3481 */
3482 static NTSTATUS samr_ValidatePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3483                                       struct samr_ValidatePassword *r)
3484 {
3485         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3486 }
3487
3488
3489 /* include the generated boilerplate */
3490 #include "librpc/gen_ndr/ndr_samr_s.c"