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