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