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