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