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