r18775: Performing an ldb op of 'do nothing' is pointless, and breaks against
[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         const 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(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         const 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_linearize(mem_ctx, 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         const 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_linearize(mem_ctx, 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_linearize(mem_ctx, 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_string_compose(mem_ctx, d_state->domain_dn,
938                                         "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         if (ret != 0) {
948                 DEBUG(0,("Failed to create group record %s\n",
949                          ldb_dn_linearize(mem_ctx, msg->dn)));
950                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
951         }
952
953         a_state = talloc(d_state, struct samr_account_state);
954         if (!a_state) {
955                 return NT_STATUS_NO_MEMORY;
956         }
957         a_state->sam_ctx = d_state->sam_ctx;
958         a_state->access_mask = r->in.access_mask;
959         a_state->domain_state = talloc_reference(a_state, d_state);
960         a_state->account_dn = talloc_steal(a_state, msg->dn);
961
962         /* retrieve the sid for the group just created */
963         sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
964                                    msg->dn, "objectSid", NULL);
965         if (sid == NULL) {
966                 return NT_STATUS_UNSUCCESSFUL;
967         }
968
969         a_state->account_name = talloc_strdup(a_state, groupname);
970         if (!a_state->account_name) {
971                 return NT_STATUS_NO_MEMORY;
972         }
973
974         /* create the policy handle */
975         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
976         if (!g_handle) {
977                 return NT_STATUS_NO_MEMORY;
978         }
979
980         g_handle->data = talloc_steal(g_handle, a_state);
981
982         *r->out.group_handle = g_handle->wire_handle;
983         *r->out.rid = sid->sub_auths[sid->num_auths-1];
984
985         return NT_STATUS_OK;
986 }
987
988
989 /*
990   comparison function for sorting SamEntry array
991 */
992 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
993 {
994         return e1->idx - e2->idx;
995 }
996
997 /* 
998   samr_EnumDomainGroups 
999 */
1000 static NTSTATUS samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1001                                       struct samr_EnumDomainGroups *r)
1002 {
1003         struct dcesrv_handle *h;
1004         struct samr_domain_state *d_state;
1005         struct ldb_message **res;
1006         int ldb_cnt, count, i, first;
1007         struct samr_SamEntry *entries;
1008         const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1009
1010         *r->out.resume_handle = 0;
1011         r->out.sam = NULL;
1012         r->out.num_entries = 0;
1013
1014         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1015
1016         d_state = h->data;
1017
1018         /* search for all domain groups in this domain. This could possibly be
1019            cached and resumed based on resume_key */
1020         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1021                                       d_state->domain_dn, &res, attrs,
1022                                       d_state->domain_sid,
1023                                       "(&(grouptype=%d)(objectclass=group))",
1024                                       GTYPE_SECURITY_GLOBAL_GROUP);
1025         if (ldb_cnt == -1) {
1026                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1027         }
1028         if (ldb_cnt == 0 || r->in.max_size == 0) {
1029                 return NT_STATUS_OK;
1030         }
1031
1032         /* convert to SamEntry format */
1033         entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1034         if (!entries) {
1035                 return NT_STATUS_NO_MEMORY;
1036         }
1037
1038         count = 0;
1039
1040         for (i=0;i<ldb_cnt;i++) {
1041                 struct dom_sid *group_sid;
1042
1043                 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
1044                                                  "objectSid");
1045                 if (group_sid == NULL)
1046                         continue;
1047
1048                 entries[count].idx =
1049                         group_sid->sub_auths[group_sid->num_auths-1];
1050                 entries[count].name.string =
1051                         samdb_result_string(res[i], "sAMAccountName", "");
1052                 count += 1;
1053         }
1054
1055         /* sort the results by rid */
1056         qsort(entries, count, sizeof(struct samr_SamEntry), 
1057               (comparison_fn_t)compare_SamEntry);
1058
1059         /* find the first entry to return */
1060         for (first=0;
1061              first<count && entries[first].idx <= *r->in.resume_handle;
1062              first++) ;
1063
1064         if (first == count) {
1065                 return NT_STATUS_OK;
1066         }
1067
1068         /* return the rest, limit by max_size. Note that we 
1069            use the w2k3 element size value of 54 */
1070         r->out.num_entries = count - first;
1071         r->out.num_entries = MIN(r->out.num_entries, 
1072                                  1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1073
1074         r->out.sam = talloc(mem_ctx, struct samr_SamArray);
1075         if (!r->out.sam) {
1076                 return NT_STATUS_NO_MEMORY;
1077         }
1078
1079         r->out.sam->entries = entries+first;
1080         r->out.sam->count = r->out.num_entries;
1081
1082         if (r->out.num_entries < count - first) {
1083                 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
1084                 return STATUS_MORE_ENTRIES;
1085         }
1086
1087         return NT_STATUS_OK;
1088 }
1089
1090
1091 /* 
1092   samr_CreateUser2 
1093
1094   This call uses transactions to ensure we don't get a new conflicting
1095   user while we are processing this, and to ensure the user either
1096   completly exists, or does not.
1097 */
1098 static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1099                                  struct samr_CreateUser2 *r)
1100 {
1101         struct samr_domain_state *d_state;
1102         struct samr_account_state *a_state;
1103         struct dcesrv_handle *h;
1104         const char *name;
1105         struct ldb_message *msg;
1106         struct dom_sid *sid;
1107         const char *account_name;
1108         struct dcesrv_handle *u_handle;
1109         int ret;
1110         const char *container, *obj_class=NULL;
1111         char *cn_name;
1112         int cn_name_len;
1113
1114         const char *attrs[] = {
1115                 "objectSid", 
1116                 "userAccountControl",
1117                 NULL
1118         };
1119
1120         uint32_t user_account_control;
1121
1122         struct ldb_message **msgs;
1123
1124         ZERO_STRUCTP(r->out.user_handle);
1125         *r->out.access_granted = 0;
1126         *r->out.rid = 0;
1127
1128         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1129
1130         d_state = h->data;
1131
1132         account_name = r->in.account_name->string;
1133
1134         if (account_name == NULL) {
1135                 return NT_STATUS_INVALID_PARAMETER;
1136         }
1137
1138         ret = ldb_transaction_start(d_state->sam_ctx);
1139         if (ret != 0) {
1140                 DEBUG(0,("Failed to start a transaction for user creation: %s\n",
1141                          ldb_errstring(d_state->sam_ctx)));
1142                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1143         }
1144
1145         /* check if the user already exists */
1146         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL, 
1147                                    "sAMAccountName", 
1148                                    "(&(sAMAccountName=%s)(objectclass=user))", 
1149                                    ldb_binary_encode_string(mem_ctx, account_name));
1150         if (name != NULL) {
1151                 ldb_transaction_cancel(d_state->sam_ctx);
1152                 return NT_STATUS_USER_EXISTS;
1153         }
1154
1155         msg = ldb_msg_new(mem_ctx);
1156         if (msg == NULL) {
1157                 ldb_transaction_cancel(d_state->sam_ctx);
1158                 return NT_STATUS_NO_MEMORY;
1159         }
1160
1161         cn_name   = talloc_strdup(mem_ctx, account_name);
1162         if (!cn_name) {
1163                 ldb_transaction_cancel(d_state->sam_ctx);
1164                 return NT_STATUS_NO_MEMORY;
1165         }
1166
1167         cn_name_len = strlen(cn_name);
1168
1169         /* This must be one of these values *only* */
1170         if (r->in.acct_flags == ACB_NORMAL) {
1171                 container = "Users";
1172                 obj_class = "user";
1173
1174         } else if (r->in.acct_flags == ACB_WSTRUST) {
1175                 if (cn_name[cn_name_len - 1] != '$') {
1176                         return NT_STATUS_FOOBAR;
1177                 }
1178                 cn_name[cn_name_len - 1] = '\0';
1179                 container = "Computers";
1180                 obj_class = "computer";
1181
1182         } else if (r->in.acct_flags == ACB_SVRTRUST) {
1183                 if (cn_name[cn_name_len - 1] != '$') {
1184                         return NT_STATUS_FOOBAR;                
1185                 }
1186                 cn_name[cn_name_len - 1] = '\0';
1187                 container = "Domain Controllers";
1188                 obj_class = "computer";
1189
1190         } else if (r->in.acct_flags == ACB_DOMTRUST) {
1191                 container = "Users";
1192                 obj_class = "user";
1193
1194         } else {
1195                 ldb_transaction_cancel(d_state->sam_ctx);
1196                 return NT_STATUS_INVALID_PARAMETER;
1197         }
1198
1199         /* add core elements to the ldb_message for the user */
1200         msg->dn = ldb_dn_build_child(mem_ctx, "CN", cn_name, ldb_dn_build_child(mem_ctx, "CN", container, d_state->domain_dn));
1201         if (!msg->dn) {
1202                 ldb_transaction_cancel(d_state->sam_ctx);
1203                 return NT_STATUS_NO_MEMORY;             
1204         }
1205         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", account_name);
1206         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", obj_class);
1207         
1208         /* Start a transaction, so we can query and do a subsequent atomic modify */
1209         
1210         /* create the user */
1211         ret = samdb_add(d_state->sam_ctx, mem_ctx, msg);
1212         switch (ret) {
1213         case  LDB_SUCCESS:
1214                 break;
1215         case  LDB_ERR_ENTRY_ALREADY_EXISTS:
1216                 ldb_transaction_cancel(d_state->sam_ctx);
1217                 DEBUG(0,("Failed to create user record %s: %s\n",
1218                          ldb_dn_linearize(mem_ctx, msg->dn),
1219                          ldb_errstring(d_state->sam_ctx)));
1220                 return NT_STATUS_USER_EXISTS;
1221         default:
1222                 ldb_transaction_cancel(d_state->sam_ctx);
1223                 DEBUG(0,("Failed to create user record %s: %s\n",
1224                          ldb_dn_linearize(mem_ctx, msg->dn),
1225                          ldb_errstring(d_state->sam_ctx)));
1226                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1227         }
1228
1229         a_state = talloc(d_state, struct samr_account_state);
1230         if (!a_state) {
1231                 ldb_transaction_cancel(d_state->sam_ctx);
1232                 return NT_STATUS_NO_MEMORY;
1233         }
1234         a_state->sam_ctx = d_state->sam_ctx;
1235         a_state->access_mask = r->in.access_mask;
1236         a_state->domain_state = talloc_reference(a_state, d_state);
1237         a_state->account_dn = talloc_steal(a_state, msg->dn);
1238
1239         /* retrieve the sid and account control bits for the user just created */
1240         ret = gendb_search_dn(d_state->sam_ctx, a_state,
1241                               msg->dn, &msgs, attrs);
1242
1243         if (ret != 1) {
1244                 ldb_transaction_cancel(d_state->sam_ctx);
1245                 DEBUG(0,("Apparently we failed to create an account record, as %s now doesn't exist\n",
1246                          ldb_dn_linearize(mem_ctx, msg->dn)));
1247                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1248         }
1249         sid = samdb_result_dom_sid(mem_ctx, msgs[0], "objectSid");
1250         if (sid == NULL) {
1251                 ldb_transaction_cancel(d_state->sam_ctx);
1252                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1253         }
1254
1255         /* Change the account control to be the correct account type.
1256          * The default is for a workstation account */
1257         user_account_control = samdb_result_uint(msgs[0], "userAccountControl", 0);
1258         user_account_control = (user_account_control & 
1259                                 ~(UF_NORMAL_ACCOUNT |
1260                                   UF_INTERDOMAIN_TRUST_ACCOUNT | 
1261                                   UF_WORKSTATION_TRUST_ACCOUNT | 
1262                                   UF_SERVER_TRUST_ACCOUNT));
1263         user_account_control |= samdb_acb2uf(r->in.acct_flags);
1264
1265         talloc_free(msg);
1266         msg = ldb_msg_new(mem_ctx);
1267         if (msg == NULL) {
1268                 ldb_transaction_cancel(d_state->sam_ctx);
1269                 return NT_STATUS_NO_MEMORY;
1270         }
1271
1272         msg->dn = ldb_dn_copy(msg, a_state->account_dn);
1273
1274         if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, msg, 
1275                                "userAccountControl", 
1276                                user_account_control) != 0) { 
1277                 ldb_transaction_cancel(d_state->sam_ctx);
1278                 return NT_STATUS_NO_MEMORY; 
1279         }
1280
1281         /* modify the samdb record */
1282         ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
1283         if (ret != 0) {
1284                 DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n",
1285                          ldb_dn_linearize(mem_ctx, msg->dn),
1286                          ldb_errstring(d_state->sam_ctx)));
1287                 ldb_transaction_cancel(d_state->sam_ctx);
1288
1289                 /* we really need samdb.c to return NTSTATUS */
1290                 return NT_STATUS_UNSUCCESSFUL;
1291         }
1292
1293         ret = ldb_transaction_commit(d_state->sam_ctx);
1294         if (ret != 0) {
1295                 DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n",
1296                          ldb_dn_linearize(mem_ctx, msg->dn),
1297                          ldb_errstring(d_state->sam_ctx)));
1298                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1299         }
1300
1301         a_state->account_name = talloc_steal(a_state, account_name);
1302         if (!a_state->account_name) {
1303                 return NT_STATUS_NO_MEMORY;
1304         }
1305
1306         /* create the policy handle */
1307         u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
1308         if (!u_handle) {
1309                 return NT_STATUS_NO_MEMORY;
1310         }
1311
1312         u_handle->data = talloc_steal(u_handle, a_state);
1313
1314         *r->out.user_handle = u_handle->wire_handle;
1315         *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1316
1317         *r->out.rid = sid->sub_auths[sid->num_auths-1];
1318
1319         return NT_STATUS_OK;
1320 }
1321
1322
1323 /* 
1324   samr_CreateUser 
1325 */
1326 static NTSTATUS samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1327                                 struct samr_CreateUser *r)
1328 {
1329         struct samr_CreateUser2 r2;
1330         uint32_t access_granted = 0;
1331
1332
1333         /* a simple wrapper around samr_CreateUser2 works nicely */
1334         r2.in.domain_handle = r->in.domain_handle;
1335         r2.in.account_name = r->in.account_name;
1336         r2.in.acct_flags = ACB_NORMAL;
1337         r2.in.access_mask = r->in.access_mask;
1338         r2.out.user_handle = r->out.user_handle;
1339         r2.out.access_granted = &access_granted;
1340         r2.out.rid = r->out.rid;
1341
1342         return samr_CreateUser2(dce_call, mem_ctx, &r2);
1343 }
1344
1345 /* 
1346   samr_EnumDomainUsers 
1347 */
1348 static NTSTATUS samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1349                                      struct samr_EnumDomainUsers *r)
1350 {
1351         struct dcesrv_handle *h;
1352         struct samr_domain_state *d_state;
1353         struct ldb_message **res;
1354         int count, i, first;
1355         struct samr_SamEntry *entries;
1356         const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1357
1358         *r->out.resume_handle = 0;
1359         r->out.sam = NULL;
1360         r->out.num_entries = 0;
1361
1362         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1363
1364         d_state = h->data;
1365         
1366         /* search for all users in this domain. This could possibly be cached and 
1367            resumed based on resume_key */
1368         count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs, 
1369                              "objectclass=user");
1370         if (count == -1) {
1371                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1372         }
1373         if (count == 0 || r->in.max_size == 0) {
1374                 return NT_STATUS_OK;
1375         }
1376
1377         /* convert to SamEntry format */
1378         entries = talloc_array(mem_ctx, struct samr_SamEntry, count);
1379         if (!entries) {
1380                 return NT_STATUS_NO_MEMORY;
1381         }
1382         for (i=0;i<count;i++) {
1383                 entries[i].idx = samdb_result_rid_from_sid(mem_ctx, res[i], "objectSid", 0);
1384                 entries[i].name.string = samdb_result_string(res[i], "sAMAccountName", "");
1385         }
1386
1387         /* sort the results by rid */
1388         qsort(entries, count, sizeof(struct samr_SamEntry), 
1389               (comparison_fn_t)compare_SamEntry);
1390
1391         /* find the first entry to return */
1392         for (first=0;
1393              first<count && entries[first].idx <= *r->in.resume_handle;
1394              first++) ;
1395
1396         if (first == count) {
1397                 return NT_STATUS_OK;
1398         }
1399
1400         /* return the rest, limit by max_size. Note that we 
1401            use the w2k3 element size value of 54 */
1402         r->out.num_entries = count - first;
1403         r->out.num_entries = MIN(r->out.num_entries, 
1404                                  1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1405
1406         r->out.sam = talloc(mem_ctx, struct samr_SamArray);
1407         if (!r->out.sam) {
1408                 return NT_STATUS_NO_MEMORY;
1409         }
1410
1411         r->out.sam->entries = entries+first;
1412         r->out.sam->count = r->out.num_entries;
1413
1414         if (r->out.num_entries < count - first) {
1415                 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
1416                 return STATUS_MORE_ENTRIES;
1417         }
1418
1419         return NT_STATUS_OK;
1420 }
1421
1422
1423 /* 
1424   samr_CreateDomAlias 
1425 */
1426 static NTSTATUS samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1427                        struct samr_CreateDomAlias *r)
1428 {
1429         struct samr_domain_state *d_state;
1430         struct samr_account_state *a_state;
1431         struct dcesrv_handle *h;
1432         const char *alias_name, *name;
1433         struct ldb_message *msg;
1434         struct dom_sid *sid;
1435         struct dcesrv_handle *a_handle;
1436         int ret;
1437
1438         ZERO_STRUCTP(r->out.alias_handle);
1439         *r->out.rid = 0;
1440
1441         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1442
1443         d_state = h->data;
1444
1445         alias_name = r->in.alias_name->string;
1446
1447         if (alias_name == NULL) {
1448                 return NT_STATUS_INVALID_PARAMETER;
1449         }
1450
1451         /* Check if alias already exists */
1452         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1453                                    "sAMAccountName",
1454                                    "(sAMAccountName=%s)(objectclass=group))",
1455                                    ldb_binary_encode_string(mem_ctx, alias_name));
1456
1457         if (name != NULL) {
1458                 return NT_STATUS_ALIAS_EXISTS;
1459         }
1460
1461         msg = ldb_msg_new(mem_ctx);
1462         if (msg == NULL) {
1463                 return NT_STATUS_NO_MEMORY;
1464         }
1465
1466         /* add core elements to the ldb_message for the alias */
1467         msg->dn = ldb_dn_string_compose(mem_ctx, d_state->domain_dn,
1468                                         "CN=%s, CN=Users", alias_name);
1469         if (!msg->dn) {
1470                 return NT_STATUS_NO_MEMORY;
1471         }
1472
1473         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", alias_name);
1474         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1475         samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "groupType", GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1476
1477         /* create the alias */
1478         ret = samdb_add(d_state->sam_ctx, mem_ctx, msg);
1479         switch (ret) {
1480         case LDB_SUCCESS:
1481                 break;
1482         case LDB_ERR_ENTRY_ALREADY_EXISTS:
1483                 return NT_STATUS_ALIAS_EXISTS;
1484         default:
1485                 DEBUG(0,("Failed to create alias record %s: %s\n",
1486                          ldb_dn_linearize(mem_ctx, msg->dn),
1487                          ldb_errstring(d_state->sam_ctx)));
1488                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1489         }
1490
1491         a_state = talloc(d_state, struct samr_account_state);
1492         if (!a_state) {
1493                 return NT_STATUS_NO_MEMORY;
1494         }
1495
1496         a_state->sam_ctx = d_state->sam_ctx;
1497         a_state->access_mask = r->in.access_mask;
1498         a_state->domain_state = talloc_reference(a_state, d_state);
1499         a_state->account_dn = talloc_steal(a_state, msg->dn);
1500
1501         /* retrieve the sid for the alias just created */
1502         sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1503                                    msg->dn, "objectSid", NULL);
1504
1505         a_state->account_name = talloc_strdup(a_state, alias_name);
1506         if (!a_state->account_name) {
1507                 return NT_STATUS_NO_MEMORY;
1508         }
1509
1510         /* create the policy handle */
1511         a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1512         if (a_handle == NULL)
1513                 return NT_STATUS_NO_MEMORY;
1514
1515         a_handle->data = talloc_steal(a_handle, a_state);
1516
1517         *r->out.alias_handle = a_handle->wire_handle;
1518
1519         *r->out.rid = sid->sub_auths[sid->num_auths-1];
1520
1521         return NT_STATUS_OK;
1522 }
1523
1524
1525 /* 
1526   samr_EnumDomainAliases 
1527 */
1528 static NTSTATUS samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1529                        struct samr_EnumDomainAliases *r)
1530 {
1531         struct dcesrv_handle *h;
1532         struct samr_domain_state *d_state;
1533         struct ldb_message **res;
1534         int ldb_cnt, count, i, first;
1535         struct samr_SamEntry *entries;
1536         const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1537
1538         *r->out.resume_handle = 0;
1539         r->out.sam = NULL;
1540         r->out.num_entries = 0;
1541
1542         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1543
1544         d_state = h->data;
1545
1546         /* search for all domain groups in this domain. This could possibly be
1547            cached and resumed based on resume_key */
1548         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1549                                       d_state->domain_dn,
1550                                       &res, attrs, 
1551                                       d_state->domain_sid,
1552                                       "(&(|(grouptype=%d)(grouptype=%d)))"
1553                                       "(objectclass=group))",
1554                                       GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1555                                       GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1556         if (ldb_cnt == -1) {
1557                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1558         }
1559         if (ldb_cnt == 0) {
1560                 return NT_STATUS_OK;
1561         }
1562
1563         /* convert to SamEntry format */
1564         entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1565         if (!entries) {
1566                 return NT_STATUS_NO_MEMORY;
1567         }
1568
1569         count = 0;
1570
1571         for (i=0;i<ldb_cnt;i++) {
1572                 struct dom_sid *alias_sid;
1573
1574                 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1575                                                  "objectSid");
1576
1577                 if (alias_sid == NULL)
1578                         continue;
1579
1580                 entries[count].idx =
1581                         alias_sid->sub_auths[alias_sid->num_auths-1];
1582                 entries[count].name.string =
1583                         samdb_result_string(res[i], "sAMAccountName", "");
1584                 count += 1;
1585         }
1586
1587         /* sort the results by rid */
1588         qsort(entries, count, sizeof(struct samr_SamEntry), 
1589               (comparison_fn_t)compare_SamEntry);
1590
1591         /* find the first entry to return */
1592         for (first=0;
1593              first<count && entries[first].idx <= *r->in.resume_handle;
1594              first++) ;
1595
1596         if (first == count) {
1597                 return NT_STATUS_OK;
1598         }
1599
1600         r->out.num_entries = count - first;
1601         r->out.num_entries = MIN(r->out.num_entries, 1000);
1602
1603         r->out.sam = talloc(mem_ctx, struct samr_SamArray);
1604         if (!r->out.sam) {
1605                 return NT_STATUS_NO_MEMORY;
1606         }
1607
1608         r->out.sam->entries = entries+first;
1609         r->out.sam->count = r->out.num_entries;
1610
1611         if (r->out.num_entries < count - first) {
1612                 *r->out.resume_handle =
1613                         entries[first+r->out.num_entries-1].idx;
1614                 return STATUS_MORE_ENTRIES;
1615         }
1616
1617         return NT_STATUS_OK;
1618 }
1619
1620
1621 /* 
1622   samr_GetAliasMembership 
1623 */
1624 static NTSTATUS samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1625                        struct samr_GetAliasMembership *r)
1626 {
1627         struct dcesrv_handle *h;
1628         struct samr_domain_state *d_state;
1629         struct ldb_message **res;
1630         int i, count = 0;
1631
1632         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1633
1634         d_state = h->data;
1635
1636         if (r->in.sids->num_sids > 0) {
1637                 const char *filter;
1638                 const char * const attrs[2] = { "objectSid", NULL };
1639
1640                 filter = talloc_asprintf(mem_ctx,
1641                                          "(&(|(grouptype=%d)(grouptype=%d))"
1642                                          "(objectclass=group)(|",
1643                                          GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1644                                          GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1645                 if (filter == NULL)
1646                         return NT_STATUS_NO_MEMORY;
1647
1648                 for (i=0; i<r->in.sids->num_sids; i++) {
1649                         const char *memberdn;
1650
1651                         memberdn = 
1652                                 samdb_search_string(d_state->sam_ctx,
1653                                                     mem_ctx, NULL, "distinguishedName",
1654                                                     "(objectSid=%s)",
1655                                                     ldap_encode_ndr_dom_sid(mem_ctx, 
1656                                                                             r->in.sids->sids[i].sid));
1657
1658                         if (memberdn == NULL)
1659                                 continue;
1660
1661                         filter = talloc_asprintf(mem_ctx, "%s(member=%s)",
1662                                                  filter, memberdn);
1663                         if (filter == NULL)
1664                                 return NT_STATUS_NO_MEMORY;
1665                 }
1666
1667                 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1668                                             d_state->domain_dn, &res, attrs,
1669                                             d_state->domain_sid, "%s))", filter);
1670                 if (count < 0)
1671                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1672         }
1673
1674         r->out.rids->count = 0;
1675         r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1676         if (r->out.rids->ids == NULL)
1677                 return NT_STATUS_NO_MEMORY;
1678
1679         for (i=0; i<count; i++) {
1680                 struct dom_sid *alias_sid;
1681
1682                 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1683
1684                 if (alias_sid == NULL) {
1685                         DEBUG(0, ("Could not find objectSid\n"));
1686                         continue;
1687                 }
1688
1689                 r->out.rids->ids[r->out.rids->count] =
1690                         alias_sid->sub_auths[alias_sid->num_auths-1];
1691                 r->out.rids->count += 1;
1692         }
1693
1694         return NT_STATUS_OK;
1695 }
1696
1697
1698 /* 
1699   samr_LookupNames 
1700 */
1701 static NTSTATUS samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1702                                  struct samr_LookupNames *r)
1703 {
1704         struct dcesrv_handle *h;
1705         struct samr_domain_state *d_state;
1706         int i;
1707         NTSTATUS status = NT_STATUS_OK;
1708         const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1709         int count;
1710
1711         ZERO_STRUCT(r->out.rids);
1712         ZERO_STRUCT(r->out.types);
1713
1714         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1715
1716         d_state = h->data;
1717
1718         if (r->in.num_names == 0) {
1719                 return NT_STATUS_OK;
1720         }
1721
1722         r->out.rids.ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1723         r->out.types.ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1724         if (!r->out.rids.ids || !r->out.types.ids) {
1725                 return NT_STATUS_NO_MEMORY;
1726         }
1727         r->out.rids.count = r->in.num_names;
1728         r->out.types.count = r->in.num_names;
1729
1730         for (i=0;i<r->in.num_names;i++) {
1731                 struct ldb_message **res;
1732                 struct dom_sid *sid;
1733                 uint32_t atype, rtype;
1734
1735                 r->out.rids.ids[i] = 0;
1736                 r->out.types.ids[i] = SID_NAME_UNKNOWN;
1737
1738                 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs, 
1739                                      "sAMAccountName=%s", 
1740                                      ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1741                 if (count != 1) {
1742                         status = STATUS_SOME_UNMAPPED;
1743                         continue;
1744                 }
1745
1746                 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1747                 if (sid == NULL) {
1748                         status = STATUS_SOME_UNMAPPED;
1749                         continue;
1750                 }
1751                 
1752                 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1753                 if (atype == 0) {
1754                         status = STATUS_SOME_UNMAPPED;
1755                         continue;
1756                 }
1757
1758                 rtype = samdb_atype_map(atype);
1759                 
1760                 if (rtype == SID_NAME_UNKNOWN) {
1761                         status = STATUS_SOME_UNMAPPED;
1762                         continue;
1763                 }
1764
1765                 r->out.rids.ids[i] = sid->sub_auths[sid->num_auths-1];
1766                 r->out.types.ids[i] = rtype;
1767         }
1768         
1769
1770         return status;
1771 }
1772
1773
1774 /* 
1775   samr_LookupRids 
1776 */
1777 static NTSTATUS samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1778                        struct samr_LookupRids *r)
1779 {
1780         struct dcesrv_handle *h;
1781         struct samr_domain_state *d_state;
1782         int i, total;
1783         NTSTATUS status = NT_STATUS_OK;
1784         struct lsa_String *names;
1785         uint32_t *ids;
1786
1787         ZERO_STRUCT(r->out.names);
1788         ZERO_STRUCT(r->out.types);
1789
1790         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1791
1792         d_state = h->data;
1793
1794         if (r->in.num_rids == 0)
1795                 return NT_STATUS_OK;
1796
1797         names = talloc_array(mem_ctx, struct lsa_String, r->in.num_rids);
1798         ids = talloc_array(mem_ctx, uint32_t, r->in.num_rids);
1799
1800         if ((names == NULL) || (ids == NULL))
1801                 return NT_STATUS_NO_MEMORY;
1802
1803         total = 0;
1804
1805         for (i=0; i<r->in.num_rids; i++) {
1806                 struct ldb_message **res;
1807                 int count;
1808                 const char * const attrs[] = {  "sAMAccountType",
1809                                                 "sAMAccountName", NULL };
1810                 uint32_t atype;
1811                 struct dom_sid *sid;
1812
1813                 ids[i] = SID_NAME_UNKNOWN;
1814
1815                 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rids[i]);
1816                 if (sid == NULL) {
1817                         names[i].string = NULL;
1818                         status = STATUS_SOME_UNMAPPED;
1819                         continue;
1820                 }
1821                 
1822                 count = gendb_search(d_state->sam_ctx, mem_ctx,
1823                                      d_state->domain_dn, &res, attrs,
1824                                      "(objectSid=%s)", 
1825                                      ldap_encode_ndr_dom_sid(mem_ctx, sid));
1826                 if (count != 1) {
1827                         names[i].string = NULL;
1828                         status = STATUS_SOME_UNMAPPED;
1829                         continue;
1830                 }
1831
1832                 names[i].string = samdb_result_string(res[0], "sAMAccountName",
1833                                                       NULL);
1834
1835                 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1836                 if (atype == 0) {
1837                         status = STATUS_SOME_UNMAPPED;
1838                         continue;
1839                 }
1840
1841                 ids[i] = samdb_atype_map(atype);
1842                 
1843                 if (ids[i] == SID_NAME_UNKNOWN) {
1844                         status = STATUS_SOME_UNMAPPED;
1845                         continue;
1846                 }
1847         }
1848
1849         r->out.names.names = names;
1850         r->out.names.count = r->in.num_rids;
1851
1852         r->out.types.ids = ids;
1853         r->out.types.count = r->in.num_rids;
1854
1855         return status;
1856 }
1857
1858
1859 /* 
1860   samr_OpenGroup 
1861 */
1862 static NTSTATUS samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1863                        struct samr_OpenGroup *r)
1864 {
1865         struct samr_domain_state *d_state;
1866         struct samr_account_state *a_state;
1867         struct dcesrv_handle *h;
1868         const char *groupname;
1869         struct dom_sid *sid;
1870         struct ldb_message **msgs;
1871         struct dcesrv_handle *g_handle;
1872         const char * const attrs[2] = { "sAMAccountName", NULL };
1873         int ret;
1874
1875         ZERO_STRUCTP(r->out.group_handle);
1876
1877         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1878
1879         d_state = h->data;
1880
1881         /* form the group SID */
1882         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1883         if (!sid) {
1884                 return NT_STATUS_NO_MEMORY;
1885         }
1886
1887         /* search for the group record */
1888         ret = gendb_search(d_state->sam_ctx,
1889                            mem_ctx, d_state->domain_dn, &msgs, attrs,
1890                            "(&(objectSid=%s)(objectclass=group)"
1891                            "(grouptype=%d))",
1892                            ldap_encode_ndr_dom_sid(mem_ctx, sid),
1893                            GTYPE_SECURITY_GLOBAL_GROUP);
1894         if (ret == 0) {
1895                 return NT_STATUS_NO_SUCH_GROUP;
1896         }
1897         if (ret != 1) {
1898                 DEBUG(0,("Found %d records matching sid %s\n", 
1899                          ret, dom_sid_string(mem_ctx, sid)));
1900                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1901         }
1902
1903         groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
1904         if (groupname == NULL) {
1905                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
1906                          dom_sid_string(mem_ctx, sid)));
1907                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1908         }
1909
1910         a_state = talloc(d_state, struct samr_account_state);
1911         if (!a_state) {
1912                 return NT_STATUS_NO_MEMORY;
1913         }
1914         a_state->sam_ctx = d_state->sam_ctx;
1915         a_state->access_mask = r->in.access_mask;
1916         a_state->domain_state = talloc_reference(a_state, d_state);
1917         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1918         a_state->account_sid = talloc_steal(a_state, sid);
1919         a_state->account_name = talloc_strdup(a_state, groupname);
1920         if (!a_state->account_name) {
1921                 return NT_STATUS_NO_MEMORY;
1922         }
1923
1924         /* create the policy handle */
1925         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1926         if (!g_handle) {
1927                 return NT_STATUS_NO_MEMORY;
1928         }
1929
1930         g_handle->data = talloc_steal(g_handle, a_state);
1931
1932         *r->out.group_handle = g_handle->wire_handle;
1933
1934         return NT_STATUS_OK;
1935 }
1936
1937 /* 
1938   samr_QueryGroupInfo 
1939 */
1940 static NTSTATUS samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1941                        struct samr_QueryGroupInfo *r)
1942 {
1943         struct dcesrv_handle *h;
1944         struct samr_account_state *a_state;
1945         struct ldb_message *msg, **res;
1946         const char * const attrs[4] = { "sAMAccountName", "description",
1947                                         "numMembers", NULL };
1948         int ret;
1949
1950         r->out.info = NULL;
1951
1952         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1953
1954         a_state = h->data;
1955
1956         /* pull all the group attributes */
1957         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
1958                               a_state->account_dn, &res, attrs);
1959         if (ret != 1) {
1960                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1961         }
1962         msg = res[0];
1963
1964         /* allocate the info structure */
1965         r->out.info = talloc(mem_ctx, union samr_GroupInfo);
1966         if (r->out.info == NULL) {
1967                 return NT_STATUS_NO_MEMORY;
1968         }
1969         ZERO_STRUCTP(r->out.info);
1970
1971         /* Fill in the level */
1972         switch (r->in.level) {
1973         case GROUPINFOALL:
1974                 QUERY_STRING(msg, all.name.string,        "sAMAccountName");
1975                 r->out.info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1976                 QUERY_UINT  (msg, all.num_members,      "numMembers")
1977                 QUERY_STRING(msg, all.description.string, "description");
1978                 break;
1979         case GROUPINFONAME:
1980                 QUERY_STRING(msg, name.string,            "sAMAccountName");
1981                 break;
1982         case GROUPINFOATTRIBUTES:
1983                 r->out.info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1984                 break;
1985         case GROUPINFODESCRIPTION:
1986                 QUERY_STRING(msg, description.string, "description");
1987                 break;
1988         case GROUPINFOALL2:
1989                 QUERY_STRING(msg, all2.name.string,        "sAMAccountName");
1990                 r->out.info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1991                 QUERY_UINT  (msg, all2.num_members,      "numMembers")
1992                 QUERY_STRING(msg, all2.description.string, "description");
1993                 break;
1994         default:
1995                 r->out.info = NULL;
1996                 return NT_STATUS_INVALID_INFO_CLASS;
1997         }
1998         
1999         return NT_STATUS_OK;
2000 }
2001
2002
2003 /* 
2004   samr_SetGroupInfo 
2005 */
2006 static NTSTATUS samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2007                                   struct samr_SetGroupInfo *r)
2008 {
2009         struct dcesrv_handle *h;
2010         struct samr_account_state *g_state;
2011         struct ldb_message *msg;
2012         struct ldb_context *sam_ctx;
2013         int ret;
2014
2015         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2016
2017         g_state = h->data;
2018         sam_ctx = g_state->sam_ctx;
2019
2020         msg = ldb_msg_new(mem_ctx);
2021         if (msg == NULL) {
2022                 return NT_STATUS_NO_MEMORY;
2023         }       
2024
2025         msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
2026         if (!msg->dn) {
2027                 return NT_STATUS_NO_MEMORY;
2028         }
2029
2030         switch (r->in.level) {
2031         case GROUPINFODESCRIPTION:
2032                 SET_STRING(msg, description.string,         "description");
2033                 break;
2034         case GROUPINFONAME:
2035                 /* On W2k3 this does not change the name, it changes the
2036                  * sAMAccountName attribute */
2037                 SET_STRING(msg, name.string,                "sAMAccountName");
2038                 break;
2039         case GROUPINFOATTRIBUTES:
2040                 /* This does not do anything obviously visible in W2k3 LDAP */
2041                 return NT_STATUS_OK;
2042         default:
2043                 return NT_STATUS_INVALID_INFO_CLASS;
2044         }
2045
2046         /* modify the samdb record */
2047         ret = samdb_replace(g_state->sam_ctx, mem_ctx, msg);
2048         if (ret != 0) {
2049                 /* we really need samdb.c to return NTSTATUS */
2050                 return NT_STATUS_UNSUCCESSFUL;
2051         }
2052
2053         return NT_STATUS_OK;
2054 }
2055
2056
2057 /* 
2058   samr_AddGroupMember 
2059 */
2060 static NTSTATUS samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2061                        struct samr_AddGroupMember *r)
2062 {
2063         struct dcesrv_handle *h;
2064         struct samr_account_state *a_state;
2065         struct samr_domain_state *d_state;
2066         struct ldb_message *mod;
2067         struct dom_sid *membersid;
2068         const char *memberdn;
2069         struct ldb_result *res;
2070         const char * const attrs[] = { NULL };
2071         const char *filter;
2072         int ret;
2073
2074         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2075
2076         a_state = h->data;
2077         d_state = a_state->domain_state;
2078
2079         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2080         if (membersid == NULL)
2081                 return NT_STATUS_NO_MEMORY;
2082
2083         filter = talloc_asprintf(mem_ctx, "(&(objectSid=%s)(objectclass=user))",
2084                                  ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2085
2086         /* In native mode, AD can also nest domain groups. Not sure yet
2087          * whether this is also available via RPC. */
2088         ret = ldb_search(d_state->sam_ctx, d_state->domain_dn, LDB_SCOPE_SUBTREE,
2089                          filter, attrs, &res);
2090
2091         if (ret != 0) {
2092                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2093         }
2094         talloc_steal(mem_ctx, res);
2095
2096         if (res->count == 0) {
2097                 return NT_STATUS_NO_SUCH_USER;
2098         }
2099                 
2100         if (res->count > 1) {
2101                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2102         }
2103
2104         memberdn = ldb_dn_linearize(mem_ctx, res->msgs[0]->dn);
2105
2106         if (memberdn == NULL)
2107                 return NT_STATUS_NO_MEMORY;
2108
2109         mod = ldb_msg_new(mem_ctx);
2110         if (mod == NULL) {
2111                 return NT_STATUS_NO_MEMORY;
2112         }
2113
2114         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2115
2116         if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2117                                  memberdn) != 0)
2118                 return NT_STATUS_UNSUCCESSFUL;
2119
2120         ret = samdb_modify(a_state->sam_ctx, mem_ctx, mod);
2121         switch (ret) {
2122         case LDB_SUCCESS:
2123                 return NT_STATUS_OK;
2124         case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
2125                 return NT_STATUS_MEMBER_IN_GROUP;
2126         default:
2127                 return NT_STATUS_UNSUCCESSFUL;
2128         }
2129
2130 }
2131
2132
2133 /* 
2134   samr_DeleteDomainGroup 
2135 */
2136 static NTSTATUS samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2137                        struct samr_DeleteDomainGroup *r)
2138 {
2139         struct dcesrv_handle *h;
2140         struct samr_account_state *a_state;
2141         int ret;
2142
2143         *r->out.group_handle = *r->in.group_handle;
2144
2145         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2146
2147         a_state = h->data;
2148
2149         ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
2150         if (ret != 0) {
2151                 return NT_STATUS_UNSUCCESSFUL;
2152         }
2153
2154         ZERO_STRUCTP(r->out.group_handle);
2155
2156         return NT_STATUS_OK;
2157 }
2158
2159
2160 /* 
2161   samr_DeleteGroupMember 
2162 */
2163 static NTSTATUS samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2164                        struct samr_DeleteGroupMember *r)
2165 {
2166         struct dcesrv_handle *h;
2167         struct samr_account_state *a_state;
2168         struct samr_domain_state *d_state;
2169         struct ldb_message *mod;
2170         struct dom_sid *membersid;
2171         const char *memberdn;
2172         struct ldb_result *res;
2173         const char * const attrs[] = { NULL };
2174         const char *filter;
2175         int ret;
2176
2177         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2178
2179         a_state = h->data;
2180         d_state = a_state->domain_state;
2181
2182         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2183         if (membersid == NULL)
2184                 return NT_STATUS_NO_MEMORY;
2185
2186         filter = talloc_asprintf(mem_ctx, "(&(objectSid=%s)(objectclass=user))",
2187                                  ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2188
2189         /* In native mode, AD can also nest domain groups. Not sure yet
2190          * whether this is also available via RPC. */
2191         ret = ldb_search(d_state->sam_ctx, d_state->domain_dn, LDB_SCOPE_SUBTREE,
2192                          filter, attrs, &res);
2193
2194         if (ret != 0) {
2195                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2196         }
2197         talloc_steal(mem_ctx, res);
2198
2199         if (res->count == 0) {
2200                 return NT_STATUS_NO_SUCH_USER;
2201         }
2202                 
2203         if (res->count > 1) {
2204                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2205         }
2206
2207         memberdn = ldb_dn_linearize(mem_ctx, res->msgs[0]->dn);
2208
2209         if (memberdn == NULL)
2210                 return NT_STATUS_NO_MEMORY;
2211
2212         mod = ldb_msg_new(mem_ctx);
2213         if (mod == NULL) {
2214                 return NT_STATUS_NO_MEMORY;
2215         }
2216
2217         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2218
2219         if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2220                                  memberdn) != 0) {
2221                 return NT_STATUS_NO_MEMORY;
2222         }
2223
2224         ret = samdb_modify(a_state->sam_ctx, mem_ctx, mod);
2225         switch (ret) {
2226         case LDB_SUCCESS:
2227                 return NT_STATUS_OK;
2228         case LDB_ERR_NO_SUCH_ATTRIBUTE:
2229                 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2230         default:
2231                 return NT_STATUS_UNSUCCESSFUL;
2232         }
2233
2234 }
2235
2236
2237 /* 
2238   samr_QueryGroupMember 
2239 */
2240 static NTSTATUS samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2241                                       struct samr_QueryGroupMember *r)
2242 {
2243         struct dcesrv_handle *h;
2244         struct samr_account_state *a_state;
2245         struct ldb_message **res;
2246         struct ldb_message_element *el;
2247         struct samr_RidTypeArray *array;
2248         const char * const attrs[2] = { "member", NULL };
2249         int ret;
2250
2251         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2252
2253         a_state = h->data;
2254
2255         /* pull the member attribute */
2256         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2257                               a_state->account_dn, &res, attrs);
2258
2259         if (ret != 1) {
2260                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2261         }
2262
2263         array = talloc(mem_ctx, struct samr_RidTypeArray);
2264
2265         if (array == NULL)
2266                 return NT_STATUS_NO_MEMORY;
2267
2268         ZERO_STRUCTP(array);
2269
2270         el = ldb_msg_find_element(res[0], "member");
2271
2272         if (el != NULL) {
2273                 int i;
2274
2275                 array->count = el->num_values;
2276
2277                 array->rids = talloc_array(mem_ctx, uint32_t,
2278                                              el->num_values);
2279                 if (array->rids == NULL)
2280                         return NT_STATUS_NO_MEMORY;
2281
2282                 array->types = talloc_array(mem_ctx, uint32_t,
2283                                             el->num_values);
2284                 if (array->types == NULL)
2285                         return NT_STATUS_NO_MEMORY;
2286
2287                 for (i=0; i<el->num_values; i++) {
2288                         struct ldb_message **res2;
2289                         const char * const attrs2[2] = { "objectSid", NULL };
2290                         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2291                                            ldb_dn_explode(mem_ctx, (const char *)el->values[i].data),
2292                                            &res2, attrs2);
2293                         if (ret != 1)
2294                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2295
2296                         array->rids[i] =
2297                                 samdb_result_rid_from_sid(mem_ctx, res2[0],
2298                                                           "objectSid", 0);
2299
2300                         if (array->rids[i] == 0)
2301                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2302
2303                         array->types[i] = 7; /* RID type of some kind, not sure what the value means. */
2304                 }
2305         }
2306
2307         r->out.rids = array;
2308
2309         return NT_STATUS_OK;
2310 }
2311
2312
2313 /* 
2314   samr_SetMemberAttributesOfGroup 
2315 */
2316 static NTSTATUS samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2317                        struct samr_SetMemberAttributesOfGroup *r)
2318 {
2319         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2320 }
2321
2322
2323 /* 
2324   samr_OpenAlias 
2325 */
2326 static NTSTATUS samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2327                        struct samr_OpenAlias *r)
2328 {
2329         struct samr_domain_state *d_state;
2330         struct samr_account_state *a_state;
2331         struct dcesrv_handle *h;
2332         const char *alias_name;
2333         struct dom_sid *sid;
2334         struct ldb_message **msgs;
2335         struct dcesrv_handle *g_handle;
2336         const char * const attrs[2] = { "sAMAccountName", NULL };
2337         int ret;
2338
2339         ZERO_STRUCTP(r->out.alias_handle);
2340
2341         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2342
2343         d_state = h->data;
2344
2345         /* form the alias SID */
2346         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2347         if (sid == NULL)
2348                 return NT_STATUS_NO_MEMORY;
2349
2350         /* search for the group record */
2351         ret = gendb_search(d_state->sam_ctx,
2352                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2353                            "(&(objectSid=%s)(objectclass=group)"
2354                            "(|(grouptype=%d)(grouptype=%d)))",
2355                            ldap_encode_ndr_dom_sid(mem_ctx, sid),
2356                            GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2357                            GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2358         if (ret == 0) {
2359                 return NT_STATUS_NO_SUCH_ALIAS;
2360         }
2361         if (ret != 1) {
2362                 DEBUG(0,("Found %d records matching sid %s\n", 
2363                          ret, dom_sid_string(mem_ctx, sid)));
2364                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2365         }
2366
2367         alias_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2368         if (alias_name == NULL) {
2369                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2370                          dom_sid_string(mem_ctx, sid)));
2371                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2372         }
2373
2374         a_state = talloc(d_state, struct samr_account_state);
2375         if (!a_state) {
2376                 return NT_STATUS_NO_MEMORY;
2377         }
2378         a_state->sam_ctx = d_state->sam_ctx;
2379         a_state->access_mask = r->in.access_mask;
2380         a_state->domain_state = talloc_reference(a_state, d_state);
2381         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2382         a_state->account_sid = talloc_steal(a_state, sid);
2383         a_state->account_name = talloc_strdup(a_state, alias_name);
2384         if (!a_state->account_name) {
2385                 return NT_STATUS_NO_MEMORY;
2386         }
2387
2388         /* create the policy handle */
2389         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2390         if (!g_handle) {
2391                 return NT_STATUS_NO_MEMORY;
2392         }
2393
2394         g_handle->data = talloc_steal(g_handle, a_state);
2395
2396         *r->out.alias_handle = g_handle->wire_handle;
2397
2398         return NT_STATUS_OK;
2399 }
2400
2401
2402 /* 
2403   samr_QueryAliasInfo 
2404 */
2405 static NTSTATUS samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2406                        struct samr_QueryAliasInfo *r)
2407 {
2408         struct dcesrv_handle *h;
2409         struct samr_account_state *a_state;
2410         struct ldb_message *msg, **res;
2411         const char * const attrs[4] = { "sAMAccountName", "description",
2412                                         "numMembers", NULL };
2413         int ret;
2414
2415         r->out.info = NULL;
2416
2417         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2418
2419         a_state = h->data;
2420
2421         /* pull all the alias attributes */
2422         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2423                               a_state->account_dn ,&res, attrs);
2424         if (ret != 1) {
2425                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2426         }
2427         msg = res[0];
2428
2429         /* allocate the info structure */
2430         r->out.info = talloc(mem_ctx, union samr_AliasInfo);
2431         if (r->out.info == NULL) {
2432                 return NT_STATUS_NO_MEMORY;
2433         }
2434         ZERO_STRUCTP(r->out.info);
2435
2436         switch(r->in.level) {
2437         case ALIASINFOALL:
2438                 QUERY_STRING(msg, all.name.string, "sAMAccountName");
2439                 QUERY_UINT  (msg, all.num_members, "numMembers");
2440                 QUERY_STRING(msg, all.description.string, "description");
2441                 break;
2442         case ALIASINFONAME:
2443                 QUERY_STRING(msg, name.string, "sAMAccountName");
2444                 break;
2445         case ALIASINFODESCRIPTION:
2446                 QUERY_STRING(msg, description.string, "description");
2447                 break;
2448         default:
2449                 r->out.info = NULL;
2450                 return NT_STATUS_INVALID_INFO_CLASS;
2451         }
2452         
2453         return NT_STATUS_OK;
2454 }
2455
2456
2457 /* 
2458   samr_SetAliasInfo 
2459 */
2460 static NTSTATUS samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2461                        struct samr_SetAliasInfo *r)
2462 {
2463         struct dcesrv_handle *h;
2464         struct samr_account_state *a_state;
2465         struct ldb_message *msg;
2466         struct ldb_context *sam_ctx;
2467         int ret;
2468
2469         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2470
2471         a_state = h->data;
2472         sam_ctx = a_state->sam_ctx;
2473
2474         msg = ldb_msg_new(mem_ctx);
2475         if (msg == NULL) {
2476                 return NT_STATUS_NO_MEMORY;
2477         }
2478
2479         msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2480         if (!msg->dn) {
2481                 return NT_STATUS_NO_MEMORY;
2482         }
2483
2484         switch (r->in.level) {
2485         case ALIASINFODESCRIPTION:
2486                 SET_STRING(msg, description.string,         "description");
2487                 break;
2488         case ALIASINFONAME:
2489                 /* On W2k3 this does not change the name, it changes the
2490                  * sAMAccountName attribute */
2491                 SET_STRING(msg, name.string,                "sAMAccountName");
2492                 break;
2493         default:
2494                 return NT_STATUS_INVALID_INFO_CLASS;
2495         }
2496
2497         /* modify the samdb record */
2498         ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
2499         if (ret != 0) {
2500                 /* we really need samdb.c to return NTSTATUS */
2501                 return NT_STATUS_UNSUCCESSFUL;
2502         }
2503
2504         return NT_STATUS_OK;
2505 }
2506
2507
2508 /* 
2509   samr_DeleteDomAlias 
2510 */
2511 static NTSTATUS samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2512                        struct samr_DeleteDomAlias *r)
2513 {
2514         struct dcesrv_handle *h;
2515         struct samr_account_state *a_state;
2516         int ret;
2517
2518         *r->out.alias_handle = *r->in.alias_handle;
2519
2520         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2521
2522         a_state = h->data;
2523
2524         ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
2525         if (ret != 0) {
2526                 return NT_STATUS_UNSUCCESSFUL;
2527         }
2528
2529         ZERO_STRUCTP(r->out.alias_handle);
2530
2531         return NT_STATUS_OK;
2532 }
2533
2534
2535 /* 
2536   samr_AddAliasMember 
2537 */
2538 static NTSTATUS samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2539                        struct samr_AddAliasMember *r)
2540 {
2541         struct dcesrv_handle *h;
2542         struct samr_account_state *a_state;
2543         struct samr_domain_state *d_state;
2544         struct ldb_message *mod;
2545         struct ldb_message **msgs;
2546         const char * const attrs[] = { NULL };
2547         struct ldb_dn *memberdn = NULL;
2548         int ret;
2549         NTSTATUS status;
2550
2551         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2552
2553         a_state = h->data;
2554         d_state = a_state->domain_state;
2555
2556         ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2557                            &msgs, attrs, "(objectsid=%s)", 
2558                            ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2559
2560         if (ret == 1) {
2561                 memberdn = msgs[0]->dn;
2562         } else  if (ret > 1) {
2563                 DEBUG(0,("Found %d records matching sid %s\n", 
2564                          ret, dom_sid_string(mem_ctx, r->in.sid)));
2565                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2566         } else if (ret == 0) {
2567                 status = samdb_create_foreign_security_principal(d_state->sam_ctx, mem_ctx, 
2568                                                                  r->in.sid, &memberdn);
2569                 if (!NT_STATUS_IS_OK(status)) {
2570                         return status;
2571                 }
2572         } else {
2573                 DEBUG(0, ("samdb_search returned %d: %s\n", ret, ldb_errstring(d_state->sam_ctx)));
2574         }
2575
2576         if (memberdn == NULL) {
2577                 DEBUG(0, ("Could not find memberdn\n"));
2578                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2579         }
2580
2581         mod = ldb_msg_new(mem_ctx);
2582         if (mod == NULL) {
2583                 return NT_STATUS_NO_MEMORY;
2584         }
2585
2586         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2587
2588         if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2589                                  ldb_dn_linearize(mem_ctx, memberdn)) != 0)
2590                 return NT_STATUS_UNSUCCESSFUL;
2591
2592         if (samdb_modify(a_state->sam_ctx, mem_ctx, mod) != 0)
2593                 return NT_STATUS_UNSUCCESSFUL;
2594
2595         return NT_STATUS_OK;
2596 }
2597
2598
2599 /* 
2600   samr_DeleteAliasMember 
2601 */
2602 static NTSTATUS samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2603                        struct samr_DeleteAliasMember *r)
2604 {
2605         struct dcesrv_handle *h;
2606         struct samr_account_state *a_state;
2607         struct samr_domain_state *d_state;
2608         struct ldb_message *mod;
2609         const char *memberdn;
2610
2611         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2612
2613         a_state = h->data;
2614         d_state = a_state->domain_state;
2615
2616         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2617                                        "distinguishedName", "(objectSid=%s)", 
2618                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2619
2620         if (memberdn == NULL)
2621                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2622
2623         mod = ldb_msg_new(mem_ctx);
2624         if (mod == NULL) {
2625                 return NT_STATUS_NO_MEMORY;
2626         }
2627
2628         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2629
2630         if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2631                                  memberdn) != 0)
2632                 return NT_STATUS_UNSUCCESSFUL;
2633
2634         if (samdb_modify(a_state->sam_ctx, mem_ctx, mod) != 0)
2635                 return NT_STATUS_UNSUCCESSFUL;
2636
2637         return NT_STATUS_OK;
2638 }
2639
2640
2641 /* 
2642   samr_GetMembersInAlias 
2643 */
2644 static NTSTATUS samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2645                        struct samr_GetMembersInAlias *r)
2646 {
2647         struct dcesrv_handle *h;
2648         struct samr_account_state *a_state;
2649         struct samr_domain_state *d_state;
2650         struct ldb_message **msgs;
2651         struct lsa_SidPtr *sids;
2652         struct ldb_message_element *el;
2653         const char * const attrs[2] = { "member", NULL};
2654         int ret;
2655
2656         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2657
2658         a_state = h->data;
2659         d_state = a_state->domain_state;
2660
2661         ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
2662                               a_state->account_dn, &msgs, attrs);
2663
2664         if (ret != 1)
2665                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2666
2667         r->out.sids->num_sids = 0;
2668         r->out.sids->sids = NULL;
2669
2670         el = ldb_msg_find_element(msgs[0], "member");
2671
2672         if (el != NULL) {
2673                 int i;
2674
2675                 sids = talloc_array(mem_ctx, struct lsa_SidPtr,
2676                                       el->num_values);
2677
2678                 if (sids == NULL)
2679                         return NT_STATUS_NO_MEMORY;
2680
2681                 for (i=0; i<el->num_values; i++) {
2682                         struct ldb_message **msgs2;
2683                         const char * const attrs2[2] = { "objectSid", NULL };
2684                         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2685                                            ldb_dn_explode(mem_ctx, (const char *)el->values[i].data),
2686                                            &msgs2, attrs2);
2687                         if (ret != 1)
2688                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2689
2690                         sids[i].sid = samdb_result_dom_sid(mem_ctx, msgs2[0],
2691                                                            "objectSid");
2692
2693                         if (sids[i].sid == NULL)
2694                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2695                 }
2696                 r->out.sids->num_sids = el->num_values;
2697                 r->out.sids->sids = sids;
2698         }
2699
2700         return NT_STATUS_OK;
2701 }
2702
2703 /* 
2704   samr_OpenUser 
2705 */
2706 static NTSTATUS samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2707                               struct samr_OpenUser *r)
2708 {
2709         struct samr_domain_state *d_state;
2710         struct samr_account_state *a_state;
2711         struct dcesrv_handle *h;
2712         const char *account_name;
2713         struct dom_sid *sid;
2714         struct ldb_message **msgs;
2715         struct dcesrv_handle *u_handle;
2716         const char * const attrs[2] = { "sAMAccountName", NULL };
2717         int ret;
2718
2719         ZERO_STRUCTP(r->out.user_handle);
2720
2721         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2722
2723         d_state = h->data;
2724
2725         /* form the users SID */
2726         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2727         if (!sid) {
2728                 return NT_STATUS_NO_MEMORY;
2729         }
2730
2731         /* search for the user record */
2732         ret = gendb_search(d_state->sam_ctx,
2733                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2734                            "(&(objectSid=%s)(objectclass=user))", 
2735                            ldap_encode_ndr_dom_sid(mem_ctx, sid));
2736         if (ret == 0) {
2737                 return NT_STATUS_NO_SUCH_USER;
2738         }
2739         if (ret != 1) {
2740                 DEBUG(0,("Found %d records matching sid %s\n", ret, 
2741                          dom_sid_string(mem_ctx, sid)));
2742                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2743         }
2744
2745         account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2746         if (account_name == NULL) {
2747                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2748                          dom_sid_string(mem_ctx, sid)));
2749                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2750         }
2751
2752         a_state = talloc(mem_ctx, struct samr_account_state);
2753         if (!a_state) {
2754                 return NT_STATUS_NO_MEMORY;
2755         }
2756         a_state->sam_ctx = d_state->sam_ctx;
2757         a_state->access_mask = r->in.access_mask;
2758         a_state->domain_state = talloc_reference(a_state, d_state);
2759         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2760         a_state->account_sid = talloc_steal(a_state, sid);
2761         a_state->account_name = talloc_strdup(a_state, account_name);
2762         if (!a_state->account_name) {
2763                 return NT_STATUS_NO_MEMORY;
2764         }
2765
2766         /* create the policy handle */
2767         u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2768         if (!u_handle) {
2769                 return NT_STATUS_NO_MEMORY;
2770         }
2771
2772         u_handle->data = talloc_steal(u_handle, a_state);
2773
2774         *r->out.user_handle = u_handle->wire_handle;
2775
2776         return NT_STATUS_OK;
2777
2778 }
2779
2780
2781 /* 
2782   samr_DeleteUser 
2783 */
2784 static NTSTATUS samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2785                                 struct samr_DeleteUser *r)
2786 {
2787         struct dcesrv_handle *h;
2788         struct samr_account_state *a_state;
2789         int ret;
2790
2791         *r->out.user_handle = *r->in.user_handle;
2792
2793         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2794
2795         a_state = h->data;
2796
2797         ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
2798         if (ret != 0) {
2799                 return NT_STATUS_UNSUCCESSFUL;
2800         }
2801
2802         ZERO_STRUCTP(r->out.user_handle);
2803
2804         return NT_STATUS_OK;
2805 }
2806
2807
2808 /* 
2809   samr_QueryUserInfo 
2810 */
2811 static NTSTATUS samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2812                                    struct samr_QueryUserInfo *r)
2813 {
2814         struct dcesrv_handle *h;
2815         struct samr_account_state *a_state;
2816         struct ldb_message *msg, **res;
2817         int ret;
2818         struct ldb_context *sam_ctx;
2819
2820         const char * const *attrs = NULL;
2821
2822         r->out.info = NULL;
2823
2824         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2825
2826         a_state = h->data;
2827         sam_ctx = a_state->sam_ctx;
2828
2829         /* fill in the reply */
2830         switch (r->in.level) {
2831         case 1:
2832         {
2833                 static const char * const attrs2[] = {"sAMAccountName", "displayName",
2834                                                       "primaryGroupID", "description",
2835                                                       "comment", NULL};
2836                 attrs = attrs2;
2837                 break;
2838         }
2839         case 2:
2840         {
2841                 static const char * const attrs2[] = {"comment", "countryCode", "codePage", NULL};
2842                 attrs = attrs2;
2843                 break;
2844         }
2845         case 3:
2846         {
2847                 static const char * const attrs2[] = {"sAMAccountName",
2848                                                       "displayName",
2849                                                       "objectSid",
2850                                                       "primaryGroupID",
2851                                                       "homeDirectory",
2852                                                       "homeDrive",
2853                                                       "scriptPath",
2854                                                       "profilePath",
2855                                                       "userWorkstations",
2856                                                       "lastLogon",
2857                                                       "lastLogoff",
2858                                                       "pwdLastSet",
2859                                                       "logonHours",
2860                                                       "badPwdCount",
2861                                                       "logonCount",
2862                                                       "userAccountControl", NULL};
2863                 attrs = attrs2;
2864                 break;
2865         }
2866         case 4:
2867         {
2868                 static const char * const attrs2[] = {"logonHours", NULL};
2869                 attrs = attrs2;
2870                 break;
2871         }
2872         case 5:
2873         {
2874                 static const char * const attrs2[] = {"sAMAccountName", 
2875                                                       "displayName",
2876                                                       "objectSid",
2877                                                       "primaryGroupID",
2878                                                       "homeDirectory",
2879                                                       "homeDrive",
2880                                                       "scriptPath", 
2881                                                       "profilePath",
2882                                                       "description",
2883                                                       "userWorkstations",
2884                                                       "lastLogon",
2885                                                       "lastLogoff",
2886                                                       "logonHours",
2887                                                       "badPwdCount",
2888                                                       "logonCount",
2889                                                       "pwdLastSet",
2890                                                       "accountExpires",
2891                                                       "userAccountControl",
2892                                                       NULL};
2893                 attrs = attrs2;
2894                 break;
2895         }
2896         case 6:
2897         {
2898                 static const char * const attrs2[] = {"sAMAccountName", "displayName", NULL};
2899                 attrs = attrs2;
2900                 break;
2901         }
2902         case 7:
2903         {
2904                 static const char * const attrs2[] = {"sAMAccountName", NULL};
2905                 attrs = attrs2;
2906                 break;
2907         }
2908         case 8:
2909         {
2910                 static const char * const attrs2[] = {"displayName", NULL};
2911                 attrs = attrs2;
2912                 break;
2913         }
2914         case 9:
2915         {
2916                 static const char * const attrs2[] = {"primaryGroupID", NULL};
2917                 attrs = attrs2;
2918                 break;
2919         }
2920         case 10:
2921         {
2922                 static const char * const attrs2[] = {"homeDirectory", "homeDrive", NULL};
2923                 attrs = attrs2;
2924                 break;
2925         }
2926         case 11:
2927         {
2928                 static const char * const attrs2[] = {"scriptPath", NULL};
2929                 attrs = attrs2;
2930                 break;
2931         }
2932         case 12:
2933         {
2934                 static const char * const attrs2[] = {"profilePath", NULL};
2935                 attrs = attrs2;
2936                 break;
2937         }
2938         case 13:
2939         {
2940                 static const char * const attrs2[] = {"description", NULL};
2941                 attrs = attrs2;
2942                 break;
2943         }
2944         case 14:
2945         {
2946                 static const char * const attrs2[] = {"userWorkstations", NULL};
2947                 attrs = attrs2;
2948                 break;
2949         }
2950         case 16:
2951         {
2952                 static const char * const attrs2[] = {"userAccountControl", NULL};
2953                 attrs = attrs2;
2954                 break;
2955         }
2956         case 17:
2957         {
2958                 static const char * const attrs2[] = {"accountExpires", NULL};
2959                 attrs = attrs2;
2960                 break;
2961         }
2962         case 20:
2963         {
2964                 static const char * const attrs2[] = {"userParameters", NULL};
2965                 attrs = attrs2;
2966                 break;
2967         }
2968         case 21:
2969         {
2970                 static const char * const attrs2[] = {"lastLogon",
2971                                                       "lastLogoff",
2972                                                       "pwdLastSet",
2973                                                       "accountExpires",
2974                                                       "sAMAccountName",
2975                                                       "displayName",
2976                                                       "homeDirectory",
2977                                                       "homeDrive",
2978                                                       "scriptPath",
2979                                                       "profilePath",
2980                                                       "description",
2981                                                       "userWorkstations",
2982                                                       "comment",
2983                                                       "userParameters",
2984                                                       "objectSid",
2985                                                       "primaryGroupID",
2986                                                       "userAccountControl",
2987                                                       "logonHours",
2988                                                       "badPwdCount",
2989                                                       "logonCount",
2990                                                       "countryCode",
2991                                                       "codePage",
2992                                                       NULL};
2993                 attrs = attrs2;
2994                 break;
2995         }
2996         }
2997
2998         /* pull all the user attributes */
2999         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
3000                               a_state->account_dn ,&res, attrs);
3001         if (ret != 1) {
3002                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3003         }
3004         msg = res[0];
3005
3006         /* allocate the info structure */
3007         r->out.info = talloc(mem_ctx, union samr_UserInfo);
3008         if (r->out.info == NULL) {
3009                 return NT_STATUS_NO_MEMORY;
3010         }
3011         ZERO_STRUCTP(r->out.info);
3012
3013         /* fill in the reply */
3014         switch (r->in.level) {
3015         case 1:
3016                 QUERY_STRING(msg, info1.account_name.string,   "sAMAccountName");
3017                 QUERY_STRING(msg, info1.full_name.string,      "displayName");
3018                 QUERY_UINT  (msg, info1.primary_gid,           "primaryGroupID");
3019                 QUERY_STRING(msg, info1.description.string,    "description");
3020                 QUERY_STRING(msg, info1.comment.string,        "comment");
3021                 break;
3022
3023         case 2:
3024                 QUERY_STRING(msg, info2.comment.string,        "comment");
3025                 QUERY_UINT  (msg, info2.country_code,          "countryCode");
3026                 QUERY_UINT  (msg, info2.code_page,             "codePage");
3027                 break;
3028
3029         case 3:
3030                 QUERY_STRING(msg, info3.account_name.string,   "sAMAccountName");
3031                 QUERY_STRING(msg, info3.full_name.string,      "displayName");
3032                 QUERY_RID   (msg, info3.rid,                   "objectSid");
3033                 QUERY_UINT  (msg, info3.primary_gid,           "primaryGroupID");
3034                 QUERY_STRING(msg, info3.home_directory.string, "homeDirectory");
3035                 QUERY_STRING(msg, info3.home_drive.string,     "homeDrive");
3036                 QUERY_STRING(msg, info3.logon_script.string,   "scriptPath");
3037                 QUERY_STRING(msg, info3.profile_path.string,   "profilePath");
3038                 QUERY_STRING(msg, info3.workstations.string,   "userWorkstations");
3039                 QUERY_NTTIME(msg, info3.last_logon,            "lastLogon");
3040                 QUERY_NTTIME(msg, info3.last_logoff,           "lastLogoff");
3041                 QUERY_NTTIME(msg, info3.last_password_change,  "pwdLastSet");
3042                 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
3043                 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
3044                 QUERY_LHOURS(msg, info3.logon_hours,           "logonHours");
3045                 QUERY_UINT  (msg, info3.bad_password_count,    "badPwdCount");
3046                 QUERY_UINT  (msg, info3.logon_count,           "logonCount");
3047                 QUERY_AFLAGS(msg, info3.acct_flags,            "userAccountControl");
3048                 break;
3049
3050         case 4:
3051                 QUERY_LHOURS(msg, info4.logon_hours,           "logonHours");
3052                 break;
3053
3054         case 5:
3055                 QUERY_STRING(msg, info5.account_name.string,   "sAMAccountName");
3056                 QUERY_STRING(msg, info5.full_name.string,      "displayName");
3057                 QUERY_RID   (msg, info5.rid,                   "objectSid");
3058                 QUERY_UINT  (msg, info5.primary_gid,           "primaryGroupID");
3059                 QUERY_STRING(msg, info5.home_directory.string, "homeDirectory");
3060                 QUERY_STRING(msg, info5.home_drive.string,     "homeDrive");
3061                 QUERY_STRING(msg, info5.logon_script.string,   "scriptPath");
3062                 QUERY_STRING(msg, info5.profile_path.string,   "profilePath");
3063                 QUERY_STRING(msg, info5.description.string,    "description");
3064                 QUERY_STRING(msg, info5.workstations.string,   "userWorkstations");
3065                 QUERY_NTTIME(msg, info5.last_logon,            "lastLogon");
3066                 QUERY_NTTIME(msg, info5.last_logoff,           "lastLogoff");
3067                 QUERY_LHOURS(msg, info5.logon_hours,           "logonHours");
3068                 QUERY_UINT  (msg, info5.bad_password_count,    "badPwdCount");
3069                 QUERY_UINT  (msg, info5.logon_count,           "logonCount");
3070                 QUERY_NTTIME(msg, info5.last_password_change,  "pwdLastSet");
3071                 QUERY_NTTIME(msg, info5.acct_expiry,           "accountExpires");
3072                 QUERY_AFLAGS(msg, info5.acct_flags,            "userAccountControl");
3073                 break;
3074
3075         case 6:
3076                 QUERY_STRING(msg, info6.account_name.string,   "sAMAccountName");
3077                 QUERY_STRING(msg, info6.full_name.string,      "displayName");
3078                 break;
3079
3080         case 7:
3081                 QUERY_STRING(msg, info7.account_name.string,   "sAMAccountName");
3082                 break;
3083
3084         case 8:
3085                 QUERY_STRING(msg, info8.full_name.string,      "displayName");
3086                 break;
3087
3088         case 9:
3089                 QUERY_UINT  (msg, info9.primary_gid,           "primaryGroupID");
3090                 break;
3091
3092         case 10:
3093                 QUERY_STRING(msg, info10.home_directory.string,"homeDirectory");
3094                 QUERY_STRING(msg, info10.home_drive.string,    "homeDrive");
3095                 break;
3096
3097         case 11:
3098                 QUERY_STRING(msg, info11.logon_script.string,  "scriptPath");
3099                 break;
3100
3101         case 12:
3102                 QUERY_STRING(msg, info12.profile_path.string,  "profilePath");
3103                 break;
3104
3105         case 13:
3106                 QUERY_STRING(msg, info13.description.string,   "description");
3107                 break;
3108
3109         case 14:
3110                 QUERY_STRING(msg, info14.workstations.string,  "userWorkstations");
3111                 break;
3112
3113         case 16:
3114                 QUERY_AFLAGS(msg, info16.acct_flags,           "userAccountControl");
3115                 break;
3116
3117         case 17:
3118                 QUERY_NTTIME(msg, info17.acct_expiry,          "accountExpires");
3119
3120         case 20:
3121                 QUERY_STRING(msg, info20.parameters.string,    "userParameters");
3122                 break;
3123
3124         case 21:
3125                 QUERY_NTTIME(msg, info21.last_logon,           "lastLogon");
3126                 QUERY_NTTIME(msg, info21.last_logoff,          "lastLogoff");
3127                 QUERY_NTTIME(msg, info21.last_password_change, "pwdLastSet");
3128                 QUERY_NTTIME(msg, info21.acct_expiry,          "accountExpires");
3129                 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3130                 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3131                 QUERY_STRING(msg, info21.account_name.string,  "sAMAccountName");
3132                 QUERY_STRING(msg, info21.full_name.string,     "displayName");
3133                 QUERY_STRING(msg, info21.home_directory.string,"homeDirectory");
3134                 QUERY_STRING(msg, info21.home_drive.string,    "homeDrive");
3135                 QUERY_STRING(msg, info21.logon_script.string,  "scriptPath");
3136                 QUERY_STRING(msg, info21.profile_path.string,  "profilePath");
3137                 QUERY_STRING(msg, info21.description.string,   "description");
3138                 QUERY_STRING(msg, info21.workstations.string,  "userWorkstations");
3139                 QUERY_STRING(msg, info21.comment.string,       "comment");
3140                 QUERY_STRING(msg, info21.parameters.string,    "userParameters");
3141                 QUERY_RID   (msg, info21.rid,                  "objectSid");
3142                 QUERY_UINT  (msg, info21.primary_gid,          "primaryGroupID");
3143                 QUERY_AFLAGS(msg, info21.acct_flags,           "userAccountControl");
3144                 r->out.info->info21.fields_present = 0x00FFFFFF;
3145                 QUERY_LHOURS(msg, info21.logon_hours,          "logonHours");
3146                 QUERY_UINT  (msg, info21.bad_password_count,   "badPwdCount");
3147                 QUERY_UINT  (msg, info21.logon_count,          "logonCount");
3148                 QUERY_UINT  (msg, info21.country_code,         "countryCode");
3149                 QUERY_UINT  (msg, info21.code_page,            "codePage");
3150                 break;
3151                 
3152
3153         default:
3154                 r->out.info = NULL;
3155                 return NT_STATUS_INVALID_INFO_CLASS;
3156         }
3157         
3158         return NT_STATUS_OK;
3159 }
3160
3161
3162 /* 
3163   samr_SetUserInfo 
3164 */
3165 static NTSTATUS samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3166                                  struct samr_SetUserInfo *r)
3167 {
3168         struct dcesrv_handle *h;
3169         struct samr_account_state *a_state;
3170         struct ldb_message *msg;
3171         int ret;
3172         NTSTATUS status = NT_STATUS_OK;
3173         struct ldb_context *sam_ctx;
3174
3175         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3176
3177         a_state = h->data;
3178         sam_ctx = a_state->sam_ctx;
3179
3180         msg = ldb_msg_new(mem_ctx);
3181         if (msg == NULL) {
3182                 return NT_STATUS_NO_MEMORY;
3183         }
3184
3185         msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3186         if (!msg->dn) {
3187                 return NT_STATUS_NO_MEMORY;
3188         }
3189
3190         switch (r->in.level) {
3191         case 2:
3192                 SET_STRING(msg, info2.comment.string,          "comment");
3193                 SET_UINT  (msg, info2.country_code,            "countryCode");
3194                 SET_UINT  (msg, info2.code_page,               "codePage");
3195                 break;
3196
3197         case 4:
3198                 SET_LHOURS(msg, info4.logon_hours,             "logonHours");
3199                 break;
3200
3201         case 6:
3202                 SET_STRING(msg, info6.full_name.string,        "displayName");
3203                 break;
3204
3205         case 7:
3206                 SET_STRING(msg, info7.account_name.string,     "samAccountName");
3207                 break;
3208
3209         case 8:
3210                 SET_STRING(msg, info8.full_name.string,        "displayName");
3211                 break;
3212
3213         case 9:
3214                 SET_UINT(msg, info9.primary_gid,               "primaryGroupID");
3215                 break;
3216
3217         case 10:
3218                 SET_STRING(msg, info10.home_directory.string,  "homeDirectory");
3219                 SET_STRING(msg, info10.home_drive.string,      "homeDrive");
3220                 break;
3221
3222         case 11:
3223                 SET_STRING(msg, info11.logon_script.string,    "scriptPath");
3224                 break;
3225
3226         case 12:
3227                 SET_STRING(msg, info12.profile_path.string,    "profilePath");
3228                 break;
3229
3230         case 13:
3231                 SET_STRING(msg, info13.description.string,     "description");
3232                 break;
3233
3234         case 14:
3235                 SET_STRING(msg, info14.workstations.string,    "userWorkstations");
3236                 break;
3237
3238         case 16:
3239                 SET_AFLAGS(msg, info16.acct_flags,             "userAccountControl");
3240                 break;
3241
3242         case 20:
3243                 SET_STRING(msg, info20.parameters.string,      "userParameters");
3244                 break;
3245
3246         case 21:
3247 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3248                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
3249                         SET_STRING(msg, info21.account_name.string, "samAccountName");
3250                 IFSET(SAMR_FIELD_FULL_NAME)         
3251                         SET_STRING(msg, info21.full_name.string,    "displayName");
3252                 IFSET(SAMR_FIELD_DESCRIPTION)  
3253                         SET_STRING(msg, info21.description.string,  "description");
3254                 IFSET(SAMR_FIELD_COMMENT)      
3255                         SET_STRING(msg, info21.comment.string,      "comment");
3256                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
3257                         SET_STRING(msg, info21.logon_script.string, "scriptPath");
3258                 IFSET(SAMR_FIELD_PROFILE_PATH)      
3259                         SET_STRING(msg, info21.profile_path.string, "profilePath");
3260                 IFSET(SAMR_FIELD_WORKSTATIONS)  
3261                         SET_STRING(msg, info21.workstations.string, "userWorkstations");
3262                 IFSET(SAMR_FIELD_LOGON_HOURS)  
3263                         SET_LHOURS(msg, info21.logon_hours,         "logonHours");
3264                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
3265                         SET_AFLAGS(msg, info21.acct_flags,          "userAccountControl");
3266                 IFSET(SAMR_FIELD_PARAMETERS)     
3267                         SET_STRING(msg, info21.parameters.string,   "userParameters");
3268                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
3269                         SET_UINT  (msg, info21.country_code,        "countryCode");
3270                 IFSET(SAMR_FIELD_CODE_PAGE)    
3271                         SET_UINT  (msg, info21.code_page,           "codePage");
3272
3273
3274                 /* Any reason the rest of these can't be set? */
3275 #undef IFSET
3276                 break;
3277
3278         case 23:
3279 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3280                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
3281                         SET_STRING(msg, info23.info.account_name.string, "samAccountName");
3282                 IFSET(SAMR_FIELD_FULL_NAME)         
3283                         SET_STRING(msg, info23.info.full_name.string,    "displayName");
3284                 IFSET(SAMR_FIELD_DESCRIPTION)  
3285                         SET_STRING(msg, info23.info.description.string,  "description");
3286                 IFSET(SAMR_FIELD_COMMENT)      
3287                         SET_STRING(msg, info23.info.comment.string,      "comment");
3288                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
3289                         SET_STRING(msg, info23.info.logon_script.string, "scriptPath");
3290                 IFSET(SAMR_FIELD_PROFILE_PATH)      
3291                         SET_STRING(msg, info23.info.profile_path.string, "profilePath");
3292                 IFSET(SAMR_FIELD_WORKSTATIONS)  
3293                         SET_STRING(msg, info23.info.workstations.string, "userWorkstations");
3294                 IFSET(SAMR_FIELD_LOGON_HOURS)  
3295                         SET_LHOURS(msg, info23.info.logon_hours,         "logonHours");
3296                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
3297                         SET_AFLAGS(msg, info23.info.acct_flags,          "userAccountControl");
3298                 IFSET(SAMR_FIELD_PARAMETERS)     
3299                         SET_STRING(msg, info23.info.parameters.string,   "userParameters");
3300                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
3301                         SET_UINT  (msg, info23.info.country_code,        "countryCode");
3302                 IFSET(SAMR_FIELD_CODE_PAGE)    
3303                         SET_UINT  (msg, info23.info.code_page,           "codePage");
3304                 IFSET(SAMR_FIELD_PASSWORD) {
3305                         status = samr_set_password(dce_call,
3306                                                    a_state->sam_ctx,
3307                                                    a_state->account_dn,
3308                                                    a_state->domain_state->domain_dn,
3309                                                    mem_ctx, msg, 
3310                                                    &r->in.info->info23.password);
3311                 } else IFSET(SAMR_FIELD_PASSWORD2) {
3312                         status = samr_set_password(dce_call,
3313                                                    a_state->sam_ctx,
3314                                                    a_state->account_dn,
3315                                                    a_state->domain_state->domain_dn,
3316                                                    mem_ctx, msg, 
3317                                                    &r->in.info->info23.password);
3318                 }
3319 #undef IFSET
3320                 break;
3321
3322                 /* the set password levels are handled separately */
3323         case 24:
3324                 status = samr_set_password(dce_call,
3325                                            a_state->sam_ctx,
3326                                            a_state->account_dn,
3327                                            a_state->domain_state->domain_dn,
3328                                            mem_ctx, msg, 
3329                                            &r->in.info->info24.password);
3330                 break;
3331
3332         case 25:
3333 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3334                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
3335                         SET_STRING(msg, info25.info.account_name.string, "samAccountName");
3336                 IFSET(SAMR_FIELD_FULL_NAME)         
3337                         SET_STRING(msg, info25.info.full_name.string,    "displayName");
3338                 IFSET(SAMR_FIELD_DESCRIPTION)  
3339                         SET_STRING(msg, info25.info.description.string,  "description");
3340                 IFSET(SAMR_FIELD_COMMENT)      
3341                         SET_STRING(msg, info25.info.comment.string,      "comment");
3342                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
3343                         SET_STRING(msg, info25.info.logon_script.string, "scriptPath");
3344                 IFSET(SAMR_FIELD_PROFILE_PATH)      
3345                         SET_STRING(msg, info25.info.profile_path.string, "profilePath");
3346                 IFSET(SAMR_FIELD_WORKSTATIONS)  
3347                         SET_STRING(msg, info25.info.workstations.string, "userWorkstations");
3348                 IFSET(SAMR_FIELD_LOGON_HOURS)  
3349                         SET_LHOURS(msg, info25.info.logon_hours,         "logonHours");
3350                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
3351                         SET_AFLAGS(msg, info25.info.acct_flags,          "userAccountControl");
3352                 IFSET(SAMR_FIELD_PARAMETERS)     
3353                         SET_STRING(msg, info25.info.parameters.string,   "userParameters");
3354                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
3355                         SET_UINT  (msg, info25.info.country_code,        "countryCode");
3356                 IFSET(SAMR_FIELD_CODE_PAGE)    
3357                         SET_UINT  (msg, info25.info.code_page,           "codePage");
3358                 IFSET(SAMR_FIELD_PASSWORD) {
3359                         status = samr_set_password_ex(dce_call,
3360                                                       a_state->sam_ctx,
3361                                                       a_state->account_dn,
3362                                                       a_state->domain_state->domain_dn,
3363                                                       mem_ctx, msg, 
3364                                                       &r->in.info->info25.password);
3365                 } else IFSET(SAMR_FIELD_PASSWORD2) {
3366                         status = samr_set_password_ex(dce_call,
3367                                                       a_state->sam_ctx,
3368                                                       a_state->account_dn,
3369                                                       a_state->domain_state->domain_dn,
3370                                                       mem_ctx, msg, 
3371                                                       &r->in.info->info25.password);
3372                 }
3373 #undef IFSET
3374                 break;
3375
3376                 /* the set password levels are handled separately */
3377         case 26:
3378                 status = samr_set_password_ex(dce_call,
3379                                               a_state->sam_ctx,
3380                                               a_state->account_dn,
3381                                               a_state->domain_state->domain_dn,
3382                                               mem_ctx, msg, 
3383                                               &r->in.info->info26.password);
3384                 break;
3385                 
3386
3387         default:
3388                 /* many info classes are not valid for SetUserInfo */
3389                 return NT_STATUS_INVALID_INFO_CLASS;
3390         }
3391
3392         if (!NT_STATUS_IS_OK(status)) {
3393                 return status;
3394         }
3395
3396         /* modify the samdb record */
3397         ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
3398         if (ret != 0) {
3399                 DEBUG(1,("Failed to modify record %s: %s\n",
3400                          ldb_dn_linearize(mem_ctx, a_state->account_dn),
3401                          ldb_errstring(a_state->sam_ctx)));
3402
3403                 /* we really need samdb.c to return NTSTATUS */
3404                 return NT_STATUS_UNSUCCESSFUL;
3405         }
3406
3407         return NT_STATUS_OK;
3408 }
3409
3410
3411 /* 
3412   samr_GetGroupsForUser 
3413 */
3414 static NTSTATUS samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3415                        struct samr_GetGroupsForUser *r)
3416 {
3417         struct dcesrv_handle *h;
3418         struct samr_account_state *a_state;
3419         struct samr_domain_state *d_state;
3420         struct ldb_message **res;
3421         const char * const attrs[2] = { "objectSid", NULL };
3422         struct samr_RidWithAttributeArray *array;
3423         int count;
3424
3425         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3426
3427         a_state = h->data;
3428         d_state = a_state->domain_state;
3429
3430         count = samdb_search_domain(a_state->sam_ctx, mem_ctx, d_state->domain_dn, &res,
3431                                     attrs, d_state->domain_sid,
3432                                     "(&(member=%s)(grouptype=%d)(objectclass=group))",
3433                                     ldb_dn_linearize(mem_ctx, a_state->account_dn),
3434                                     GTYPE_SECURITY_GLOBAL_GROUP);
3435         if (count < 0)
3436                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3437
3438         array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3439         if (array == NULL)
3440                 return NT_STATUS_NO_MEMORY;
3441
3442         array->count = 0;
3443         array->rids = NULL;
3444
3445         if (count > 0) {
3446                 int i;
3447                 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3448                                             count);
3449
3450                 if (array->rids == NULL)
3451                         return NT_STATUS_NO_MEMORY;
3452
3453                 for (i=0; i<count; i++) {
3454                         struct dom_sid *group_sid;
3455
3456                         group_sid = samdb_result_dom_sid(mem_ctx, res[i],
3457                                                          "objectSid");
3458                         if (group_sid == NULL) {
3459                                 DEBUG(0, ("Couldn't find objectSid attrib\n"));
3460                                 continue;
3461                         }
3462
3463                         array->rids[array->count].rid =
3464                                 group_sid->sub_auths[group_sid->num_auths-1];
3465                         array->rids[array->count].attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3466                         array->count += 1;
3467                 }
3468         }
3469
3470         r->out.rids = array;
3471
3472         return NT_STATUS_OK;
3473 }
3474
3475
3476 /* 
3477   samr_QueryDisplayInfo 
3478 */
3479 static NTSTATUS samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3480                        struct samr_QueryDisplayInfo *r)
3481 {
3482         struct dcesrv_handle *h;
3483         struct samr_domain_state *d_state;
3484         struct ldb_message **res;
3485         int ldb_cnt, count, i;
3486         const char * const attrs[4] = { "objectSid", "sAMAccountName",
3487                                         "description", NULL };
3488         struct samr_DispEntryFull *entriesFull = NULL;
3489         struct samr_DispEntryAscii *entriesAscii = NULL;
3490         struct samr_DispEntryGeneral * entriesGeneral = NULL;
3491         const char *filter;
3492
3493         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3494
3495         d_state = h->data;
3496
3497         switch (r->in.level) {
3498         case 1:
3499         case 4:
3500                 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3501                                          "(sAMAccountType=%u))",
3502                                          ATYPE_NORMAL_ACCOUNT);
3503                 break;
3504         case 2:
3505                 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3506                                          "(sAMAccountType=%u))",
3507                                          ATYPE_WORKSTATION_TRUST);
3508                 break;
3509         case 3:
3510         case 5:
3511                 filter = talloc_asprintf(mem_ctx, "(&(grouptype=%d)"
3512                                          "(objectclass=group))",
3513                                          GTYPE_SECURITY_GLOBAL_GROUP);
3514                 break;
3515         default:
3516                 return NT_STATUS_INVALID_INFO_CLASS;
3517         }
3518
3519         /* search for all requested objects in this domain. This could
3520            possibly be cached and resumed based on resume_key */
3521         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3522                                       d_state->domain_dn, &res, attrs,
3523                                       d_state->domain_sid, "%s", filter);
3524         if (ldb_cnt == -1) {
3525                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3526         }
3527         if (ldb_cnt == 0 || r->in.max_entries == 0) {
3528                 return NT_STATUS_OK;
3529         }
3530
3531         switch (r->in.level) {
3532         case 1:
3533                 entriesGeneral = talloc_array(mem_ctx,
3534                                                 struct samr_DispEntryGeneral,
3535                                                 ldb_cnt);
3536                 break;
3537         case 2:
3538         case 3:
3539                 entriesFull = talloc_array(mem_ctx,
3540                                              struct samr_DispEntryFull,
3541                                              ldb_cnt);
3542                 break;
3543         case 4:
3544         case 5:
3545                 entriesAscii = talloc_array(mem_ctx,
3546                                               struct samr_DispEntryAscii,
3547                                               ldb_cnt);
3548                 break;
3549         }
3550
3551         if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3552             (entriesAscii == NULL))
3553                 return NT_STATUS_NO_MEMORY;
3554
3555         count = 0;
3556
3557         for (i=0; i<ldb_cnt; i++) {
3558                 struct dom_sid *objectsid;
3559
3560                 objectsid = samdb_result_dom_sid(mem_ctx, res[i],
3561                                                  "objectSid");
3562                 if (objectsid == NULL)
3563                         continue;
3564
3565                 switch(r->in.level) {
3566                 case 1:
3567                         entriesGeneral[count].idx = count + 1;
3568                         entriesGeneral[count].rid = 
3569                                 objectsid->sub_auths[objectsid->num_auths-1];
3570                         entriesGeneral[count].acct_flags =
3571                                 samdb_result_acct_flags(res[i], 
3572                                                         "userAccountControl");
3573                         entriesGeneral[count].account_name.string =
3574                                 samdb_result_string(res[i],
3575                                                     "sAMAccountName", "");
3576                         entriesGeneral[count].full_name.string =
3577                                 samdb_result_string(res[i], "displayName", "");
3578                         entriesGeneral[count].description.string =
3579                                 samdb_result_string(res[i], "description", "");
3580                         break;
3581                 case 2:
3582                 case 3:
3583                         entriesFull[count].idx = count + 1;
3584                         entriesFull[count].rid =
3585                                 objectsid->sub_auths[objectsid->num_auths-1];
3586                         entriesFull[count].acct_flags =
3587                                 samdb_result_acct_flags(res[i], 
3588                                                         "userAccountControl");
3589                         if (r->in.level == 3) {
3590                                 /* We get a "7" here for groups */
3591                                 entriesFull[count].acct_flags = 7;
3592                         }
3593                         entriesFull[count].account_name.string =
3594                                 samdb_result_string(res[i], "sAMAccountName",
3595                                                     "");
3596                         entriesFull[count].description.string =
3597                                 samdb_result_string(res[i], "description", "");
3598                         break;
3599                 case 4:
3600                 case 5:
3601                         entriesAscii[count].idx = count + 1;
3602                         entriesAscii[count].account_name.string =
3603                                 samdb_result_string(res[i], "sAMAccountName",
3604                                                     "");
3605                         break;
3606                 }
3607
3608                 count += 1;
3609         }
3610
3611         r->out.total_size = count;
3612
3613         if (r->in.start_idx >= count) {
3614                 r->out.returned_size = 0;
3615                 switch(r->in.level) {
3616                 case 1:
3617                         r->out.info.info1.count = r->out.returned_size;
3618                         r->out.info.info1.entries = NULL;
3619                         break;
3620                 case 2:
3621                         r->out.info.info2.count = r->out.returned_size;
3622                         r->out.info.info2.entries = NULL;
3623                         break;
3624                 case 3:
3625                         r->out.info.info3.count = r->out.returned_size;
3626                         r->out.info.info3.entries = NULL;
3627                         break;
3628                 case 4:
3629                         r->out.info.info4.count = r->out.returned_size;
3630                         r->out.info.info4.entries = NULL;
3631                         break;
3632                 case 5:
3633                         r->out.info.info5.count = r->out.returned_size;
3634                         r->out.info.info5.entries = NULL;
3635                         break;
3636                 }
3637         } else {
3638                 r->out.returned_size = MIN(count - r->in.start_idx,
3639                                            r->in.max_entries);
3640                 switch(r->in.level) {
3641                 case 1:
3642                         r->out.info.info1.count = r->out.returned_size;
3643                         r->out.info.info1.entries =
3644                                 &(entriesGeneral[r->in.start_idx]);
3645                         break;
3646                 case 2:
3647                         r->out.info.info2.count = r->out.returned_size;
3648                         r->out.info.info2.entries =
3649                                 &(entriesFull[r->in.start_idx]);
3650                         break;
3651                 case 3:
3652                         r->out.info.info3.count = r->out.returned_size;
3653                         r->out.info.info3.entries =
3654                                 &(entriesFull[r->in.start_idx]);
3655                         break;
3656                 case 4:
3657                         r->out.info.info4.count = r->out.returned_size;
3658                         r->out.info.info4.entries =
3659                                 &(entriesAscii[r->in.start_idx]);
3660                         break;
3661                 case 5:
3662                         r->out.info.info5.count = r->out.returned_size;
3663                         r->out.info.info5.entries =
3664                                 &(entriesAscii[r->in.start_idx]);
3665                         break;
3666                 }
3667         }
3668
3669         return (r->out.returned_size < (count - r->in.start_idx)) ?
3670                 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3671 }
3672
3673
3674 /* 
3675   samr_GetDisplayEnumerationIndex 
3676 */
3677 static NTSTATUS samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3678                        struct samr_GetDisplayEnumerationIndex *r)
3679 {
3680         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3681 }
3682
3683
3684 /* 
3685   samr_TestPrivateFunctionsDomain 
3686 */
3687 static NTSTATUS samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3688                        struct samr_TestPrivateFunctionsDomain *r)
3689 {
3690         return NT_STATUS_NOT_IMPLEMENTED;
3691 }
3692
3693
3694 /* 
3695   samr_TestPrivateFunctionsUser 
3696 */
3697 static NTSTATUS samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3698                        struct samr_TestPrivateFunctionsUser *r)
3699 {
3700         return NT_STATUS_NOT_IMPLEMENTED;
3701 }
3702
3703
3704 /* 
3705   samr_GetUserPwInfo 
3706 */
3707 static NTSTATUS samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3708                                    struct samr_GetUserPwInfo *r)
3709 {
3710         struct dcesrv_handle *h;
3711         struct samr_account_state *a_state;
3712
3713         ZERO_STRUCT(r->out.info);
3714
3715         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3716
3717         a_state = h->data;
3718
3719         r->out.info.min_password_length = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0,
3720                                                             a_state->domain_state->domain_dn, "minPwdLength", 
3721                                                             NULL);
3722         r->out.info.password_properties = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0,
3723                                                             a_state->account_dn, 
3724                                                             "pwdProperties", NULL);
3725         return NT_STATUS_OK;
3726 }
3727
3728
3729 /* 
3730   samr_RemoveMemberFromForeignDomain 
3731 */
3732 static NTSTATUS samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3733                        struct samr_RemoveMemberFromForeignDomain *r)
3734 {
3735         struct dcesrv_handle *h;
3736         struct samr_domain_state *d_state;
3737         const char *memberdn;
3738         struct ldb_message **res;
3739         const char * const attrs[3] = { "distinguishedName", "objectSid", NULL };
3740         int i, count;
3741
3742         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3743
3744         d_state = h->data;
3745
3746         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3747                                        "distinguishedName", "(objectSid=%s)", 
3748                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3749         /* Nothing to do */
3750         if (memberdn == NULL) {
3751                 return NT_STATUS_OK;
3752         }
3753
3754         /* TODO: Does this call only remove alias members, or does it do this
3755          * for domain groups as well? */
3756
3757         count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3758                                     d_state->domain_dn, &res, attrs,
3759                                     d_state->domain_sid,
3760                                     "(&(member=%s)(objectClass=group)"
3761                                     "(|(groupType=%d)(groupType=%d)))",
3762                                     memberdn,
3763                                     GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
3764                                     GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
3765
3766         if (count < 0)
3767                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3768
3769         for (i=0; i<count; i++) {
3770                 struct ldb_message *mod;
3771
3772                 mod = ldb_msg_new(mem_ctx);
3773                 if (mod == NULL) {
3774                         return NT_STATUS_NO_MEMORY;
3775                 }
3776
3777                 mod->dn = samdb_result_dn(mod, res[i], "distinguishedName", NULL);
3778                 if (mod->dn == NULL) {
3779                         talloc_free(mod);
3780                         continue;
3781                 }
3782
3783                 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
3784                                          "member", memberdn) != 0)
3785                         return NT_STATUS_NO_MEMORY;
3786
3787                 if (samdb_modify(d_state->sam_ctx, mem_ctx, mod) != 0)
3788                         return NT_STATUS_UNSUCCESSFUL;
3789
3790                 talloc_free(mod);
3791         }
3792
3793         return NT_STATUS_OK;
3794 }
3795
3796
3797 /* 
3798   samr_QueryDomainInfo2 
3799
3800   just an alias for samr_QueryDomainInfo
3801 */
3802 static NTSTATUS samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3803                        struct samr_QueryDomainInfo2 *r)
3804 {
3805         struct samr_QueryDomainInfo r1;
3806         NTSTATUS status;
3807
3808         ZERO_STRUCT(r1.out);
3809         r1.in.domain_handle = r->in.domain_handle;
3810         r1.in.level  = r->in.level;
3811         
3812         status = samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
3813         
3814         r->out.info = r1.out.info;
3815
3816         return status;
3817 }
3818
3819
3820 /* 
3821   samr_QueryUserInfo2 
3822
3823   just an alias for samr_QueryUserInfo
3824 */
3825 static NTSTATUS samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3826                                     struct samr_QueryUserInfo2 *r)
3827 {
3828         struct samr_QueryUserInfo r1;
3829         NTSTATUS status;
3830
3831         ZERO_STRUCT(r1.out);
3832         r1.in.user_handle = r->in.user_handle;
3833         r1.in.level  = r->in.level;
3834         
3835         status = samr_QueryUserInfo(dce_call, mem_ctx, &r1);
3836         
3837         r->out.info = r1.out.info;
3838
3839         return status;
3840 }
3841
3842
3843 /* 
3844   samr_QueryDisplayInfo2 
3845 */
3846 static NTSTATUS samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3847                                        struct samr_QueryDisplayInfo2 *r)
3848 {
3849         struct samr_QueryDisplayInfo q;
3850         NTSTATUS result;
3851
3852         q.in.domain_handle = r->in.domain_handle;
3853         q.in.level = r->in.level;
3854         q.in.start_idx = r->in.start_idx;
3855         q.in.max_entries = r->in.max_entries;
3856         q.in.buf_size = r->in.buf_size;
3857         ZERO_STRUCT(q.out);
3858
3859         result = samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
3860
3861         r->out.total_size = q.out.total_size;
3862         r->out.returned_size = q.out.returned_size;
3863         r->out.info = q.out.info;
3864
3865         return result;
3866 }
3867
3868
3869 /* 
3870   samr_GetDisplayEnumerationIndex2 
3871 */
3872 static NTSTATUS samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3873                        struct samr_GetDisplayEnumerationIndex2 *r)
3874 {
3875         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3876 }
3877
3878
3879 /* 
3880   samr_QueryDisplayInfo3 
3881 */
3882 static NTSTATUS samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3883                        struct samr_QueryDisplayInfo3 *r)
3884 {
3885         struct samr_QueryDisplayInfo q;
3886         NTSTATUS result;
3887
3888         q.in.domain_handle = r->in.domain_handle;
3889         q.in.level = r->in.level;
3890         q.in.start_idx = r->in.start_idx;
3891         q.in.max_entries = r->in.max_entries;
3892         q.in.buf_size = r->in.buf_size;
3893         ZERO_STRUCT(q.out);
3894
3895         result = samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
3896
3897         r->out.total_size = q.out.total_size;
3898         r->out.returned_size = q.out.returned_size;
3899         r->out.info = q.out.info;
3900
3901         return result;
3902 }
3903
3904
3905 /* 
3906   samr_AddMultipleMembersToAlias 
3907 */
3908 static NTSTATUS samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3909                        struct samr_AddMultipleMembersToAlias *r)
3910 {
3911         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3912 }
3913
3914
3915 /* 
3916   samr_RemoveMultipleMembersFromAlias 
3917 */
3918 static NTSTATUS samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3919                        struct samr_RemoveMultipleMembersFromAlias *r)
3920 {
3921         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3922 }
3923
3924
3925 /* 
3926   samr_GetDomPwInfo 
3927
3928   this fetches the default password properties for a domain
3929
3930   note that w2k3 completely ignores the domain name in this call, and 
3931   always returns the information for the servers primary domain
3932 */
3933 static NTSTATUS samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3934                                   struct samr_GetDomPwInfo *r)
3935 {
3936         struct ldb_message **msgs;
3937         int ret;
3938         const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
3939         struct ldb_context *sam_ctx;
3940
3941         ZERO_STRUCT(r->out.info);
3942
3943         sam_ctx = samdb_connect(mem_ctx, dce_call->conn->auth_state.session_info); 
3944         if (sam_ctx == NULL) {
3945                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
3946         }
3947
3948         /* The domain name in this call is ignored */
3949         ret = gendb_search_dn(sam_ctx, 
3950                            mem_ctx, NULL, &msgs, attrs);
3951         if (ret <= 0) {
3952                 return NT_STATUS_NO_SUCH_DOMAIN;
3953         }
3954         if (ret > 1) {
3955                 talloc_free(msgs);
3956                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3957         }
3958
3959         r->out.info.min_password_length = samdb_result_uint(msgs[0], "minPwdLength", 0);
3960         r->out.info.password_properties = samdb_result_uint(msgs[0], "pwdProperties", 1);
3961
3962         talloc_free(msgs);
3963
3964         talloc_free(sam_ctx);
3965         return NT_STATUS_OK;
3966 }
3967
3968
3969 /* 
3970   samr_Connect2 
3971 */
3972 static NTSTATUS samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3973                               struct samr_Connect2 *r)
3974 {
3975         struct samr_Connect c;
3976
3977         c.in.system_name = NULL;
3978         c.in.access_mask = r->in.access_mask;
3979         c.out.connect_handle = r->out.connect_handle;
3980
3981         return samr_Connect(dce_call, mem_ctx, &c);
3982 }
3983
3984
3985 /* 
3986   samr_SetUserInfo2 
3987
3988   just an alias for samr_SetUserInfo
3989 */
3990 static NTSTATUS samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3991                                   struct samr_SetUserInfo2 *r)
3992 {
3993         struct samr_SetUserInfo r2;
3994
3995         r2.in.user_handle = r->in.user_handle;
3996         r2.in.level = r->in.level;
3997         r2.in.info = r->in.info;
3998
3999         return samr_SetUserInfo(dce_call, mem_ctx, &r2);
4000 }
4001
4002
4003 /* 
4004   samr_SetBootKeyInformation 
4005 */
4006 static NTSTATUS samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4007                        struct samr_SetBootKeyInformation *r)
4008 {
4009         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4010 }
4011
4012
4013 /* 
4014   samr_GetBootKeyInformation 
4015 */
4016 static NTSTATUS samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4017                        struct samr_GetBootKeyInformation *r)
4018 {
4019         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4020 }
4021
4022
4023 /* 
4024   samr_Connect3 
4025 */
4026 static NTSTATUS samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4027                        struct samr_Connect3 *r)
4028 {
4029         struct samr_Connect c;
4030
4031         c.in.system_name = NULL;
4032         c.in.access_mask = r->in.access_mask;
4033         c.out.connect_handle = r->out.connect_handle;
4034
4035         return samr_Connect(dce_call, mem_ctx, &c);
4036 }
4037
4038
4039 /* 
4040   samr_Connect4 
4041 */
4042 static NTSTATUS samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4043                        struct samr_Connect4 *r)
4044 {
4045         struct samr_Connect c;
4046
4047         c.in.system_name = NULL;
4048         c.in.access_mask = r->in.access_mask;
4049         c.out.connect_handle = r->out.connect_handle;
4050
4051         return samr_Connect(dce_call, mem_ctx, &c);
4052 }
4053
4054
4055 /* 
4056   samr_Connect5 
4057 */
4058 static NTSTATUS samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4059                               struct samr_Connect5 *r)
4060 {
4061         struct samr_Connect c;
4062         NTSTATUS status;
4063
4064         c.in.system_name = NULL;
4065         c.in.access_mask = r->in.access_mask;
4066         c.out.connect_handle = r->out.connect_handle;
4067
4068         status = samr_Connect(dce_call, mem_ctx, &c);
4069
4070         r->out.info->info1.unknown1 = 3;
4071         r->out.info->info1.unknown2 = 0;
4072         r->out.level = r->in.level;
4073
4074         return status;
4075 }
4076
4077
4078 /* 
4079   samr_RidToSid 
4080 */
4081 static NTSTATUS samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4082                               struct samr_RidToSid *r)
4083 {
4084         struct samr_domain_state *d_state;
4085         struct dcesrv_handle *h;
4086
4087         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4088
4089         d_state = h->data;
4090
4091         /* form the users SID */
4092         r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4093         if (!r->out.sid) {
4094                 return NT_STATUS_NO_MEMORY;
4095         }
4096
4097         return NT_STATUS_OK;
4098 }
4099
4100
4101 /* 
4102   samr_SetDsrmPassword 
4103 */
4104 static NTSTATUS samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4105                        struct samr_SetDsrmPassword *r)
4106 {
4107         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4108 }
4109
4110
4111 /* 
4112   samr_ValidatePassword 
4113 */
4114 static NTSTATUS samr_ValidatePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4115                                       struct samr_ValidatePassword *r)
4116 {
4117         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4118 }
4119
4120
4121 /* include the generated boilerplate */
4122 #include "librpc/gen_ndr/ndr_samr_s.c"