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