921d2965d7ccc91249912c3840761663c2406c77
[samba.git] / source4 / rpc_server / samr / dcesrv_samr.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    endpoint server for the samr pipe
5
6    Copyright (C) Andrew Tridgell 2004
7    Copyright (C) Volker Lendecke 2004
8    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
9    Copyright (C) Matthias Dieter Wallnöfer 2009
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26 #include "librpc/gen_ndr/ndr_samr.h"
27 #include "rpc_server/dcerpc_server.h"
28 #include "rpc_server/common/common.h"
29 #include "rpc_server/samr/dcesrv_samr.h"
30 #include "system/time.h"
31 #include <ldb.h>
32 #include <ldb_errors.h>
33 #include "../libds/common/flags.h"
34 #include "dsdb/samdb/samdb.h"
35 #include "dsdb/common/util.h"
36 #include "libcli/ldap/ldap_ndr.h"
37 #include "libcli/security/security.h"
38 #include "rpc_server/samr/proto.h"
39 #include "../lib/util/util_ldb.h"
40 #include "param/param.h"
41 #include "lib/util/tsort.h"
42 #include "libds/common/flag_mapping.h"
43
44 #define DCESRV_INTERFACE_SAMR_BIND(call, iface) \
45        dcesrv_interface_samr_bind(call, iface)
46 static NTSTATUS dcesrv_interface_samr_bind(struct dcesrv_call_state *dce_call,
47                                              const struct dcesrv_interface *iface)
48 {
49         return dcesrv_interface_bind_reject_connect(dce_call, iface);
50 }
51
52 /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
53
54 #define QUERY_STRING(msg, field, attr) \
55         info->field.string = ldb_msg_find_attr_as_string(msg, attr, "");
56 #define QUERY_UINT(msg, field, attr) \
57         info->field = ldb_msg_find_attr_as_uint(msg, attr, 0);
58 #define QUERY_RID(msg, field, attr) \
59         info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
60 #define QUERY_UINT64(msg, field, attr) \
61         info->field = ldb_msg_find_attr_as_uint64(msg, attr, 0);
62 #define QUERY_APASSC(msg, field, attr) \
63         info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
64                                                          a_state->domain_state->domain_dn, msg, attr);
65 #define QUERY_BPWDCT(msg, field, attr) \
66         info->field = samdb_result_effective_badPwdCount(sam_ctx, mem_ctx, \
67                                                          a_state->domain_state->domain_dn, msg);
68 #define QUERY_LHOURS(msg, field, attr) \
69         info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
70 #define QUERY_AFLAGS(msg, field, attr) \
71         info->field = samdb_result_acct_flags(msg, attr);
72
73
74 /* these are used to make the Set[User|Group]Info code easier to follow */
75
76 #define SET_STRING(msg, field, attr) do {                               \
77         struct ldb_message_element *set_el;                             \
78         if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
79         if (r->in.info->field.string[0] == '\0') {                      \
80                 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL) != LDB_SUCCESS) { \
81                         return NT_STATUS_NO_MEMORY;                     \
82                 }                                                       \
83         }                                                               \
84         if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != LDB_SUCCESS) { \
85                 return NT_STATUS_NO_MEMORY;                             \
86         }                                                               \
87         set_el = ldb_msg_find_element(msg, attr);                       \
88         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
89 } while (0)
90
91 #define SET_UINT(msg, field, attr) do {                                 \
92         struct ldb_message_element *set_el;                             \
93         if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
94                 return NT_STATUS_NO_MEMORY;                             \
95         }                                                               \
96         set_el = ldb_msg_find_element(msg, attr);                       \
97         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
98 } while (0)
99
100 #define SET_INT64(msg, field, attr) do {                                \
101         struct ldb_message_element *set_el;                             \
102         if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
103                 return NT_STATUS_NO_MEMORY;                             \
104         }                                                               \
105         set_el = ldb_msg_find_element(msg, attr);                       \
106         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
107 } while (0)
108
109 #define SET_UINT64(msg, field, attr) do {                               \
110         struct ldb_message_element *set_el;                             \
111         if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
112                 return NT_STATUS_NO_MEMORY;                             \
113         }                                                               \
114         set_el = ldb_msg_find_element(msg, attr);                       \
115         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
116 } while (0)
117
118 /* Set account flags, discarding flags that cannot be set with SAMR */
119 #define SET_AFLAGS(msg, field, attr) do {                               \
120         struct ldb_message_element *set_el;                             \
121         if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
122                 return NT_STATUS_NO_MEMORY;                             \
123         }                                                               \
124         set_el = ldb_msg_find_element(msg, attr);                       \
125         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
126 } while (0)
127
128 #define SET_LHOURS(msg, field, attr) do {                               \
129         struct ldb_message_element *set_el;                             \
130         if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
131                 return NT_STATUS_NO_MEMORY;                             \
132         }                                                               \
133         set_el = ldb_msg_find_element(msg, attr);                       \
134         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
135 } while (0)
136
137 #define SET_PARAMETERS(msg, field, attr) do {                           \
138         struct ldb_message_element *set_el;                             \
139         if (r->in.info->field.length != 0) {                            \
140                 if (samdb_msg_add_parameters(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
141                         return NT_STATUS_NO_MEMORY;                     \
142                 }                                                       \
143                 set_el = ldb_msg_find_element(msg, attr);               \
144                 set_el->flags = LDB_FLAG_MOD_REPLACE;                   \
145         }                                                               \
146 } while (0)
147
148 /*
149  * Clear a GUID cache
150  */
151 static void clear_guid_cache(struct samr_guid_cache *cache)
152 {
153         cache->handle = 0;
154         cache->size = 0;
155         TALLOC_FREE(cache->entries);
156 }
157
158 /*
159  * initialize a GUID cache
160  */
161 static void initialize_guid_cache(struct samr_guid_cache *cache)
162 {
163         cache->handle = 0;
164         cache->size = 0;
165         cache->entries = NULL;
166 }
167
168 static NTSTATUS load_guid_cache(
169         struct samr_guid_cache *cache,
170         struct samr_domain_state *d_state,
171         unsigned int ldb_cnt,
172         struct ldb_message **res)
173 {
174         NTSTATUS status = NT_STATUS_OK;
175         unsigned int i;
176         TALLOC_CTX *frame = talloc_stackframe();
177
178         clear_guid_cache(cache);
179
180         /*
181          * Store the GUID's in the cache.
182          */
183         cache->handle = 0;
184         cache->size = ldb_cnt;
185         cache->entries = talloc_array(d_state, struct GUID, ldb_cnt);
186         if (cache->entries == NULL) {
187                 clear_guid_cache(cache);
188                 status = NT_STATUS_NO_MEMORY;
189                 goto exit;
190         }
191
192         /*
193          * Extract a list of the GUIDs for all the matching objects
194          * we cache just the GUIDS to reduce the memory overhead of
195          * the result cache.
196          */
197         for (i = 0; i < ldb_cnt; i++) {
198                 cache->entries[i] = samdb_result_guid(res[i], "objectGUID");
199         }
200 exit:
201         TALLOC_FREE(frame);
202         return status;
203 }
204
205 /*
206   samr_Connect
207
208   create a connection to the SAM database
209 */
210 static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
211                              struct samr_Connect *r)
212 {
213         struct 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) {
3010                 return NT_STATUS_NO_MEMORY;
3011         }
3012
3013         u_handle->data = talloc_steal(u_handle, a_state);
3014
3015         *r->out.user_handle = u_handle->wire_handle;
3016
3017         return NT_STATUS_OK;
3018
3019 }
3020
3021
3022 /*
3023   samr_DeleteUser
3024 */
3025 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3026                                 struct samr_DeleteUser *r)
3027 {
3028         struct dcesrv_handle *h;
3029         struct samr_account_state *a_state;
3030         int ret;
3031
3032         *r->out.user_handle = *r->in.user_handle;
3033
3034         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3035
3036         a_state = h->data;
3037
3038         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
3039         if (ret != LDB_SUCCESS) {
3040                 DEBUG(1, ("Failed to delete user: %s: %s\n",
3041                           ldb_dn_get_linearized(a_state->account_dn),
3042                           ldb_errstring(a_state->sam_ctx)));
3043                 return dsdb_ldb_err_to_ntstatus(ret);
3044         }
3045
3046         talloc_free(h);
3047         ZERO_STRUCTP(r->out.user_handle);
3048
3049         return NT_STATUS_OK;
3050 }
3051
3052
3053 /*
3054   samr_QueryUserInfo
3055 */
3056 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3057                                    struct samr_QueryUserInfo *r)
3058 {
3059         struct dcesrv_handle *h;
3060         struct samr_account_state *a_state;
3061         struct ldb_message *msg, **res;
3062         int ret;
3063         struct ldb_context *sam_ctx;
3064
3065         const char * const *attrs = NULL;
3066         union samr_UserInfo *info;
3067
3068         NTSTATUS status;
3069
3070         *r->out.info = NULL;
3071
3072         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3073
3074         a_state = h->data;
3075         sam_ctx = a_state->sam_ctx;
3076
3077         /* fill in the reply */
3078         switch (r->in.level) {
3079         case 1:
3080         {
3081                 static const char * const attrs2[] = {"sAMAccountName",
3082                                                       "displayName",
3083                                                       "primaryGroupID",
3084                                                       "description",
3085                                                       "comment",
3086                                                       NULL};
3087                 attrs = attrs2;
3088                 break;
3089         }
3090         case 2:
3091         {
3092                 static const char * const attrs2[] = {"comment",
3093                                                       "countryCode",
3094                                                       "codePage",
3095                                                       NULL};
3096                 attrs = attrs2;
3097                 break;
3098         }
3099         case 3:
3100         {
3101                 static const char * const attrs2[] = {"sAMAccountName",
3102                                                       "displayName",
3103                                                       "objectSid",
3104                                                       "primaryGroupID",
3105                                                       "homeDirectory",
3106                                                       "homeDrive",
3107                                                       "scriptPath",
3108                                                       "profilePath",
3109                                                       "userWorkstations",
3110                                                       "lastLogon",
3111                                                       "lastLogoff",
3112                                                       "pwdLastSet",
3113                                                       "msDS-UserPasswordExpiryTimeComputed",
3114                                                       "logonHours",
3115                                                       "badPwdCount",
3116                                                       "badPasswordTime",
3117                                                       "logonCount",
3118                                                       "userAccountControl",
3119                                                       "msDS-User-Account-Control-Computed",
3120                                                       NULL};
3121                 attrs = attrs2;
3122                 break;
3123         }
3124         case 4:
3125         {
3126                 static const char * const attrs2[] = {"logonHours",
3127                                                       NULL};
3128                 attrs = attrs2;
3129                 break;
3130         }
3131         case 5:
3132         {
3133                 static const char * const attrs2[] = {"sAMAccountName",
3134                                                       "displayName",
3135                                                       "objectSid",
3136                                                       "primaryGroupID",
3137                                                       "homeDirectory",
3138                                                       "homeDrive",
3139                                                       "scriptPath",
3140                                                       "profilePath",
3141                                                       "description",
3142                                                       "userWorkstations",
3143                                                       "lastLogon",
3144                                                       "lastLogoff",
3145                                                       "logonHours",
3146                                                       "badPwdCount",
3147                                                       "badPasswordTime",
3148                                                       "logonCount",
3149                                                       "pwdLastSet",
3150                                                       "msDS-ResultantPSO",
3151                                                       "msDS-UserPasswordExpiryTimeComputed",
3152                                                       "accountExpires",
3153                                                       "userAccountControl",
3154                                                       "msDS-User-Account-Control-Computed",
3155                                                       NULL};
3156                 attrs = attrs2;
3157                 break;
3158         }
3159         case 6:
3160         {
3161                 static const char * const attrs2[] = {"sAMAccountName",
3162                                                       "displayName",
3163                                                       NULL};
3164                 attrs = attrs2;
3165                 break;
3166         }
3167         case 7:
3168         {
3169                 static const char * const attrs2[] = {"sAMAccountName",
3170                                                       NULL};
3171                 attrs = attrs2;
3172                 break;
3173         }
3174         case 8:
3175         {
3176                 static const char * const attrs2[] = {"displayName",
3177                                                       NULL};
3178                 attrs = attrs2;
3179                 break;
3180         }
3181         case 9:
3182         {
3183                 static const char * const attrs2[] = {"primaryGroupID",
3184                                                       NULL};
3185                 attrs = attrs2;
3186                 break;
3187         }
3188         case 10:
3189         {
3190                 static const char * const attrs2[] = {"homeDirectory",
3191                                                       "homeDrive",
3192                                                       NULL};
3193                 attrs = attrs2;
3194                 break;
3195         }
3196         case 11:
3197         {
3198                 static const char * const attrs2[] = {"scriptPath",
3199                                                       NULL};
3200                 attrs = attrs2;
3201                 break;
3202         }
3203         case 12:
3204         {
3205                 static const char * const attrs2[] = {"profilePath",
3206                                                       NULL};
3207                 attrs = attrs2;
3208                 break;
3209         }
3210         case 13:
3211         {
3212                 static const char * const attrs2[] = {"description",
3213                                                       NULL};
3214                 attrs = attrs2;
3215                 break;
3216         }
3217         case 14:
3218         {
3219                 static const char * const attrs2[] = {"userWorkstations",
3220                                                       NULL};
3221                 attrs = attrs2;
3222                 break;
3223         }
3224         case 16:
3225         {
3226                 static const char * const attrs2[] = {"userAccountControl",
3227                                                       "msDS-User-Account-Control-Computed",
3228                                                       "pwdLastSet",
3229                                                       "msDS-UserPasswordExpiryTimeComputed",
3230                                                       NULL};
3231                 attrs = attrs2;
3232                 break;
3233         }
3234         case 17:
3235         {
3236                 static const char * const attrs2[] = {"accountExpires",
3237                                                       NULL};
3238                 attrs = attrs2;
3239                 break;
3240         }
3241         case 18:
3242         {
3243                 return NT_STATUS_NOT_SUPPORTED;
3244         }
3245         case 20:
3246         {
3247                 static const char * const attrs2[] = {"userParameters",
3248                                                       NULL};
3249                 attrs = attrs2;
3250                 break;
3251         }
3252         case 21:
3253         {
3254                 static const char * const attrs2[] = {"lastLogon",
3255                                                       "lastLogoff",
3256                                                       "pwdLastSet",
3257                                                       "msDS-ResultantPSO",
3258                                                       "msDS-UserPasswordExpiryTimeComputed",
3259                                                       "accountExpires",
3260                                                       "sAMAccountName",
3261                                                       "displayName",
3262                                                       "homeDirectory",
3263                                                       "homeDrive",
3264                                                       "scriptPath",
3265                                                       "profilePath",
3266                                                       "description",
3267                                                       "userWorkstations",
3268                                                       "comment",
3269                                                       "userParameters",
3270                                                       "objectSid",
3271                                                       "primaryGroupID",
3272                                                       "userAccountControl",
3273                                                       "msDS-User-Account-Control-Computed",
3274                                                       "logonHours",
3275                                                       "badPwdCount",
3276                                                       "badPasswordTime",
3277                                                       "logonCount",
3278                                                       "countryCode",
3279                                                       "codePage",
3280                                                       NULL};
3281                 attrs = attrs2;
3282                 break;
3283         }
3284         case 23:
3285         case 24:
3286         case 25:
3287         case 26:
3288         {
3289                 return NT_STATUS_NOT_SUPPORTED;
3290         }
3291         default:
3292         {
3293                 return NT_STATUS_INVALID_INFO_CLASS;
3294         }
3295         }
3296
3297         /* pull all the user attributes */
3298         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
3299                               a_state->account_dn, &res, attrs);
3300         if (ret == 0) {
3301                 return NT_STATUS_NO_SUCH_USER;
3302         }
3303         if (ret != 1) {
3304                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3305         }
3306         msg = res[0];
3307
3308         /* allocate the info structure */
3309         info = talloc_zero(mem_ctx, union samr_UserInfo);
3310         if (info == NULL) {
3311                 return NT_STATUS_NO_MEMORY;
3312         }
3313
3314         /* fill in the reply */
3315         switch (r->in.level) {
3316         case 1:
3317                 QUERY_STRING(msg, info1.account_name,          "sAMAccountName");
3318                 QUERY_STRING(msg, info1.full_name,             "displayName");
3319                 QUERY_UINT  (msg, info1.primary_gid,           "primaryGroupID");
3320                 QUERY_STRING(msg, info1.description,           "description");
3321                 QUERY_STRING(msg, info1.comment,               "comment");
3322                 break;
3323
3324         case 2:
3325                 QUERY_STRING(msg, info2.comment,               "comment");
3326                 QUERY_UINT  (msg, info2.country_code,          "countryCode");
3327                 QUERY_UINT  (msg, info2.code_page,             "codePage");
3328                 break;
3329
3330         case 3:
3331                 QUERY_STRING(msg, info3.account_name,          "sAMAccountName");
3332                 QUERY_STRING(msg, info3.full_name,             "displayName");
3333                 QUERY_RID   (msg, info3.rid,                   "objectSid");
3334                 QUERY_UINT  (msg, info3.primary_gid,           "primaryGroupID");
3335                 QUERY_STRING(msg, info3.home_directory,        "homeDirectory");
3336                 QUERY_STRING(msg, info3.home_drive,            "homeDrive");
3337                 QUERY_STRING(msg, info3.logon_script,          "scriptPath");
3338                 QUERY_STRING(msg, info3.profile_path,          "profilePath");
3339                 QUERY_STRING(msg, info3.workstations,          "userWorkstations");
3340                 QUERY_UINT64(msg, info3.last_logon,            "lastLogon");
3341                 QUERY_UINT64(msg, info3.last_logoff,           "lastLogoff");
3342                 QUERY_UINT64(msg, info3.last_password_change,  "pwdLastSet");
3343                 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
3344                 QUERY_UINT64(msg, info3.force_password_change, "msDS-UserPasswordExpiryTimeComputed");
3345                 QUERY_LHOURS(msg, info3.logon_hours,           "logonHours");
3346                 /* level 3 gives the raw badPwdCount value */
3347                 QUERY_UINT  (msg, info3.bad_password_count,    "badPwdCount");
3348                 QUERY_UINT  (msg, info3.logon_count,           "logonCount");
3349                 QUERY_AFLAGS(msg, info3.acct_flags,            "msDS-User-Account-Control-Computed");
3350                 break;
3351
3352         case 4:
3353                 QUERY_LHOURS(msg, info4.logon_hours,           "logonHours");
3354                 break;
3355
3356         case 5:
3357                 QUERY_STRING(msg, info5.account_name,          "sAMAccountName");
3358                 QUERY_STRING(msg, info5.full_name,             "displayName");
3359                 QUERY_RID   (msg, info5.rid,                   "objectSid");
3360                 QUERY_UINT  (msg, info5.primary_gid,           "primaryGroupID");
3361                 QUERY_STRING(msg, info5.home_directory,        "homeDirectory");
3362                 QUERY_STRING(msg, info5.home_drive,            "homeDrive");
3363                 QUERY_STRING(msg, info5.logon_script,          "scriptPath");
3364                 QUERY_STRING(msg, info5.profile_path,          "profilePath");
3365                 QUERY_STRING(msg, info5.description,           "description");
3366                 QUERY_STRING(msg, info5.workstations,          "userWorkstations");
3367                 QUERY_UINT64(msg, info5.last_logon,            "lastLogon");
3368                 QUERY_UINT64(msg, info5.last_logoff,           "lastLogoff");
3369                 QUERY_LHOURS(msg, info5.logon_hours,           "logonHours");
3370                 QUERY_BPWDCT(msg, info5.bad_password_count,    "badPwdCount");
3371                 QUERY_UINT  (msg, info5.logon_count,           "logonCount");
3372                 QUERY_UINT64(msg, info5.last_password_change,  "pwdLastSet");
3373                 QUERY_UINT64(msg, info5.acct_expiry,           "accountExpires");
3374                 QUERY_AFLAGS(msg, info5.acct_flags,            "msDS-User-Account-Control-Computed");
3375                 break;
3376
3377         case 6:
3378                 QUERY_STRING(msg, info6.account_name,   "sAMAccountName");
3379                 QUERY_STRING(msg, info6.full_name,      "displayName");
3380                 break;
3381
3382         case 7:
3383                 QUERY_STRING(msg, info7.account_name,   "sAMAccountName");
3384                 break;
3385
3386         case 8:
3387                 QUERY_STRING(msg, info8.full_name,      "displayName");
3388                 break;
3389
3390         case 9:
3391                 QUERY_UINT  (msg, info9.primary_gid,    "primaryGroupID");
3392                 break;
3393
3394         case 10:
3395                 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3396                 QUERY_STRING(msg, info10.home_drive,    "homeDrive");
3397                 break;
3398
3399         case 11:
3400                 QUERY_STRING(msg, info11.logon_script,  "scriptPath");
3401                 break;
3402
3403         case 12:
3404                 QUERY_STRING(msg, info12.profile_path,  "profilePath");
3405                 break;
3406
3407         case 13:
3408                 QUERY_STRING(msg, info13.description,   "description");
3409                 break;
3410
3411         case 14:
3412                 QUERY_STRING(msg, info14.workstations,  "userWorkstations");
3413                 break;
3414
3415         case 16:
3416                 QUERY_AFLAGS(msg, info16.acct_flags,    "msDS-User-Account-Control-Computed");
3417                 break;
3418
3419         case 17:
3420                 QUERY_UINT64(msg, info17.acct_expiry,   "accountExpires");
3421                 break;
3422
3423         case 20:
3424                 status = samdb_result_parameters(mem_ctx, msg, "userParameters", &info->info20.parameters);
3425                 if (!NT_STATUS_IS_OK(status)) {
3426                         talloc_free(info);
3427                         return status;
3428                 }
3429                 break;
3430
3431         case 21:
3432                 QUERY_UINT64(msg, info21.last_logon,           "lastLogon");
3433                 QUERY_UINT64(msg, info21.last_logoff,          "lastLogoff");
3434                 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3435                 QUERY_UINT64(msg, info21.acct_expiry,          "accountExpires");
3436                 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3437                 QUERY_UINT64(msg, info21.force_password_change, "msDS-UserPasswordExpiryTimeComputed");
3438                 QUERY_STRING(msg, info21.account_name,         "sAMAccountName");
3439                 QUERY_STRING(msg, info21.full_name,            "displayName");
3440                 QUERY_STRING(msg, info21.home_directory,       "homeDirectory");
3441                 QUERY_STRING(msg, info21.home_drive,           "homeDrive");
3442                 QUERY_STRING(msg, info21.logon_script,         "scriptPath");
3443                 QUERY_STRING(msg, info21.profile_path,         "profilePath");
3444                 QUERY_STRING(msg, info21.description,          "description");
3445                 QUERY_STRING(msg, info21.workstations,         "userWorkstations");
3446                 QUERY_STRING(msg, info21.comment,              "comment");
3447                 status = samdb_result_parameters(mem_ctx, msg, "userParameters", &info->info21.parameters);
3448                 if (!NT_STATUS_IS_OK(status)) {
3449                         talloc_free(info);
3450                         return status;
3451                 }
3452
3453                 QUERY_RID   (msg, info21.rid,                  "objectSid");
3454                 QUERY_UINT  (msg, info21.primary_gid,          "primaryGroupID");
3455                 QUERY_AFLAGS(msg, info21.acct_flags,           "msDS-User-Account-Control-Computed");
3456                 info->info21.fields_present = 0x08FFFFFF;
3457                 QUERY_LHOURS(msg, info21.logon_hours,          "logonHours");
3458                 QUERY_BPWDCT(msg, info21.bad_password_count,   "badPwdCount");
3459                 QUERY_UINT  (msg, info21.logon_count,          "logonCount");
3460                 if ((info->info21.acct_flags & ACB_PW_EXPIRED) != 0) {
3461                         info->info21.password_expired = PASS_MUST_CHANGE_AT_NEXT_LOGON;
3462                 } else {
3463                         info->info21.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
3464                 }
3465                 QUERY_UINT  (msg, info21.country_code,         "countryCode");
3466                 QUERY_UINT  (msg, info21.code_page,            "codePage");
3467                 break;
3468
3469
3470         default:
3471                 talloc_free(info);
3472                 return NT_STATUS_INVALID_INFO_CLASS;
3473         }
3474
3475         *r->out.info = info;
3476
3477         return NT_STATUS_OK;
3478 }
3479
3480
3481 /*
3482   samr_SetUserInfo
3483 */
3484 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3485                                  struct samr_SetUserInfo *r)
3486 {
3487         struct dcesrv_handle *h;
3488         struct samr_account_state *a_state;
3489         struct ldb_message *msg;
3490         int ret;
3491         NTSTATUS status = NT_STATUS_OK;
3492         struct ldb_context *sam_ctx;
3493
3494         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3495
3496         a_state = h->data;
3497         sam_ctx = a_state->sam_ctx;
3498
3499         msg = ldb_msg_new(mem_ctx);
3500         if (msg == NULL) {
3501                 return NT_STATUS_NO_MEMORY;
3502         }
3503
3504         msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3505         if (!msg->dn) {
3506                 return NT_STATUS_NO_MEMORY;
3507         }
3508
3509         switch (r->in.level) {
3510         case 2:
3511                 SET_STRING(msg, info2.comment,          "comment");
3512                 SET_UINT  (msg, info2.country_code,     "countryCode");
3513                 SET_UINT  (msg, info2.code_page,        "codePage");
3514                 break;
3515
3516         case 4:
3517                 SET_LHOURS(msg, info4.logon_hours,      "logonHours");
3518                 break;
3519
3520         case 6:
3521                 SET_STRING(msg, info6.account_name,     "samAccountName");
3522                 SET_STRING(msg, info6.full_name,        "displayName");
3523                 break;
3524
3525         case 7:
3526                 SET_STRING(msg, info7.account_name,     "samAccountName");
3527                 break;
3528
3529         case 8:
3530                 SET_STRING(msg, info8.full_name,        "displayName");
3531                 break;
3532
3533         case 9:
3534                 SET_UINT(msg, info9.primary_gid,        "primaryGroupID");
3535                 break;
3536
3537         case 10:
3538                 SET_STRING(msg, info10.home_directory,  "homeDirectory");
3539                 SET_STRING(msg, info10.home_drive,      "homeDrive");
3540                 break;
3541
3542         case 11:
3543                 SET_STRING(msg, info11.logon_script,    "scriptPath");
3544                 break;
3545
3546         case 12:
3547                 SET_STRING(msg, info12.profile_path,    "profilePath");
3548                 break;
3549
3550         case 13:
3551                 SET_STRING(msg, info13.description,     "description");
3552                 break;
3553
3554         case 14:
3555                 SET_STRING(msg, info14.workstations,    "userWorkstations");
3556                 break;
3557
3558         case 16:
3559                 SET_AFLAGS(msg, info16.acct_flags,      "userAccountControl");
3560                 break;
3561
3562         case 17:
3563                 SET_UINT64(msg, info17.acct_expiry,     "accountExpires");
3564                 break;
3565
3566         case 18:
3567                 status = samr_set_password_buffers(dce_call,
3568                                                    a_state->sam_ctx,
3569                                                    a_state->account_dn,
3570                                                    a_state->domain_state->domain_dn,
3571                                                    mem_ctx,
3572                                                    r->in.info->info18.lm_pwd_active ? r->in.info->info18.lm_pwd.hash : NULL,
3573                                                    r->in.info->info18.nt_pwd_active ? r->in.info->info18.nt_pwd.hash : NULL);
3574                 if (!NT_STATUS_IS_OK(status)) {
3575                         return status;
3576                 }
3577
3578                 if (r->in.info->info18.password_expired > 0) {
3579                         struct ldb_message_element *set_el;
3580                         if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3581                                 return NT_STATUS_NO_MEMORY;
3582                         }
3583                         set_el = ldb_msg_find_element(msg, "pwdLastSet");
3584                         set_el->flags = LDB_FLAG_MOD_REPLACE;
3585                 }
3586                 break;
3587
3588         case 20:
3589                 SET_PARAMETERS(msg, info20.parameters,      "userParameters");
3590                 break;
3591
3592         case 21:
3593                 if (r->in.info->info21.fields_present == 0)
3594                         return NT_STATUS_INVALID_PARAMETER;
3595
3596 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3597                 IFSET(SAMR_FIELD_LAST_LOGON)
3598                         SET_UINT64(msg, info21.last_logon,     "lastLogon");
3599                 IFSET(SAMR_FIELD_LAST_LOGOFF)
3600                         SET_UINT64(msg, info21.last_logoff,    "lastLogoff");
3601                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3602                         SET_UINT64(msg, info21.acct_expiry,    "accountExpires");
3603                 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3604                         SET_STRING(msg, info21.account_name,   "samAccountName");
3605                 IFSET(SAMR_FIELD_FULL_NAME)
3606                         SET_STRING(msg, info21.full_name,      "displayName");
3607                 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3608                         SET_STRING(msg, info21.home_directory, "homeDirectory");
3609                 IFSET(SAMR_FIELD_HOME_DRIVE)
3610                         SET_STRING(msg, info21.home_drive,     "homeDrive");
3611                 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3612                         SET_STRING(msg, info21.logon_script,   "scriptPath");
3613                 IFSET(SAMR_FIELD_PROFILE_PATH)
3614                         SET_STRING(msg, info21.profile_path,   "profilePath");
3615                 IFSET(SAMR_FIELD_DESCRIPTION)
3616                         SET_STRING(msg, info21.description,    "description");
3617                 IFSET(SAMR_FIELD_WORKSTATIONS)
3618                         SET_STRING(msg, info21.workstations,   "userWorkstations");
3619                 IFSET(SAMR_FIELD_COMMENT)
3620                         SET_STRING(msg, info21.comment,        "comment");
3621                 IFSET(SAMR_FIELD_PARAMETERS)
3622                         SET_PARAMETERS(msg, info21.parameters, "userParameters");
3623                 IFSET(SAMR_FIELD_PRIMARY_GID)
3624                         SET_UINT(msg, info21.primary_gid,      "primaryGroupID");
3625                 IFSET(SAMR_FIELD_ACCT_FLAGS)
3626                         SET_AFLAGS(msg, info21.acct_flags,     "userAccountControl");
3627                 IFSET(SAMR_FIELD_LOGON_HOURS)
3628                         SET_LHOURS(msg, info21.logon_hours,    "logonHours");
3629                 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3630                         SET_UINT  (msg, info21.bad_password_count, "badPwdCount");
3631                 IFSET(SAMR_FIELD_NUM_LOGONS)
3632                         SET_UINT  (msg, info21.logon_count,    "logonCount");
3633                 IFSET(SAMR_FIELD_COUNTRY_CODE)
3634                         SET_UINT  (msg, info21.country_code,   "countryCode");
3635                 IFSET(SAMR_FIELD_CODE_PAGE)
3636                         SET_UINT  (msg, info21.code_page,      "codePage");
3637
3638                 /* password change fields */
3639                &