r16794: Make Samba4 pass it's own RPC-SAMR test, at least in part. There are
[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, samdb_base_dn(mem_ctx), &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, samdb_base_dn(mem_ctx), &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, samdb_base_dn(mem_ctx), &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_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_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_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_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_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_uint64(dom_msgs[0], "modifiedCount", 
570                                                time(NULL));
571
572         info->domain_create_time = ldb_msg_find_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_int64(dom_msgs[0], "lockoutDuration", 
606                                                     -18000000000LL);
607         info->lockout_window = ldb_msg_find_int64(dom_msgs[0], "lockOutObservationWindow",
608                                                     -18000000000LL);
609         info->lockout_threshold = ldb_msg_find_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_int64(dom_msgs[0], "lockoutDuration", 
623                                                     -18000000000LL);
624         info->lockout_window = ldb_msg_find_int64(dom_msgs[0], "lockOutObservationWindow",
625                                                     -18000000000LL);
626         info->lockout_threshold = ldb_msg_find_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_uint64(dom_msgs[0], "modifiedCount", 
640                                                time(NULL));
641
642         info->domain_create_time = ldb_msg_find_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, samdb_base_dn(mem_ctx), 
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, samdb_base_dn(mem_ctx), "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
2531         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2532
2533         a_state = h->data;
2534         d_state = a_state->domain_state;
2535
2536         ret = gendb_search(d_state->sam_ctx, mem_ctx, samdb_base_dn(mem_ctx),
2537                            &msgs, attrs, "(objectsid=%s)", 
2538                            ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2539
2540         if (ret == 1) {
2541                 memberdn = msgs[0]->dn;
2542         } else  if (ret > 1) {
2543                 DEBUG(0,("Found %d records matching sid %s\n", 
2544                          ret, dom_sid_string(mem_ctx, r->in.sid)));
2545                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2546         } else if (ret == 0) {
2547                 struct ldb_message *msg;
2548                 struct ldb_dn *basedn;
2549                 const char *sidstr;
2550
2551                 sidstr = dom_sid_string(mem_ctx, r->in.sid);
2552                 NT_STATUS_HAVE_NO_MEMORY(sidstr);
2553
2554                 /* We might have to create a ForeignSecurityPrincipal, even if this user
2555                  * is in our own domain */
2556
2557                 msg = ldb_msg_new(mem_ctx);
2558                 if (msg == NULL) {
2559                         return NT_STATUS_NO_MEMORY;
2560                 }
2561
2562                 /* TODO: Hmmm. This feels wrong. How do I find the base dn to
2563                  * put the ForeignSecurityPrincipals? d_state->domain_dn does
2564                  * not work, this is wrong for the Builtin domain, there's no
2565                  * cn=For...,cn=Builtin,dc={BASEDN}.  -- vl
2566                  */
2567
2568                 basedn = samdb_search_dn(d_state->sam_ctx, mem_ctx, samdb_base_dn(mem_ctx),
2569                                          "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
2570
2571                 if (basedn == NULL) {
2572                         DEBUG(0, ("Failed to find DN for "
2573                                   "ForeignSecurityPrincipal container\n"));
2574                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
2575                 }
2576
2577                 /* add core elements to the ldb_message for the alias */
2578                 msg->dn = ldb_dn_build_child(mem_ctx, "CN", sidstr, basedn);
2579                 if (msg->dn == NULL)
2580                         return NT_STATUS_NO_MEMORY;
2581
2582                 memberdn = msg->dn;
2583
2584                 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg,
2585                                      "objectClass",
2586                                      "foreignSecurityPrincipal");
2587
2588                 /* create the alias */
2589                 ret = samdb_add(d_state->sam_ctx, mem_ctx, msg);
2590                 if (ret != 0) {
2591                         DEBUG(0,("Failed to create foreignSecurityPrincipal "
2592                                  "record %s: %s\n", 
2593                                  ldb_dn_linearize(mem_ctx, msg->dn),
2594                                  ldb_errstring(d_state->sam_ctx)));
2595                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
2596                 }
2597         } else {
2598                 DEBUG(0, ("samdb_search returned %d\n", ret));
2599         }
2600
2601         if (memberdn == NULL) {
2602                 DEBUG(0, ("Could not find memberdn\n"));
2603                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2604         }
2605
2606         mod = ldb_msg_new(mem_ctx);
2607         if (mod == NULL) {
2608                 return NT_STATUS_NO_MEMORY;
2609         }
2610
2611         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2612
2613         if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2614                                  ldb_dn_linearize(mem_ctx, memberdn)) != 0)
2615                 return NT_STATUS_UNSUCCESSFUL;
2616
2617         if (samdb_modify(a_state->sam_ctx, mem_ctx, mod) != 0)
2618                 return NT_STATUS_UNSUCCESSFUL;
2619
2620         return NT_STATUS_OK;
2621 }
2622
2623
2624 /* 
2625   samr_DeleteAliasMember 
2626 */
2627 static NTSTATUS samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2628                        struct samr_DeleteAliasMember *r)
2629 {
2630         struct dcesrv_handle *h;
2631         struct samr_account_state *a_state;
2632         struct samr_domain_state *d_state;
2633         struct ldb_message *mod;
2634         const char *memberdn;
2635
2636         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2637
2638         a_state = h->data;
2639         d_state = a_state->domain_state;
2640
2641         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, samdb_base_dn(mem_ctx),
2642                                        "distinguishedName", "(objectSid=%s)", 
2643                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2644
2645         if (memberdn == NULL)
2646                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2647
2648         mod = ldb_msg_new(mem_ctx);
2649         if (mod == NULL) {
2650                 return NT_STATUS_NO_MEMORY;
2651         }
2652
2653         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2654
2655         if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2656                                  memberdn) != 0)
2657                 return NT_STATUS_UNSUCCESSFUL;
2658
2659         if (samdb_modify(a_state->sam_ctx, mem_ctx, mod) != 0)
2660                 return NT_STATUS_UNSUCCESSFUL;
2661
2662         return NT_STATUS_OK;
2663 }
2664
2665
2666 /* 
2667   samr_GetMembersInAlias 
2668 */
2669 static NTSTATUS samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2670                        struct samr_GetMembersInAlias *r)
2671 {
2672         struct dcesrv_handle *h;
2673         struct samr_account_state *a_state;
2674         struct samr_domain_state *d_state;
2675         struct ldb_message **msgs;
2676         struct lsa_SidPtr *sids;
2677         struct ldb_message_element *el;
2678         const char * const attrs[2] = { "member", NULL};
2679         int ret;
2680
2681         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2682
2683         a_state = h->data;
2684         d_state = a_state->domain_state;
2685
2686         ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
2687                               a_state->account_dn, &msgs, attrs);
2688
2689         if (ret != 1)
2690                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2691
2692         r->out.sids->num_sids = 0;
2693         r->out.sids->sids = NULL;
2694
2695         el = ldb_msg_find_element(msgs[0], "member");
2696
2697         if (el != NULL) {
2698                 int i;
2699
2700                 sids = talloc_array(mem_ctx, struct lsa_SidPtr,
2701                                       el->num_values);
2702
2703                 if (sids == NULL)
2704                         return NT_STATUS_NO_MEMORY;
2705
2706                 for (i=0; i<el->num_values; i++) {
2707                         struct ldb_message **msgs2;
2708                         const char * const attrs2[2] = { "objectSid", NULL };
2709                         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2710                                            ldb_dn_explode(mem_ctx, (const char *)el->values[i].data),
2711                                            &msgs2, attrs2);
2712                         if (ret != 1)
2713                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2714
2715                         sids[i].sid = samdb_result_dom_sid(mem_ctx, msgs2[0],
2716                                                            "objectSid");
2717
2718                         if (sids[i].sid == NULL)
2719                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2720                 }
2721                 r->out.sids->num_sids = el->num_values;
2722                 r->out.sids->sids = sids;
2723         }
2724
2725         return NT_STATUS_OK;
2726 }
2727
2728 /* 
2729   samr_OpenUser 
2730 */
2731 static NTSTATUS samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2732                               struct samr_OpenUser *r)
2733 {
2734         struct samr_domain_state *d_state;
2735         struct samr_account_state *a_state;
2736         struct dcesrv_handle *h;
2737         const char *account_name;
2738         struct dom_sid *sid;
2739         struct ldb_message **msgs;
2740         struct dcesrv_handle *u_handle;
2741         const char * const attrs[2] = { "sAMAccountName", NULL };
2742         int ret;
2743
2744         ZERO_STRUCTP(r->out.user_handle);
2745
2746         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2747
2748         d_state = h->data;
2749
2750         /* form the users SID */
2751         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2752         if (!sid) {
2753                 return NT_STATUS_NO_MEMORY;
2754         }
2755
2756         /* search for the user record */
2757         ret = gendb_search(d_state->sam_ctx,
2758                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2759                            "(&(objectSid=%s)(objectclass=user))", 
2760                            ldap_encode_ndr_dom_sid(mem_ctx, sid));
2761         if (ret == 0) {
2762                 return NT_STATUS_NO_SUCH_USER;
2763         }
2764         if (ret != 1) {
2765                 DEBUG(0,("Found %d records matching sid %s\n", ret, 
2766                          dom_sid_string(mem_ctx, sid)));
2767                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2768         }
2769
2770         account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2771         if (account_name == NULL) {
2772                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2773                          dom_sid_string(mem_ctx, sid)));
2774                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2775         }
2776
2777         a_state = talloc(mem_ctx, struct samr_account_state);
2778         if (!a_state) {
2779                 return NT_STATUS_NO_MEMORY;
2780         }
2781         a_state->sam_ctx = d_state->sam_ctx;
2782         a_state->access_mask = r->in.access_mask;
2783         a_state->domain_state = talloc_reference(a_state, d_state);
2784         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2785         a_state->account_sid = talloc_steal(a_state, sid);
2786         a_state->account_name = talloc_strdup(a_state, account_name);
2787         if (!a_state->account_name) {
2788                 return NT_STATUS_NO_MEMORY;
2789         }
2790
2791         /* create the policy handle */
2792         u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2793         if (!u_handle) {
2794                 return NT_STATUS_NO_MEMORY;
2795         }
2796
2797         u_handle->data = talloc_steal(u_handle, a_state);
2798
2799         *r->out.user_handle = u_handle->wire_handle;
2800
2801         return NT_STATUS_OK;
2802
2803 }
2804
2805
2806 /* 
2807   samr_DeleteUser 
2808 */
2809 static NTSTATUS samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2810                                 struct samr_DeleteUser *r)
2811 {
2812         struct dcesrv_handle *h;
2813         struct samr_account_state *a_state;
2814         int ret;
2815
2816         *r->out.user_handle = *r->in.user_handle;
2817
2818         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2819
2820         a_state = h->data;
2821
2822         ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
2823         if (ret != 0) {
2824                 return NT_STATUS_UNSUCCESSFUL;
2825         }
2826
2827         ZERO_STRUCTP(r->out.user_handle);
2828
2829         return NT_STATUS_OK;
2830 }
2831
2832
2833 /* 
2834   samr_QueryUserInfo 
2835 */
2836 static NTSTATUS samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2837                                    struct samr_QueryUserInfo *r)
2838 {
2839         struct dcesrv_handle *h;
2840         struct samr_account_state *a_state;
2841         struct ldb_message *msg, **res;
2842         int ret;
2843         struct ldb_context *sam_ctx;
2844
2845         const char * const *attrs = NULL;
2846
2847         r->out.info = NULL;
2848
2849         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2850
2851         a_state = h->data;
2852         sam_ctx = a_state->sam_ctx;
2853
2854         /* fill in the reply */
2855         switch (r->in.level) {
2856         case 1:
2857         {
2858                 static const char * const attrs2[] = {"sAMAccountName", "displayName",
2859                                                       "primaryGroupID", "description",
2860                                                       "comment", NULL};
2861                 attrs = attrs2;
2862                 break;
2863         }
2864         case 2:
2865         {
2866                 static const char * const attrs2[] = {"comment", "countryCode", "codePage", NULL};
2867                 attrs = attrs2;
2868                 break;
2869         }
2870         case 3:
2871         {
2872                 static const char * const attrs2[] = {"sAMAccountName",
2873                                                       "displayName",
2874                                                       "objectSid",
2875                                                       "primaryGroupID",
2876                                                       "homeDirectory",
2877                                                       "homeDrive",
2878                                                       "scriptPath",
2879                                                       "profilePath",
2880                                                       "userWorkstations",
2881                                                       "lastLogon",
2882                                                       "lastLogoff",
2883                                                       "pwdLastSet",
2884                                                       "logonHours",
2885                                                       "badPwdCount",
2886                                                       "logonCount",
2887                                                       "userAccountControl", NULL};
2888                 attrs = attrs2;
2889                 break;
2890         }
2891         case 4:
2892         {
2893                 static const char * const attrs2[] = {"logonHours", NULL};
2894                 attrs = attrs2;
2895                 break;
2896         }
2897         case 5:
2898         {
2899                 static const char * const attrs2[] = {"sAMAccountName", 
2900                                                       "displayName",
2901                                                       "objectSid",
2902                                                       "primaryGroupID",
2903                                                       "homeDirectory",
2904                                                       "homeDrive",
2905                                                       "scriptPath", 
2906                                                       "profilePath",
2907                                                       "description",
2908                                                       "userWorkstations",
2909                                                       "lastLogon",
2910                                                       "lastLogoff",
2911                                                       "logonHours",
2912                                                       "badPwdCount",
2913                                                       "logonCount",
2914                                                       "pwdLastSet",
2915                                                       "accountExpires",
2916                                                       "userAccountControl",
2917                                                       NULL};
2918                 attrs = attrs2;
2919                 break;
2920         }
2921         case 6:
2922         {
2923                 static const char * const attrs2[] = {"sAMAccountName", "displayName", NULL};
2924                 attrs = attrs2;
2925                 break;
2926         }
2927         case 7:
2928         {
2929                 static const char * const attrs2[] = {"sAMAccountName", NULL};
2930                 attrs = attrs2;
2931                 break;
2932         }
2933         case 8:
2934         {
2935                 static const char * const attrs2[] = {"displayName", NULL};
2936                 attrs = attrs2;
2937                 break;
2938         }
2939         case 9:
2940         {
2941                 static const char * const attrs2[] = {"primaryGroupID", NULL};
2942                 attrs = attrs2;
2943                 break;
2944         }
2945         case 10:
2946         {
2947                 static const char * const attrs2[] = {"homeDirectory", "homeDrive", NULL};
2948                 attrs = attrs2;
2949                 break;
2950         }
2951         case 11:
2952         {
2953                 static const char * const attrs2[] = {"scriptPath", NULL};
2954                 attrs = attrs2;
2955                 break;
2956         }
2957         case 12:
2958         {
2959                 static const char * const attrs2[] = {"profilePath", NULL};
2960                 attrs = attrs2;
2961                 break;
2962         }
2963         case 13:
2964         {
2965                 static const char * const attrs2[] = {"description", NULL};
2966                 attrs = attrs2;
2967                 break;
2968         }
2969         case 14:
2970         {
2971                 static const char * const attrs2[] = {"userWorkstations", NULL};
2972                 attrs = attrs2;
2973                 break;
2974         }
2975         case 16:
2976         {
2977                 static const char * const attrs2[] = {"userAccountControl", NULL};
2978                 attrs = attrs2;
2979                 break;
2980         }
2981         case 17:
2982         {
2983                 static const char * const attrs2[] = {"accountExpires", NULL};
2984                 attrs = attrs2;
2985                 break;
2986         }
2987         case 20:
2988         {
2989                 static const char * const attrs2[] = {"userParameters", NULL};
2990                 attrs = attrs2;
2991                 break;
2992         }
2993         case 21:
2994         {
2995                 static const char * const attrs2[] = {"lastLogon",
2996                                                       "lastLogoff",
2997                                                       "pwdLastSet",
2998                                                       "accountExpires",
2999                                                       "sAMAccountName",
3000                                                       "displayName",
3001                                                       "homeDirectory",
3002                                                       "homeDrive",
3003                                                       "scriptPath",
3004                                                       "profilePath",
3005                                                       "description",
3006                                                       "userWorkstations",
3007                                                       "comment",
3008                                                       "userParameters",
3009                                                       "objectSid",
3010                                                       "primaryGroupID",
3011                                                       "userAccountControl",
3012                                                       "logonHours",
3013                                                       "badPwdCount",
3014                                                       "logonCount",
3015                                                       "countryCode",
3016                                                       "codePage",
3017                                                       NULL};
3018                 attrs = attrs2;
3019                 break;
3020         }
3021         }
3022
3023         /* pull all the user attributes */
3024         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
3025                               a_state->account_dn ,&res, attrs);
3026         if (ret != 1) {
3027                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3028         }
3029         msg = res[0];
3030
3031         /* allocate the info structure */
3032         r->out.info = talloc(mem_ctx, union samr_UserInfo);
3033         if (r->out.info == NULL) {
3034                 return NT_STATUS_NO_MEMORY;
3035         }
3036         ZERO_STRUCTP(r->out.info);
3037
3038         /* fill in the reply */
3039         switch (r->in.level) {
3040         case 1:
3041                 QUERY_STRING(msg, info1.account_name.string,   "sAMAccountName");
3042                 QUERY_STRING(msg, info1.full_name.string,      "displayName");
3043                 QUERY_UINT  (msg, info1.primary_gid,           "primaryGroupID");
3044                 QUERY_STRING(msg, info1.description.string,    "description");
3045                 QUERY_STRING(msg, info1.comment.string,        "comment");
3046                 break;
3047
3048         case 2:
3049                 QUERY_STRING(msg, info2.comment.string,        "comment");
3050                 QUERY_UINT  (msg, info2.country_code,          "countryCode");
3051                 QUERY_UINT  (msg, info2.code_page,             "codePage");
3052                 break;
3053
3054         case 3:
3055                 QUERY_STRING(msg, info3.account_name.string,   "sAMAccountName");
3056                 QUERY_STRING(msg, info3.full_name.string,      "displayName");
3057                 QUERY_RID   (msg, info3.rid,                   "objectSid");
3058                 QUERY_UINT  (msg, info3.primary_gid,           "primaryGroupID");
3059                 QUERY_STRING(msg, info3.home_directory.string, "homeDirectory");
3060                 QUERY_STRING(msg, info3.home_drive.string,     "homeDrive");
3061                 QUERY_STRING(msg, info3.logon_script.string,   "scriptPath");
3062                 QUERY_STRING(msg, info3.profile_path.string,   "profilePath");
3063                 QUERY_STRING(msg, info3.workstations.string,   "userWorkstations");
3064                 QUERY_NTTIME(msg, info3.last_logon,            "lastLogon");
3065                 QUERY_NTTIME(msg, info3.last_logoff,           "lastLogoff");
3066                 QUERY_NTTIME(msg, info3.last_password_change,  "pwdLastSet");
3067                 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
3068                 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
3069                 QUERY_LHOURS(msg, info3.logon_hours,           "logonHours");
3070                 QUERY_UINT  (msg, info3.bad_password_count,    "badPwdCount");
3071                 QUERY_UINT  (msg, info3.logon_count,           "logonCount");
3072                 QUERY_AFLAGS(msg, info3.acct_flags,            "userAccountControl");
3073                 break;
3074
3075         case 4:
3076                 QUERY_LHOURS(msg, info4.logon_hours,           "logonHours");
3077                 break;
3078
3079         case 5:
3080                 QUERY_STRING(msg, info5.account_name.string,   "sAMAccountName");
3081                 QUERY_STRING(msg, info5.full_name.string,      "displayName");
3082                 QUERY_RID   (msg, info5.rid,                   "objectSid");
3083                 QUERY_UINT  (msg, info5.primary_gid,           "primaryGroupID");
3084                 QUERY_STRING(msg, info5.home_directory.string, "homeDirectory");
3085                 QUERY_STRING(msg, info5.home_drive.string,     "homeDrive");
3086                 QUERY_STRING(msg, info5.logon_script.string,   "scriptPath");
3087                 QUERY_STRING(msg, info5.profile_path.string,   "profilePath");
3088                 QUERY_STRING(msg, info5.description.string,    "description");
3089                 QUERY_STRING(msg, info5.workstations.string,   "userWorkstations");
3090                 QUERY_NTTIME(msg, info5.last_logon,            "lastLogon");
3091                 QUERY_NTTIME(msg, info5.last_logoff,           "lastLogoff");
3092                 QUERY_LHOURS(msg, info5.logon_hours,           "logonHours");
3093                 QUERY_UINT  (msg, info5.bad_password_count,    "badPwdCount");
3094                 QUERY_UINT  (msg, info5.logon_count,           "logonCount");
3095                 QUERY_NTTIME(msg, info5.last_password_change,  "pwdLastSet");
3096                 QUERY_NTTIME(msg, info5.acct_expiry,           "accountExpires");
3097                 QUERY_AFLAGS(msg, info5.acct_flags,            "userAccountControl");
3098                 break;
3099
3100         case 6:
3101                 QUERY_STRING(msg, info6.account_name.string,   "sAMAccountName");
3102                 QUERY_STRING(msg, info6.full_name.string,      "displayName");
3103                 break;
3104
3105         case 7:
3106                 QUERY_STRING(msg, info7.account_name.string,   "sAMAccountName");
3107                 break;
3108
3109         case 8:
3110                 QUERY_STRING(msg, info8.full_name.string,      "displayName");
3111                 break;
3112
3113         case 9:
3114                 QUERY_UINT  (msg, info9.primary_gid,           "primaryGroupID");
3115                 break;
3116
3117         case 10:
3118                 QUERY_STRING(msg, info10.home_directory.string,"homeDirectory");
3119                 QUERY_STRING(msg, info10.home_drive.string,    "homeDrive");
3120                 break;
3121
3122         case 11:
3123                 QUERY_STRING(msg, info11.logon_script.string,  "scriptPath");
3124                 break;
3125
3126         case 12:
3127                 QUERY_STRING(msg, info12.profile_path.string,  "profilePath");
3128                 break;
3129
3130         case 13:
3131                 QUERY_STRING(msg, info13.description.string,   "description");
3132                 break;
3133
3134         case 14:
3135                 QUERY_STRING(msg, info14.workstations.string,  "userWorkstations");
3136                 break;
3137
3138         case 16:
3139                 QUERY_AFLAGS(msg, info16.acct_flags,           "userAccountControl");
3140                 break;
3141
3142         case 17:
3143                 QUERY_NTTIME(msg, info17.acct_expiry,          "accountExpires");
3144
3145         case 20:
3146                 QUERY_STRING(msg, info20.parameters.string,    "userParameters");
3147                 break;
3148
3149         case 21:
3150                 QUERY_NTTIME(msg, info21.last_logon,           "lastLogon");
3151                 QUERY_NTTIME(msg, info21.last_logoff,          "lastLogoff");
3152                 QUERY_NTTIME(msg, info21.last_password_change, "pwdLastSet");
3153                 QUERY_NTTIME(msg, info21.acct_expiry,          "accountExpires");
3154                 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3155                 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3156                 QUERY_STRING(msg, info21.account_name.string,  "sAMAccountName");
3157                 QUERY_STRING(msg, info21.full_name.string,     "displayName");
3158                 QUERY_STRING(msg, info21.home_directory.string,"homeDirectory");
3159                 QUERY_STRING(msg, info21.home_drive.string,    "homeDrive");
3160                 QUERY_STRING(msg, info21.logon_script.string,  "scriptPath");
3161                 QUERY_STRING(msg, info21.profile_path.string,  "profilePath");
3162                 QUERY_STRING(msg, info21.description.string,   "description");
3163                 QUERY_STRING(msg, info21.workstations.string,  "userWorkstations");
3164                 QUERY_STRING(msg, info21.comment.string,       "comment");
3165                 QUERY_STRING(msg, info21.parameters.string,    "userParameters");
3166                 QUERY_RID   (msg, info21.rid,                  "objectSid");
3167                 QUERY_UINT  (msg, info21.primary_gid,          "primaryGroupID");
3168                 QUERY_AFLAGS(msg, info21.acct_flags,           "userAccountControl");
3169                 r->out.info->info21.fields_present = 0x00FFFFFF;
3170                 QUERY_LHOURS(msg, info21.logon_hours,          "logonHours");
3171                 QUERY_UINT  (msg, info21.bad_password_count,   "badPwdCount");
3172                 QUERY_UINT  (msg, info21.logon_count,          "logonCount");
3173                 QUERY_UINT  (msg, info21.country_code,         "countryCode");
3174                 QUERY_UINT  (msg, info21.code_page,            "codePage");
3175                 break;
3176                 
3177
3178         default:
3179                 r->out.info = NULL;
3180                 return NT_STATUS_INVALID_INFO_CLASS;
3181         }
3182         
3183         return NT_STATUS_OK;
3184 }
3185
3186
3187 /* 
3188   samr_SetUserInfo 
3189 */
3190 static NTSTATUS samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3191                                  struct samr_SetUserInfo *r)
3192 {
3193         struct dcesrv_handle *h;
3194         struct samr_account_state *a_state;
3195         struct ldb_message *msg;
3196         int ret;
3197         NTSTATUS status = NT_STATUS_OK;
3198         struct ldb_context *sam_ctx;
3199
3200         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3201
3202         a_state = h->data;
3203         sam_ctx = a_state->sam_ctx;
3204
3205         msg = ldb_msg_new(mem_ctx);
3206         if (msg == NULL) {
3207                 return NT_STATUS_NO_MEMORY;
3208         }
3209
3210         msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3211         if (!msg->dn) {
3212                 return NT_STATUS_NO_MEMORY;
3213         }
3214
3215         switch (r->in.level) {
3216         case 2:
3217                 SET_STRING(msg, info2.comment.string,          "comment");
3218                 SET_UINT  (msg, info2.country_code,            "countryCode");
3219                 SET_UINT  (msg, info2.code_page,               "codePage");
3220                 break;
3221
3222         case 4:
3223                 SET_LHOURS(msg, info4.logon_hours,             "logonHours");
3224                 break;
3225
3226         case 6:
3227                 SET_STRING(msg, info6.full_name.string,        "displayName");
3228                 break;
3229
3230         case 7:
3231                 SET_STRING(msg, info7.account_name.string,     "samAccountName");
3232                 break;
3233
3234         case 8:
3235                 SET_STRING(msg, info8.full_name.string,        "displayName");
3236                 break;
3237
3238         case 9:
3239                 SET_UINT(msg, info9.primary_gid,               "primaryGroupID");
3240                 break;
3241
3242         case 10:
3243                 SET_STRING(msg, info10.home_directory.string,  "homeDirectory");
3244                 SET_STRING(msg, info10.home_drive.string,      "homeDrive");
3245                 break;
3246
3247         case 11:
3248                 SET_STRING(msg, info11.logon_script.string,    "scriptPath");
3249                 break;
3250
3251         case 12:
3252                 SET_STRING(msg, info12.profile_path.string,    "profilePath");
3253                 break;
3254
3255         case 13:
3256                 SET_STRING(msg, info13.description.string,     "description");
3257                 break;
3258
3259         case 14:
3260                 SET_STRING(msg, info14.workstations.string,    "userWorkstations");
3261                 break;
3262
3263         case 16:
3264                 SET_AFLAGS(msg, info16.acct_flags,             "userAccountControl");
3265                 break;
3266
3267         case 20:
3268                 SET_STRING(msg, info20.parameters.string,      "userParameters");
3269                 break;
3270
3271         case 21:
3272 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3273                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
3274                         SET_STRING(msg, info21.account_name.string, "samAccountName");
3275                 IFSET(SAMR_FIELD_FULL_NAME)         
3276                         SET_STRING(msg, info21.full_name.string,    "displayName");
3277                 IFSET(SAMR_FIELD_DESCRIPTION)  
3278                         SET_STRING(msg, info21.description.string,  "description");
3279                 IFSET(SAMR_FIELD_COMMENT)      
3280                         SET_STRING(msg, info21.comment.string,      "comment");
3281                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
3282                         SET_STRING(msg, info21.logon_script.string, "scriptPath");
3283                 IFSET(SAMR_FIELD_PROFILE_PATH)      
3284                         SET_STRING(msg, info21.profile_path.string, "profilePath");
3285                 IFSET(SAMR_FIELD_WORKSTATIONS)  
3286                         SET_STRING(msg, info21.workstations.string, "userWorkstations");
3287                 IFSET(SAMR_FIELD_LOGON_HOURS)  
3288                         SET_LHOURS(msg, info21.logon_hours,         "logonHours");
3289                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
3290                         SET_AFLAGS(msg, info21.acct_flags,          "userAccountControl");
3291                 IFSET(SAMR_FIELD_PARAMETERS)     
3292                         SET_STRING(msg, info21.parameters.string,   "userParameters");
3293                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
3294                         SET_UINT  (msg, info21.country_code,        "countryCode");
3295                 IFSET(SAMR_FIELD_CODE_PAGE)    
3296                         SET_UINT  (msg, info21.code_page,           "codePage");
3297
3298
3299                 /* Any reason the rest of these can't be set? */
3300 #undef IFSET
3301                 break;
3302
3303         case 23:
3304 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3305                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
3306                         SET_STRING(msg, info23.info.account_name.string, "samAccountName");
3307                 IFSET(SAMR_FIELD_FULL_NAME)         
3308                         SET_STRING(msg, info23.info.full_name.string,    "displayName");
3309                 IFSET(SAMR_FIELD_DESCRIPTION)  
3310                         SET_STRING(msg, info23.info.description.string,  "description");
3311                 IFSET(SAMR_FIELD_COMMENT)      
3312                         SET_STRING(msg, info23.info.comment.string,      "comment");
3313                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
3314                         SET_STRING(msg, info23.info.logon_script.string, "scriptPath");
3315                 IFSET(SAMR_FIELD_PROFILE_PATH)      
3316                         SET_STRING(msg, info23.info.profile_path.string, "profilePath");
3317                 IFSET(SAMR_FIELD_WORKSTATIONS)  
3318                         SET_STRING(msg, info23.info.workstations.string, "userWorkstations");
3319                 IFSET(SAMR_FIELD_LOGON_HOURS)  
3320                         SET_LHOURS(msg, info23.info.logon_hours,         "logonHours");
3321                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
3322                         SET_AFLAGS(msg, info23.info.acct_flags,          "userAccountControl");
3323                 IFSET(SAMR_FIELD_PARAMETERS)     
3324                         SET_STRING(msg, info23.info.parameters.string,   "userParameters");
3325                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
3326                         SET_UINT  (msg, info23.info.country_code,        "countryCode");
3327                 IFSET(SAMR_FIELD_CODE_PAGE)    
3328                         SET_UINT  (msg, info23.info.code_page,           "codePage");
3329                 IFSET(SAMR_FIELD_PASSWORD) {
3330                         status = samr_set_password(dce_call,
3331                                                    a_state->sam_ctx,
3332                                                    a_state->account_dn,
3333                                                    a_state->domain_state->domain_dn,
3334                                                    mem_ctx, msg, 
3335                                                    &r->in.info->info23.password);
3336                 } else IFSET(SAMR_FIELD_PASSWORD2) {
3337                         status = samr_set_password(dce_call,
3338                                                    a_state->sam_ctx,
3339                                                    a_state->account_dn,
3340                                                    a_state->domain_state->domain_dn,
3341                                                    mem_ctx, msg, 
3342                                                    &r->in.info->info23.password);
3343                 }
3344 #undef IFSET
3345                 break;
3346
3347                 /* the set password levels are handled separately */
3348         case 24:
3349                 status = samr_set_password(dce_call,
3350                                            a_state->sam_ctx,
3351                                            a_state->account_dn,
3352                                            a_state->domain_state->domain_dn,
3353                                            mem_ctx, msg, 
3354                                            &r->in.info->info24.password);
3355                 break;
3356
3357         case 25:
3358 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3359                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
3360                         SET_STRING(msg, info25.info.account_name.string, "samAccountName");
3361                 IFSET(SAMR_FIELD_FULL_NAME)         
3362                         SET_STRING(msg, info25.info.full_name.string,    "displayName");
3363                 IFSET(SAMR_FIELD_DESCRIPTION)  
3364                         SET_STRING(msg, info25.info.description.string,  "description");
3365                 IFSET(SAMR_FIELD_COMMENT)      
3366                         SET_STRING(msg, info25.info.comment.string,      "comment");
3367                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
3368                         SET_STRING(msg, info25.info.logon_script.string, "scriptPath");
3369                 IFSET(SAMR_FIELD_PROFILE_PATH)      
3370                         SET_STRING(msg, info25.info.profile_path.string, "profilePath");
3371                 IFSET(SAMR_FIELD_WORKSTATIONS)  
3372                         SET_STRING(msg, info25.info.workstations.string, "userWorkstations");
3373                 IFSET(SAMR_FIELD_LOGON_HOURS)  
3374                         SET_LHOURS(msg, info25.info.logon_hours,         "logonHours");
3375                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
3376                         SET_AFLAGS(msg, info25.info.acct_flags,          "userAccountControl");
3377                 IFSET(SAMR_FIELD_PARAMETERS)     
3378                         SET_STRING(msg, info25.info.parameters.string,   "userParameters");
3379                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
3380                         SET_UINT  (msg, info25.info.country_code,        "countryCode");
3381                 IFSET(SAMR_FIELD_CODE_PAGE)    
3382                         SET_UINT  (msg, info25.info.code_page,           "codePage");
3383                 IFSET(SAMR_FIELD_PASSWORD) {
3384                         status = samr_set_password_ex(dce_call,
3385                                                       a_state->sam_ctx,
3386                                                       a_state->account_dn,
3387                                                       a_state->domain_state->domain_dn,
3388                                                       mem_ctx, msg, 
3389                                                       &r->in.info->info25.password);
3390                 } else IFSET(SAMR_FIELD_PASSWORD2) {
3391                         status = samr_set_password_ex(dce_call,
3392                                                       a_state->sam_ctx,
3393                                                       a_state->account_dn,
3394                                                       a_state->domain_state->domain_dn,
3395                                                       mem_ctx, msg, 
3396                                                       &r->in.info->info25.password);
3397                 }
3398 #undef IFSET
3399                 break;
3400
3401                 /* the set password levels are handled separately */
3402         case 26:
3403                 status = samr_set_password_ex(dce_call,
3404                                               a_state->sam_ctx,
3405                                               a_state->account_dn,
3406                                               a_state->domain_state->domain_dn,
3407                                               mem_ctx, msg, 
3408                                               &r->in.info->info26.password);
3409                 break;
3410                 
3411
3412         default:
3413                 /* many info classes are not valid for SetUserInfo */
3414                 return NT_STATUS_INVALID_INFO_CLASS;
3415         }
3416
3417         if (!NT_STATUS_IS_OK(status)) {
3418                 return status;
3419         }
3420
3421         /* modify the samdb record */
3422         ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
3423         if (ret != 0) {
3424                 DEBUG(1,("Failed to modify record %s: %s\n",
3425                          ldb_dn_linearize(mem_ctx, a_state->account_dn),
3426                          ldb_errstring(a_state->sam_ctx)));
3427
3428                 /* we really need samdb.c to return NTSTATUS */
3429                 return NT_STATUS_UNSUCCESSFUL;
3430         }
3431
3432         return NT_STATUS_OK;
3433 }
3434
3435
3436 /* 
3437   samr_GetGroupsForUser 
3438 */
3439 static NTSTATUS samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3440                        struct samr_GetGroupsForUser *r)
3441 {
3442         struct dcesrv_handle *h;
3443         struct samr_account_state *a_state;
3444         struct samr_domain_state *d_state;
3445         struct ldb_message **res;
3446         const char * const attrs[2] = { "objectSid", NULL };
3447         struct samr_RidWithAttributeArray *array;
3448         int count;
3449
3450         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3451
3452         a_state = h->data;
3453         d_state = a_state->domain_state;
3454
3455         count = samdb_search_domain(a_state->sam_ctx, mem_ctx, d_state->domain_dn, &res,
3456                                     attrs, d_state->domain_sid,
3457                                     "(&(member=%s)(grouptype=%d)(objectclass=group))",
3458                                     ldb_dn_linearize(mem_ctx, a_state->account_dn),
3459                                     GTYPE_SECURITY_GLOBAL_GROUP);
3460         if (count < 0)
3461                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3462
3463         array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3464         if (array == NULL)
3465                 return NT_STATUS_NO_MEMORY;
3466
3467         array->count = 0;
3468         array->rids = NULL;
3469
3470         if (count > 0) {
3471                 int i;
3472                 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3473                                             count);
3474
3475                 if (array->rids == NULL)
3476                         return NT_STATUS_NO_MEMORY;
3477
3478                 for (i=0; i<count; i++) {
3479                         struct dom_sid *group_sid;
3480
3481                         group_sid = samdb_result_dom_sid(mem_ctx, res[i],
3482                                                          "objectSid");
3483                         if (group_sid == NULL) {
3484                                 DEBUG(0, ("Couldn't find objectSid attrib\n"));
3485                                 continue;
3486                         }
3487
3488                         array->rids[array->count].rid =
3489                                 group_sid->sub_auths[group_sid->num_auths-1];
3490                         array->rids[array->count].attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3491                         array->count += 1;
3492                 }
3493         }
3494
3495         r->out.rids = array;
3496
3497         return NT_STATUS_OK;
3498 }
3499
3500
3501 /* 
3502   samr_QueryDisplayInfo 
3503 */
3504 static NTSTATUS samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3505                        struct samr_QueryDisplayInfo *r)
3506 {
3507         struct dcesrv_handle *h;
3508         struct samr_domain_state *d_state;
3509         struct ldb_message **res;
3510         int ldb_cnt, count, i;
3511         const char * const attrs[4] = { "objectSid", "sAMAccountName",
3512                                         "description", NULL };
3513         struct samr_DispEntryFull *entriesFull = NULL;
3514         struct samr_DispEntryAscii *entriesAscii = NULL;
3515         struct samr_DispEntryGeneral * entriesGeneral = NULL;
3516         const char *filter;
3517
3518         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3519
3520         d_state = h->data;
3521
3522         switch (r->in.level) {
3523         case 1:
3524         case 4:
3525                 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3526                                          "(sAMAccountType=%u))",
3527                                          ATYPE_NORMAL_ACCOUNT);
3528                 break;
3529         case 2:
3530                 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3531                                          "(sAMAccountType=%u))",
3532                                          ATYPE_WORKSTATION_TRUST);
3533                 break;
3534         case 3:
3535         case 5:
3536                 filter = talloc_asprintf(mem_ctx, "(&(grouptype=%d)"
3537                                          "(objectclass=group))",
3538                                          GTYPE_SECURITY_GLOBAL_GROUP);
3539                 break;
3540         default:
3541                 return NT_STATUS_INVALID_INFO_CLASS;
3542         }
3543
3544         /* search for all requested objects in this domain. This could
3545            possibly be cached and resumed based on resume_key */
3546         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3547                                       d_state->domain_dn, &res, attrs,
3548                                       d_state->domain_sid, "%s", filter);
3549         if (ldb_cnt == -1) {
3550                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3551         }
3552         if (ldb_cnt == 0 || r->in.max_entries == 0) {
3553                 return NT_STATUS_OK;
3554         }
3555
3556         switch (r->in.level) {
3557         case 1:
3558                 entriesGeneral = talloc_array(mem_ctx,
3559                                                 struct samr_DispEntryGeneral,
3560                                                 ldb_cnt);
3561                 break;
3562         case 2:
3563         case 3:
3564                 entriesFull = talloc_array(mem_ctx,
3565                                              struct samr_DispEntryFull,
3566                                              ldb_cnt);
3567                 break;
3568         case 4:
3569         case 5:
3570                 entriesAscii = talloc_array(mem_ctx,
3571                                               struct samr_DispEntryAscii,
3572                                               ldb_cnt);
3573                 break;
3574         }
3575
3576         if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3577             (entriesAscii == NULL))
3578                 return NT_STATUS_NO_MEMORY;
3579
3580         count = 0;
3581
3582         for (i=0; i<ldb_cnt; i++) {
3583                 struct dom_sid *objectsid;
3584
3585                 objectsid = samdb_result_dom_sid(mem_ctx, res[i],
3586                                                  "objectSid");
3587                 if (objectsid == NULL)
3588                         continue;
3589
3590                 switch(r->in.level) {
3591                 case 1:
3592                         entriesGeneral[count].idx = count + 1;
3593                         entriesGeneral[count].rid = 
3594                                 objectsid->sub_auths[objectsid->num_auths-1];
3595                         entriesGeneral[count].acct_flags =
3596                                 samdb_result_acct_flags(res[i], 
3597                                                         "userAccountControl");
3598                         entriesGeneral[count].account_name.string =
3599                                 samdb_result_string(res[i],
3600                                                     "sAMAccountName", "");
3601                         entriesGeneral[count].full_name.string =
3602                                 samdb_result_string(res[i], "displayName", "");
3603                         entriesGeneral[count].description.string =
3604                                 samdb_result_string(res[i], "description", "");
3605                         break;
3606                 case 2:
3607                 case 3:
3608                         entriesFull[count].idx = count + 1;
3609                         entriesFull[count].rid =
3610                                 objectsid->sub_auths[objectsid->num_auths-1];
3611                         entriesFull[count].acct_flags =
3612                                 samdb_result_acct_flags(res[i], 
3613                                                         "userAccountControl");
3614                         if (r->in.level == 3) {
3615                                 /* We get a "7" here for groups */
3616                                 entriesFull[count].acct_flags = 7;
3617                         }
3618                         entriesFull[count].account_name.string =
3619                                 samdb_result_string(res[i], "sAMAccountName",
3620                                                     "");
3621                         entriesFull[count].description.string =
3622                                 samdb_result_string(res[i], "description", "");
3623                         break;
3624                 case 4:
3625                 case 5:
3626                         entriesAscii[count].idx = count + 1;
3627                         entriesAscii[count].account_name.string =
3628                                 samdb_result_string(res[i], "sAMAccountName",
3629                                                     "");
3630                         break;
3631                 }
3632
3633                 count += 1;
3634         }
3635
3636         r->out.total_size = count;
3637
3638         if (r->in.start_idx >= count) {
3639                 r->out.returned_size = 0;
3640                 switch(r->in.level) {
3641                 case 1:
3642                         r->out.info.info1.count = r->out.returned_size;
3643                         r->out.info.info1.entries = NULL;
3644                         break;
3645                 case 2:
3646                         r->out.info.info2.count = r->out.returned_size;
3647                         r->out.info.info2.entries = NULL;
3648                         break;
3649                 case 3:
3650                         r->out.info.info3.count = r->out.returned_size;
3651                         r->out.info.info3.entries = NULL;
3652                         break;
3653                 case 4:
3654                         r->out.info.info4.count = r->out.returned_size;
3655                         r->out.info.info4.entries = NULL;
3656                         break;
3657                 case 5:
3658                         r->out.info.info5.count = r->out.returned_size;
3659                         r->out.info.info5.entries = NULL;
3660                         break;
3661                 }
3662         } else {
3663                 r->out.returned_size = MIN(count - r->in.start_idx,
3664                                            r->in.max_entries);
3665                 switch(r->in.level) {
3666                 case 1:
3667                         r->out.info.info1.count = r->out.returned_size;
3668                         r->out.info.info1.entries =
3669                                 &(entriesGeneral[r->in.start_idx]);
3670                         break;
3671                 case 2:
3672                         r->out.info.info2.count = r->out.returned_size;
3673                         r->out.info.info2.entries =
3674                                 &(entriesFull[r->in.start_idx]);
3675                         break;
3676                 case 3:
3677                         r->out.info.info3.count = r->out.returned_size;
3678                         r->out.info.info3.entries =
3679                                 &(entriesFull[r->in.start_idx]);
3680                         break;
3681                 case 4:
3682                         r->out.info.info4.count = r->out.returned_size;
3683                         r->out.info.info4.entries =
3684                                 &(entriesAscii[r->in.start_idx]);
3685                         break;
3686                 case 5:
3687                         r->out.info.info5.count = r->out.returned_size;
3688                         r->out.info.info5.entries =
3689                                 &(entriesAscii[r->in.start_idx]);
3690                         break;
3691                 }
3692         }
3693
3694         return (r->out.returned_size < (count - r->in.start_idx)) ?
3695                 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3696 }
3697
3698
3699 /* 
3700   samr_GetDisplayEnumerationIndex 
3701 */
3702 static NTSTATUS samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3703                        struct samr_GetDisplayEnumerationIndex *r)
3704 {
3705         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3706 }
3707
3708
3709 /* 
3710   samr_TestPrivateFunctionsDomain 
3711 */
3712 static NTSTATUS samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3713                        struct samr_TestPrivateFunctionsDomain *r)
3714 {
3715         return NT_STATUS_NOT_IMPLEMENTED;
3716 }
3717
3718
3719 /* 
3720   samr_TestPrivateFunctionsUser 
3721 */
3722 static NTSTATUS samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3723                        struct samr_TestPrivateFunctionsUser *r)
3724 {
3725         return NT_STATUS_NOT_IMPLEMENTED;
3726 }
3727
3728
3729 /* 
3730   samr_GetUserPwInfo 
3731 */
3732 static NTSTATUS samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3733                                    struct samr_GetUserPwInfo *r)
3734 {
3735         struct dcesrv_handle *h;
3736         struct samr_account_state *a_state;
3737
3738         ZERO_STRUCT(r->out.info);
3739
3740         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3741
3742         a_state = h->data;
3743
3744         r->out.info.min_password_length = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0,
3745                                                             a_state->domain_state->domain_dn, "minPwdLength", 
3746                                                             NULL);
3747         r->out.info.password_properties = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0,
3748                                                             a_state->account_dn, 
3749                                                             "pwdProperties", NULL);
3750         return NT_STATUS_OK;
3751 }
3752
3753
3754 /* 
3755   samr_RemoveMemberFromForeignDomain 
3756 */
3757 static NTSTATUS samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3758                        struct samr_RemoveMemberFromForeignDomain *r)
3759 {
3760         struct dcesrv_handle *h;
3761         struct samr_domain_state *d_state;
3762         const char *memberdn;
3763         struct ldb_message **res;
3764         const char * const attrs[3] = { "distinguishedName", "objectSid", NULL };
3765         int i, count;
3766
3767         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3768
3769         d_state = h->data;
3770
3771         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3772                                        "distinguishedName", "(objectSid=%s)", 
3773                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3774         /* Nothing to do */
3775         if (memberdn == NULL) {
3776                 return NT_STATUS_OK;
3777         }
3778
3779         /* TODO: Does this call only remove alias members, or does it do this
3780          * for domain groups as well? */
3781
3782         count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3783                                     d_state->domain_dn, &res, attrs,
3784                                     d_state->domain_sid,
3785                                     "(&(member=%s)(objectClass=group)"
3786                                     "(|(groupType=%d)(groupType=%d)))",
3787                                     memberdn,
3788                                     GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
3789                                     GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
3790
3791         if (count < 0)
3792                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3793
3794         for (i=0; i<count; i++) {
3795                 struct ldb_message *mod;
3796
3797                 mod = ldb_msg_new(mem_ctx);
3798                 if (mod == NULL) {
3799                         return NT_STATUS_NO_MEMORY;
3800                 }
3801
3802                 mod->dn = samdb_result_dn(mod, res[i], "distinguishedName", NULL);
3803                 if (mod->dn == NULL) {
3804                         talloc_free(mod);
3805                         continue;
3806                 }
3807
3808                 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
3809                                          "member", memberdn) != 0)
3810                         return NT_STATUS_NO_MEMORY;
3811
3812                 if (samdb_modify(d_state->sam_ctx, mem_ctx, mod) != 0)
3813                         return NT_STATUS_UNSUCCESSFUL;
3814
3815                 talloc_free(mod);
3816         }
3817
3818         return NT_STATUS_OK;
3819 }
3820
3821
3822 /* 
3823   samr_QueryDomainInfo2 
3824
3825   just an alias for samr_QueryDomainInfo
3826 */
3827 static NTSTATUS samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3828                        struct samr_QueryDomainInfo2 *r)
3829 {
3830         struct samr_QueryDomainInfo r1;
3831         NTSTATUS status;
3832
3833         ZERO_STRUCT(r1.out);
3834         r1.in.domain_handle = r->in.domain_handle;
3835         r1.in.level  = r->in.level;
3836         
3837         status = samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
3838         
3839         r->out.info = r1.out.info;
3840
3841         return status;
3842 }
3843
3844
3845 /* 
3846   samr_QueryUserInfo2 
3847
3848   just an alias for samr_QueryUserInfo
3849 */
3850 static NTSTATUS samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3851                                     struct samr_QueryUserInfo2 *r)
3852 {
3853         struct samr_QueryUserInfo r1;
3854         NTSTATUS status;
3855
3856         ZERO_STRUCT(r1.out);
3857         r1.in.user_handle = r->in.user_handle;
3858         r1.in.level  = r->in.level;
3859         
3860         status = samr_QueryUserInfo(dce_call, mem_ctx, &r1);
3861         
3862         r->out.info = r1.out.info;
3863
3864         return status;
3865 }
3866
3867
3868 /* 
3869   samr_QueryDisplayInfo2 
3870 */
3871 static NTSTATUS samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3872                                        struct samr_QueryDisplayInfo2 *r)
3873 {
3874         struct samr_QueryDisplayInfo q;
3875         NTSTATUS result;
3876
3877         q.in.domain_handle = r->in.domain_handle;
3878         q.in.level = r->in.level;
3879         q.in.start_idx = r->in.start_idx;
3880         q.in.max_entries = r->in.max_entries;
3881         q.in.buf_size = r->in.buf_size;
3882         ZERO_STRUCT(q.out);
3883
3884         result = samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
3885
3886         r->out.total_size = q.out.total_size;
3887         r->out.returned_size = q.out.returned_size;
3888         r->out.info = q.out.info;
3889
3890         return result;
3891 }
3892
3893
3894 /* 
3895   samr_GetDisplayEnumerationIndex2 
3896 */
3897 static NTSTATUS samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3898                        struct samr_GetDisplayEnumerationIndex2 *r)
3899 {
3900         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3901 }
3902
3903
3904 /* 
3905   samr_QueryDisplayInfo3 
3906 */
3907 static NTSTATUS samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3908                        struct samr_QueryDisplayInfo3 *r)
3909 {
3910         struct samr_QueryDisplayInfo q;
3911         NTSTATUS result;
3912
3913         q.in.domain_handle = r->in.domain_handle;
3914         q.in.level = r->in.level;
3915         q.in.start_idx = r->in.start_idx;
3916         q.in.max_entries = r->in.max_entries;
3917         q.in.buf_size = r->in.buf_size;
3918         ZERO_STRUCT(q.out);
3919
3920         result = samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
3921
3922         r->out.total_size = q.out.total_size;
3923         r->out.returned_size = q.out.returned_size;
3924         r->out.info = q.out.info;
3925
3926         return result;
3927 }
3928
3929
3930 /* 
3931   samr_AddMultipleMembersToAlias 
3932 */
3933 static NTSTATUS samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3934                        struct samr_AddMultipleMembersToAlias *r)
3935 {
3936         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3937 }
3938
3939
3940 /* 
3941   samr_RemoveMultipleMembersFromAlias 
3942 */
3943 static NTSTATUS samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3944                        struct samr_RemoveMultipleMembersFromAlias *r)
3945 {
3946         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3947 }
3948
3949
3950 /* 
3951   samr_GetDomPwInfo 
3952
3953   this fetches the default password properties for a domain
3954
3955   note that w2k3 completely ignores the domain name in this call, and 
3956   always returns the information for the servers primary domain
3957 */
3958 static NTSTATUS samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3959                                   struct samr_GetDomPwInfo *r)
3960 {
3961         struct ldb_message **msgs;
3962         int ret;
3963         const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
3964         struct ldb_context *sam_ctx;
3965
3966         ZERO_STRUCT(r->out.info);
3967
3968         sam_ctx = samdb_connect(mem_ctx, dce_call->conn->auth_state.session_info); 
3969         if (sam_ctx == NULL) {
3970                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
3971         }
3972
3973         /* The domain name in this call is ignored */
3974         ret = gendb_search_dn(sam_ctx, 
3975                            mem_ctx, samdb_base_dn(mem_ctx), &msgs, attrs);
3976         if (ret <= 0) {
3977                 return NT_STATUS_NO_SUCH_DOMAIN;
3978         }
3979         if (ret > 1) {
3980                 talloc_free(msgs);
3981                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3982         }
3983
3984         r->out.info.min_password_length = samdb_result_uint(msgs[0], "minPwdLength", 0);
3985         r->out.info.password_properties = samdb_result_uint(msgs[0], "pwdProperties", 1);
3986
3987         talloc_free(msgs);
3988
3989         talloc_free(sam_ctx);
3990         return NT_STATUS_OK;
3991 }
3992
3993
3994 /* 
3995   samr_Connect2 
3996 */
3997 static NTSTATUS samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3998                               struct samr_Connect2 *r)
3999 {
4000         struct samr_Connect c;
4001
4002         c.in.system_name = NULL;
4003         c.in.access_mask = r->in.access_mask;
4004         c.out.connect_handle = r->out.connect_handle;
4005
4006         return samr_Connect(dce_call, mem_ctx, &c);
4007 }
4008
4009
4010 /* 
4011   samr_SetUserInfo2 
4012
4013   just an alias for samr_SetUserInfo
4014 */
4015 static NTSTATUS samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4016                                   struct samr_SetUserInfo2 *r)
4017 {
4018         struct samr_SetUserInfo r2;
4019
4020         r2.in.user_handle = r->in.user_handle;
4021         r2.in.level = r->in.level;
4022         r2.in.info = r->in.info;
4023
4024         return samr_SetUserInfo(dce_call, mem_ctx, &r2);
4025 }
4026
4027
4028 /* 
4029   samr_SetBootKeyInformation 
4030 */
4031 static NTSTATUS samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4032                        struct samr_SetBootKeyInformation *r)
4033 {
4034         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4035 }
4036
4037
4038 /* 
4039   samr_GetBootKeyInformation 
4040 */
4041 static NTSTATUS samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4042                        struct samr_GetBootKeyInformation *r)
4043 {
4044         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4045 }
4046
4047
4048 /* 
4049   samr_Connect3 
4050 */
4051 static NTSTATUS samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4052                        struct samr_Connect3 *r)
4053 {
4054         struct samr_Connect c;
4055
4056         c.in.system_name = NULL;
4057         c.in.access_mask = r->in.access_mask;
4058         c.out.connect_handle = r->out.connect_handle;
4059
4060         return samr_Connect(dce_call, mem_ctx, &c);
4061 }
4062
4063
4064 /* 
4065   samr_Connect4 
4066 */
4067 static NTSTATUS samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4068                        struct samr_Connect4 *r)
4069 {
4070         struct samr_Connect c;
4071
4072         c.in.system_name = NULL;
4073         c.in.access_mask = r->in.access_mask;
4074         c.out.connect_handle = r->out.connect_handle;
4075
4076         return samr_Connect(dce_call, mem_ctx, &c);
4077 }
4078
4079
4080 /* 
4081   samr_Connect5 
4082 */
4083 static NTSTATUS samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4084                               struct samr_Connect5 *r)
4085 {
4086         struct samr_Connect c;
4087         NTSTATUS status;
4088
4089         c.in.system_name = NULL;
4090         c.in.access_mask = r->in.access_mask;
4091         c.out.connect_handle = r->out.connect_handle;
4092
4093         status = samr_Connect(dce_call, mem_ctx, &c);
4094
4095         r->out.info->info1.unknown1 = 3;
4096         r->out.info->info1.unknown2 = 0;
4097         r->out.level = r->in.level;
4098
4099         return status;
4100 }
4101
4102
4103 /* 
4104   samr_RidToSid 
4105 */
4106 static NTSTATUS samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4107                               struct samr_RidToSid *r)
4108 {
4109         struct samr_domain_state *d_state;
4110         struct dcesrv_handle *h;
4111
4112         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4113
4114         d_state = h->data;
4115
4116         /* form the users SID */
4117         r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4118         if (!r->out.sid) {
4119                 return NT_STATUS_NO_MEMORY;
4120         }
4121
4122         return NT_STATUS_OK;
4123 }
4124
4125
4126 /* 
4127   samr_SetDsrmPassword 
4128 */
4129 static NTSTATUS samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4130                        struct samr_SetDsrmPassword *r)
4131 {
4132         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4133 }
4134
4135
4136 /* 
4137   samr_ValidatePassword 
4138 */
4139 static NTSTATUS samr_ValidatePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4140                                       struct samr_ValidatePassword *r)
4141 {
4142         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4143 }
4144
4145
4146 /* include the generated boilerplate */
4147 #include "librpc/gen_ndr/ndr_samr_s.c"