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