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