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