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