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