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