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