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