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