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