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