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