python:tests: Store keys as bytes rather than as lists of ints
[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 #undef strcasecmp
45
46 #define DCESRV_INTERFACE_SAMR_BIND(context, iface) \
47        dcesrv_interface_samr_bind(context, iface)
48 static NTSTATUS dcesrv_interface_samr_bind(struct dcesrv_connection_context *context,
49                                              const struct dcesrv_interface *iface)
50 {
51         return dcesrv_interface_bind_reject_connect(context, iface);
52 }
53
54 /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
55
56 #define QUERY_STRING(msg, field, attr) \
57         info->field.string = ldb_msg_find_attr_as_string(msg, attr, "");
58 #define QUERY_UINT(msg, field, attr) \
59         info->field = ldb_msg_find_attr_as_uint(msg, attr, 0);
60 #define QUERY_RID(msg, field, attr) \
61         info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
62 #define QUERY_UINT64(msg, field, attr) \
63         info->field = ldb_msg_find_attr_as_uint64(msg, attr, 0);
64 #define QUERY_APASSC(msg, field, attr) \
65         info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
66                                                          a_state->domain_state->domain_dn, msg, attr);
67 #define QUERY_BPWDCT(msg, field, attr) \
68         info->field = samdb_result_effective_badPwdCount(sam_ctx, mem_ctx, \
69                                                          a_state->domain_state->domain_dn, msg);
70 #define QUERY_LHOURS(msg, field, attr) \
71         info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
72 #define QUERY_AFLAGS(msg, field, attr) \
73         info->field = samdb_result_acct_flags(msg, attr);
74
75
76 /* these are used to make the Set[User|Group]Info code easier to follow */
77
78 #define SET_STRING(msg, field, attr) do {                               \
79         struct ldb_message_element *set_el;                             \
80         if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
81         if (r->in.info->field.string[0] == '\0') {                      \
82                 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL) != LDB_SUCCESS) { \
83                         return NT_STATUS_NO_MEMORY;                     \
84                 }                                                       \
85         }                                                               \
86         if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != LDB_SUCCESS) { \
87                 return NT_STATUS_NO_MEMORY;                             \
88         }                                                               \
89         set_el = ldb_msg_find_element(msg, attr);                       \
90         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
91 } while (0)
92
93 #define SET_UINT(msg, field, attr) do {                                 \
94         struct ldb_message_element *set_el;                             \
95         if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
96                 return NT_STATUS_NO_MEMORY;                             \
97         }                                                               \
98         set_el = ldb_msg_find_element(msg, attr);                       \
99         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
100 } while (0)
101
102 #define SET_INT64(msg, field, attr) do {                                \
103         struct ldb_message_element *set_el;                             \
104         if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
105                 return NT_STATUS_NO_MEMORY;                             \
106         }                                                               \
107         set_el = ldb_msg_find_element(msg, attr);                       \
108         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
109 } while (0)
110
111 #define SET_UINT64(msg, field, attr) do {                               \
112         struct ldb_message_element *set_el;                             \
113         if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
114                 return NT_STATUS_NO_MEMORY;                             \
115         }                                                               \
116         set_el = ldb_msg_find_element(msg, attr);                       \
117         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
118 } while (0)
119
120 /* Set account flags, discarding flags that cannot be set with SAMR */
121 #define SET_AFLAGS(msg, field, attr) do {                               \
122         struct ldb_message_element *set_el;                             \
123         if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
124                 return NT_STATUS_NO_MEMORY;                             \
125         }                                                               \
126         set_el = ldb_msg_find_element(msg, attr);                       \
127         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
128 } while (0)
129
130 #define SET_LHOURS(msg, field, attr) do {                               \
131         struct ldb_message_element *set_el;                             \
132         if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
133                 return NT_STATUS_NO_MEMORY;                             \
134         }                                                               \
135         set_el = ldb_msg_find_element(msg, attr);                       \
136         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
137 } while (0)
138
139 #define SET_PARAMETERS(msg, field, attr) do {                           \
140         struct ldb_message_element *set_el;                             \
141         if (r->in.info->field.length != 0) {                            \
142                 if (samdb_msg_add_parameters(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
143                         return NT_STATUS_NO_MEMORY;                     \
144                 }                                                       \
145                 set_el = ldb_msg_find_element(msg, attr);               \
146                 set_el->flags = LDB_FLAG_MOD_REPLACE;                   \
147         }                                                               \
148 } while (0)
149
150 /*
151  * Clear a GUID cache
152  */
153 static void clear_guid_cache(struct samr_guid_cache *cache)
154 {
155         cache->handle = 0;
156         cache->size = 0;
157         TALLOC_FREE(cache->entries);
158 }
159
160 /*
161  * initialize a GUID cache
162  */
163 static void initialize_guid_cache(struct samr_guid_cache *cache)
164 {
165         cache->handle = 0;
166         cache->size = 0;
167         cache->entries = NULL;
168 }
169
170 static NTSTATUS load_guid_cache(
171         struct samr_guid_cache *cache,
172         struct samr_domain_state *d_state,
173         unsigned int ldb_cnt,
174         struct ldb_message **res)
175 {
176         NTSTATUS status = NT_STATUS_OK;
177         unsigned int i;
178         TALLOC_CTX *frame = talloc_stackframe();
179
180         clear_guid_cache(cache);
181
182         /*
183          * Store the GUID's in the cache.
184          */
185         cache->handle = 0;
186         cache->size = ldb_cnt;
187         cache->entries = talloc_array(d_state, struct GUID, ldb_cnt);
188         if (cache->entries == NULL) {
189                 clear_guid_cache(cache);
190                 status = NT_STATUS_NO_MEMORY;
191                 goto exit;
192         }
193
194         /*
195          * Extract a list of the GUIDs for all the matching objects
196          * we cache just the GUIDS to reduce the memory overhead of
197          * the result cache.
198          */
199         for (i = 0; i < ldb_cnt; i++) {
200                 cache->entries[i] = samdb_result_guid(res[i], "objectGUID");
201         }
202 exit:
203         TALLOC_FREE(frame);
204         return status;
205 }
206
207 /*
208   samr_Connect
209
210   create a connection to the SAM database
211 */
212 static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
213                              struct samr_Connect *r)
214 {
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 = dcesrv_samdb_connect_as_user(c_state, dce_call);
227         if (c_state->sam_ctx == NULL) {
228                 talloc_free(c_state);
229                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
230         }
231
232         handle = dcesrv_handle_create(dce_call, SAMR_HANDLE_CONNECT);
233         if (!handle) {
234                 talloc_free(c_state);
235                 return NT_STATUS_NO_MEMORY;
236         }
237
238         handle->data = talloc_steal(handle, c_state);
239
240         c_state->access_mask = r->in.access_mask;
241         *r->out.connect_handle = handle->wire_handle;
242
243         return NT_STATUS_OK;
244 }
245
246
247 /*
248   samr_Close
249 */
250 static NTSTATUS dcesrv_samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
251                            struct samr_Close *r)
252 {
253         struct dcesrv_handle *h;
254
255         *r->out.handle = *r->in.handle;
256
257         DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
258
259         talloc_free(h);
260
261         ZERO_STRUCTP(r->out.handle);
262
263         return NT_STATUS_OK;
264 }
265
266
267 /*
268   samr_SetSecurity
269 */
270 static NTSTATUS dcesrv_samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
271                                  struct samr_SetSecurity *r)
272 {
273         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
274 }
275
276
277 /*
278   samr_QuerySecurity
279 */
280 static NTSTATUS dcesrv_samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
281                                    struct samr_QuerySecurity *r)
282 {
283         struct dcesrv_handle *h;
284         struct sec_desc_buf *sd;
285
286         *r->out.sdbuf = NULL;
287
288         DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
289
290         sd = talloc(mem_ctx, struct sec_desc_buf);
291         if (sd == NULL) {
292                 return NT_STATUS_NO_MEMORY;
293         }
294
295         sd->sd = samdb_default_security_descriptor(mem_ctx);
296
297         *r->out.sdbuf = sd;
298
299         return NT_STATUS_OK;
300 }
301
302
303 /*
304   samr_Shutdown
305
306   we refuse this operation completely. If a admin wants to shutdown samr
307   in Samba then they should use the samba admin tools to disable the samr pipe
308 */
309 static NTSTATUS dcesrv_samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
310                               struct samr_Shutdown *r)
311 {
312         return NT_STATUS_ACCESS_DENIED;
313 }
314
315
316 /*
317   samr_LookupDomain
318
319   this maps from a domain name to a SID
320 */
321 static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
322                                   struct samr_LookupDomain *r)
323 {
324         struct samr_connect_state *c_state;
325         struct dcesrv_handle *h;
326         struct dom_sid *sid;
327         const char * const dom_attrs[] = { "objectSid", NULL};
328         struct ldb_message **dom_msgs;
329         int ret;
330
331         *r->out.sid = NULL;
332
333         DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
334
335         c_state = h->data;
336
337         if (r->in.domain_name->string == NULL) {
338                 return NT_STATUS_INVALID_PARAMETER;
339         }
340
341         if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
342                 ret = gendb_search(c_state->sam_ctx,
343                                    mem_ctx, NULL, &dom_msgs, dom_attrs,
344                                    "(objectClass=builtinDomain)");
345         } else if (strcasecmp_m(r->in.domain_name->string, lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx)) == 0) {
346                 ret = gendb_search_dn(c_state->sam_ctx,
347                                       mem_ctx, ldb_get_default_basedn(c_state->sam_ctx),
348                                       &dom_msgs, dom_attrs);
349         } else {
350                 return NT_STATUS_NO_SUCH_DOMAIN;
351         }
352         if (ret != 1) {
353                 return NT_STATUS_NO_SUCH_DOMAIN;
354         }
355
356         sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
357                                    "objectSid");
358
359         if (sid == NULL) {
360                 return NT_STATUS_NO_SUCH_DOMAIN;
361         }
362
363         *r->out.sid = sid;
364
365         return NT_STATUS_OK;
366 }
367
368
369 /*
370   samr_EnumDomains
371
372   list the domains in the SAM
373 */
374 static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
375                                  struct samr_EnumDomains *r)
376 {
377         struct dcesrv_handle *h;
378         struct samr_SamArray *array;
379         uint32_t i, start_i;
380
381         *r->out.resume_handle = 0;
382         *r->out.sam = NULL;
383         *r->out.num_entries = 0;
384
385         DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
386
387         *r->out.resume_handle = 2;
388
389         start_i = *r->in.resume_handle;
390
391         if (start_i >= 2) {
392                 /* search past end of list is not an error for this call */
393                 return NT_STATUS_OK;
394         }
395
396         array = talloc(mem_ctx, struct samr_SamArray);
397         if (array == NULL) {
398                 return NT_STATUS_NO_MEMORY;
399         }
400
401         array->count = 0;
402         array->entries = NULL;
403
404         array->entries = talloc_array(mem_ctx, struct samr_SamEntry, 2 - start_i);
405         if (array->entries == NULL) {
406                 return NT_STATUS_NO_MEMORY;
407         }
408
409         for (i=0;i<2-start_i;i++) {
410                 array->entries[i].idx = start_i + i;
411                 if (i == 0) {
412                         array->entries[i].name.string = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx);
413                 } else {
414                         array->entries[i].name.string = "BUILTIN";
415                 }
416         }
417
418         *r->out.sam = array;
419         *r->out.num_entries = i;
420         array->count = *r->out.num_entries;
421
422         return NT_STATUS_OK;
423 }
424
425
426 /*
427   samr_OpenDomain
428 */
429 static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
430                                 struct samr_OpenDomain *r)
431 {
432         struct dcesrv_handle *h_conn, *h_domain;
433         struct samr_connect_state *c_state;
434         struct samr_domain_state *d_state;
435         const char * const dom_attrs[] = { "cn", NULL};
436         struct ldb_message **dom_msgs;
437         int ret;
438         unsigned int i;
439
440         ZERO_STRUCTP(r->out.domain_handle);
441
442         DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
443
444         c_state = h_conn->data;
445
446         if (r->in.sid == NULL) {
447                 return NT_STATUS_INVALID_PARAMETER;
448         }
449
450         d_state = talloc(mem_ctx, struct samr_domain_state);
451         if (!d_state) {
452                 return NT_STATUS_NO_MEMORY;
453         }
454
455         d_state->domain_sid = talloc_steal(d_state, r->in.sid);
456
457         if (dom_sid_equal(d_state->domain_sid, &global_sid_Builtin)) {
458                 d_state->builtin = true;
459                 d_state->domain_name = "BUILTIN";
460         } else {
461                 d_state->builtin = false;
462                 d_state->domain_name = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx);
463         }
464
465         ret = gendb_search(c_state->sam_ctx,
466                            mem_ctx, ldb_get_default_basedn(c_state->sam_ctx), &dom_msgs, dom_attrs,
467                            "(objectSid=%s)",
468                            ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
469
470         if (ret == 0) {
471                 talloc_free(d_state);
472                 return NT_STATUS_NO_SUCH_DOMAIN;
473         } else if (ret > 1) {
474                 talloc_free(d_state);
475                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
476         } else if (ret == -1) {
477                 talloc_free(d_state);
478                 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx)));
479                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
480         }
481
482         d_state->domain_dn = talloc_steal(d_state, dom_msgs[0]->dn);
483         d_state->role = lpcfg_server_role(dce_call->conn->dce_ctx->lp_ctx);
484         d_state->connect_state = talloc_reference(d_state, c_state);
485         d_state->sam_ctx = c_state->sam_ctx;
486         d_state->access_mask = r->in.access_mask;
487         d_state->domain_users_cached = NULL;
488
489         d_state->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
490
491         for (i = 0; i < SAMR_LAST_CACHE; i++) {
492                 initialize_guid_cache(&d_state->guid_caches[i]);
493         }
494
495         h_domain = dcesrv_handle_create(dce_call, SAMR_HANDLE_DOMAIN);
496         if (!h_domain) {
497                 talloc_free(d_state);
498                 return NT_STATUS_NO_MEMORY;
499         }
500
501         h_domain->data = talloc_steal(h_domain, d_state);
502
503         *r->out.domain_handle = h_domain->wire_handle;
504
505         return NT_STATUS_OK;
506 }
507
508 /*
509   return DomInfo1
510 */
511 static NTSTATUS dcesrv_samr_info_DomInfo1(struct samr_domain_state *state,
512                                           TALLOC_CTX *mem_ctx,
513                                           struct ldb_message **dom_msgs,
514                                           struct samr_DomInfo1 *info)
515 {
516         info->min_password_length =
517                 ldb_msg_find_attr_as_uint(dom_msgs[0], "minPwdLength", 0);
518         info->password_history_length =
519                 ldb_msg_find_attr_as_uint(dom_msgs[0], "pwdHistoryLength", 0);
520         info->password_properties =
521                 ldb_msg_find_attr_as_uint(dom_msgs[0], "pwdProperties", 0);
522         info->max_password_age =
523                 ldb_msg_find_attr_as_int64(dom_msgs[0], "maxPwdAge", 0);
524         info->min_password_age =
525                 ldb_msg_find_attr_as_int64(dom_msgs[0], "minPwdAge", 0);
526
527         return NT_STATUS_OK;
528 }
529
530 /*
531   return DomInfo2
532 */
533 static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state *state,
534                                                        TALLOC_CTX *mem_ctx,
535                                                        struct ldb_message **dom_msgs,
536                                                        struct samr_DomGeneralInformation *info)
537 {
538         size_t count = 0;
539         const enum ldb_scope scope = LDB_SCOPE_SUBTREE;
540         int ret = 0;
541
542         /* MS-SAMR 2.2.4.1 - ReplicaSourceNodeName: "domainReplica" attribute */
543         info->primary.string = ldb_msg_find_attr_as_string(dom_msgs[0],
544                                                            "domainReplica",
545                                                            "");
546
547         info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
548                                                             0x8000000000000000LL);
549
550         info->oem_information.string = ldb_msg_find_attr_as_string(dom_msgs[0],
551                                                                    "oEMInformation",
552                                                                    "");
553         info->domain_name.string  = state->domain_name;
554
555         info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
556                                                  0);
557         switch (state->role) {
558         case ROLE_ACTIVE_DIRECTORY_DC:
559                 /* This pulls the NetBIOS name from the
560                    cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
561                    string */
562                 if (samdb_is_pdc(state->sam_ctx)) {
563                         info->role = SAMR_ROLE_DOMAIN_PDC;
564                 } else {
565                         info->role = SAMR_ROLE_DOMAIN_BDC;
566                 }
567                 break;
568         case ROLE_DOMAIN_PDC:
569         case ROLE_DOMAIN_BDC:
570         case ROLE_IPA_DC:
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         /*
582          * Users are not meant to be in BUILTIN
583          * so to speed up the query we do not filter on domain_sid
584          */
585         ret = dsdb_domain_count(
586                 state->sam_ctx,
587                 &count,
588                 state->domain_dn,
589                 NULL,
590                 scope,
591                 "(objectClass=user)");
592         if (ret != LDB_SUCCESS || count > UINT32_MAX) {
593                 goto error;
594         }
595         info->num_users = count;
596
597         /*
598          * Groups are not meant to be in BUILTIN
599          * so to speed up the query we do not filter on domain_sid
600          */
601         ret = dsdb_domain_count(
602                 state->sam_ctx,
603                 &count,
604                 state->domain_dn,
605                 NULL,
606                 scope,
607                 "(&(objectClass=group)(|(groupType=%d)(groupType=%d)))",
608                 GTYPE_SECURITY_UNIVERSAL_GROUP,
609                 GTYPE_SECURITY_GLOBAL_GROUP);
610         if (ret != LDB_SUCCESS || count > UINT32_MAX) {
611                 goto error;
612         }
613         info->num_groups = count;
614
615         ret = dsdb_domain_count(
616                 state->sam_ctx,
617                 &count,
618                 state->domain_dn,
619                 state->domain_sid,
620                 scope,
621                 "(&(objectClass=group)(|(groupType=%d)(groupType=%d)))",
622                 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
623                 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
624         if (ret != LDB_SUCCESS || count > UINT32_MAX) {
625                 goto error;
626         }
627         info->num_aliases = count;
628
629         return NT_STATUS_OK;
630
631 error:
632         if (count > UINT32_MAX) {
633                 return NT_STATUS_INTEGER_OVERFLOW;
634         }
635         return dsdb_ldb_err_to_ntstatus(ret);
636
637 }
638
639 /*
640   return DomInfo3
641 */
642 static NTSTATUS dcesrv_samr_info_DomInfo3(struct samr_domain_state *state,
643                                           TALLOC_CTX *mem_ctx,
644                                           struct ldb_message **dom_msgs,
645                                           struct samr_DomInfo3 *info)
646 {
647         info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
648                                                       0x8000000000000000LL);
649
650         return NT_STATUS_OK;
651 }
652
653 /*
654   return DomInfo4
655 */
656 static NTSTATUS dcesrv_samr_info_DomOEMInformation(struct samr_domain_state *state,
657                                    TALLOC_CTX *mem_ctx,
658                                     struct ldb_message **dom_msgs,
659                                    struct samr_DomOEMInformation *info)
660 {
661         info->oem_information.string = ldb_msg_find_attr_as_string(dom_msgs[0],
662                                                                    "oEMInformation",
663                                                                    "");
664
665         return NT_STATUS_OK;
666 }
667
668 /*
669   return DomInfo5
670 */
671 static NTSTATUS dcesrv_samr_info_DomInfo5(struct samr_domain_state *state,
672                                           TALLOC_CTX *mem_ctx,
673                                           struct ldb_message **dom_msgs,
674                                           struct samr_DomInfo5 *info)
675 {
676         info->domain_name.string  = state->domain_name;
677
678         return NT_STATUS_OK;
679 }
680
681 /*
682   return DomInfo6
683 */
684 static NTSTATUS dcesrv_samr_info_DomInfo6(struct samr_domain_state *state,
685                                           TALLOC_CTX *mem_ctx,
686                                           struct ldb_message **dom_msgs,
687                                           struct samr_DomInfo6 *info)
688 {
689         /* MS-SAMR 2.2.4.1 - ReplicaSourceNodeName: "domainReplica" attribute */
690         info->primary.string = ldb_msg_find_attr_as_string(dom_msgs[0],
691                                                            "domainReplica",
692                                                            "");
693
694         return NT_STATUS_OK;
695 }
696
697 /*
698   return DomInfo7
699 */
700 static NTSTATUS dcesrv_samr_info_DomInfo7(struct samr_domain_state *state,
701                                           TALLOC_CTX *mem_ctx,
702                                           struct ldb_message **dom_msgs,
703                                           struct samr_DomInfo7 *info)
704 {
705
706         switch (state->role) {
707         case ROLE_ACTIVE_DIRECTORY_DC:
708                 /* This pulls the NetBIOS name from the
709                    cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
710                    string */
711                 if (samdb_is_pdc(state->sam_ctx)) {
712                         info->role = SAMR_ROLE_DOMAIN_PDC;
713                 } else {
714                         info->role = SAMR_ROLE_DOMAIN_BDC;
715                 }
716                 break;
717         case ROLE_DOMAIN_PDC:
718         case ROLE_DOMAIN_BDC:
719         case ROLE_IPA_DC:
720         case ROLE_AUTO:
721                 return NT_STATUS_INTERNAL_ERROR;
722         case ROLE_DOMAIN_MEMBER:
723                 info->role = SAMR_ROLE_DOMAIN_MEMBER;
724                 break;
725         case ROLE_STANDALONE:
726                 info->role = SAMR_ROLE_STANDALONE;
727                 break;
728         }
729
730         return NT_STATUS_OK;
731 }
732
733 /*
734   return DomInfo8
735 */
736 static NTSTATUS dcesrv_samr_info_DomInfo8(struct samr_domain_state *state,
737                                           TALLOC_CTX *mem_ctx,
738                                           struct ldb_message **dom_msgs,
739                                           struct samr_DomInfo8 *info)
740 {
741         info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
742                                                time(NULL));
743
744         info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
745                                                      0x0LL);
746
747         return NT_STATUS_OK;
748 }
749
750 /*
751   return DomInfo9
752 */
753 static NTSTATUS dcesrv_samr_info_DomInfo9(struct samr_domain_state *state,
754                                           TALLOC_CTX *mem_ctx,
755                                           struct ldb_message **dom_msgs,
756                                           struct samr_DomInfo9 *info)
757 {
758         info->domain_server_state = DOMAIN_SERVER_ENABLED;
759
760         return NT_STATUS_OK;
761 }
762
763 /*
764   return DomInfo11
765 */
766 static NTSTATUS dcesrv_samr_info_DomGeneralInformation2(struct samr_domain_state *state,
767                                                         TALLOC_CTX *mem_ctx,
768                                                         struct ldb_message **dom_msgs,
769                                                         struct samr_DomGeneralInformation2 *info)
770 {
771         NTSTATUS status;
772         status = dcesrv_samr_info_DomGeneralInformation(state, mem_ctx, dom_msgs, &info->general);
773         if (!NT_STATUS_IS_OK(status)) {
774                 return status;
775         }
776
777         info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
778                                                     -18000000000LL);
779         info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
780                                                     -18000000000LL);
781         info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
782
783         return NT_STATUS_OK;
784 }
785
786 /*
787   return DomInfo12
788 */
789 static NTSTATUS dcesrv_samr_info_DomInfo12(struct samr_domain_state *state,
790                                            TALLOC_CTX *mem_ctx,
791                                            struct ldb_message **dom_msgs,
792                                            struct samr_DomInfo12 *info)
793 {
794         info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
795                                                     -18000000000LL);
796         info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
797                                                     -18000000000LL);
798         info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
799
800         return NT_STATUS_OK;
801 }
802
803 /*
804   return DomInfo13
805 */
806 static NTSTATUS dcesrv_samr_info_DomInfo13(struct samr_domain_state *state,
807                                            TALLOC_CTX *mem_ctx,
808                                            struct ldb_message **dom_msgs,
809                                            struct samr_DomInfo13 *info)
810 {
811         info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
812                                                time(NULL));
813
814         info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
815                                                      0x0LL);
816
817         info->modified_count_at_last_promotion = 0;
818
819         return NT_STATUS_OK;
820 }
821
822 /*
823   samr_QueryDomainInfo
824 */
825 static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call,
826                                             TALLOC_CTX *mem_ctx,
827                                             struct samr_QueryDomainInfo *r)
828 {
829         struct dcesrv_handle *h;
830         struct samr_domain_state *d_state;
831         union samr_DomainInfo *info;
832
833         struct ldb_message **dom_msgs;
834         const char * const *attrs = NULL;
835
836         *r->out.info = NULL;
837
838         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
839
840         d_state = h->data;
841
842         switch (r->in.level) {
843         case 1:
844         {
845                 static const char * const attrs2[] = { "minPwdLength",
846                                                        "pwdHistoryLength",
847                                                        "pwdProperties",
848                                                        "maxPwdAge",
849                                                        "minPwdAge",
850                                                        NULL };
851                 attrs = attrs2;
852                 break;
853         }
854         case 2:
855         {
856                 static const char * const attrs2[] = {"forceLogoff",
857                                                       "oEMInformation",
858                                                       "modifiedCount",
859                                                       "domainReplica",
860                                                       NULL};
861                 attrs = attrs2;
862                 break;
863         }
864         case 3:
865         {
866                 static const char * const attrs2[] = {"forceLogoff",
867                                                       NULL};
868                 attrs = attrs2;
869                 break;
870         }
871         case 4:
872         {
873                 static const char * const attrs2[] = {"oEMInformation",
874                                                       NULL};
875                 attrs = attrs2;
876                 break;
877         }
878         case 5:
879         {
880                 attrs = NULL;
881                 break;
882         }
883         case 6:
884         {
885                 static const char * const attrs2[] = { "domainReplica",
886                                                        NULL };
887                 attrs = attrs2;
888                 break;
889         }
890         case 7:
891         {
892                 attrs = NULL;
893                 break;
894         }
895         case 8:
896         {
897                 static const char * const attrs2[] = { "modifiedCount",
898                                                        "creationTime",
899                                                        NULL };
900                 attrs = attrs2;
901                 break;
902         }
903         case 9:
904         {
905                 attrs = NULL;
906                 break;
907         }
908         case 11:
909         {
910                 static const char * const attrs2[] = { "oEMInformation",
911                                                        "forceLogoff",
912                                                        "modifiedCount",
913                                                        "lockoutDuration",
914                                                        "lockOutObservationWindow",
915                                                        "lockoutThreshold",
916                                                        NULL};
917                 attrs = attrs2;
918                 break;
919         }
920         case 12:
921         {
922                 static const char * const attrs2[] = { "lockoutDuration",
923                                                        "lockOutObservationWindow",
924                                                        "lockoutThreshold",
925                                                        NULL};
926                 attrs = attrs2;
927                 break;
928         }
929         case 13:
930         {
931                 static const char * const attrs2[] = { "modifiedCount",
932                                                        "creationTime",
933                                                        NULL };
934                 attrs = attrs2;
935                 break;
936         }
937         default:
938         {
939                 return NT_STATUS_INVALID_INFO_CLASS;
940         }
941         }
942
943         /* some levels don't need a search */
944         if (attrs) {
945                 int ret;
946                 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
947                                       d_state->domain_dn, &dom_msgs, attrs);
948                 if (ret == 0) {
949                         return NT_STATUS_NO_SUCH_DOMAIN;
950                 }
951                 if (ret != 1) {
952                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
953                 }
954         }
955
956         /* allocate the info structure */
957         info = talloc_zero(mem_ctx, union samr_DomainInfo);
958         if (info == NULL) {
959                 return NT_STATUS_NO_MEMORY;
960         }
961
962         *r->out.info = info;
963
964         switch (r->in.level) {
965         case 1:
966                 return dcesrv_samr_info_DomInfo1(d_state, mem_ctx, dom_msgs,
967                                                  &info->info1);
968         case 2:
969                 return dcesrv_samr_info_DomGeneralInformation(d_state, mem_ctx, dom_msgs,
970                                                               &info->general);
971         case 3:
972                 return dcesrv_samr_info_DomInfo3(d_state, mem_ctx, dom_msgs,
973                                                  &info->info3);
974         case 4:
975                 return dcesrv_samr_info_DomOEMInformation(d_state, mem_ctx, dom_msgs,
976                                                           &info->oem);
977         case 5:
978                 return dcesrv_samr_info_DomInfo5(d_state, mem_ctx, dom_msgs,
979                                                  &info->info5);
980         case 6:
981                 return dcesrv_samr_info_DomInfo6(d_state, mem_ctx, dom_msgs,
982                                                  &info->info6);
983         case 7:
984                 return dcesrv_samr_info_DomInfo7(d_state, mem_ctx, dom_msgs,
985                                                  &info->info7);
986         case 8:
987                 return dcesrv_samr_info_DomInfo8(d_state, mem_ctx, dom_msgs,
988                                                  &info->info8);
989         case 9:
990                 return dcesrv_samr_info_DomInfo9(d_state, mem_ctx, dom_msgs,
991                                                  &info->info9);
992         case 11:
993                 return dcesrv_samr_info_DomGeneralInformation2(d_state, mem_ctx, dom_msgs,
994                                                                &info->general2);
995         case 12:
996                 return dcesrv_samr_info_DomInfo12(d_state, mem_ctx, dom_msgs,
997                                                   &info->info12);
998         case 13:
999                 return dcesrv_samr_info_DomInfo13(d_state, mem_ctx, dom_msgs,
1000                                                   &info->info13);
1001         default:
1002                 return NT_STATUS_INVALID_INFO_CLASS;
1003         }
1004 }
1005
1006
1007 /*
1008   samr_SetDomainInfo
1009 */
1010 static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1011                        struct samr_SetDomainInfo *r)
1012 {
1013         struct dcesrv_handle *h;
1014         struct samr_domain_state *d_state;
1015         struct ldb_message *msg;
1016         int ret;
1017         struct ldb_context *sam_ctx;
1018
1019         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1020
1021         d_state = h->data;
1022         sam_ctx = d_state->sam_ctx;
1023
1024         msg = ldb_msg_new(mem_ctx);
1025         if (msg == NULL) {
1026                 return NT_STATUS_NO_MEMORY;
1027         }
1028
1029         msg->dn = talloc_reference(mem_ctx, d_state->domain_dn);
1030         if (!msg->dn) {
1031                 return NT_STATUS_NO_MEMORY;
1032         }
1033
1034         switch (r->in.level) {
1035         case 1:
1036                 SET_UINT  (msg, info1.min_password_length,     "minPwdLength");
1037                 SET_UINT  (msg, info1.password_history_length, "pwdHistoryLength");
1038                 SET_UINT  (msg, info1.password_properties,     "pwdProperties");
1039                 SET_INT64  (msg, info1.max_password_age,       "maxPwdAge");
1040                 SET_INT64  (msg, info1.min_password_age,       "minPwdAge");
1041                 break;
1042         case 3:
1043                 SET_UINT64  (msg, info3.force_logoff_time,     "forceLogoff");
1044                 break;
1045         case 4:
1046                 SET_STRING(msg, oem.oem_information,           "oEMInformation");
1047                 break;
1048
1049         case 6:
1050         case 7:
1051         case 9:
1052                 /* No op, we don't know where to set these */
1053                 return NT_STATUS_OK;
1054
1055         case 12:
1056                 /*
1057                  * It is not possible to set lockout_duration < lockout_window.
1058                  * (The test is the other way around since the negative numbers
1059                  *  are stored...)
1060                  *
1061                  * TODO:
1062                  *   This check should be moved to the backend, i.e. to some
1063                  *   ldb module under dsdb/samdb/ldb_modules/ .
1064                  *
1065                  * This constraint is documented here for the samr rpc service:
1066                  * MS-SAMR 3.1.1.6 Attribute Constraints for Originating Updates
1067                  * http://msdn.microsoft.com/en-us/library/cc245667%28PROT.10%29.aspx
1068                  *
1069                  * And here for the ldap backend:
1070                  * MS-ADTS 3.1.1.5.3.2 Constraints
1071                  * http://msdn.microsoft.com/en-us/library/cc223462(PROT.10).aspx
1072                  */
1073                 if (r->in.info->info12.lockout_duration >
1074                     r->in.info->info12.lockout_window)
1075                 {
1076                         return NT_STATUS_INVALID_PARAMETER;
1077                 }
1078                 SET_INT64  (msg, info12.lockout_duration,      "lockoutDuration");
1079                 SET_INT64  (msg, info12.lockout_window,        "lockOutObservationWindow");
1080                 SET_INT64  (msg, info12.lockout_threshold,     "lockoutThreshold");
1081                 break;
1082
1083         default:
1084                 /* many info classes are not valid for SetDomainInfo */
1085                 return NT_STATUS_INVALID_INFO_CLASS;
1086         }
1087
1088         /* modify the samdb record */
1089         ret = ldb_modify(sam_ctx, msg);
1090         if (ret != LDB_SUCCESS) {
1091                 DEBUG(1,("Failed to modify record %s: %s\n",
1092                          ldb_dn_get_linearized(d_state->domain_dn),
1093                          ldb_errstring(sam_ctx)));
1094                 return dsdb_ldb_err_to_ntstatus(ret);
1095         }
1096
1097         return NT_STATUS_OK;
1098 }
1099
1100 /*
1101   samr_CreateDomainGroup
1102 */
1103 static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1104                                        struct samr_CreateDomainGroup *r)
1105 {
1106         NTSTATUS status;
1107         struct samr_domain_state *d_state;
1108         struct samr_account_state *a_state;
1109         struct dcesrv_handle *h;
1110         const char *groupname;
1111         struct dom_sid *group_sid;
1112         struct ldb_dn *group_dn;
1113         struct dcesrv_handle *g_handle;
1114
1115         ZERO_STRUCTP(r->out.group_handle);
1116         *r->out.rid = 0;
1117
1118         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1119
1120         d_state = h->data;
1121
1122         if (d_state->builtin) {
1123                 DEBUG(5, ("Cannot create a domain group in the BUILTIN domain\n"));
1124                 return NT_STATUS_ACCESS_DENIED;
1125         }
1126
1127         groupname = r->in.name->string;
1128
1129         if (groupname == NULL) {
1130                 return NT_STATUS_INVALID_PARAMETER;
1131         }
1132
1133         status = dsdb_add_domain_group(d_state->sam_ctx, mem_ctx, groupname, &group_sid, &group_dn);
1134         if (!NT_STATUS_IS_OK(status)) {
1135                 return status;
1136         }
1137
1138         a_state = talloc(mem_ctx, struct samr_account_state);
1139         if (!a_state) {
1140                 return NT_STATUS_NO_MEMORY;
1141         }
1142         a_state->sam_ctx = d_state->sam_ctx;
1143         a_state->access_mask = r->in.access_mask;
1144         a_state->domain_state = talloc_reference(a_state, d_state);
1145         a_state->account_dn = talloc_steal(a_state, group_dn);
1146
1147         a_state->account_name = talloc_steal(a_state, groupname);
1148
1149         /* create the policy handle */
1150         g_handle = dcesrv_handle_create(dce_call, SAMR_HANDLE_GROUP);
1151         if (!g_handle) {
1152                 return NT_STATUS_NO_MEMORY;
1153         }
1154
1155         g_handle->data = talloc_steal(g_handle, a_state);
1156
1157         *r->out.group_handle = g_handle->wire_handle;
1158         *r->out.rid = group_sid->sub_auths[group_sid->num_auths-1];
1159
1160         return NT_STATUS_OK;
1161 }
1162
1163
1164 /*
1165   comparison function for sorting SamEntry array
1166 */
1167 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
1168 {
1169         return NUMERIC_CMP(e1->idx, e2->idx);
1170 }
1171
1172 static int compare_msgRid(struct ldb_message **m1, struct ldb_message **m2) {
1173         struct dom_sid *sid1 = NULL;
1174         struct dom_sid *sid2 = NULL;
1175         uint32_t rid1;
1176         uint32_t rid2;
1177         int res = 0;
1178         NTSTATUS status;
1179         TALLOC_CTX *frame = talloc_stackframe();
1180
1181         sid1 = samdb_result_dom_sid(frame, *m1, "objectSid");
1182         sid2 = samdb_result_dom_sid(frame, *m2, "objectSid");
1183
1184         /*
1185          * If entries don't have a SID we want to sort them to the end of
1186          * the list.
1187          */
1188         if (sid1 == NULL && sid2 == NULL) {
1189                 res = 0;
1190                 goto exit;
1191         } else if (sid2 == NULL) {
1192                 res = 1;
1193                 goto exit;
1194         } else if (sid1 == NULL) {
1195                 res = -1;
1196                 goto exit;
1197         }
1198
1199         /*
1200          * Get and compare the rids. If we fail to extract a rid (because
1201          * there are no subauths) the msg goes to the end of the list, but
1202          * before the NULL SIDs.
1203          */
1204         status = dom_sid_split_rid(NULL, sid1, NULL, &rid1);
1205         if (!NT_STATUS_IS_OK(status)) {
1206                 res = 1;
1207                 goto exit;
1208         }
1209
1210         status = dom_sid_split_rid(NULL, sid2, NULL, &rid2);
1211         if (!NT_STATUS_IS_OK(status)) {
1212                 res = -1;
1213                 goto exit;
1214         }
1215
1216         if (rid1 == rid2) {
1217                 res = 0;
1218         }
1219         else if (rid1 > rid2) {
1220                 res = 1;
1221         }
1222         else {
1223                 res = -1;
1224         }
1225 exit:
1226         TALLOC_FREE(frame);
1227         return res;
1228 }
1229
1230 /*
1231   samr_EnumDomainGroups
1232 */
1233 static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1234                                       struct samr_EnumDomainGroups *r)
1235 {
1236         struct dcesrv_handle *h;
1237         struct samr_domain_state *d_state;
1238         struct ldb_message **res;
1239         uint32_t i;
1240         uint32_t count;
1241         uint32_t results;
1242         uint32_t max_entries;
1243         uint32_t remaining_entries;
1244         uint32_t resume_handle;
1245         struct samr_SamEntry *entries;
1246         const char * const attrs[] = { "objectSid", "sAMAccountName", NULL };
1247         const char * const cache_attrs[] = { "objectSid", "objectGUID", NULL };
1248         struct samr_SamArray *sam;
1249         struct samr_guid_cache *cache = NULL;
1250
1251         *r->out.resume_handle = 0;
1252         *r->out.sam = NULL;
1253         *r->out.num_entries = 0;
1254
1255         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1256
1257         d_state = h->data;
1258         cache = &d_state->guid_caches[SAMR_ENUM_DOMAIN_GROUPS_CACHE];
1259
1260         /*
1261          * If the resume_handle is zero, query the database and cache the
1262          * matching GUID's
1263          */
1264         if (*r->in.resume_handle == 0) {
1265                 NTSTATUS status;
1266                 int ldb_cnt;
1267                 clear_guid_cache(cache);
1268                 /*
1269                  * search for all domain groups in this domain.
1270                  */
1271                 ldb_cnt = samdb_search_domain(
1272                     d_state->sam_ctx,
1273                     mem_ctx,
1274                     d_state->domain_dn,
1275                     &res,
1276                     cache_attrs,
1277                     d_state->domain_sid,
1278                     "(&(|(groupType=%d)(groupType=%d))(objectClass=group))",
1279                     GTYPE_SECURITY_UNIVERSAL_GROUP,
1280                     GTYPE_SECURITY_GLOBAL_GROUP);
1281                 if (ldb_cnt < 0) {
1282                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1283                 }
1284                 /*
1285                  * Sort the results into RID order, while the spec states there
1286                  * is no order, Windows appears to sort the results by RID and
1287                  * so it is possible that there are clients that depend on
1288                  * this ordering
1289                  */
1290                 TYPESAFE_QSORT(res, ldb_cnt, compare_msgRid);
1291
1292                 /*
1293                  * cache the sorted GUID's
1294                  */
1295                 status = load_guid_cache(cache, d_state, ldb_cnt, res);
1296                 TALLOC_FREE(res);
1297                 if (!NT_STATUS_IS_OK(status)) {
1298                         return status;
1299                 }
1300                 cache->handle = 0;
1301         }
1302
1303
1304         /*
1305          * If the resume handle is out of range we return an empty response
1306          * and invalidate the cache.
1307          *
1308          * From the specification:
1309          * Servers SHOULD validate that EnumerationContext is an expected
1310          * value for the server's implementation. Windows does NOT validate
1311          * the input, though the result of malformed information merely results
1312          * in inconsistent output to the client.
1313          */
1314         if (*r->in.resume_handle >= cache->size) {
1315                 clear_guid_cache(cache);
1316                 sam = talloc(mem_ctx, struct samr_SamArray);
1317                 if (!sam) {
1318                         return NT_STATUS_NO_MEMORY;
1319                 }
1320                 sam->entries = NULL;
1321                 sam->count = 0;
1322
1323                 *r->out.sam = sam;
1324                 *r->out.resume_handle = 0;
1325                 return NT_STATUS_OK;
1326         }
1327
1328
1329         /*
1330          * Calculate the number of entries to return limit by max_size.
1331          * Note that we use the w2k3 element size value of 54
1332          */
1333         max_entries = 1 + (r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER);
1334         remaining_entries = cache->size - *r->in.resume_handle;
1335         results = MIN(remaining_entries, max_entries);
1336
1337         /*
1338          * Process the list of result GUID's.
1339          * Read the details of each object and populate the Entries
1340          * for the current level.
1341          */
1342         count = 0;
1343         resume_handle = *r->in.resume_handle;
1344         entries = talloc_array(mem_ctx, struct samr_SamEntry, results);
1345         if (entries == NULL) {
1346                 clear_guid_cache(cache);
1347                 return NT_STATUS_NO_MEMORY;
1348         }
1349         for (i = 0; i < results; i++) {
1350                 struct dom_sid *objectsid;
1351                 uint32_t rid;
1352                 struct ldb_result *rec;
1353                 const uint32_t idx = *r->in.resume_handle + i;
1354                 int ret;
1355                 NTSTATUS status;
1356                 const char *name = NULL;
1357                 resume_handle++;
1358                 /*
1359                  * Read an object from disk using the GUID as the key
1360                  *
1361                  * If the object can not be read, or it does not have a SID
1362                  * it is ignored.
1363                  *
1364                  * As a consequence of this, if all the remaining GUID's
1365                  * have been deleted an empty result will be returned.
1366                  * i.e. even if the previous call returned a non zero
1367                  * resume_handle it is possible for no results to be returned.
1368                  *
1369                  */
1370                 ret = dsdb_search_by_dn_guid(d_state->sam_ctx,
1371                                              mem_ctx,
1372                                              &rec,
1373                                              &cache->entries[idx],
1374                                              attrs,
1375                                              0);
1376                 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1377                         struct GUID_txt_buf guid_buf;
1378                         DBG_WARNING(
1379                             "GUID [%s] not found\n",
1380                             GUID_buf_string(&cache->entries[idx], &guid_buf));
1381                         continue;
1382                 } else if (ret != LDB_SUCCESS) {
1383                         clear_guid_cache(cache);
1384                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1385                 }
1386
1387                 objectsid = samdb_result_dom_sid(mem_ctx,
1388                                                  rec->msgs[0],
1389                                                  "objectSID");
1390                 if (objectsid == NULL) {
1391                         struct GUID_txt_buf guid_buf;
1392                         DBG_WARNING(
1393                             "objectSID for GUID [%s] not found\n",
1394                             GUID_buf_string(&cache->entries[idx], &guid_buf));
1395                         continue;
1396                 }
1397                 status = dom_sid_split_rid(NULL,
1398                                            objectsid,
1399                                            NULL,
1400                                            &rid);
1401                 if (!NT_STATUS_IS_OK(status)) {
1402                         struct dom_sid_buf sid_buf;
1403                         struct GUID_txt_buf guid_buf;
1404                         DBG_WARNING(
1405                             "objectSID [%s] for GUID [%s] invalid\n",
1406                             dom_sid_str_buf(objectsid, &sid_buf),
1407                             GUID_buf_string(&cache->entries[idx], &guid_buf));
1408                         continue;
1409                 }
1410
1411                 entries[count].idx = rid;
1412                 name = ldb_msg_find_attr_as_string(
1413                     rec->msgs[0], "sAMAccountName", "");
1414                 entries[count].name.string = talloc_strdup(entries, name);
1415                 count++;
1416         }
1417
1418         sam = talloc(mem_ctx, struct samr_SamArray);
1419         if (!sam) {
1420                 clear_guid_cache(cache);
1421                 return NT_STATUS_NO_MEMORY;
1422         }
1423
1424         sam->entries = entries;
1425         sam->count = count;
1426
1427         *r->out.sam = sam;
1428         *r->out.resume_handle = resume_handle;
1429         *r->out.num_entries = count;
1430
1431         /*
1432          * Signal no more results by returning zero resume handle,
1433          * the cache is also cleared at this point
1434          */
1435         if (*r->out.resume_handle >= cache->size) {
1436                 *r->out.resume_handle = 0;
1437                 clear_guid_cache(cache);
1438                 return NT_STATUS_OK;
1439         }
1440         /*
1441          * There are more results to be returned.
1442          */
1443         return STATUS_MORE_ENTRIES;
1444 }
1445
1446
1447 /*
1448   samr_CreateUser2
1449
1450   This call uses transactions to ensure we don't get a new conflicting
1451   user while we are processing this, and to ensure the user either
1452   completely exists, or does not.
1453 */
1454 static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1455                                  struct samr_CreateUser2 *r)
1456 {
1457         NTSTATUS status;
1458         struct samr_domain_state *d_state;
1459         struct samr_account_state *a_state;
1460         struct dcesrv_handle *h;
1461         struct ldb_dn *dn;
1462         struct dom_sid *sid;
1463         struct dcesrv_handle *u_handle;
1464         const char *account_name;
1465
1466         ZERO_STRUCTP(r->out.user_handle);
1467         *r->out.access_granted = 0;
1468         *r->out.rid = 0;
1469
1470         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1471
1472         d_state = h->data;
1473
1474         if (d_state->builtin) {
1475                 DEBUG(5, ("Cannot create a user in the BUILTIN domain\n"));
1476                 return NT_STATUS_ACCESS_DENIED;
1477         } else if (r->in.acct_flags == ACB_DOMTRUST) {
1478                 /* Domain trust accounts must be created by the LSA calls */
1479                 return NT_STATUS_ACCESS_DENIED;
1480         }
1481         account_name = r->in.account_name->string;
1482
1483         if (account_name == NULL) {
1484                 return NT_STATUS_INVALID_PARAMETER;
1485         }
1486
1487         status = dsdb_add_user(d_state->sam_ctx, mem_ctx, account_name, r->in.acct_flags, NULL,
1488                                &sid, &dn);
1489         if (!NT_STATUS_IS_OK(status)) {
1490                 return status;
1491         }
1492         a_state = talloc(mem_ctx, struct samr_account_state);
1493         if (!a_state) {
1494                 return NT_STATUS_NO_MEMORY;
1495         }
1496         a_state->sam_ctx = d_state->sam_ctx;
1497         a_state->access_mask = r->in.access_mask;
1498         a_state->domain_state = talloc_reference(a_state, d_state);
1499         a_state->account_dn = talloc_steal(a_state, dn);
1500
1501         a_state->account_name = talloc_steal(a_state, account_name);
1502         if (!a_state->account_name) {
1503                 return NT_STATUS_NO_MEMORY;
1504         }
1505
1506         /* create the policy handle */
1507         u_handle = dcesrv_handle_create(dce_call, SAMR_HANDLE_USER);
1508         if (!u_handle) {
1509                 return NT_STATUS_NO_MEMORY;
1510         }
1511
1512         u_handle->data = talloc_steal(u_handle, a_state);
1513
1514         *r->out.user_handle = u_handle->wire_handle;
1515         *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1516
1517         *r->out.rid = sid->sub_auths[sid->num_auths-1];
1518
1519         return NT_STATUS_OK;
1520 }
1521
1522
1523 /*
1524   samr_CreateUser
1525 */
1526 static NTSTATUS dcesrv_samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1527                                 struct samr_CreateUser *r)
1528 {
1529         struct samr_CreateUser2 r2;
1530         uint32_t access_granted = 0;
1531
1532
1533         /* a simple wrapper around samr_CreateUser2 works nicely */
1534
1535         r2 = (struct samr_CreateUser2) {
1536                 .in.domain_handle = r->in.domain_handle,
1537                 .in.account_name = r->in.account_name,
1538                 .in.acct_flags = ACB_NORMAL,
1539                 .in.access_mask = r->in.access_mask,
1540                 .out.user_handle = r->out.user_handle,
1541                 .out.access_granted = &access_granted,
1542                 .out.rid = r->out.rid
1543         };
1544
1545         return dcesrv_samr_CreateUser2(dce_call, mem_ctx, &r2);
1546 }
1547
1548 struct enum_dom_users_ctx {
1549         struct samr_SamEntry *entries;
1550         uint32_t num_entries;
1551         uint32_t acct_flags;
1552         struct dom_sid *domain_sid;
1553 };
1554
1555 static int user_iterate_callback(struct ldb_request *req,
1556                                  struct ldb_reply *ares);
1557
1558 /*
1559  * Iterate users and add all those that match a domain SID and pass an acct
1560  * flags check to an array of SamEntry objects.
1561  */
1562 static int user_iterate_callback(struct ldb_request *req,
1563                                  struct ldb_reply *ares)
1564 {
1565         struct enum_dom_users_ctx *ac =\
1566                 talloc_get_type(req->context, struct enum_dom_users_ctx);
1567         int ret = LDB_ERR_OPERATIONS_ERROR;
1568
1569         if (!ares) {
1570                 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
1571         }
1572         if (ares->error != LDB_SUCCESS) {
1573                 return ldb_request_done(req, ares->error);
1574         }
1575
1576         switch (ares->type) {
1577         case LDB_REPLY_ENTRY:
1578         {
1579                 struct ldb_message *msg = ares->message;
1580                 const struct ldb_val *val;
1581                 struct samr_SamEntry *ent;
1582                 struct dom_sid objectsid;
1583                 uint32_t rid;
1584                 size_t entries_array_len = 0;
1585                 NTSTATUS status;
1586                 ssize_t sid_size;
1587
1588                 if (ac->acct_flags && ((samdb_result_acct_flags(msg, NULL) &
1589                                         ac->acct_flags) == 0)) {
1590                         ret = LDB_SUCCESS;
1591                         break;
1592                 }
1593
1594                 val = ldb_msg_find_ldb_val(msg, "objectSID");
1595                 if (val == NULL) {
1596                         DBG_WARNING("objectSID for DN %s not found\n",
1597                                     ldb_dn_get_linearized(msg->dn));
1598                         ret = ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
1599                         break;
1600                 }
1601
1602                 sid_size = sid_parse(val->data, val->length, &objectsid);
1603                 if (sid_size == -1) {
1604                         struct dom_sid_buf sid_buf;
1605                         DBG_WARNING("objectsid [%s] for DN [%s] invalid\n",
1606                                     dom_sid_str_buf(&objectsid, &sid_buf),
1607                                     ldb_dn_get_linearized(msg->dn));
1608                         ret = ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
1609                         break;
1610                 }
1611
1612                 if (!dom_sid_in_domain(ac->domain_sid, &objectsid)) {
1613                         /* Ignore if user isn't in the domain */
1614                         ret = LDB_SUCCESS;
1615                         break;
1616                 }
1617
1618                 status = dom_sid_split_rid(ares, &objectsid, NULL, &rid);
1619                 if (!NT_STATUS_IS_OK(status)) {
1620                         struct dom_sid_buf sid_buf;
1621                         DBG_WARNING("Couldn't split RID from "
1622                                     "SID [%s] of DN [%s]\n",
1623                                     dom_sid_str_buf(&objectsid, &sid_buf),
1624                                     ldb_dn_get_linearized(msg->dn));
1625                         ret = ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
1626                         break;
1627                 }
1628
1629                 entries_array_len = talloc_array_length(ac->entries);
1630                 if (ac->num_entries >= entries_array_len) {
1631                         if (entries_array_len * 2 < entries_array_len) {
1632                                 ret = ldb_request_done(req,
1633                                         LDB_ERR_OPERATIONS_ERROR);
1634                                 break;
1635                         }
1636                         ac->entries = talloc_realloc(ac,
1637                                                      ac->entries,
1638                                                      struct samr_SamEntry,
1639                                                      entries_array_len * 2);
1640                         if (ac->entries == NULL) {
1641                                 ret = ldb_request_done(req,
1642                                         LDB_ERR_OPERATIONS_ERROR);
1643                                 break;
1644                         }
1645                 }
1646
1647                 ent = &(ac->entries[ac->num_entries++]);
1648                 val = ldb_msg_find_ldb_val(msg, "samaccountname");
1649                 if (val == NULL) {
1650                         DBG_WARNING("samaccountname attribute not found\n");
1651                         ret = ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
1652                         break;
1653                 }
1654                 ent->name.string = talloc_steal(ac->entries,
1655                                                 (char *)val->data);
1656                 ent->idx = rid;
1657                 ret = LDB_SUCCESS;
1658                 break;
1659         }
1660         case LDB_REPLY_DONE:
1661         {
1662                 if (ac->num_entries != 0 &&
1663                     ac->num_entries != talloc_array_length(ac->entries)) {
1664                         ac->entries = talloc_realloc(ac,
1665                                                      ac->entries,
1666                                                      struct samr_SamEntry,
1667                                                      ac->num_entries);
1668                         if (ac->entries == NULL) {
1669                                 ret = ldb_request_done(req,
1670                                         LDB_ERR_OPERATIONS_ERROR);
1671                                 break;
1672                         }
1673                 }
1674                 ret = ldb_request_done(req, LDB_SUCCESS);
1675                 break;
1676         }
1677         case LDB_REPLY_REFERRAL:
1678         {
1679                 ret = LDB_SUCCESS;
1680                 break;
1681         }
1682         default:
1683                 /* Doesn't happen */
1684                 ret = LDB_ERR_OPERATIONS_ERROR;
1685         }
1686         TALLOC_FREE(ares);
1687
1688         return ret;
1689 }
1690
1691 /*
1692  * samr_EnumDomainUsers
1693  * The previous implementation did an initial search and stored a list of
1694  * matching GUIDs on the connection handle's domain state, then did direct
1695  * GUID lookups for each record in a page indexed by resume_handle. That
1696  * approach was memory efficient, requiring only 16 bytes per record, but
1697  * was too slow for winbind which needs this RPC call for getpwent.
1698  *
1699  * Now we use an iterate pattern to populate a cached list of the rids and
1700  * names for each record. This improves runtime performance but requires
1701  * about 200 bytes per record which will mean for a 100k database we use
1702  * about 2MB, which is fine. The speedup achieved by this new approach is
1703  * around 50%.
1704  */
1705 static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call,
1706                                             TALLOC_CTX *mem_ctx,
1707                                             struct samr_EnumDomainUsers *r)
1708 {
1709         struct dcesrv_handle *h;
1710         struct samr_domain_state *d_state;
1711         uint32_t results;
1712         uint32_t max_entries;
1713         uint32_t num_entries;
1714         uint32_t remaining_entries;
1715         struct samr_SamEntry *entries;
1716         const char * const attrs[] = { "objectSid", "sAMAccountName",
1717                 "userAccountControl", NULL };
1718         struct samr_SamArray *sam;
1719         struct ldb_request *req;
1720
1721         *r->out.resume_handle = 0;
1722         *r->out.sam = NULL;
1723         *r->out.num_entries = 0;
1724
1725         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1726
1727         d_state = h->data;
1728         entries = d_state->domain_users_cached;
1729
1730         /*
1731          * If the resume_handle is zero, query the database and cache the
1732          * matching entries.
1733          */
1734         if (*r->in.resume_handle == 0) {
1735                 int ret;
1736                 struct enum_dom_users_ctx *ac;
1737                 if (entries != NULL) {
1738                         talloc_free(entries);
1739                         d_state->domain_users_cached = NULL;
1740                 }
1741
1742                 ac = talloc(mem_ctx, struct enum_dom_users_ctx);
1743                 ac->num_entries = 0;
1744                 ac->domain_sid = d_state->domain_sid;
1745                 ac->entries = talloc_array(ac,
1746                                            struct samr_SamEntry,
1747                                            100);
1748                 if (ac->entries == NULL) {
1749                         talloc_free(ac);
1750                         return NT_STATUS_NO_MEMORY;
1751                 }
1752                 ac->acct_flags = r->in.acct_flags;
1753
1754                 ret = ldb_build_search_req(&req,
1755                                            d_state->sam_ctx,
1756                                            mem_ctx,
1757                                            d_state->domain_dn,
1758                                            LDB_SCOPE_SUBTREE,
1759                                            "(objectClass=user)",
1760                                            attrs,
1761                                            NULL,
1762                                            ac,
1763                                            user_iterate_callback,
1764                                            NULL);
1765                 if (ret != LDB_SUCCESS) {
1766                         talloc_free(ac);
1767                         return dsdb_ldb_err_to_ntstatus(ret);
1768                 }
1769
1770                 ret = ldb_request(d_state->sam_ctx, req);
1771                 if (ret != LDB_SUCCESS) {
1772                         talloc_free(ac);
1773                         return dsdb_ldb_err_to_ntstatus(ret);
1774                 }
1775
1776                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1777                 if (ret != LDB_SUCCESS) {
1778                         return dsdb_ldb_err_to_ntstatus(ret);
1779                 }
1780
1781                 if (ac->num_entries == 0) {
1782                         DBG_WARNING("No users in domain %s\n",
1783                                     ldb_dn_get_linearized(d_state->domain_dn));
1784                         talloc_free(ac);
1785
1786                         /*
1787                          * test_EnumDomainUsers_all() expects that r.out.sam
1788                          * should be non-NULL, even if we have no entries.
1789                          */
1790                         sam = talloc_zero(mem_ctx, struct samr_SamArray);
1791                         if (sam == NULL) {
1792                                 return NT_STATUS_NO_MEMORY;
1793                         }
1794                         *r->out.sam = sam;
1795
1796                         return NT_STATUS_OK;
1797                 }
1798
1799                 entries = talloc_steal(d_state, ac->entries);
1800                 d_state->domain_users_cached = entries;
1801                 num_entries = ac->num_entries;
1802                 talloc_free(ac);
1803
1804                 /*
1805                  * Sort the entries into RID order, while the spec states there
1806                  * is no order, Windows appears to sort the results by RID and
1807                  * so it is possible that there are clients that depend on
1808                  * this ordering
1809                  */
1810                 TYPESAFE_QSORT(entries, num_entries, compare_SamEntry);
1811         } else {
1812                 num_entries = talloc_array_length(entries);
1813         }
1814
1815         /*
1816          * If the resume handle is out of range we return an empty response
1817          * and invalidate the cache.
1818          *
1819          * From the specification:
1820          * Servers SHOULD validate that EnumerationContext is an expected
1821          * value for the server's implementation. Windows does NOT validate
1822          * the input, though the result of malformed information merely results
1823          * in inconsistent output to the client.
1824          */
1825         if (*r->in.resume_handle >= num_entries) {
1826                 talloc_free(entries);
1827                 d_state->domain_users_cached = NULL;
1828                 sam = talloc(mem_ctx, struct samr_SamArray);
1829                 if (!sam) {
1830                         return NT_STATUS_NO_MEMORY;
1831                 }
1832                 sam->entries = NULL;
1833                 sam->count = 0;
1834
1835                 *r->out.sam = sam;
1836                 *r->out.resume_handle = 0;
1837                 return NT_STATUS_OK;
1838         }
1839
1840         /*
1841          * Calculate the number of entries to return limit by max_size.
1842          * Note that we use the w2k3 element size value of 54
1843          */
1844         max_entries = 1 + (r->in.max_size / SAMR_ENUM_USERS_MULTIPLIER);
1845         remaining_entries = num_entries - *r->in.resume_handle;
1846         results = MIN(remaining_entries, max_entries);
1847
1848         sam = talloc(mem_ctx, struct samr_SamArray);
1849         if (!sam) {
1850                 d_state->domain_users_cached = NULL;
1851                 return NT_STATUS_NO_MEMORY;
1852         }
1853
1854         sam->entries = entries + *r->in.resume_handle;
1855         sam->count = results;
1856
1857         *r->out.sam = sam;
1858         *r->out.resume_handle = *r->in.resume_handle + results;
1859         *r->out.num_entries = results;
1860
1861         /*
1862          * Signal no more results by returning zero resume handle,
1863          * the cache is also cleared at this point
1864          */
1865         if (*r->out.resume_handle >= num_entries) {
1866                 *r->out.resume_handle = 0;
1867                 return NT_STATUS_OK;
1868         }
1869         /*
1870          * There are more results to be returned.
1871          */
1872         return STATUS_MORE_ENTRIES;
1873 }
1874
1875
1876 /*
1877   samr_CreateDomAlias
1878 */
1879 static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1880                        struct samr_CreateDomAlias *r)
1881 {
1882         struct samr_domain_state *d_state;
1883         struct samr_account_state *a_state;
1884         struct dcesrv_handle *h;
1885         const char *alias_name;
1886         struct dom_sid *sid;
1887         struct dcesrv_handle *a_handle;
1888         struct ldb_dn *dn;
1889         NTSTATUS status;
1890
1891         ZERO_STRUCTP(r->out.alias_handle);
1892         *r->out.rid = 0;
1893
1894         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1895
1896         d_state = h->data;
1897
1898         if (d_state->builtin) {
1899                 DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain\n"));
1900                 return NT_STATUS_ACCESS_DENIED;
1901         }
1902
1903         alias_name = r->in.alias_name->string;
1904
1905         if (alias_name == NULL) {
1906                 return NT_STATUS_INVALID_PARAMETER;
1907         }
1908
1909         status = dsdb_add_domain_alias(d_state->sam_ctx, mem_ctx, alias_name, &sid, &dn);
1910         if (!NT_STATUS_IS_OK(status)) {
1911                 return status;
1912         }
1913
1914         a_state = talloc(mem_ctx, struct samr_account_state);
1915         if (!a_state) {
1916                 return NT_STATUS_NO_MEMORY;
1917         }
1918
1919         a_state->sam_ctx = d_state->sam_ctx;
1920         a_state->access_mask = r->in.access_mask;
1921         a_state->domain_state = talloc_reference(a_state, d_state);
1922         a_state->account_dn = talloc_steal(a_state, dn);
1923
1924         a_state->account_name = talloc_steal(a_state, alias_name);
1925
1926         /* create the policy handle */
1927         a_handle = dcesrv_handle_create(dce_call, SAMR_HANDLE_ALIAS);
1928         if (a_handle == NULL)
1929                 return NT_STATUS_NO_MEMORY;
1930
1931         a_handle->data = talloc_steal(a_handle, a_state);
1932
1933         *r->out.alias_handle = a_handle->wire_handle;
1934
1935         *r->out.rid = sid->sub_auths[sid->num_auths-1];
1936
1937         return NT_STATUS_OK;
1938 }
1939
1940
1941 /*
1942   samr_EnumDomainAliases
1943 */
1944 static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1945                        struct samr_EnumDomainAliases *r)
1946 {
1947         struct dcesrv_handle *h;
1948         struct samr_domain_state *d_state;
1949         struct ldb_message **res;
1950         int i, ldb_cnt;
1951         uint32_t first, count;
1952         struct samr_SamEntry *entries;
1953         const char * const attrs[] = { "objectSid", "sAMAccountName", NULL };
1954         struct samr_SamArray *sam;
1955
1956         *r->out.resume_handle = 0;
1957         *r->out.sam = NULL;
1958         *r->out.num_entries = 0;
1959
1960         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1961
1962         d_state = h->data;
1963
1964         /* search for all domain aliases in this domain. This could possibly be
1965            cached and resumed based on resume_key */
1966         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx, NULL,
1967                                       &res, attrs,
1968                                       d_state->domain_sid,
1969                                       "(&(|(grouptype=%d)(grouptype=%d)))"
1970                                       "(objectclass=group))",
1971                                       GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1972                                       GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1973         if (ldb_cnt < 0) {
1974                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1975         }
1976
1977         /* convert to SamEntry format */
1978         entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1979         if (!entries) {
1980                 return NT_STATUS_NO_MEMORY;
1981         }
1982
1983         count = 0;
1984
1985         for (i=0;i<ldb_cnt;i++) {
1986                 struct dom_sid *alias_sid;
1987
1988                 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1989                                                  "objectSid");
1990
1991                 if (alias_sid == NULL) {
1992                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1993                 }
1994
1995                 entries[count].idx =
1996                         alias_sid->sub_auths[alias_sid->num_auths-1];
1997                 entries[count].name.string =
1998                         ldb_msg_find_attr_as_string(res[i], "sAMAccountName", "");
1999                 count += 1;
2000         }
2001
2002         /* sort the results by rid */
2003         TYPESAFE_QSORT(entries, count, compare_SamEntry);
2004
2005         /* find the first entry to return */
2006         for (first=0;
2007              first<count && entries[first].idx <= *r->in.resume_handle;
2008              first++) ;
2009
2010         /* return the rest, limit by max_size. Note that we
2011            use the w2k3 element size value of 54 */
2012         *r->out.num_entries = count - first;
2013         *r->out.num_entries = MIN(*r->out.num_entries,
2014                                   1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
2015
2016         sam = talloc(mem_ctx, struct samr_SamArray);
2017         if (!sam) {
2018                 return NT_STATUS_NO_MEMORY;
2019         }
2020
2021         sam->entries = entries+first;
2022         sam->count = *r->out.num_entries;
2023
2024         *r->out.sam = sam;
2025
2026         if (first == count) {
2027                 return NT_STATUS_OK;
2028         }
2029
2030         if (*r->out.num_entries < count - first) {
2031                 *r->out.resume_handle =
2032                         entries[first+*r->out.num_entries-1].idx;
2033                 return STATUS_MORE_ENTRIES;
2034         }
2035
2036         return NT_STATUS_OK;
2037 }
2038
2039
2040 /*
2041   samr_GetAliasMembership
2042 */
2043 static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2044                        struct samr_GetAliasMembership *r)
2045 {
2046         struct dcesrv_handle *h;
2047         struct samr_domain_state *d_state;
2048         char *filter;
2049         const char * const attrs[] = { "objectSid", NULL };
2050         struct ldb_message **res;
2051         uint32_t i;
2052         int count = 0;
2053
2054         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2055
2056         d_state = h->data;
2057
2058         filter = talloc_asprintf(mem_ctx,
2059                                  "(&(|(grouptype=%d)(grouptype=%d))"
2060                                  "(objectclass=group)(|",
2061                                  GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2062                                  GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2063         if (filter == NULL) {
2064                 return NT_STATUS_NO_MEMORY;
2065         }
2066
2067         for (i=0; i<r->in.sids->num_sids; i++) {
2068                 struct dom_sid_buf buf;
2069
2070                 filter = talloc_asprintf_append(
2071                         filter,
2072                         "(member=<SID=%s>)",
2073                         dom_sid_str_buf(r->in.sids->sids[i].sid, &buf));
2074
2075                 if (filter == NULL) {
2076                         return NT_STATUS_NO_MEMORY;
2077                 }
2078         }
2079
2080         /* Find out if we had at least one valid member SID passed - otherwise
2081          * just skip the search. */
2082         if (strstr(filter, "member") != NULL) {
2083                 count = samdb_search_domain(d_state->sam_ctx, mem_ctx, NULL,
2084                                             &res, attrs, d_state->domain_sid,
2085                                             "%s))", filter);
2086                 if (count < 0) {
2087                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
2088                 }
2089         }
2090
2091         r->out.rids->count = 0;
2092         r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
2093         if (r->out.rids->ids == NULL)
2094                 return NT_STATUS_NO_MEMORY;
2095
2096         for (i=0; i<count; i++) {
2097                 struct dom_sid *alias_sid;
2098
2099                 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
2100                 if (alias_sid == NULL) {
2101                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
2102                 }
2103
2104                 r->out.rids->ids[r->out.rids->count] =
2105                         alias_sid->sub_auths[alias_sid->num_auths-1];
2106                 r->out.rids->count += 1;
2107         }
2108
2109         return NT_STATUS_OK;
2110 }
2111
2112
2113 /*
2114   samr_LookupNames
2115 */
2116 static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2117                                  struct samr_LookupNames *r)
2118 {
2119         struct dcesrv_handle *h;
2120         struct samr_domain_state *d_state;
2121         uint32_t i, num_mapped;
2122         NTSTATUS status = NT_STATUS_OK;
2123         const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
2124         int count;
2125
2126         ZERO_STRUCTP(r->out.rids);
2127         ZERO_STRUCTP(r->out.types);
2128
2129         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2130
2131         d_state = h->data;
2132
2133         if (r->in.num_names == 0) {
2134                 return NT_STATUS_OK;
2135         }
2136
2137         r->out.rids->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
2138         r->out.types->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
2139         if (!r->out.rids->ids || !r->out.types->ids) {
2140                 return NT_STATUS_NO_MEMORY;
2141         }
2142         r->out.rids->count = r->in.num_names;
2143         r->out.types->count = r->in.num_names;
2144
2145         num_mapped = 0;
2146
2147         for (i=0;i<r->in.num_names;i++) {
2148                 struct ldb_message **res;
2149                 struct dom_sid *sid;
2150                 uint32_t atype, rtype;
2151
2152                 r->out.rids->ids[i] = 0;
2153                 r->out.types->ids[i] = SID_NAME_UNKNOWN;
2154
2155                 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
2156                                      "sAMAccountName=%s",
2157                                      ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
2158                 if (count != 1) {
2159                         status = STATUS_SOME_UNMAPPED;
2160                         continue;
2161                 }
2162
2163                 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
2164                 if (sid == NULL) {
2165                         status = STATUS_SOME_UNMAPPED;
2166                         continue;
2167                 }
2168
2169                 atype = ldb_msg_find_attr_as_uint(res[0], "sAMAccountType", 0);
2170                 if (atype == 0) {
2171                         status = STATUS_SOME_UNMAPPED;
2172                         continue;
2173                 }
2174
2175                 rtype = ds_atype_map(atype);
2176
2177                 if (rtype == SID_NAME_UNKNOWN) {
2178                         status = STATUS_SOME_UNMAPPED;
2179                         continue;
2180                 }
2181
2182                 r->out.rids->ids[i] = sid->sub_auths[sid->num_auths-1];
2183                 r->out.types->ids[i] = rtype;
2184                 num_mapped++;
2185         }
2186
2187         if (num_mapped == 0) {
2188                 return NT_STATUS_NONE_MAPPED;
2189         }
2190         return status;
2191 }
2192
2193
2194 /*
2195   samr_LookupRids
2196 */
2197 static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2198                        struct samr_LookupRids *r)
2199 {
2200         NTSTATUS status;
2201         struct dcesrv_handle *h;
2202         struct samr_domain_state *d_state;
2203         const char **names;
2204         struct lsa_String *lsa_names;
2205         enum lsa_SidType *ids;
2206
2207         ZERO_STRUCTP(r->out.names);
2208         ZERO_STRUCTP(r->out.types);
2209
2210         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2211
2212         d_state = h->data;
2213
2214         if (r->in.num_rids == 0)
2215                 return NT_STATUS_OK;
2216
2217         lsa_names = talloc_zero_array(mem_ctx, struct lsa_String, r->in.num_rids);
2218         names = talloc_zero_array(mem_ctx, const char *, r->in.num_rids);
2219         ids = talloc_zero_array(mem_ctx, enum lsa_SidType, r->in.num_rids);
2220
2221         if ((lsa_names == NULL) || (names == NULL) || (ids == NULL))
2222                 return NT_STATUS_NO_MEMORY;
2223
2224         r->out.names->names = lsa_names;
2225         r->out.names->count = r->in.num_rids;
2226
2227         r->out.types->ids = (uint32_t *) ids;
2228         r->out.types->count = r->in.num_rids;
2229
2230         status = dsdb_lookup_rids(d_state->sam_ctx, mem_ctx, d_state->domain_sid,
2231                                   r->in.num_rids, r->in.rids, names, ids);
2232         if (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED) || NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
2233                 uint32_t i;
2234                 for (i = 0; i < r->in.num_rids; i++) {
2235                         lsa_names[i].string = names[i];
2236                 }
2237         }
2238         return status;
2239 }
2240
2241
2242 /*
2243   samr_OpenGroup
2244 */
2245 static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2246                        struct samr_OpenGroup *r)
2247 {
2248         struct samr_domain_state *d_state;
2249         struct samr_account_state *a_state;
2250         struct dcesrv_handle *h;
2251         const char *groupname;
2252         struct dom_sid *sid;
2253         struct ldb_message **msgs;
2254         struct dcesrv_handle *g_handle;
2255         const char * const attrs[2] = { "sAMAccountName", NULL };
2256         int ret;
2257
2258         ZERO_STRUCTP(r->out.group_handle);
2259
2260         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2261
2262         d_state = h->data;
2263
2264         /* form the group SID */
2265         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2266         if (!sid) {
2267                 return NT_STATUS_NO_MEMORY;
2268         }
2269
2270         /* search for the group record */
2271         if (d_state->builtin) {
2272                 ret = gendb_search(d_state->sam_ctx,
2273                                    mem_ctx, d_state->domain_dn, &msgs, attrs,
2274                                    "(&(objectSid=%s)(objectClass=group)"
2275                                    "(groupType=%d))",
2276                                    ldap_encode_ndr_dom_sid(mem_ctx, sid),
2277                                    GTYPE_SECURITY_BUILTIN_LOCAL_GROUP);
2278         } else {
2279                 ret = gendb_search(d_state->sam_ctx,
2280                                    mem_ctx, d_state->domain_dn, &msgs, attrs,
2281                                    "(&(objectSid=%s)(objectClass=group)"
2282                                    "(|(groupType=%d)(groupType=%d)))",
2283                                    ldap_encode_ndr_dom_sid(mem_ctx, sid),
2284                                    GTYPE_SECURITY_UNIVERSAL_GROUP,
2285                                    GTYPE_SECURITY_GLOBAL_GROUP);
2286         }
2287         if (ret == 0) {
2288                 return NT_STATUS_NO_SUCH_GROUP;
2289         }
2290         if (ret != 1) {
2291                 DEBUG(0,("Found %d records matching sid %s\n",
2292                          ret, dom_sid_string(mem_ctx, sid)));
2293                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2294         }
2295
2296         groupname = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2297         if (groupname == NULL) {
2298                 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2299                          dom_sid_string(mem_ctx, sid)));
2300                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2301         }
2302
2303         a_state = talloc(mem_ctx, struct samr_account_state);
2304         if (!a_state) {
2305                 return NT_STATUS_NO_MEMORY;
2306         }
2307         a_state->sam_ctx = d_state->sam_ctx;
2308         a_state->access_mask = r->in.access_mask;
2309         a_state->domain_state = talloc_reference(a_state, d_state);
2310         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2311         a_state->account_sid = talloc_steal(a_state, sid);
2312         a_state->account_name = talloc_strdup(a_state, groupname);
2313         if (!a_state->account_name) {
2314                 return NT_STATUS_NO_MEMORY;
2315         }
2316
2317         /* create the policy handle */
2318         g_handle = dcesrv_handle_create(dce_call, SAMR_HANDLE_GROUP);
2319         if (!g_handle) {
2320                 return NT_STATUS_NO_MEMORY;
2321         }
2322
2323         g_handle->data = talloc_steal(g_handle, a_state);
2324
2325         *r->out.group_handle = g_handle->wire_handle;
2326
2327         return NT_STATUS_OK;
2328 }
2329
2330 /*
2331   samr_QueryGroupInfo
2332 */
2333 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2334                        struct samr_QueryGroupInfo *r)
2335 {
2336         struct dcesrv_handle *h;
2337         struct samr_account_state *a_state;
2338         struct ldb_message *msg, **res;
2339         const char * const attrs[4] = { "sAMAccountName", "description",
2340                                         "numMembers", NULL };
2341         int ret;
2342         union samr_GroupInfo *info;
2343
2344         *r->out.info = NULL;
2345
2346         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2347
2348         a_state = h->data;
2349
2350         /* pull all the group attributes */
2351         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2352                               a_state->account_dn, &res, attrs);
2353         if (ret == 0) {
2354                 return NT_STATUS_NO_SUCH_GROUP;
2355         }
2356         if (ret != 1) {
2357                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2358         }
2359         msg = res[0];
2360
2361         /* allocate the info structure */
2362         info = talloc_zero(mem_ctx, union samr_GroupInfo);
2363         if (info == NULL) {
2364                 return NT_STATUS_NO_MEMORY;
2365         }
2366
2367         /* Fill in the level */
2368         switch (r->in.level) {
2369         case GROUPINFOALL:
2370                 QUERY_STRING(msg, all.name,        "sAMAccountName");
2371                 info->all.attributes = SE_GROUP_DEFAULT_FLAGS; /* Do like w2k3 */
2372                 QUERY_UINT  (msg, all.num_members,      "numMembers")
2373                 QUERY_STRING(msg, all.description, "description");
2374                 break;
2375         case GROUPINFONAME:
2376                 QUERY_STRING(msg, name,            "sAMAccountName");
2377                 break;
2378         case GROUPINFOATTRIBUTES:
2379                 info->attributes.attributes = SE_GROUP_DEFAULT_FLAGS; /* Do like w2k3 */
2380                 break;
2381         case GROUPINFODESCRIPTION:
2382                 QUERY_STRING(msg, description, "description");
2383                 break;
2384         case GROUPINFOALL2:
2385                 QUERY_STRING(msg, all2.name,        "sAMAccountName");
2386                 info->all.attributes = SE_GROUP_DEFAULT_FLAGS; /* Do like w2k3 */
2387                 QUERY_UINT  (msg, all2.num_members,      "numMembers")
2388                 QUERY_STRING(msg, all2.description, "description");
2389                 break;
2390         default:
2391                 talloc_free(info);
2392                 return NT_STATUS_INVALID_INFO_CLASS;
2393         }
2394
2395         *r->out.info = info;
2396
2397         return NT_STATUS_OK;
2398 }
2399
2400
2401 /*
2402   samr_SetGroupInfo
2403 */
2404 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2405                                   struct samr_SetGroupInfo *r)
2406 {
2407         struct dcesrv_handle *h;
2408         struct samr_account_state *g_state;
2409         struct ldb_message *msg;
2410         int ret;
2411
2412         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2413
2414         g_state = h->data;
2415
2416         msg = ldb_msg_new(mem_ctx);
2417         if (msg == NULL) {
2418                 return NT_STATUS_NO_MEMORY;
2419         }
2420
2421         msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
2422         if (!msg->dn) {
2423                 return NT_STATUS_NO_MEMORY;
2424         }
2425
2426         switch (r->in.level) {
2427         case GROUPINFODESCRIPTION:
2428                 SET_STRING(msg, description,         "description");
2429                 break;
2430         case GROUPINFONAME:
2431                 /* On W2k3 this does not change the name, it changes the
2432                  * sAMAccountName attribute */
2433                 SET_STRING(msg, name,                "sAMAccountName");
2434                 break;
2435         case GROUPINFOATTRIBUTES:
2436                 /* This does not do anything obviously visible in W2k3 LDAP */
2437                 return NT_STATUS_OK;
2438         default:
2439                 return NT_STATUS_INVALID_INFO_CLASS;
2440         }
2441
2442         /* modify the samdb record */
2443         ret = ldb_modify(g_state->sam_ctx, msg);
2444         if (ret != LDB_SUCCESS) {
2445                 return dsdb_ldb_err_to_ntstatus(ret);
2446         }
2447
2448         return NT_STATUS_OK;
2449 }
2450
2451
2452 /*
2453   samr_AddGroupMember
2454 */
2455 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2456                        struct samr_AddGroupMember *r)
2457 {
2458         struct dcesrv_handle *h;
2459         struct samr_account_state *a_state;
2460         struct samr_domain_state *d_state;
2461         struct ldb_message *mod;
2462         struct dom_sid *membersid;
2463         const char *memberdn;
2464         struct ldb_result *res;
2465         const char * const attrs[] = { NULL };
2466         int ret;
2467
2468         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2469
2470         a_state = h->data;
2471         d_state = a_state->domain_state;
2472
2473         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2474         if (membersid == NULL) {
2475                 return NT_STATUS_NO_MEMORY;
2476         }
2477
2478         /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
2479         ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2480                          d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2481                          "(objectSid=%s)",
2482                          ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2483
2484         if (ret != LDB_SUCCESS) {
2485                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2486         }
2487
2488         if (res->count == 0) {
2489                 return NT_STATUS_NO_SUCH_USER;
2490         }
2491
2492         if (res->count > 1) {
2493                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2494         }
2495
2496         memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2497
2498         if (memberdn == NULL)
2499                 return NT_STATUS_NO_MEMORY;
2500
2501         mod = ldb_msg_new(mem_ctx);
2502         if (mod == NULL) {
2503                 return NT_STATUS_NO_MEMORY;
2504         }
2505
2506         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2507
2508         ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2509                                                                 memberdn);
2510         if (ret != LDB_SUCCESS) {
2511                 return dsdb_ldb_err_to_ntstatus(ret);
2512         }
2513
2514         ret = ldb_modify(a_state->sam_ctx, mod);
2515         switch (ret) {
2516         case LDB_SUCCESS:
2517                 return NT_STATUS_OK;
2518         case LDB_ERR_ENTRY_ALREADY_EXISTS:
2519                 return NT_STATUS_MEMBER_IN_GROUP;
2520         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2521                 return NT_STATUS_ACCESS_DENIED;
2522         default:
2523                 return dsdb_ldb_err_to_ntstatus(ret);
2524         }
2525 }
2526
2527
2528 /*
2529   samr_DeleteDomainGroup
2530 */
2531 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2532                        struct samr_DeleteDomainGroup *r)
2533 {
2534         struct dcesrv_handle *h;
2535         struct samr_account_state *a_state;
2536         int ret;
2537
2538         *r->out.group_handle = *r->in.group_handle;
2539
2540         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2541
2542         a_state = h->data;
2543
2544         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2545         if (ret != LDB_SUCCESS) {
2546                 return dsdb_ldb_err_to_ntstatus(ret);
2547         }
2548
2549         talloc_free(h);
2550         ZERO_STRUCTP(r->out.group_handle);
2551
2552         return NT_STATUS_OK;
2553 }
2554
2555
2556 /*
2557   samr_DeleteGroupMember
2558 */
2559 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2560                        struct samr_DeleteGroupMember *r)
2561 {
2562         struct dcesrv_handle *h;
2563         struct samr_account_state *a_state;
2564         struct samr_domain_state *d_state;
2565         struct ldb_message *mod;
2566         struct dom_sid *membersid;
2567         const char *memberdn;
2568         struct ldb_result *res;
2569         const char * const attrs[] = { NULL };
2570         int ret;
2571
2572         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2573
2574         a_state = h->data;
2575         d_state = a_state->domain_state;
2576
2577         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2578         if (membersid == NULL) {
2579                 return NT_STATUS_NO_MEMORY;
2580         }
2581
2582         /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
2583         ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2584                          d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2585                          "(objectSid=%s)",
2586                          ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2587
2588         if (ret != LDB_SUCCESS) {
2589                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2590         }
2591
2592         if (res->count == 0) {
2593                 return NT_STATUS_NO_SUCH_USER;
2594         }
2595
2596         if (res->count > 1) {
2597                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2598         }
2599
2600         memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2601
2602         if (memberdn == NULL)
2603                 return NT_STATUS_NO_MEMORY;
2604
2605         mod = ldb_msg_new(mem_ctx);
2606         if (mod == NULL) {
2607                 return NT_STATUS_NO_MEMORY;
2608         }
2609
2610         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2611
2612         ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2613                                                                 memberdn);
2614         if (ret != LDB_SUCCESS) {
2615                 return NT_STATUS_NO_MEMORY;
2616         }
2617
2618         ret = ldb_modify(a_state->sam_ctx, mod);
2619         switch (ret) {
2620         case LDB_SUCCESS:
2621                 return NT_STATUS_OK;
2622         case LDB_ERR_UNWILLING_TO_PERFORM:
2623         case LDB_ERR_NO_SUCH_ATTRIBUTE:
2624                 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2625         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2626                 return NT_STATUS_ACCESS_DENIED;
2627         default:
2628                 return dsdb_ldb_err_to_ntstatus(ret);
2629         }
2630 }
2631
2632
2633 /*
2634   samr_QueryGroupMember
2635 */
2636 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2637                                       struct samr_QueryGroupMember *r)
2638 {
2639         struct dcesrv_handle *h;
2640         struct samr_account_state *a_state;
2641         struct samr_domain_state *d_state;
2642         struct samr_RidAttrArray *array;
2643         unsigned int i, num_members;
2644         struct dom_sid *members;
2645         NTSTATUS status;
2646
2647         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2648
2649         a_state = h->data;
2650         d_state = a_state->domain_state;
2651
2652         status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
2653                                      a_state->account_dn, &members,
2654                                      &num_members);
2655         if (!NT_STATUS_IS_OK(status)) {
2656                 return status;
2657         }
2658
2659         array = talloc_zero(mem_ctx, struct samr_RidAttrArray);
2660         if (array == NULL) {
2661                 return NT_STATUS_NO_MEMORY;
2662         }
2663
2664         if (num_members == 0) {
2665                 *r->out.rids = array;
2666
2667                 return NT_STATUS_OK;
2668         }
2669
2670         array->rids = talloc_array(array, uint32_t, num_members);
2671         if (array->rids == NULL) {
2672                 return NT_STATUS_NO_MEMORY;
2673         }
2674
2675         array->attributes = talloc_array(array, uint32_t, num_members);
2676         if (array->attributes == NULL) {
2677                 return NT_STATUS_NO_MEMORY;
2678         }
2679
2680         array->count = 0;
2681         for (i=0; i<num_members; i++) {
2682                 if (!dom_sid_in_domain(d_state->domain_sid, &members[i])) {
2683                         continue;
2684                 }
2685
2686                 status = dom_sid_split_rid(NULL, &members[i], NULL,
2687                                            &array->rids[array->count]);
2688                 if (!NT_STATUS_IS_OK(status)) {
2689                         return status;
2690                 }
2691
2692                 array->attributes[array->count] = SE_GROUP_DEFAULT_FLAGS;
2693                 array->count++;
2694         }
2695
2696         *r->out.rids = array;
2697
2698         return NT_STATUS_OK;
2699 }
2700
2701
2702 /*
2703   samr_SetMemberAttributesOfGroup
2704 */
2705 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2706                        struct samr_SetMemberAttributesOfGroup *r)
2707 {
2708         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2709 }
2710
2711
2712 /*
2713   samr_OpenAlias
2714 */
2715 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2716                        struct samr_OpenAlias *r)
2717 {
2718         struct samr_domain_state *d_state;
2719         struct samr_account_state *a_state;
2720         struct dcesrv_handle *h;
2721         const char *alias_name;
2722         struct dom_sid *sid;
2723         struct ldb_message **msgs;
2724         struct dcesrv_handle *g_handle;
2725         const char * const attrs[2] = { "sAMAccountName", NULL };
2726         int ret;
2727
2728         ZERO_STRUCTP(r->out.alias_handle);
2729
2730         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2731
2732         d_state = h->data;
2733
2734         /* form the alias SID */
2735         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2736         if (sid == NULL)
2737                 return NT_STATUS_NO_MEMORY;
2738
2739         /* search for the group record */
2740         ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL, &msgs, attrs,
2741                            "(&(objectSid=%s)(objectclass=group)"
2742                            "(|(grouptype=%d)(grouptype=%d)))",
2743                            ldap_encode_ndr_dom_sid(mem_ctx, sid),
2744                            GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2745                            GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2746         if (ret == 0) {
2747                 return NT_STATUS_NO_SUCH_ALIAS;
2748         }
2749         if (ret != 1) {
2750                 DEBUG(0,("Found %d records matching sid %s\n",
2751                          ret, dom_sid_string(mem_ctx, sid)));
2752                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2753         }
2754
2755         alias_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2756         if (alias_name == NULL) {
2757                 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2758                          dom_sid_string(mem_ctx, sid)));
2759                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2760         }
2761
2762         a_state = talloc(mem_ctx, struct samr_account_state);
2763         if (!a_state) {
2764                 return NT_STATUS_NO_MEMORY;
2765         }
2766         a_state->sam_ctx = d_state->sam_ctx;
2767         a_state->access_mask = r->in.access_mask;
2768         a_state->domain_state = talloc_reference(a_state, d_state);
2769         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2770         a_state->account_sid = talloc_steal(a_state, sid);
2771         a_state->account_name = talloc_strdup(a_state, alias_name);
2772         if (!a_state->account_name) {
2773                 return NT_STATUS_NO_MEMORY;
2774         }
2775
2776         /* create the policy handle */
2777         g_handle = dcesrv_handle_create(dce_call, SAMR_HANDLE_ALIAS);
2778         if (!g_handle) {
2779                 return NT_STATUS_NO_MEMORY;
2780         }
2781
2782         g_handle->data = talloc_steal(g_handle, a_state);
2783
2784         *r->out.alias_handle = g_handle->wire_handle;
2785
2786         return NT_STATUS_OK;
2787 }
2788
2789
2790 /*
2791   samr_QueryAliasInfo
2792 */
2793 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2794                        struct samr_QueryAliasInfo *r)
2795 {
2796         struct dcesrv_handle *h;
2797         struct samr_account_state *a_state;
2798         struct ldb_message *msg, **res;
2799         const char * const attrs[4] = { "sAMAccountName", "description",
2800                                         "numMembers", NULL };
2801         int ret;
2802         union samr_AliasInfo *info;
2803
2804         *r->out.info = NULL;
2805
2806         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2807
2808         a_state = h->data;
2809
2810         /* pull all the alias attributes */
2811         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2812                               a_state->account_dn, &res, attrs);
2813         if (ret == 0) {
2814                 return NT_STATUS_NO_SUCH_ALIAS;
2815         }
2816         if (ret != 1) {
2817                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2818         }
2819         msg = res[0];
2820
2821         /* allocate the info structure */
2822         info = talloc_zero(mem_ctx, union samr_AliasInfo);
2823         if (info == NULL) {
2824                 return NT_STATUS_NO_MEMORY;
2825         }
2826
2827         switch(r->in.level) {
2828         case ALIASINFOALL:
2829                 QUERY_STRING(msg, all.name, "sAMAccountName");
2830                 QUERY_UINT  (msg, all.num_members, "numMembers");
2831                 QUERY_STRING(msg, all.description, "description");
2832                 break;
2833         case ALIASINFONAME:
2834                 QUERY_STRING(msg, name, "sAMAccountName");
2835                 break;
2836         case ALIASINFODESCRIPTION:
2837                 QUERY_STRING(msg, description, "description");
2838                 break;
2839         default:
2840                 talloc_free(info);
2841                 return NT_STATUS_INVALID_INFO_CLASS;
2842         }
2843
2844         *r->out.info = info;
2845
2846         return NT_STATUS_OK;
2847 }
2848
2849
2850 /*
2851   samr_SetAliasInfo
2852 */
2853 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2854                        struct samr_SetAliasInfo *r)
2855 {
2856         struct dcesrv_handle *h;
2857         struct samr_account_state *a_state;
2858         struct ldb_message *msg;
2859         int ret;
2860
2861         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2862
2863         a_state = h->data;
2864
2865         msg = ldb_msg_new(mem_ctx);
2866         if (msg == NULL) {
2867                 return NT_STATUS_NO_MEMORY;
2868         }
2869
2870         msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2871         if (!msg->dn) {
2872                 return NT_STATUS_NO_MEMORY;
2873         }
2874
2875         switch (r->in.level) {
2876         case ALIASINFODESCRIPTION:
2877                 SET_STRING(msg, description,         "description");
2878                 break;
2879         case ALIASINFONAME:
2880                 /* On W2k3 this does not change the name, it changes the
2881                  * sAMAccountName attribute */
2882                 SET_STRING(msg, name,                "sAMAccountName");
2883                 break;
2884         default:
2885                 return NT_STATUS_INVALID_INFO_CLASS;
2886         }
2887
2888         /* modify the samdb record */
2889         ret = ldb_modify(a_state->sam_ctx, msg);
2890         if (ret != LDB_SUCCESS) {
2891                 return dsdb_ldb_err_to_ntstatus(ret);
2892         }
2893
2894         return NT_STATUS_OK;
2895 }
2896
2897
2898 /*
2899   samr_DeleteDomAlias
2900 */
2901 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2902                        struct samr_DeleteDomAlias *r)
2903 {
2904         struct dcesrv_handle *h;
2905         struct samr_account_state *a_state;
2906         int ret;
2907
2908         *r->out.alias_handle = *r->in.alias_handle;
2909
2910         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2911
2912         a_state = h->data;
2913
2914         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2915         if (ret != LDB_SUCCESS) {
2916                 return dsdb_ldb_err_to_ntstatus(ret);
2917         }
2918
2919         talloc_free(h);
2920         ZERO_STRUCTP(r->out.alias_handle);
2921
2922         return NT_STATUS_OK;
2923 }
2924
2925
2926 /*
2927   samr_AddAliasMember
2928 */
2929 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2930                        struct samr_AddAliasMember *r)
2931 {
2932         struct dcesrv_handle *h;
2933         struct samr_account_state *a_state;
2934         struct samr_domain_state *d_state;
2935         struct ldb_message *mod;
2936         struct ldb_message **msgs;
2937         const char * const attrs[] = { NULL };
2938         struct ldb_dn *memberdn = NULL;
2939         int ret;
2940         NTSTATUS status;
2941
2942         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2943
2944         a_state = h->data;
2945         d_state = a_state->domain_state;
2946
2947         ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2948                            &msgs, attrs, "(objectsid=%s)",
2949                            ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2950
2951         if (ret == 1) {
2952                 memberdn = msgs[0]->dn;
2953         } else if (ret == 0) {
2954                 status = samdb_create_foreign_security_principal(
2955                         d_state->sam_ctx, mem_ctx, r->in.sid, &memberdn);
2956                 if (!NT_STATUS_IS_OK(status)) {
2957                         return status;
2958                 }
2959         } else {
2960                 DEBUG(0,("Found %d records matching sid %s\n",
2961                          ret, dom_sid_string(mem_ctx, r->in.sid)));
2962                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2963         }
2964
2965         if (memberdn == NULL) {
2966                 DEBUG(0, ("Could not find memberdn\n"));
2967                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2968         }
2969
2970         mod = ldb_msg_new(mem_ctx);
2971         if (mod == NULL) {
2972                 return NT_STATUS_NO_MEMORY;
2973         }
2974
2975         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2976
2977         ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2978                                  ldb_dn_alloc_linearized(mem_ctx, memberdn));
2979         if (ret != LDB_SUCCESS) {
2980                 return dsdb_ldb_err_to_ntstatus(ret);
2981         }
2982
2983         ret = ldb_modify(a_state->sam_ctx, mod);
2984         switch (ret) {
2985         case LDB_SUCCESS:
2986                 return NT_STATUS_OK;
2987         case LDB_ERR_ENTRY_ALREADY_EXISTS:
2988                 return NT_STATUS_MEMBER_IN_GROUP;
2989         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2990                 return NT_STATUS_ACCESS_DENIED;
2991         default:
2992                 return dsdb_ldb_err_to_ntstatus(ret);
2993         }
2994 }
2995
2996
2997 /*
2998   samr_DeleteAliasMember
2999 */
3000 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3001                        struct samr_DeleteAliasMember *r)
3002 {
3003         struct dcesrv_handle *h;
3004         struct samr_account_state *a_state;
3005         struct samr_domain_state *d_state;
3006         struct ldb_message *mod;
3007         const char *memberdn;
3008         int ret;
3009
3010         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
3011
3012         a_state = h->data;
3013         d_state = a_state->domain_state;
3014
3015         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3016                                        "distinguishedName", "(objectSid=%s)",
3017                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3018         if (memberdn == NULL) {
3019                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3020         }
3021
3022         mod = ldb_msg_new(mem_ctx);
3023         if (mod == NULL) {
3024                 return NT_STATUS_NO_MEMORY;
3025         }
3026
3027         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
3028
3029         ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
3030                                                                  memberdn);
3031         if (ret != LDB_SUCCESS) {
3032                 return dsdb_ldb_err_to_ntstatus(ret);
3033         }
3034
3035         ret = ldb_modify(a_state->sam_ctx, mod);
3036         switch (ret) {
3037         case LDB_SUCCESS:
3038                 return NT_STATUS_OK;
3039         case LDB_ERR_UNWILLING_TO_PERFORM:
3040                 return NT_STATUS_MEMBER_NOT_IN_GROUP;
3041         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
3042                 return NT_STATUS_ACCESS_DENIED;
3043         default:
3044                 return dsdb_ldb_err_to_ntstatus(ret);
3045         }
3046 }
3047
3048
3049 /*
3050   samr_GetMembersInAlias
3051 */
3052 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3053                        struct samr_GetMembersInAlias *r)
3054 {
3055         struct dcesrv_handle *h;
3056         struct samr_account_state *a_state;
3057         struct samr_domain_state *d_state;
3058         struct lsa_SidPtr *array;
3059         unsigned int i, num_members;
3060         struct dom_sid *members;
3061         NTSTATUS status;
3062
3063         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
3064
3065         a_state = h->data;
3066         d_state = a_state->domain_state;
3067
3068         status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
3069                                      a_state->account_dn, &members,
3070                                      &num_members);
3071         if (!NT_STATUS_IS_OK(status)) {
3072                 return status;
3073         }
3074
3075         if (num_members == 0) {
3076                 r->out.sids->sids = NULL;
3077
3078                 return NT_STATUS_OK;
3079         }
3080
3081         array = talloc_array(mem_ctx, struct lsa_SidPtr, num_members);
3082         if (array == NULL) {
3083                 return NT_STATUS_NO_MEMORY;
3084         }
3085
3086         for (i=0; i<num_members; i++) {
3087                 array[i].sid = &members[i];
3088         }
3089
3090         r->out.sids->num_sids = num_members;
3091         r->out.sids->sids = array;
3092
3093         return NT_STATUS_OK;
3094 }
3095
3096 /*
3097   samr_OpenUser
3098 */
3099 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3100                               struct samr_OpenUser *r)
3101 {
3102         struct samr_domain_state *d_state;
3103         struct samr_account_state *a_state;
3104         struct dcesrv_handle *h;
3105         const char *account_name;
3106         struct dom_sid *sid;
3107         struct ldb_message **msgs;
3108         struct dcesrv_handle *u_handle;
3109         const char * const attrs[2] = { "sAMAccountName", NULL };
3110         int ret;
3111
3112         ZERO_STRUCTP(r->out.user_handle);
3113
3114         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3115
3116         d_state = h->data;
3117
3118         /* form the users SID */
3119         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
3120         if (!sid) {
3121                 return NT_STATUS_NO_MEMORY;
3122         }
3123
3124         /* search for the user record */
3125         ret = gendb_search(d_state->sam_ctx,
3126                            mem_ctx, d_state->domain_dn, &msgs, attrs,
3127                            "(&(objectSid=%s)(objectclass=user))",
3128                            ldap_encode_ndr_dom_sid(mem_ctx, sid));
3129         if (ret == 0) {
3130                 return NT_STATUS_NO_SUCH_USER;
3131         }
3132         if (ret != 1) {
3133                 DEBUG(0,("Found %d records matching sid %s\n", ret,
3134                          dom_sid_string(mem_ctx, sid)));
3135                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3136         }
3137
3138         account_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
3139         if (account_name == NULL) {
3140                 DEBUG(0,("sAMAccountName field missing for sid %s\n",
3141                          dom_sid_string(mem_ctx, sid)));
3142                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3143         }
3144
3145         a_state = talloc(mem_ctx, struct samr_account_state);
3146         if (!a_state) {
3147                 return NT_STATUS_NO_MEMORY;
3148         }
3149         a_state->sam_ctx = d_state->sam_ctx;
3150         a_state->access_mask = r->in.access_mask;
3151         a_state->domain_state = talloc_reference(a_state, d_state);
3152         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
3153         a_state->account_sid = talloc_steal(a_state, sid);
3154         a_state->account_name = talloc_strdup(a_state, account_name);
3155         if (!a_state->account_name) {
3156                 return NT_STATUS_NO_MEMORY;
3157         }
3158
3159         /* create the policy handle */
3160         u_handle = dcesrv_handle_create(dce_call, SAMR_HANDLE_USER);
3161         if (!u_handle) {
3162                 return NT_STATUS_NO_MEMORY;
3163         }
3164
3165         u_handle->data = talloc_steal(u_handle, a_state);
3166
3167         *r->out.user_handle = u_handle->wire_handle;
3168
3169         return NT_STATUS_OK;
3170
3171 }
3172
3173
3174 /*
3175   samr_DeleteUser
3176 */
3177 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3178                                 struct samr_DeleteUser *r)
3179 {
3180         struct dcesrv_handle *h;
3181         struct samr_account_state *a_state;
3182         int ret;
3183
3184         *r->out.user_handle = *r->in.user_handle;
3185
3186         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3187
3188         a_state = h->data;
3189
3190         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
3191         if (ret != LDB_SUCCESS) {
3192                 DEBUG(1, ("Failed to delete user: %s: %s\n",
3193                           ldb_dn_get_linearized(a_state->account_dn),
3194                           ldb_errstring(a_state->sam_ctx)));
3195                 return dsdb_ldb_err_to_ntstatus(ret);
3196         }
3197
3198         talloc_free(h);
3199         ZERO_STRUCTP(r->out.user_handle);
3200
3201         return NT_STATUS_OK;
3202 }
3203
3204
3205 /*
3206   samr_QueryUserInfo
3207 */
3208 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3209                                    struct samr_QueryUserInfo *r)
3210 {
3211         struct dcesrv_handle *h;
3212         struct samr_account_state *a_state;
3213         struct ldb_message *msg, **res;
3214         int ret;
3215         struct ldb_context *sam_ctx;
3216
3217         const char * const *attrs = NULL;
3218         union samr_UserInfo *info;
3219
3220         NTSTATUS status;
3221
3222         *r->out.info = NULL;
3223
3224         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3225
3226         a_state = h->data;
3227         sam_ctx = a_state->sam_ctx;
3228
3229         /* fill in the reply */
3230         switch (r->in.level) {
3231         case 1:
3232         {
3233                 static const char * const attrs2[] = {"sAMAccountName",
3234                                                       "displayName",
3235                                                       "primaryGroupID",
3236                                                       "description",
3237                                                       "comment",
3238                                                       NULL};
3239                 attrs = attrs2;
3240                 break;
3241         }
3242         case 2:
3243         {
3244                 static const char * const attrs2[] = {"comment",
3245                                                       "countryCode",
3246                                                       "codePage",
3247                                                       NULL};
3248                 attrs = attrs2;
3249                 break;
3250         }
3251         case 3:
3252         {
3253                 static const char * const attrs2[] = {"sAMAccountName",
3254                                                       "displayName",
3255                                                       "objectSid",
3256                                                       "primaryGroupID",
3257                                                       "homeDirectory",
3258                                                       "homeDrive",
3259                                                       "scriptPath",
3260                                                       "profilePath",
3261                                                       "userWorkstations",
3262                                                       "lastLogon",
3263                                                       "lastLogoff",
3264                                                       "pwdLastSet",
3265                                                       "msDS-UserPasswordExpiryTimeComputed",
3266                                                       "logonHours",
3267                                                       "badPwdCount",
3268                                                       "badPasswordTime",
3269                                                       "logonCount",
3270                                                       "userAccountControl",
3271                                                       "msDS-User-Account-Control-Computed",
3272                                                       NULL};
3273                 attrs = attrs2;
3274                 break;
3275         }
3276         case 4:
3277         {
3278                 static const char * const attrs2[] = {"logonHours",
3279                                                       NULL};
3280                 attrs = attrs2;
3281                 break;
3282         }
3283         case 5:
3284         {
3285                 static const char * const attrs2[] = {"sAMAccountName",
3286                                                       "displayName",
3287                                                       "objectSid",
3288                                                       "primaryGroupID",
3289                                                       "homeDirectory",
3290                                                       "homeDrive",
3291                                                       "scriptPath",
3292                                                       "profilePath",
3293                                                       "description",
3294                                                       "userWorkstations",
3295                                                       "lastLogon",
3296                                                       "lastLogoff",
3297                                                       "logonHours",
3298                                                       "badPwdCount",
3299                                                       "badPasswordTime",
3300                                                       "logonCount",
3301                                                       "pwdLastSet",
3302                                                       "msDS-ResultantPSO",
3303                                                       "msDS-UserPasswordExpiryTimeComputed",
3304                                                       "accountExpires",
3305                                                       "userAccountControl",
3306                                                       "msDS-User-Account-Control-Computed",
3307                                                       NULL};
3308                 attrs = attrs2;
3309                 break;
3310         }
3311         case 6:
3312         {
3313                 static const char * const attrs2[] = {"sAMAccountName",
3314                                                       "displayName",
3315                                                       NULL};
3316                 attrs = attrs2;
3317                 break;
3318         }
3319         case 7:
3320         {
3321                 static const char * const attrs2[] = {"sAMAccountName",
3322                                                       NULL};
3323                 attrs = attrs2;
3324                 break;
3325         }
3326         case 8:
3327         {
3328                 static const char * const attrs2[] = {"displayName",
3329                                                       NULL};
3330                 attrs = attrs2;
3331                 break;
3332         }
3333         case 9:
3334         {
3335                 static const char * const attrs2[] = {"primaryGroupID",
3336                                                       NULL};
3337                 attrs = attrs2;
3338                 break;
3339         }
3340         case 10:
3341         {
3342                 static const char * const attrs2[] = {"homeDirectory",
3343                                                       "homeDrive",
3344                                                       NULL};
3345                 attrs = attrs2;
3346                 break;
3347         }
3348         case 11:
3349         {
3350                 static const char * const attrs2[] = {"scriptPath",
3351                                                       NULL};
3352                 attrs = attrs2;
3353                 break;
3354         }
3355         case 12:
3356         {
3357                 static const char * const attrs2[] = {"profilePath",
3358                                                       NULL};
3359                 attrs = attrs2;
3360                 break;
3361         }
3362         case 13:
3363         {
3364                 static const char * const attrs2[] = {"description",
3365                                                       NULL};
3366                 attrs = attrs2;
3367                 break;
3368         }
3369         case 14:
3370         {
3371                 static const char * const attrs2[] = {"userWorkstations",
3372                                                       NULL};
3373                 attrs = attrs2;
3374                 break;
3375         }
3376         case 16:
3377         {
3378                 static const char * const attrs2[] = {"userAccountControl",
3379                                                       "msDS-User-Account-Control-Computed",
3380                                                       "pwdLastSet",
3381                                                       "msDS-UserPasswordExpiryTimeComputed",
3382                                                       NULL};
3383                 attrs = attrs2;
3384                 break;
3385         }
3386         case 17:
3387         {
3388                 static const char * const attrs2[] = {"accountExpires",
3389                                                       NULL};
3390                 attrs = attrs2;
3391                 break;
3392         }
3393         case 18:
3394         {
3395                 return NT_STATUS_NOT_SUPPORTED;
3396         }
3397         case 20:
3398         {
3399                 static const char * const attrs2[] = {"userParameters",
3400                                                       NULL};
3401                 attrs = attrs2;
3402                 break;
3403         }
3404         case 21:
3405         {
3406                 static const char * const attrs2[] = {"lastLogon",
3407                                                       "lastLogoff",
3408                                                       "pwdLastSet",
3409                                                       "msDS-ResultantPSO",
3410                                                       "msDS-UserPasswordExpiryTimeComputed",
3411                                                       "accountExpires",
3412                                                       "sAMAccountName",
3413                                                       "displayName",
3414                                                       "homeDirectory",
3415                                                       "homeDrive",
3416                                                       "scriptPath",
3417                                                       "profilePath",
3418                                                       "description",
3419                                                       "userWorkstations",
3420                                                       "comment",
3421                                                       "userParameters",
3422                                                       "objectSid",
3423                                                       "primaryGroupID",
3424                                                       "userAccountControl",
3425                                                       "msDS-User-Account-Control-Computed",
3426                                                       "logonHours",
3427                                                       "badPwdCount",
3428                                                       "badPasswordTime",
3429                                                       "logonCount",
3430                                                       "countryCode",
3431                                                       "codePage",
3432                                                       NULL};
3433                 attrs = attrs2;
3434                 break;
3435         }
3436         case 23:
3437         case 24:
3438         case 25:
3439         case 26:
3440         {
3441                 return NT_STATUS_NOT_SUPPORTED;
3442         }
3443         default:
3444         {
3445                 return NT_STATUS_INVALID_INFO_CLASS;
3446         }
3447         }
3448
3449         /* pull all the user attributes */
3450         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
3451                               a_state->account_dn, &res, attrs);
3452         if (ret == 0) {
3453                 return NT_STATUS_NO_SUCH_USER;
3454         }
3455         if (ret != 1) {
3456                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3457         }
3458         msg = res[0];
3459
3460         /* allocate the info structure */
3461         info = talloc_zero(mem_ctx, union samr_UserInfo);
3462         if (info == NULL) {
3463                 return NT_STATUS_NO_MEMORY;
3464         }
3465
3466         /* fill in the reply */
3467         switch (r->in.level) {
3468         case 1:
3469                 QUERY_STRING(msg, info1.account_name,          "sAMAccountName");
3470                 QUERY_STRING(msg, info1.full_name,             "displayName");
3471                 QUERY_UINT  (msg, info1.primary_gid,           "primaryGroupID");
3472                 QUERY_STRING(msg, info1.description,           "description");
3473                 QUERY_STRING(msg, info1.comment,               "comment");
3474                 break;
3475
3476         case 2:
3477                 QUERY_STRING(msg, info2.comment,               "comment");
3478                 QUERY_UINT  (msg, info2.country_code,          "countryCode");
3479                 QUERY_UINT  (msg, info2.code_page,             "codePage");
3480                 break;
3481
3482         case 3:
3483                 QUERY_STRING(msg, info3.account_name,          "sAMAccountName");
3484                 QUERY_STRING(msg, info3.full_name,             "displayName");
3485                 QUERY_RID   (msg, info3.rid,                   "objectSid");
3486                 QUERY_UINT  (msg, info3.primary_gid,           "primaryGroupID");
3487                 QUERY_STRING(msg, info3.home_directory,        "homeDirectory");
3488                 QUERY_STRING(msg, info3.home_drive,            "homeDrive");
3489                 QUERY_STRING(msg, info3.logon_script,          "scriptPath");
3490                 QUERY_STRING(msg, info3.profile_path,          "profilePath");
3491                 QUERY_STRING(msg, info3.workstations,          "userWorkstations");
3492                 QUERY_UINT64(msg, info3.last_logon,            "lastLogon");
3493                 QUERY_UINT64(msg, info3.last_logoff,           "lastLogoff");
3494                 QUERY_UINT64(msg, info3.last_password_change,  "pwdLastSet");
3495                 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
3496                 QUERY_UINT64(msg, info3.force_password_change, "msDS-UserPasswordExpiryTimeComputed");
3497                 QUERY_LHOURS(msg, info3.logon_hours,           "logonHours");
3498                 /* level 3 gives the raw badPwdCount value */
3499                 QUERY_UINT  (msg, info3.bad_password_count,    "badPwdCount");
3500                 QUERY_UINT  (msg, info3.logon_count,           "logonCount");
3501                 QUERY_AFLAGS(msg, info3.acct_flags,            "msDS-User-Account-Control-Computed");
3502                 break;
3503
3504         case 4:
3505                 QUERY_LHOURS(msg, info4.logon_hours,           "logonHours");
3506                 break;
3507
3508         case 5:
3509                 QUERY_STRING(msg, info5.account_name,          "sAMAccountName");
3510                 QUERY_STRING(msg, info5.full_name,             "displayName");
3511                 QUERY_RID   (msg, info5.rid,                   "objectSid");
3512                 QUERY_UINT  (msg, info5.primary_gid,           "primaryGroupID");
3513                 QUERY_STRING(msg, info5.home_directory,        "homeDirectory");
3514                 QUERY_STRING(msg, info5.home_drive,            "homeDrive");
3515                 QUERY_STRING(msg, info5.logon_script,          "scriptPath");
3516                 QUERY_STRING(msg, info5.profile_path,          "profilePath");
3517                 QUERY_STRING(msg, info5.description,           "description");
3518                 QUERY_STRING(msg, info5.workstations,          "userWorkstations");
3519                 QUERY_UINT64(msg, info5.last_logon,            "lastLogon");
3520                 QUERY_UINT64(msg, info5.last_logoff,           "lastLogoff");
3521                 QUERY_LHOURS(msg, info5.logon_hours,           "logonHours");
3522                 QUERY_BPWDCT(msg, info5.bad_password_count,    "badPwdCount");
3523                 QUERY_UINT  (msg, info5.logon_count,           "logonCount");
3524                 QUERY_UINT64(msg, info5.last_password_change,  "pwdLastSet");
3525                 QUERY_UINT64(msg, info5.acct_expiry,           "accountExpires");
3526                 QUERY_AFLAGS(msg, info5.acct_flags,            "msDS-User-Account-Control-Computed");
3527                 break;
3528
3529         case 6:
3530                 QUERY_STRING(msg, info6.account_name,   "sAMAccountName");
3531                 QUERY_STRING(msg, info6.full_name,      "displayName");
3532                 break;
3533
3534         case 7:
3535                 QUERY_STRING(msg, info7.account_name,   "sAMAccountName");
3536                 break;
3537
3538         case 8:
3539                 QUERY_STRING(msg, info8.full_name,      "displayName");
3540                 break;
3541
3542         case 9:
3543                 QUERY_UINT  (msg, info9.primary_gid,    "primaryGroupID");
3544                 break;
3545
3546         case 10:
3547                 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3548                 QUERY_STRING(msg, info10.home_drive,    "homeDrive");
3549                 break;
3550
3551         case 11:
3552                 QUERY_STRING(msg, info11.logon_script,  "scriptPath");
3553                 break;
3554
3555         case 12:
3556                 QUERY_STRING(msg, info12.profile_path,  "profilePath");
3557                 break;
3558
3559         case 13:
3560                 QUERY_STRING(msg, info13.description,   "description");
3561                 break;
3562
3563         case 14:
3564                 QUERY_STRING(msg, info14.workstations,  "userWorkstations");
3565                 break;
3566
3567         case 16:
3568                 QUERY_AFLAGS(msg, info16.acct_flags,    "msDS-User-Account-Control-Computed");
3569                 break;
3570
3571         case 17:
3572                 QUERY_UINT64(msg, info17.acct_expiry,   "accountExpires");
3573                 break;
3574
3575         case 20:
3576                 status = samdb_result_parameters(mem_ctx, msg, "userParameters", &info->info20.parameters);
3577                 if (!NT_STATUS_IS_OK(status)) {
3578                         talloc_free(info);
3579                         return status;
3580                 }
3581                 break;
3582
3583         case 21:
3584                 QUERY_UINT64(msg, info21.last_logon,           "lastLogon");
3585                 QUERY_UINT64(msg, info21.last_logoff,          "lastLogoff");
3586                 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3587                 QUERY_UINT64(msg, info21.acct_expiry,          "accountExpires");
3588                 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3589                 QUERY_UINT64(msg, info21.force_password_change, "msDS-UserPasswordExpiryTimeComputed");
3590                 QUERY_STRING(msg, info21.account_name,         "sAMAccountName");
3591                 QUERY_STRING(msg, info21.full_name,            "displayName");
3592                 QUERY_STRING(msg, info21.home_directory,       "homeDirectory");
3593                 QUERY_STRING(msg, info21.home_drive,           "homeDrive");
3594                 QUERY_STRING(msg, info21.logon_script,         "scriptPath");
3595                 QUERY_STRING(msg, info21.profile_path,         "profilePath");
3596                 QUERY_STRING(msg, info21.description,          "description");
3597                 QUERY_STRING(msg, info21.workstations,         "userWorkstations");
3598                 QUERY_STRING(msg, info21.comment,              "comment");
3599                 status = samdb_result_parameters(mem_ctx, msg, "userParameters", &info->info21.parameters);
3600                 if (!NT_STATUS_IS_OK(status)) {
3601                         talloc_free(info);
3602                         return status;
3603                 }
3604
3605                 QUERY_RID   (msg, info21.rid,                  "objectSid");
3606                 QUERY_UINT  (msg, info21.primary_gid,          "primaryGroupID");
3607                 QUERY_AFLAGS(msg, info21.acct_flags,           "msDS-User-Account-Control-Computed");
3608                 info->info21.fields_present = 0x08FFFFFF;
3609                 QUERY_LHOURS(msg, info21.logon_hours,          "logonHours");
3610                 QUERY_BPWDCT(msg, info21.bad_password_count,   "badPwdCount");
3611                 QUERY_UINT  (msg, info21.logon_count,          "logonCount");
3612                 if ((info->info21.acct_flags & ACB_PW_EXPIRED) != 0) {
3613                         info->info21.password_expired = PASS_MUST_CHANGE_AT_NEXT_LOGON;
3614                 } else {
3615                         info->info21.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
3616                 }
3617                 QUERY_UINT  (msg, info21.country_code,         "countryCode");
3618                 QUERY_UINT  (msg, info21.code_page,            "codePage");
3619                 break;
3620
3621
3622         default:
3623                 talloc_free(info);
3624                 return NT_STATUS_INVALID_INFO_CLASS;
3625         }
3626
3627         *r->out.info = info;
3628
3629         return NT_STATUS_OK;
3630 }
3631
3632
3633 /*
3634   samr_SetUserInfo
3635 */
3636 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3637                                  struct samr_SetUserInfo *r)
3638 {
3639         struct dcesrv_handle *h;
3640         struct samr_account_state *a_state;
3641         struct ldb_message *msg;
3642         int ret;
3643         NTSTATUS status = NT_STATUS_OK;
3644         struct ldb_context *sam_ctx;
3645         DATA_BLOB session_key = data_blob_null;
3646
3647         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3648
3649         a_state = h->data;
3650         sam_ctx = a_state->sam_ctx;
3651
3652         msg = ldb_msg_new(mem_ctx);
3653         if (msg == NULL) {
3654                 return NT_STATUS_NO_MEMORY;
3655         }
3656
3657         msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3658         if (!msg->dn) {
3659                 return NT_STATUS_NO_MEMORY;
3660         }
3661
3662         ret = ldb_transaction_start(sam_ctx);
3663         if (ret != LDB_SUCCESS) {
3664                 DBG_ERR("Failed to start a transaction: %s\n",
3665                         ldb_errstring(sam_ctx));
3666                 return NT_STATUS_LOCK_NOT_GRANTED;
3667         }
3668
3669         switch (r->in.level) {
3670         case 2:
3671                 SET_STRING(msg, info2.comment,          "comment");
3672                 SET_UINT  (msg, info2.country_code,     "countryCode");
3673                 SET_UINT  (msg, info2.code_page,        "codePage");
3674                 break;
3675
3676         case 4:
3677                 SET_LHOURS(msg, info4.logon_hours,      "logonHours");
3678                 break;
3679
3680         case 6:
3681                 SET_STRING(msg, info6.account_name,     "samAccountName");
3682                 SET_STRING(msg, info6.full_name,        "displayName");
3683                 break;
3684
3685         case 7:
3686                 SET_STRING(msg, info7.account_name,     "samAccountName");
3687                 break;
3688
3689         case 8:
3690                 SET_STRING(msg, info8.full_name,        "displayName");
3691                 break;
3692
3693         case 9:
3694                 SET_UINT(msg, info9.primary_gid,        "primaryGroupID");
3695                 break;
3696
3697         case 10:
3698                 SET_STRING(msg, info10.home_directory,  "homeDirectory");
3699                 SET_STRING(msg, info10.home_drive,      "homeDrive");
3700                 break;
3701
3702         case 11:
3703                 SET_STRING(msg, info11.logon_script,    "scriptPath");
3704                 break;
3705
3706         case 12:
3707                 SET_STRING(msg, info12.profile_path,    "profilePath");
3708                 break;
3709
3710         case 13:
3711                 SET_STRING(msg, info13.description,     "description");
3712                 break;
3713
3714         case 14:
3715                 SET_STRING(msg, info14.workstations,    "userWorkstations");
3716                 break;
3717
3718         case 16:
3719                 SET_AFLAGS(msg, info16.acct_flags,      "userAccountControl");
3720                 break;
3721
3722         case 17:
3723                 SET_UINT64(msg, info17.acct_expiry,     "accountExpires");
3724                 break;
3725
3726         case 18:
3727                 status = samr_set_password_buffers(dce_call,
3728                                                    sam_ctx,
3729                                                    a_state->account_dn,
3730                                                    mem_ctx,
3731                                                    r->in.info->info18.lm_pwd_active ? r->in.info->info18.lm_pwd.hash : NULL,
3732                                                    r->in.info->info18.nt_pwd_active ? r->in.info->info18.nt_pwd.hash : NULL);
3733                 if (!NT_STATUS_IS_OK(status)) {
3734                         goto done;
3735                 }
3736
3737                 if (r->in.info->info18.password_expired > 0) {
3738                         struct ldb_message_element *set_el;
3739                         if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3740                                 status = NT_STATUS_NO_MEMORY;
3741                                 goto done;
3742                         }
3743                         set_el = ldb_msg_find_element(msg, "pwdLastSet");
3744                         set_el->flags = LDB_FLAG_MOD_REPLACE;
3745                 }
3746                 break;
3747
3748         case 20:
3749                 SET_PARAMETERS(msg, info20.parameters,      "userParameters");
3750                 break;
3751
3752         case 21:
3753                 if (r->in.info->info21.fields_present == 0) {
3754                         status = NT_STATUS_INVALID_PARAMETER;
3755                         goto done;
3756                 }
3757
3758 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3759                 IFSET(SAMR_FIELD_LAST_LOGON)
3760                         SET_UINT64(msg, info21.last_logon,     "lastLogon");
3761                 IFSET(SAMR_FIELD_LAST_LOGOFF)
3762                         SET_UINT64(msg, info21.last_logoff,    "lastLogoff");
3763                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3764                         SET_UINT64(msg, info21.acct_expiry,    "accountExpires");
3765                 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3766                         SET_STRING(msg, info21.account_name,   "samAccountName");
3767                 IFSET(SAMR_FIELD_FULL_NAME)
3768                         SET_STRING(msg, info21.full_name,      "displayName");
3769                 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3770                         SET_STRING(msg, info21.home_directory, "homeDirectory");
3771                 IFSET(SAMR_FIELD_HOME_DRIVE)
3772                         SET_STRING(msg, info21.home_drive,     "homeDrive");
3773                 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3774                         SET_STRING(msg, info21.logon_script,   "scriptPath");
3775                 IFSET(SAMR_FIELD_PROFILE_PATH)
3776                         SET_STRING(msg, info21.profile_path,   "profilePath");
3777                 IFSET(SAMR_FIELD_DESCRIPTION)
3778                         SET_STRING(msg, info21.description,    "description");
3779                 IFSET(SAMR_FIELD_WORKSTATIONS)
3780                         SET_STRING(msg, info21.workstations,   "userWorkstations");
3781                 IFSET(SAMR_FIELD_COMMENT)
3782                         SET_STRING(msg, info21.comment,        "comment");
3783                 IFSET(SAMR_FIELD_PARAMETERS)
3784                         SET_PARAMETERS(msg, info21.parameters, "userParameters");
3785                 IFSET(SAMR_FIELD_PRIMARY_GID)
3786                         SET_UINT(msg, info21.primary_gid,      "primaryGroupID");
3787                 IFSET(SAMR_FIELD_ACCT_FLAGS)
3788                         SET_AFLAGS(msg, info21.acct_flags,     "userAccountControl");
3789                 IFSET(SAMR_FIELD_LOGON_HOURS)
3790                         SET_LHOURS(msg, info21.logon_hours,    "logonHours");
3791                 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3792                         SET_UINT  (msg, info21.bad_password_count, "badPwdCount");
3793                 IFSET(SAMR_FIELD_NUM_LOGONS)
3794                         SET_UINT  (msg, info21.logon_count,    "logonCount");
3795                 IFSET(SAMR_FIELD_COUNTRY_CODE)
3796                         SET_UINT  (msg, info21.country_code,   "countryCode");
3797                 IFSET(SAMR_FIELD_CODE_PAGE)
3798                         SET_UINT  (msg, info21.code_page,      "codePage");
3799
3800                 /* password change fields */
3801                 IFSET(SAMR_FIELD_LAST_PWD_CHANGE) {
3802                         status = NT_STATUS_ACCESS_DENIED;
3803                         goto done;
3804                 }
3805
3806                 IFSET((SAMR_FIELD_LM_PASSWORD_PRESENT
3807                                         | SAMR_FIELD_NT_PASSWORD_PRESENT)) {
3808                         uint8_t *lm_pwd_hash = NULL, *nt_pwd_hash = NULL;
3809
3810                         if (r->in.info->info21.lm_password_set) {
3811                                 if ((r->in.info->info21.lm_owf_password.length != 16)
3812                                  || (r->in.info->info21.lm_owf_password.size != 16)) {
3813                                         status = NT_STATUS_INVALID_PARAMETER;
3814                                         goto done;
3815                                 }
3816
3817                                 lm_pwd_hash = (uint8_t *) r->in.info->info21.lm_owf_password.array;
3818                         }
3819                         if (r->in.info->info21.nt_password_set) {
3820                                 if ((r->in.info->info21.nt_owf_password.length != 16)
3821                                  || (r->in.info->info21.nt_owf_password.size != 16)) {
3822                                         status = NT_STATUS_INVALID_PARAMETER;
3823                                         goto done;
3824                                 }
3825
3826                                 nt_pwd_hash = (uint8_t *) r->in.info->info21.nt_owf_password.array;
3827                         }
3828                         status = samr_set_password_buffers(dce_call,
3829                                                            sam_ctx,
3830                                                            a_state->account_dn,
3831                                                            mem_ctx,
3832                                                            lm_pwd_hash,
3833                                                            nt_pwd_hash);
3834                         if (!NT_STATUS_IS_OK(status)) {
3835                                 goto done;
3836                         }
3837                 }
3838
3839
3840                 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3841                         const char *t = "0";
3842                         struct ldb_message_element *set_el;
3843                         if (r->in.info->info21.password_expired
3844                                         == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3845                                 t = "-1";
3846                         }
3847                         if (ldb_msg_add_string(msg, "pwdLastSet", t) != LDB_SUCCESS) {
3848                                 status = NT_STATUS_NO_MEMORY;
3849                                 goto done;
3850                         }
3851                         set_el = ldb_msg_find_element(msg, "pwdLastSet");
3852                         set_el->flags = LDB_FLAG_MOD_REPLACE;
3853                 }
3854 #undef IFSET
3855                 break;
3856
3857         case 23:
3858                 if (r->in.info->info23.info.fields_present == 0) {
3859                         status = NT_STATUS_INVALID_PARAMETER;
3860                         goto done;
3861                 }
3862
3863 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3864                 IFSET(SAMR_FIELD_LAST_LOGON)
3865                         SET_UINT64(msg, info23.info.last_logon,     "lastLogon");
3866                 IFSET(SAMR_FIELD_LAST_LOGOFF)
3867                         SET_UINT64(msg, info23.info.last_logoff,    "lastLogoff");
3868                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3869                         SET_UINT64(msg, info23.info.acct_expiry,    "accountExpires");
3870                 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3871                         SET_STRING(msg, info23.info.account_name,   "samAccountName");
3872                 IFSET(SAMR_FIELD_FULL_NAME)
3873                         SET_STRING(msg, info23.info.full_name,      "displayName");
3874                 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3875                         SET_STRING(msg, info23.info.home_directory, "homeDirectory");
3876                 IFSET(SAMR_FIELD_HOME_DRIVE)
3877                         SET_STRING(msg, info23.info.home_drive,     "homeDrive");
3878                 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3879                         SET_STRING(msg, info23.info.logon_script,   "scriptPath");
3880                 IFSET(SAMR_FIELD_PROFILE_PATH)
3881                         SET_STRING(msg, info23.info.profile_path,   "profilePath");
3882                 IFSET(SAMR_FIELD_DESCRIPTION)
3883                         SET_STRING(msg, info23.info.description,    "description");
3884                 IFSET(SAMR_FIELD_WORKSTATIONS)
3885                         SET_STRING(msg, info23.info.workstations,   "userWorkstations");
3886                 IFSET(SAMR_FIELD_COMMENT)
3887                         SET_STRING(msg, info23.info.comment,        "comment");
3888                 IFSET(SAMR_FIELD_PARAMETERS)
3889                         SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3890                 IFSET(SAMR_FIELD_PRIMARY_GID)
3891                         SET_UINT(msg, info23.info.primary_gid,      "primaryGroupID");
3892                 IFSET(SAMR_FIELD_ACCT_FLAGS)
3893                         SET_AFLAGS(msg, info23.info.acct_flags,     "userAccountControl");
3894                 IFSET(SAMR_FIELD_LOGON_HOURS)
3895                         SET_LHOURS(msg, info23.info.logon_hours,    "logonHours");
3896                 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3897                         SET_UINT  (msg, info23.info.bad_password_count, "badPwdCount");
3898                 IFSET(SAMR_FIELD_NUM_LOGONS)
3899                         SET_UINT  (msg, info23.info.logon_count,    "logonCount");
3900
3901                 IFSET(SAMR_FIELD_COUNTRY_CODE)
3902                         SET_UINT  (msg, info23.info.country_code,   "countryCode");
3903                 IFSET(SAMR_FIELD_CODE_PAGE)
3904                         SET_UINT  (msg, info23.info.code_page,      "codePage");
3905
3906                 /* password change fields */
3907                 IFSET(SAMR_FIELD_LAST_PWD_CHANGE) {
3908                         status = NT_STATUS_ACCESS_DENIED;
3909                         goto done;
3910                 }
3911
3912                 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3913                         status = samr_set_password(dce_call,
3914                                                    sam_ctx,
3915                                                    a_state->account_dn,
3916                                                    mem_ctx,
3917                                                    &r->in.info->info23.password);
3918                 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3919                         status = samr_set_password(dce_call,
3920                                                    sam_ctx,
3921                                                    a_state->account_dn,
3922                                                    mem_ctx,
3923                                                    &r->in.info->info23.password);
3924                 }
3925                 if (!NT_STATUS_IS_OK(status)) {
3926                         goto done;
3927                 }
3928
3929                 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3930                         const char *t = "0";
3931                         struct ldb_message_element *set_el;
3932                         if (r->in.info->info23.info.password_expired
3933                                         == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3934                                 t = "-1";
3935                         }
3936                         if (ldb_msg_add_string(msg, "pwdLastSet", t) != LDB_SUCCESS) {
3937                                 status = NT_STATUS_NO_MEMORY;
3938                                 goto done;
3939                         }
3940                         set_el = ldb_msg_find_element(msg, "pwdLastSet");
3941                         set_el->flags = LDB_FLAG_MOD_REPLACE;
3942                 }
3943 #undef IFSET
3944                 break;
3945
3946                 /* the set password levels are handled separately */
3947         case 24:
3948                 status = samr_set_password(dce_call,
3949                                            sam_ctx,
3950                                            a_state->account_dn,
3951                                            mem_ctx,
3952                                            &r->in.info->info24.password);
3953                 if (!NT_STATUS_IS_OK(status)) {
3954                         goto done;
3955                 }
3956
3957                 if (r->in.info->info24.password_expired > 0) {
3958                         struct ldb_message_element *set_el;
3959                         if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3960                                 status = NT_STATUS_NO_MEMORY;
3961                                 goto done;
3962                         }
3963                         set_el = ldb_msg_find_element(msg, "pwdLastSet");
3964                         set_el->flags = LDB_FLAG_MOD_REPLACE;
3965                 }
3966                 break;
3967
3968         case 25:
3969                 if (r->in.info->info25.info.fields_present == 0) {
3970                         status = NT_STATUS_INVALID_PARAMETER;
3971                         goto done;
3972                 }
3973
3974 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3975                 IFSET(SAMR_FIELD_LAST_LOGON)
3976                         SET_UINT64(msg, info25.info.last_logon,     "lastLogon");
3977                 IFSET(SAMR_FIELD_LAST_LOGOFF)
3978                         SET_UINT64(msg, info25.info.last_logoff,    "lastLogoff");
3979                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3980                         SET_UINT64(msg, info25.info.acct_expiry,    "accountExpires");
3981                 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3982                         SET_STRING(msg, info25.info.account_name,   "samAccountName");
3983                 IFSET(SAMR_FIELD_FULL_NAME)
3984                         SET_STRING(msg, info25.info.full_name,      "displayName");
3985                 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3986                         SET_STRING(msg, info25.info.home_directory, "homeDirectory");
3987                 IFSET(SAMR_FIELD_HOME_DRIVE)
3988                         SET_STRING(msg, info25.info.home_drive,     "homeDrive");
3989                 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3990                         SET_STRING(msg, info25.info.logon_script,   "scriptPath");
3991                 IFSET(SAMR_FIELD_PROFILE_PATH)
3992                         SET_STRING(msg, info25.info.profile_path,   "profilePath");
3993                 IFSET(SAMR_FIELD_DESCRIPTION)
3994                         SET_STRING(msg, info25.info.description,    "description");
3995                 IFSET(SAMR_FIELD_WORKSTATIONS)
3996                         SET_STRING(msg, info25.info.workstations,   "userWorkstations");
3997                 IFSET(SAMR_FIELD_COMMENT)
3998                         SET_STRING(msg, info25.info.comment,        "comment");
3999                 IFSET(SAMR_FIELD_PARAMETERS)
4000                         SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
4001                 IFSET(SAMR_FIELD_PRIMARY_GID)
4002                         SET_UINT(msg, info25.info.primary_gid,      "primaryGroupID");
4003                 IFSET(SAMR_FIELD_ACCT_FLAGS)
4004                         SET_AFLAGS(msg, info25.info.acct_flags,     "userAccountControl");
4005                 IFSET(SAMR_FIELD_LOGON_HOURS)
4006                         SET_LHOURS(msg, info25.info.logon_hours,    "logonHours");
4007                 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
4008                         SET_UINT  (msg, info25.info.bad_password_count, "badPwdCount");
4009                 IFSET(SAMR_FIELD_NUM_LOGONS)
4010                         SET_UINT  (msg, info25.info.logon_count,    "logonCount");
4011                 IFSET(SAMR_FIELD_COUNTRY_CODE)
4012                         SET_UINT  (msg, info25.info.country_code,   "countryCode");
4013                 IFSET(SAMR_FIELD_CODE_PAGE)
4014                         SET_UINT  (msg, info25.info.code_page,      "codePage");
4015
4016                 /* password change fields */
4017                 IFSET(SAMR_FIELD_LAST_PWD_CHANGE) {
4018                         status = NT_STATUS_ACCESS_DENIED;
4019                         goto done;
4020                 }
4021
4022                 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
4023                         status = samr_set_password_ex(dce_call,
4024                                                       sam_ctx,
4025                                                       a_state->account_dn,
4026                                                       mem_ctx,
4027                                                       &r->in.info->info25.password);
4028                 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
4029                         status = samr_set_password_ex(dce_call,
4030                                                       sam_ctx,
4031                                                       a_state->account_dn,
4032                                                       mem_ctx,
4033                                                       &r->in.info->info25.password);
4034                 }
4035                 if (!NT_STATUS_IS_OK(status)) {
4036                         goto done;
4037                 }
4038
4039                 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
4040                         const char *t = "0";
4041                         struct ldb_message_element *set_el;
4042                         if (r->in.info->info25.info.password_expired
4043                                         == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
4044                                 t = "-1";
4045                         }
4046                         if (ldb_msg_add_string(msg, "pwdLastSet", t) != LDB_SUCCESS) {
4047                                 status = NT_STATUS_NO_MEMORY;
4048                                 goto done;
4049                         }
4050                         set_el = ldb_msg_find_element(msg, "pwdLastSet");
4051                         set_el->flags = LDB_FLAG_MOD_REPLACE;
4052                 }
4053 #undef IFSET
4054                 break;
4055
4056                 /* the set password levels are handled separately */
4057         case 26:
4058                 status = samr_set_password_ex(dce_call,
4059                                               sam_ctx,
4060                                               a_state->account_dn,
4061                                               mem_ctx,
4062                                               &r->in.info->info26.password);
4063                 if (!NT_STATUS_IS_OK(status)) {
4064                         goto done;
4065                 }
4066
4067                 if (r->in.info->info26.password_expired > 0) {
4068                         const char *t = "0";
4069                         struct ldb_message_element *set_el;
4070                         if (r->in.info->info26.password_expired
4071                                         == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
4072                                 t = "-1";
4073                         }
4074                         if (ldb_msg_add_string(msg, "pwdLastSet", t) != LDB_SUCCESS) {
4075                                 status = NT_STATUS_NO_MEMORY;
4076                                 goto done;
4077                         }
4078                         set_el = ldb_msg_find_element(msg, "pwdLastSet");
4079                         set_el->flags = LDB_FLAG_MOD_REPLACE;
4080                 }
4081                 break;
4082
4083         case 31:
4084                 status = dcesrv_transport_session_key(dce_call, &session_key);
4085                 if (!NT_STATUS_IS_OK(status)) {
4086                         DBG_NOTICE("samr: failed to get session key: %s\n",
4087                                    nt_errstr(status));
4088                         goto done;
4089                 }
4090
4091                 status = samr_set_password_aes(dce_call,
4092                                                mem_ctx,
4093                                                &session_key,
4094                                                sam_ctx,
4095                                                a_state->account_dn,
4096                                                &r->in.info->info31.password,
4097                                                DSDB_PASSWORD_RESET);
4098                 if (!NT_STATUS_IS_OK(status)) {
4099                         goto done;
4100                 }
4101
4102                 if (r->in.info->info31.password_expired > 0) {
4103                         const char *t = "0";
4104                         struct ldb_message_element *set_el = NULL;
4105
4106                         if (r->in.info->info31.password_expired ==
4107                             PASS_DONT_CHANGE_AT_NEXT_LOGON) {
4108                                 t = "-1";
4109                         }
4110
4111                         ret = ldb_msg_add_string(msg, "pwdLastSet", t);
4112                         if (ret != LDB_SUCCESS) {
4113                                 status = NT_STATUS_NO_MEMORY;
4114                                 goto done;
4115                         }
4116                         set_el = ldb_msg_find_element(msg, "pwdLastSet");
4117                         set_el->flags = LDB_FLAG_MOD_REPLACE;
4118                 }
4119
4120                 break;
4121         case 32:
4122                 status = dcesrv_transport_session_key(dce_call, &session_key);
4123                 if (!NT_STATUS_IS_OK(status)) {
4124                         DBG_NOTICE("samr: failed to get session key: %s\n",
4125                                    nt_errstr(status));
4126                         goto done;
4127                 }
4128
4129                 if (r->in.info->info32.info.fields_present == 0) {
4130                         status = NT_STATUS_INVALID_PARAMETER;
4131                         goto done;
4132                 }
4133
4134 #define IFSET(bit) if (bit & r->in.info->info32.info.fields_present)
4135                 IFSET(SAMR_FIELD_LAST_LOGON)
4136                 {
4137                         SET_UINT64(msg, info32.info.last_logon, "lastLogon");
4138                 }
4139                 IFSET(SAMR_FIELD_LAST_LOGOFF)
4140                 {
4141                         SET_UINT64(msg, info32.info.last_logoff, "lastLogoff");
4142                 }
4143                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
4144                 {
4145                         SET_UINT64(msg,
4146                                    info32.info.acct_expiry,
4147                                    "accountExpires");
4148                 }
4149                 IFSET(SAMR_FIELD_ACCOUNT_NAME)
4150                 {
4151                         SET_STRING(msg,
4152                                    info32.info.account_name,
4153                                    "samAccountName");
4154                 }
4155                 IFSET(SAMR_FIELD_FULL_NAME)
4156                 {
4157                         SET_STRING(msg, info32.info.full_name, "displayName");
4158                 }
4159                 IFSET(SAMR_FIELD_HOME_DIRECTORY)
4160                 {
4161                         SET_STRING(msg,
4162                                    info32.info.home_directory,
4163                                    "homeDirectory");
4164                 }
4165                 IFSET(SAMR_FIELD_HOME_DRIVE)
4166                 {
4167                         SET_STRING(msg, info32.info.home_drive, "homeDrive");
4168                 }
4169                 IFSET(SAMR_FIELD_LOGON_SCRIPT)
4170                 {
4171                         SET_STRING(msg, info32.info.logon_script, "scriptPath");
4172                 }
4173                 IFSET(SAMR_FIELD_PROFILE_PATH)
4174                 {
4175                         SET_STRING(msg,
4176                                    info32.info.profile_path,
4177                                    "profilePath");
4178                 }
4179                 IFSET(SAMR_FIELD_DESCRIPTION)
4180                 {
4181                         SET_STRING(msg, info32.info.description, "description");
4182                 }
4183                 IFSET(SAMR_FIELD_WORKSTATIONS)
4184                 {
4185                         SET_STRING(msg,
4186                                    info32.info.workstations,
4187                                    "userWorkstations");
4188                 }
4189                 IFSET(SAMR_FIELD_COMMENT)
4190                 {
4191                         SET_STRING(msg, info32.info.comment, "comment");
4192                 }
4193                 IFSET(SAMR_FIELD_PARAMETERS)
4194                 {
4195                         SET_PARAMETERS(msg,
4196                                        info32.info.parameters,
4197                                        "userParameters");
4198                 }
4199                 IFSET(SAMR_FIELD_PRIMARY_GID)
4200                 {
4201                         SET_UINT(msg,
4202                                  info32.info.primary_gid,
4203                                  "primaryGroupID");
4204                 }
4205                 IFSET(SAMR_FIELD_ACCT_FLAGS)
4206                 {
4207                         SET_AFLAGS(msg,
4208                                    info32.info.acct_flags,
4209                                    "userAccountControl");
4210                 }
4211                 IFSET(SAMR_FIELD_LOGON_HOURS)
4212                 {
4213                         SET_LHOURS(msg, info32.info.logon_hours, "logonHours");
4214                 }
4215                 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
4216                 {
4217                         SET_UINT(msg,
4218                                  info32.info.bad_password_count,
4219                                  "badPwdCount");
4220                 }
4221                 IFSET(SAMR_FIELD_NUM_LOGONS)
4222                 {
4223                         SET_UINT(msg, info32.info.logon_count, "logonCount");
4224                 }
4225                 IFSET(SAMR_FIELD_COUNTRY_CODE)
4226                 {
4227                         SET_UINT(msg, info32.info.country_code, "countryCode");
4228                 }
4229                 IFSET(SAMR_FIELD_CODE_PAGE)
4230                 {
4231                         SET_UINT(msg, info32.info.code_page, "codePage");
4232                 }
4233
4234                 /* password change fields */
4235                 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
4236                 {
4237                         status = NT_STATUS_ACCESS_DENIED;
4238                         goto done;
4239                 }
4240
4241                 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT)
4242                 {
4243                         status = samr_set_password_aes(
4244                                 dce_call,
4245                                 mem_ctx,
4246                                 &session_key,
4247                                 a_state->sam_ctx,
4248                                 a_state->account_dn,
4249                                 &r->in.info->info32.password,
4250                                 DSDB_PASSWORD_RESET);
4251                 }
4252                 else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT)
4253                 {
4254                         status = samr_set_password_aes(
4255                                 dce_call,
4256                                 mem_ctx,
4257                                 &session_key,
4258                                 a_state->sam_ctx,
4259                                 a_state->account_dn,
4260                                 &r->in.info->info32.password,
4261                                 DSDB_PASSWORD_RESET);
4262                 }
4263                 if (!NT_STATUS_IS_OK(status)) {
4264                         goto done;
4265                 }
4266
4267                 IFSET(SAMR_FIELD_EXPIRED_FLAG)
4268                 {
4269                         const char *t = "0";
4270                         struct ldb_message_element *set_el;
4271                         if (r->in.info->info32.info.password_expired ==
4272                             PASS_DONT_CHANGE_AT_NEXT_LOGON) {
4273                                 t = "-1";
4274                         }
4275                         if (ldb_msg_add_string(msg, "pwdLastSet", t) !=
4276                             LDB_SUCCESS) {
4277                                 status = NT_STATUS_NO_MEMORY;
4278                                 goto done;
4279                         }
4280                         set_el = ldb_msg_find_element(msg, "pwdLastSet");
4281                         set_el->flags = LDB_FLAG_MOD_REPLACE;
4282                 }
4283 #undef IFSET
4284
4285                 break;
4286         default:
4287                 /* many info classes are not valid for SetUserInfo */
4288                 status = NT_STATUS_INVALID_INFO_CLASS;
4289                 goto done;
4290         }
4291
4292         if (!NT_STATUS_IS_OK(status)) {
4293                 goto done;
4294         }
4295
4296         /* modify the samdb record */
4297         if (msg->num_elements > 0) {
4298                 ret = ldb_modify(sam_ctx, msg);
4299                 if (ret != LDB_SUCCESS) {
4300                         DEBUG(1,("Failed to modify record %s: %s\n",
4301                                  ldb_dn_get_linearized(a_state->account_dn),
4302                                  ldb_errstring(sam_ctx)));
4303
4304                         status = dsdb_ldb_err_to_ntstatus(ret);
4305                         goto done;
4306                 }
4307         }
4308
4309         ret = ldb_transaction_commit(sam_ctx);
4310         if (ret != LDB_SUCCESS) {
4311                 DBG_ERR("Failed to commit transaction modifying account record "
4312                         "%s: %s\n",
4313                         ldb_dn_get_linearized(msg->dn),
4314                         ldb_errstring(sam_ctx));
4315                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4316         }
4317
4318         status = NT_STATUS_OK;
4319 done:
4320         if (!NT_STATUS_IS_OK(status)) {
4321                 ldb_transaction_cancel(sam_ctx);
4322         }
4323
4324         return status;
4325 }
4326
4327
4328 /*
4329   samr_GetGroupsForUser
4330 */
4331 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4332                        struct samr_GetGroupsForUser *r)
4333 {
4334         struct dcesrv_handle *h;
4335         struct samr_account_state *a_state;
4336         struct samr_domain_state *d_state;
4337         struct ldb_result *res, *res_memberof;
4338         const char * const attrs[] = { "primaryGroupID",
4339                                        "memberOf",
4340                                        NULL };
4341         const char * const group_attrs[] = { "objectSid",
4342                                              NULL };
4343
4344         struct samr_RidWithAttributeArray *array;
4345         struct ldb_message_element *memberof_el;
4346         int i, ret, count = 0;
4347         uint32_t primary_group_id;
4348         char *filter;
4349
4350         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
4351
4352         a_state = h->data;
4353         d_state = a_state->domain_state;
4354
4355         ret = dsdb_search_dn(a_state->sam_ctx, mem_ctx,
4356                              &res,
4357                              a_state->account_dn,
4358                              attrs, DSDB_SEARCH_SHOW_EXTENDED_DN);
4359
4360         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
4361                 return NT_STATUS_NO_SUCH_USER;
4362         } else if (ret != LDB_SUCCESS) {
4363                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4364         } else if (res->count != 1) {
4365                 return NT_STATUS_NO_SUCH_USER;
4366         }
4367
4368         primary_group_id = ldb_msg_find_attr_as_uint(res->msgs[0], "primaryGroupID",
4369                                                      0);
4370
4371         filter = talloc_asprintf(mem_ctx,
4372                                  "(&(|(grouptype=%d)(grouptype=%d))"
4373                                  "(objectclass=group)(|",
4374                                  GTYPE_SECURITY_UNIVERSAL_GROUP,
4375                                  GTYPE_SECURITY_GLOBAL_GROUP);
4376         if (filter == NULL) {
4377                 return NT_STATUS_NO_MEMORY;
4378         }
4379
4380         memberof_el = ldb_msg_find_element(res->msgs[0], "memberOf");
4381         if (memberof_el != NULL) {
4382                 for (i = 0; i < memberof_el->num_values; i++) {
4383                         const struct ldb_val *memberof_sid_binary;
4384                         char *memberof_sid_escaped;
4385                         struct ldb_dn *memberof_dn
4386                                 = ldb_dn_from_ldb_val(mem_ctx,
4387                                                       a_state->sam_ctx,
4388                                                       &memberof_el->values[i]);
4389                         if (memberof_dn == NULL) {
4390                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4391                         }
4392
4393                         memberof_sid_binary
4394                                 = ldb_dn_get_extended_component(memberof_dn,
4395                                                                 "SID");
4396                         if (memberof_sid_binary == NULL) {
4397                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4398                         }
4399
4400                         memberof_sid_escaped = ldb_binary_encode(mem_ctx,
4401                                                                  *memberof_sid_binary);
4402                         if (memberof_sid_escaped == NULL) {
4403                                 return NT_STATUS_NO_MEMORY;
4404                         }
4405                         filter = talloc_asprintf_append(filter, "(objectSID=%s)",
4406                                                         memberof_sid_escaped);
4407                         if (filter == NULL) {
4408                                 return NT_STATUS_NO_MEMORY;
4409                         }
4410                 }
4411
4412                 ret = dsdb_search(a_state->sam_ctx, mem_ctx,
4413                                   &res_memberof,
4414                                   d_state->domain_dn,
4415                                   LDB_SCOPE_SUBTREE,
4416                                   group_attrs, 0,
4417                                   "%s))", filter);
4418
4419                 if (ret != LDB_SUCCESS) {
4420                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
4421                 }
4422                 count = res_memberof->count;
4423         }
4424
4425         array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
4426         if (array == NULL)
4427                 return NT_STATUS_NO_MEMORY;
4428
4429         array->count = 0;
4430         array->rids = NULL;
4431
4432         array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
4433                                    count + 1);
4434         if (array->rids == NULL)
4435                 return NT_STATUS_NO_MEMORY;
4436
4437         /* Adds the primary group */
4438
4439         array->rids[0].rid = primary_group_id;
4440         array->rids[0].attributes = SE_GROUP_DEFAULT_FLAGS;
4441         array->count += 1;
4442
4443         /* Adds the additional groups */
4444         for (i = 0; i < count; i++) {
4445                 struct dom_sid *group_sid;
4446
4447                 group_sid = samdb_result_dom_sid(mem_ctx,
4448                                                  res_memberof->msgs[i],
4449                                                  "objectSid");
4450                 if (group_sid == NULL) {
4451                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
4452                 }
4453
4454                 array->rids[i + 1].rid =
4455                         group_sid->sub_auths[group_sid->num_auths-1];
4456                 array->rids[i + 1].attributes = SE_GROUP_DEFAULT_FLAGS;
4457                 array->count += 1;
4458         }
4459
4460         *r->out.rids = array;
4461
4462         return NT_STATUS_OK;
4463 }
4464
4465 /*
4466  * samr_QueryDisplayInfo
4467  *
4468  * A cache of the GUID's matching the last query is maintained
4469  * in the SAMR_QUERY_DISPLAY_INFO_CACHE guid_cache maintained o
4470  * n the dcesrv_handle.
4471  */
4472 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4473                        struct samr_QueryDisplayInfo *r)
4474 {
4475         struct dcesrv_handle *h;
4476         struct samr_domain_state *d_state;
4477         struct ldb_result *res;
4478         uint32_t i;
4479         uint32_t results = 0;
4480         uint32_t count = 0;
4481         const char *const cache_attrs[] = {"objectGUID", NULL};
4482         const char *const attrs[] = {
4483             "objectSID", "sAMAccountName", "displayName", "description", NULL};
4484         struct samr_DispEntryFull *entriesFull = NULL;
4485         struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
4486         struct samr_DispEntryAscii *entriesAscii = NULL;
4487         struct samr_DispEntryGeneral *entriesGeneral = NULL;
4488         const char *filter;
4489         int ret;
4490         NTSTATUS status;
4491         struct samr_guid_cache *cache = NULL;
4492
4493         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4494
4495         d_state = h->data;
4496
4497         cache = &d_state->guid_caches[SAMR_QUERY_DISPLAY_INFO_CACHE];
4498         /*
4499          * Can the cached results be used?
4500          * The cache is discarded if the start index is zero, or the requested
4501          * level is different from that in the cache.
4502          */
4503         if ((r->in.start_idx == 0) || (r->in.level != cache->handle)) {
4504                 /*
4505                  * The cached results can not be used, so will need to query
4506                  * the database.
4507                  */
4508
4509                 /*
4510                  * Get the search filter for the current level
4511                  */
4512                 switch (r->in.level) {
4513                 case 1:
4514                 case 4:
4515                         filter = talloc_asprintf(mem_ctx,
4516                                                  "(&(objectclass=user)"
4517                                                  "(sAMAccountType=%d))",
4518                                                  ATYPE_NORMAL_ACCOUNT);
4519                         break;
4520                 case 2:
4521                         filter = talloc_asprintf(mem_ctx,
4522                                                  "(&(objectclass=user)"
4523                                                  "(sAMAccountType=%d))",
4524                                                  ATYPE_WORKSTATION_TRUST);
4525                         break;
4526                 case 3:
4527                 case 5:
4528                         filter =
4529                             talloc_asprintf(mem_ctx,
4530                                             "(&(|(groupType=%d)(groupType=%d))"
4531                                             "(objectClass=group))",
4532                                             GTYPE_SECURITY_UNIVERSAL_GROUP,
4533                                             GTYPE_SECURITY_GLOBAL_GROUP);
4534                         break;
4535                 default:
4536                         return NT_STATUS_INVALID_INFO_CLASS;
4537                 }
4538                 clear_guid_cache(cache);
4539
4540                 /*
4541                  * search for all requested objects in all domains.
4542                  */
4543                 ret = dsdb_search(d_state->sam_ctx,
4544                                   mem_ctx,
4545                                   &res,
4546                                   ldb_get_default_basedn(d_state->sam_ctx),
4547                                   LDB_SCOPE_SUBTREE,
4548                                   cache_attrs,
4549                                   0,
4550                                   "%s",
4551                                   filter);
4552                 if (ret != LDB_SUCCESS) {
4553                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
4554                 }
4555                 if ((res->count == 0) || (r->in.max_entries == 0)) {
4556                         return NT_STATUS_OK;
4557                 }
4558
4559                 status = load_guid_cache(cache, d_state, res->count, res->msgs);
4560                 TALLOC_FREE(res);
4561                 if (!NT_STATUS_IS_OK(status)) {
4562                         return status;
4563                 }
4564                 cache->handle = r->in.level;
4565         }
4566         *r->out.total_size = cache->size;
4567
4568         /*
4569          * if there are no entries or the requested start index is greater
4570          * than the number of entries, we return an empty response.
4571          */
4572         if (r->in.start_idx >= cache->size) {
4573                 *r->out.returned_size = 0;
4574                 switch(r->in.level) {
4575                 case 1:
4576                         r->out.info->info1.count = *r->out.returned_size;
4577                         r->out.info->info1.entries = NULL;
4578                         break;
4579                 case 2:
4580                         r->out.info->info2.count = *r->out.returned_size;
4581                         r->out.info->info2.entries = NULL;
4582                         break;
4583                 case 3:
4584                         r->out.info->info3.count = *r->out.returned_size;
4585                         r->out.info->info3.entries = NULL;
4586                         break;
4587                 case 4:
4588                         r->out.info->info4.count = *r->out.returned_size;
4589                         r->out.info->info4.entries = NULL;
4590                         break;
4591                 case 5:
4592                         r->out.info->info5.count = *r->out.returned_size;
4593                         r->out.info->info5.entries = NULL;
4594                         break;
4595                 }
4596                 return NT_STATUS_OK;
4597         }
4598
4599         /*
4600          * Allocate an array of the appropriate result structures for the
4601          * current query level.
4602          *
4603          * r->in.start_idx is always < cache->size due to the check above
4604          */
4605         results = MIN((cache->size - r->in.start_idx), r->in.max_entries);
4606         switch (r->in.level) {
4607         case 1:
4608                 entriesGeneral = talloc_array(
4609                     mem_ctx, struct samr_DispEntryGeneral, results);
4610                 break;
4611         case 2:
4612                 entriesFull =
4613                     talloc_array(mem_ctx, struct samr_DispEntryFull, results);
4614                 break;
4615         case 3:
4616                 entriesFullGroup = talloc_array(
4617                     mem_ctx, struct samr_DispEntryFullGroup, results);
4618                 break;
4619         case 4:
4620         case 5:
4621                 entriesAscii =
4622                     talloc_array(mem_ctx, struct samr_DispEntryAscii, results);
4623                 break;
4624         }
4625
4626         if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
4627             (entriesAscii == NULL) && (entriesFullGroup == NULL))
4628                 return NT_STATUS_NO_MEMORY;
4629
4630         /*
4631          * Process the list of result GUID's.
4632          * Read the details of each object and populate the result structure
4633          * for the current level.
4634          */
4635         count = 0;
4636         for (i = 0; i < results; i++) {
4637                 struct dom_sid *objectsid;
4638                 struct ldb_result *rec;
4639                 const uint32_t idx = r->in.start_idx + i;
4640                 uint32_t rid;
4641
4642                 /*
4643                  * Read an object from disk using the GUID as the key
4644                  *
4645                  * If the object can not be read, or it does not have a SID
4646                  * it is ignored.  In this case the number of entries returned
4647                  * will be less than the requested size, there will also be
4648                  * a gap in the idx numbers in the returned elements e.g. if
4649                  * there are 3 GUIDs a, b, c in the cache and b is deleted from
4650                  * disk then details for a, and c will be returned with
4651                  * idx values of 1 and 3 respectively.
4652                  *
4653                  */
4654                 ret = dsdb_search_by_dn_guid(d_state->sam_ctx,
4655                                              mem_ctx,
4656                                              &rec,
4657                                              &cache->entries[idx],
4658                                              attrs,
4659                                              0);
4660                 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
4661                         struct GUID_txt_buf guid_buf;
4662                         char *guid_str =
4663                                 GUID_buf_string(&cache->entries[idx],
4664                                                 &guid_buf);
4665                         DBG_WARNING("GUID [%s] not found\n", guid_str);
4666                         continue;
4667                 } else if (ret != LDB_SUCCESS) {
4668                         clear_guid_cache(cache);
4669                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
4670                 }
4671                 objectsid = samdb_result_dom_sid(mem_ctx,
4672                                                  rec->msgs[0],
4673                                                  "objectSID");
4674                 if (objectsid == NULL) {
4675                         struct GUID_txt_buf guid_buf;
4676                         DBG_WARNING(
4677                             "objectSID for GUID [%s] not found\n",
4678                             GUID_buf_string(&cache->entries[idx], &guid_buf));
4679                         continue;
4680                 }
4681                 status = dom_sid_split_rid(NULL,
4682                                            objectsid,
4683                                            NULL,
4684                                            &rid);
4685                 if (!NT_STATUS_IS_OK(status)) {
4686                         struct dom_sid_buf sid_buf;
4687                         struct GUID_txt_buf guid_buf;
4688                         DBG_WARNING(
4689                             "objectSID [%s] for GUID [%s] invalid\n",
4690                             dom_sid_str_buf(objectsid, &sid_buf),
4691                             GUID_buf_string(&cache->entries[idx], &guid_buf));
4692                         continue;
4693                 }
4694
4695                 /*
4696                  * Populate the result structure for the current object
4697                  */
4698                 switch(r->in.level) {
4699                 case 1:
4700
4701                         entriesGeneral[count].idx = idx + 1;
4702                         entriesGeneral[count].rid = rid;
4703
4704                         entriesGeneral[count].acct_flags =
4705                             samdb_result_acct_flags(rec->msgs[0], NULL);
4706                         entriesGeneral[count].account_name.string =
4707                             ldb_msg_find_attr_as_string(
4708                                 rec->msgs[0], "sAMAccountName", "");
4709                         entriesGeneral[count].full_name.string =
4710                             ldb_msg_find_attr_as_string(
4711                                 rec->msgs[0], "displayName", "");
4712                         entriesGeneral[count].description.string =
4713                             ldb_msg_find_attr_as_string(
4714                                 rec->msgs[0], "description", "");
4715                         break;
4716                 case 2:
4717                         entriesFull[count].idx = idx + 1;
4718                         entriesFull[count].rid = rid;
4719
4720                         /*
4721                          * No idea why we need to or in ACB_NORMAL here,
4722                          * but this is what Win2k3 seems to do...
4723                          */
4724                         entriesFull[count].acct_flags =
4725                             samdb_result_acct_flags(rec->msgs[0], NULL) |
4726                             ACB_NORMAL;
4727                         entriesFull[count].account_name.string =
4728                             ldb_msg_find_attr_as_string(
4729                                 rec->msgs[0], "sAMAccountName", "");
4730                         entriesFull[count].description.string =
4731                             ldb_msg_find_attr_as_string(
4732                                 rec->msgs[0], "description", "");
4733                         break;
4734                 case 3:
4735                         entriesFullGroup[count].idx = idx + 1;
4736                         entriesFullGroup[count].rid = rid;
4737
4738                         /*
4739                          * We get a "7" here for groups
4740                          */
4741                         entriesFullGroup[count].acct_flags = SE_GROUP_DEFAULT_FLAGS;
4742                         entriesFullGroup[count].account_name.string =
4743                             ldb_msg_find_attr_as_string(
4744                                 rec->msgs[0], "sAMAccountName", "");
4745                         entriesFullGroup[count].description.string =
4746                             ldb_msg_find_attr_as_string(
4747                                 rec->msgs[0], "description", "");
4748                         break;
4749                 case 4:
4750                 case 5:
4751                         entriesAscii[count].idx = idx + 1;
4752                         entriesAscii[count].account_name.string =
4753                             ldb_msg_find_attr_as_string(
4754                                 rec->msgs[0], "sAMAccountName", "");
4755                         break;
4756                 }
4757                 count++;
4758         }
4759
4760         /*
4761          * Build the response based on the request level.
4762          */
4763         *r->out.returned_size = count;
4764         switch(r->in.level) {
4765         case 1:
4766                 r->out.info->info1.count = count;
4767                 r->out.info->info1.entries = entriesGeneral;
4768                 break;
4769         case 2:
4770                 r->out.info->info2.count = count;
4771                 r->out.info->info2.entries = entriesFull;
4772                 break;
4773         case 3:
4774                 r->out.info->info3.count = count;
4775                 r->out.info->info3.entries = entriesFullGroup;
4776                 break;
4777         case 4:
4778                 r->out.info->info4.count = count;
4779                 r->out.info->info4.entries = entriesAscii;
4780                 break;
4781         case 5:
4782                 r->out.info->info5.count = count;
4783                 r->out.info->info5.entries = entriesAscii;
4784                 break;
4785         }
4786
4787         return ((r->in.start_idx + results) < cache->size)
4788                    ? STATUS_MORE_ENTRIES
4789                    : NT_STATUS_OK;
4790 }
4791
4792
4793 /*
4794   samr_GetDisplayEnumerationIndex
4795 */
4796 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4797                        struct samr_GetDisplayEnumerationIndex *r)
4798 {
4799         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4800 }
4801
4802
4803 /*
4804   samr_TestPrivateFunctionsDomain
4805 */
4806 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4807                        struct samr_TestPrivateFunctionsDomain *r)
4808 {
4809         return NT_STATUS_NOT_IMPLEMENTED;
4810 }
4811
4812
4813 /*
4814   samr_TestPrivateFunctionsUser
4815 */
4816 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4817                        struct samr_TestPrivateFunctionsUser *r)
4818 {
4819         return NT_STATUS_NOT_IMPLEMENTED;
4820 }
4821
4822
4823 /*
4824   samr_GetUserPwInfo
4825 */
4826 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4827                                    struct samr_GetUserPwInfo *r)
4828 {
4829         struct dcesrv_handle *h;
4830         struct samr_account_state *a_state;
4831
4832         ZERO_STRUCTP(r->out.info);
4833
4834         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
4835
4836         a_state = h->data;
4837
4838         r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx,
4839                 mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength",
4840                 NULL);
4841         r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx,
4842                 mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL);
4843
4844         return NT_STATUS_OK;
4845 }
4846
4847
4848 /*
4849   samr_RemoveMemberFromForeignDomain
4850 */
4851 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call,
4852                                                           TALLOC_CTX *mem_ctx,
4853                                                           struct samr_RemoveMemberFromForeignDomain *r)
4854 {
4855         struct dcesrv_handle *h;
4856         struct samr_domain_state *d_state;
4857         const char *memberdn;
4858         struct ldb_message **res;
4859         const char *no_attrs[] = { NULL };
4860         int i, count;
4861
4862         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4863
4864         d_state = h->data;
4865
4866         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
4867                                        "distinguishedName", "(objectSid=%s)",
4868                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
4869         /* Nothing to do */
4870         if (memberdn == NULL) {
4871                 return NT_STATUS_OK;
4872         }
4873
4874         count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
4875                                     d_state->domain_dn, &res, no_attrs,
4876                                     d_state->domain_sid,
4877                                     "(&(member=%s)(objectClass=group)"
4878                                     "(|(groupType=%d)(groupType=%d)))",
4879                                     memberdn,
4880                                     GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
4881                                     GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
4882
4883         if (count < 0)
4884                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4885
4886         for (i=0; i<count; i++) {
4887                 struct ldb_message *mod;
4888                 int ret;
4889
4890                 mod = ldb_msg_new(mem_ctx);
4891                 if (mod == NULL) {
4892                         return NT_STATUS_NO_MEMORY;
4893                 }
4894
4895                 mod->dn = res[i]->dn;
4896
4897                 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
4898                                          "member", memberdn) != LDB_SUCCESS)
4899                         return NT_STATUS_NO_MEMORY;
4900
4901                 ret = ldb_modify(d_state->sam_ctx, mod);
4902                 talloc_free(mod);
4903                 if (ret != LDB_SUCCESS) {
4904                         return dsdb_ldb_err_to_ntstatus(ret);
4905                 }
4906         }
4907
4908         return NT_STATUS_OK;
4909 }
4910
4911
4912 /*
4913   samr_QueryDomainInfo2
4914
4915   just an alias for samr_QueryDomainInfo
4916 */
4917 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4918                        struct samr_QueryDomainInfo2 *r)
4919 {
4920         struct samr_QueryDomainInfo r1;
4921         NTSTATUS status;
4922
4923         r1 = (struct samr_QueryDomainInfo) {
4924                 .in.domain_handle = r->in.domain_handle,
4925                 .in.level  = r->in.level,
4926                 .out.info  = r->out.info,
4927         };
4928
4929         status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
4930
4931         return status;
4932 }
4933
4934
4935 /*
4936   samr_QueryUserInfo2
4937
4938   just an alias for samr_QueryUserInfo
4939 */
4940 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4941                                     struct samr_QueryUserInfo2 *r)
4942 {
4943         struct samr_QueryUserInfo r1;
4944         NTSTATUS status;
4945
4946         r1 = (struct samr_QueryUserInfo) {
4947                 .in.user_handle = r->in.user_handle,
4948                 .in.level  = r->in.level,
4949                 .out.info  = r->out.info
4950         };
4951
4952         status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
4953
4954         return status;
4955 }
4956
4957
4958 /*
4959   samr_QueryDisplayInfo2
4960 */
4961 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4962                                        struct samr_QueryDisplayInfo2 *r)
4963 {
4964         struct samr_QueryDisplayInfo q;
4965         NTSTATUS result;
4966
4967         q = (struct samr_QueryDisplayInfo) {
4968                 .in.domain_handle = r->in.domain_handle,
4969                 .in.level = r->in.level,
4970                 .in.start_idx = r->in.start_idx,
4971                 .in.max_entries = r->in.max_entries,
4972                 .in.buf_size = r->in.buf_size,
4973                 .out.total_size = r->out.total_size,
4974                 .out.returned_size = r->out.returned_size,
4975                 .out.info = r->out.info,
4976         };
4977
4978         result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4979
4980         return result;
4981 }
4982
4983
4984 /*
4985   samr_GetDisplayEnumerationIndex2
4986 */
4987 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4988                        struct samr_GetDisplayEnumerationIndex2 *r)
4989 {
4990         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4991 }
4992
4993
4994 /*
4995   samr_QueryDisplayInfo3
4996 */
4997 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4998                        struct samr_QueryDisplayInfo3 *r)
4999 {
5000         struct samr_QueryDisplayInfo q;
5001         NTSTATUS result;
5002
5003         q = (struct samr_QueryDisplayInfo) {
5004                 .in.domain_handle = r->in.domain_handle,
5005                 .in.level = r->in.level,
5006                 .in.start_idx = r->in.start_idx,
5007                 .in.max_entries = r->in.max_entries,
5008                 .in.buf_size = r->in.buf_size,
5009                 .out.total_size = r->out.total_size,
5010                 .out.returned_size = r->out.returned_size,
5011                 .out.info = r->out.info,
5012         };
5013
5014         result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
5015
5016         return result;
5017 }
5018
5019
5020 /*
5021   samr_AddMultipleMembersToAlias
5022 */
5023 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5024                        struct samr_AddMultipleMembersToAlias *r)
5025 {
5026         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
5027 }
5028
5029
5030 /*
5031   samr_RemoveMultipleMembersFromAlias
5032 */
5033 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5034                        struct samr_RemoveMultipleMembersFromAlias *r)
5035 {
5036         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
5037 }
5038
5039
5040 /*
5041   samr_GetDomPwInfo
5042
5043   this fetches the default password properties for a domain
5044
5045   note that w2k3 completely ignores the domain name in this call, and
5046   always returns the information for the servers primary domain
5047 */
5048 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5049                                   struct samr_GetDomPwInfo *r)
5050 {
5051         struct ldb_message **msgs;
5052         int ret;
5053         const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
5054         struct ldb_context *sam_ctx;
5055
5056         ZERO_STRUCTP(r->out.info);
5057
5058         sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
5059         if (sam_ctx == NULL) {
5060                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
5061         }
5062
5063         /* The domain name in this call is ignored */
5064         ret = gendb_search_dn(sam_ctx,
5065                            mem_ctx, NULL, &msgs, attrs);
5066         if (ret <= 0) {
5067                 talloc_free(sam_ctx);
5068
5069                 return NT_STATUS_NO_SUCH_DOMAIN;
5070         }
5071         if (ret > 1) {
5072                 talloc_free(msgs);
5073                 talloc_free(sam_ctx);
5074
5075                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
5076         }
5077
5078         r->out.info->min_password_length = ldb_msg_find_attr_as_uint(msgs[0],
5079                 "minPwdLength", 0);
5080         r->out.info->password_properties = ldb_msg_find_attr_as_uint(msgs[0],
5081                 "pwdProperties", 1);
5082
5083         talloc_free(msgs);
5084         talloc_unlink(mem_ctx, sam_ctx);
5085
5086         return NT_STATUS_OK;
5087 }
5088
5089
5090 /*
5091   samr_Connect2
5092 */
5093 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5094                               struct samr_Connect2 *r)
5095 {
5096         struct samr_Connect c;
5097
5098         c = (struct samr_Connect) {
5099                 .in.system_name = NULL,
5100                 .in.access_mask = r->in.access_mask,
5101                 .out.connect_handle = r->out.connect_handle,
5102         };
5103
5104         return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
5105 }
5106
5107
5108 /*
5109   samr_SetUserInfo2
5110
5111   just an alias for samr_SetUserInfo
5112 */
5113 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5114                                   struct samr_SetUserInfo2 *r)
5115 {
5116         struct samr_SetUserInfo r2;
5117
5118         r2 = (struct samr_SetUserInfo) {
5119                 .in.user_handle = r->in.user_handle,
5120                 .in.level = r->in.level,
5121                 .in.info = r->in.info,
5122         };
5123
5124         return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
5125 }
5126
5127
5128 /*
5129   samr_SetBootKeyInformation
5130 */
5131 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5132                        struct samr_SetBootKeyInformation *r)
5133 {
5134         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
5135 }
5136
5137
5138 /*
5139   samr_GetBootKeyInformation
5140 */
5141 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5142                        struct samr_GetBootKeyInformation *r)
5143 {
5144         /* Windows Server 2008 returns this */
5145         return NT_STATUS_NOT_SUPPORTED;
5146 }
5147
5148
5149 /*
5150   samr_Connect3
5151 */
5152 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5153                        struct samr_Connect3 *r)
5154 {
5155         struct samr_Connect c;
5156
5157         c = (struct samr_Connect) {
5158                 .in.system_name = NULL,
5159                 .in.access_mask = r->in.access_mask,
5160                 .out.connect_handle = r->out.connect_handle,
5161         };
5162
5163         return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
5164 }
5165
5166
5167 /*
5168   samr_Connect4
5169 */
5170 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5171                        struct samr_Connect4 *r)
5172 {
5173         struct samr_Connect c;
5174
5175         c = (struct samr_Connect) {
5176                 .in.system_name = NULL,
5177                 .in.access_mask = r->in.access_mask,
5178                 .out.connect_handle = r->out.connect_handle,
5179         };
5180
5181         return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
5182 }
5183
5184
5185 /*
5186   samr_Connect5
5187 */
5188 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5189                               struct samr_Connect5 *r)
5190 {
5191         struct samr_Connect c;
5192         NTSTATUS status;
5193
5194         c = (struct samr_Connect) {
5195                 .in.system_name = NULL,
5196                 .in.access_mask = r->in.access_mask,
5197                 .out.connect_handle = r->out.connect_handle,
5198         };
5199
5200         status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
5201
5202         r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
5203         r->out.info_out->info1.supported_features = 0;
5204         *r->out.level_out = r->in.level_in;
5205
5206         return status;
5207 }
5208
5209
5210 /*
5211   samr_RidToSid
5212 */
5213 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5214                               struct samr_RidToSid *r)
5215 {
5216         struct samr_domain_state *d_state;
5217         struct dcesrv_handle *h;
5218
5219         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
5220
5221         d_state = h->data;
5222
5223         /* form the users SID */
5224         *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
5225         if (!*r->out.sid) {
5226                 return NT_STATUS_NO_MEMORY;
5227         }
5228
5229         return NT_STATUS_OK;
5230 }
5231
5232
5233 /*
5234   samr_SetDsrmPassword
5235 */
5236 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5237                        struct samr_SetDsrmPassword *r)
5238 {
5239         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
5240 }
5241
5242
5243 /*
5244   samr_ValidatePassword
5245
5246   For now the call checks the password complexity (if active) and the minimum
5247   password length on level 2 and 3. Level 1 is ignored for now.
5248 */
5249 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
5250                                              TALLOC_CTX *mem_ctx,
5251                                              struct samr_ValidatePassword *r)
5252 {
5253         struct samr_GetDomPwInfo r2 = {};
5254         struct samr_PwInfo pwInfo = {};
5255         const char *account = NULL;
5256         DATA_BLOB password;
5257         enum samr_ValidationStatus res;
5258         NTSTATUS status;
5259         enum dcerpc_transport_t transport =
5260                 dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description);
5261         enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
5262
5263         if (transport != NCACN_IP_TCP && transport != NCALRPC) {
5264                 DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
5265         }
5266
5267         dcesrv_call_auth_info(dce_call, NULL, &auth_level);
5268         if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
5269                 DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
5270         }
5271
5272         (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
5273
5274         r2 = (struct samr_GetDomPwInfo) {
5275                 .in.domain_name = NULL,
5276                 .out.info = &pwInfo,
5277         };
5278
5279         status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2);
5280         if (!NT_STATUS_IS_OK(status)) {
5281                 return status;
5282         }
5283
5284         switch (r->in.level) {
5285         case NetValidateAuthentication:
5286                 /* we don't support this yet */
5287                 return NT_STATUS_NOT_SUPPORTED;
5288         break;
5289         case NetValidatePasswordChange:
5290                 account = r->in.req->req2.account.string;
5291                 password = data_blob_const(r->in.req->req2.password.string,
5292                                            r->in.req->req2.password.length);
5293                 res = samdb_check_password(mem_ctx,
5294                                            dce_call->conn->dce_ctx->lp_ctx,
5295                                            account,
5296                                            NULL, /* userPrincipalName */
5297                                            NULL, /* displayName/full_name */
5298                                            &password,
5299                                            pwInfo.password_properties,
5300                                            pwInfo.min_password_length);
5301                 (*r->out.rep)->ctr2.status = res;
5302         break;
5303         case NetValidatePasswordReset:
5304                 account = r->in.req->req3.account.string;
5305                 password = data_blob_const(r->in.req->req3.password.string,
5306                                            r->in.req->req3.password.length);
5307                 res = samdb_check_password(mem_ctx,
5308                                            dce_call->conn->dce_ctx->lp_ctx,
5309                                            account,
5310                                            NULL, /* userPrincipalName */
5311                                            NULL, /* displayName/full_name */
5312                                            &password,
5313                                            pwInfo.password_properties,
5314                                            pwInfo.min_password_length);
5315                 (*r->out.rep)->ctr3.status = res;
5316         break;
5317         default:
5318                 return NT_STATUS_INVALID_INFO_CLASS;
5319         break;
5320         }
5321
5322         return NT_STATUS_OK;
5323 }
5324
5325 static void dcesrv_samr_Opnum68NotUsedOnWire(struct dcesrv_call_state *dce_call,
5326                                              TALLOC_CTX *mem_ctx,
5327                                              struct samr_Opnum68NotUsedOnWire *r)
5328 {
5329         DCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);
5330 }
5331
5332 static void dcesrv_samr_Opnum69NotUsedOnWire(struct dcesrv_call_state *dce_call,
5333                                              TALLOC_CTX *mem_ctx,
5334                                              struct samr_Opnum69NotUsedOnWire *r)
5335 {
5336         DCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);
5337 }
5338
5339 static void dcesrv_samr_Opnum70NotUsedOnWire(struct dcesrv_call_state *dce_call,
5340                                              TALLOC_CTX *mem_ctx,
5341                                              struct samr_Opnum70NotUsedOnWire *r)
5342 {
5343         DCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);
5344 }
5345
5346 static void dcesrv_samr_Opnum71NotUsedOnWire(struct dcesrv_call_state *dce_call,
5347                                              TALLOC_CTX *mem_ctx,
5348                                              struct samr_Opnum71NotUsedOnWire *r)
5349 {
5350         DCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);
5351 }
5352
5353 static void dcesrv_samr_Opnum72NotUsedOnWire(struct dcesrv_call_state *dce_call,
5354                                              TALLOC_CTX *mem_ctx,
5355                                              struct samr_Opnum72NotUsedOnWire *r)
5356 {
5357         DCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);
5358 }
5359
5360 /* include the generated boilerplate */
5361 #include "librpc/gen_ndr/ndr_samr_s.c"