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