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