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