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