b26c443fce3b1703733a126208a8476ef1ebbbb9
[sfrench/samba-autobuild/.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         char *filter;
1529         const char * const attrs[] = { "objectSid", NULL };
1530         struct ldb_message **res;
1531         uint32_t i;
1532         int count = 0;
1533         char membersidstr[DOM_SID_STR_BUFLEN];
1534
1535         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1536
1537         d_state = h->data;
1538
1539         filter = talloc_asprintf(mem_ctx,
1540                                  "(&(|(grouptype=%d)(grouptype=%d))"
1541                                  "(objectclass=group)(|",
1542                                  GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1543                                  GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1544         if (filter == NULL) {
1545                 return NT_STATUS_NO_MEMORY;
1546         }
1547
1548         for (i=0; i<r->in.sids->num_sids; i++) {
1549                 dom_sid_string_buf(r->in.sids->sids[i].sid,
1550                                    membersidstr, sizeof(membersidstr));
1551
1552                 filter = talloc_asprintf_append(filter, "(member=<SID=%s>)",
1553                                                 membersidstr);
1554                 if (filter == NULL) {
1555                         return NT_STATUS_NO_MEMORY;
1556                 }
1557         }
1558
1559         /* Find out if we had at least one valid member SID passed - otherwise
1560          * just skip the search. */
1561         if (strstr(filter, "member") != NULL) {
1562                 count = samdb_search_domain(d_state->sam_ctx, mem_ctx, NULL,
1563                                             &res, attrs, d_state->domain_sid,
1564                                             "%s))", filter);
1565                 if (count < 0) {
1566                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1567                 }
1568         }
1569
1570         r->out.rids->count = 0;
1571         r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1572         if (r->out.rids->ids == NULL)
1573                 return NT_STATUS_NO_MEMORY;
1574
1575         for (i=0; i<count; i++) {
1576                 struct dom_sid *alias_sid;
1577
1578                 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1579                 if (alias_sid == NULL) {
1580                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1581                 }
1582
1583                 r->out.rids->ids[r->out.rids->count] =
1584                         alias_sid->sub_auths[alias_sid->num_auths-1];
1585                 r->out.rids->count += 1;
1586         }
1587
1588         return NT_STATUS_OK;
1589 }
1590
1591
1592 /*
1593   samr_LookupNames
1594 */
1595 static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1596                                  struct samr_LookupNames *r)
1597 {
1598         struct dcesrv_handle *h;
1599         struct samr_domain_state *d_state;
1600         uint32_t i, num_mapped;
1601         NTSTATUS status = NT_STATUS_OK;
1602         const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1603         int count;
1604
1605         ZERO_STRUCTP(r->out.rids);
1606         ZERO_STRUCTP(r->out.types);
1607
1608         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1609
1610         d_state = h->data;
1611
1612         if (r->in.num_names == 0) {
1613                 return NT_STATUS_OK;
1614         }
1615
1616         r->out.rids->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1617         r->out.types->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1618         if (!r->out.rids->ids || !r->out.types->ids) {
1619                 return NT_STATUS_NO_MEMORY;
1620         }
1621         r->out.rids->count = r->in.num_names;
1622         r->out.types->count = r->in.num_names;
1623
1624         num_mapped = 0;
1625
1626         for (i=0;i<r->in.num_names;i++) {
1627                 struct ldb_message **res;
1628                 struct dom_sid *sid;
1629                 uint32_t atype, rtype;
1630
1631                 r->out.rids->ids[i] = 0;
1632                 r->out.types->ids[i] = SID_NAME_UNKNOWN;
1633
1634                 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
1635                                      "sAMAccountName=%s",
1636                                      ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1637                 if (count != 1) {
1638                         status = STATUS_SOME_UNMAPPED;
1639                         continue;
1640                 }
1641
1642                 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1643                 if (sid == NULL) {
1644                         status = STATUS_SOME_UNMAPPED;
1645                         continue;
1646                 }
1647
1648                 atype = ldb_msg_find_attr_as_uint(res[0], "sAMAccountType", 0);
1649                 if (atype == 0) {
1650                         status = STATUS_SOME_UNMAPPED;
1651                         continue;
1652                 }
1653
1654                 rtype = ds_atype_map(atype);
1655
1656                 if (rtype == SID_NAME_UNKNOWN) {
1657                         status = STATUS_SOME_UNMAPPED;
1658                         continue;
1659                 }
1660
1661                 r->out.rids->ids[i] = sid->sub_auths[sid->num_auths-1];
1662                 r->out.types->ids[i] = rtype;
1663                 num_mapped++;
1664         }
1665
1666         if (num_mapped == 0) {
1667                 return NT_STATUS_NONE_MAPPED;
1668         }
1669         return status;
1670 }
1671
1672
1673 /*
1674   samr_LookupRids
1675 */
1676 static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1677                        struct samr_LookupRids *r)
1678 {
1679         NTSTATUS status;
1680         struct dcesrv_handle *h;
1681         struct samr_domain_state *d_state;
1682         const char **names;
1683         struct lsa_String *lsa_names;
1684         enum lsa_SidType *ids;
1685
1686         ZERO_STRUCTP(r->out.names);
1687         ZERO_STRUCTP(r->out.types);
1688
1689         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1690
1691         d_state = h->data;
1692
1693         if (r->in.num_rids == 0)
1694                 return NT_STATUS_OK;
1695
1696         lsa_names = talloc_zero_array(mem_ctx, struct lsa_String, r->in.num_rids);
1697         names = talloc_zero_array(mem_ctx, const char *, r->in.num_rids);
1698         ids = talloc_zero_array(mem_ctx, enum lsa_SidType, r->in.num_rids);
1699
1700         if ((lsa_names == NULL) || (names == NULL) || (ids == NULL))
1701                 return NT_STATUS_NO_MEMORY;
1702
1703         r->out.names->names = lsa_names;
1704         r->out.names->count = r->in.num_rids;
1705
1706         r->out.types->ids = (uint32_t *) ids;
1707         r->out.types->count = r->in.num_rids;
1708
1709         status = dsdb_lookup_rids(d_state->sam_ctx, mem_ctx, d_state->domain_sid,
1710                                   r->in.num_rids, r->in.rids, names, ids);
1711         if (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED) || NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
1712                 uint32_t i;
1713                 for (i = 0; i < r->in.num_rids; i++) {
1714                         lsa_names[i].string = names[i];
1715                 }
1716         }
1717         return status;
1718 }
1719
1720
1721 /*
1722   samr_OpenGroup
1723 */
1724 static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1725                        struct samr_OpenGroup *r)
1726 {
1727         struct samr_domain_state *d_state;
1728         struct samr_account_state *a_state;
1729         struct dcesrv_handle *h;
1730         const char *groupname;
1731         struct dom_sid *sid;
1732         struct ldb_message **msgs;
1733         struct dcesrv_handle *g_handle;
1734         const char * const attrs[2] = { "sAMAccountName", NULL };
1735         int ret;
1736
1737         ZERO_STRUCTP(r->out.group_handle);
1738
1739         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1740
1741         d_state = h->data;
1742
1743         /* form the group SID */
1744         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1745         if (!sid) {
1746                 return NT_STATUS_NO_MEMORY;
1747         }
1748
1749         /* search for the group record */
1750         if (d_state->builtin) {
1751                 ret = gendb_search(d_state->sam_ctx,
1752                                    mem_ctx, d_state->domain_dn, &msgs, attrs,
1753                                    "(&(objectSid=%s)(objectClass=group)"
1754                                    "(groupType=%d))",
1755                                    ldap_encode_ndr_dom_sid(mem_ctx, sid),
1756                                    GTYPE_SECURITY_BUILTIN_LOCAL_GROUP);
1757         } else {
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)(groupType=%d)))",
1762                                    ldap_encode_ndr_dom_sid(mem_ctx, sid),
1763                                    GTYPE_SECURITY_UNIVERSAL_GROUP,
1764                                    GTYPE_SECURITY_GLOBAL_GROUP);
1765         }
1766         if (ret == 0) {
1767                 return NT_STATUS_NO_SUCH_GROUP;
1768         }
1769         if (ret != 1) {
1770                 DEBUG(0,("Found %d records matching sid %s\n",
1771                          ret, dom_sid_string(mem_ctx, sid)));
1772                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1773         }
1774
1775         groupname = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
1776         if (groupname == NULL) {
1777                 DEBUG(0,("sAMAccountName field missing for sid %s\n",
1778                          dom_sid_string(mem_ctx, sid)));
1779                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1780         }
1781
1782         a_state = talloc(mem_ctx, struct samr_account_state);
1783         if (!a_state) {
1784                 return NT_STATUS_NO_MEMORY;
1785         }
1786         a_state->sam_ctx = d_state->sam_ctx;
1787         a_state->access_mask = r->in.access_mask;
1788         a_state->domain_state = talloc_reference(a_state, d_state);
1789         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1790         a_state->account_sid = talloc_steal(a_state, sid);
1791         a_state->account_name = talloc_strdup(a_state, groupname);
1792         if (!a_state->account_name) {
1793                 return NT_STATUS_NO_MEMORY;
1794         }
1795
1796         /* create the policy handle */
1797         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1798         if (!g_handle) {
1799                 return NT_STATUS_NO_MEMORY;
1800         }
1801
1802         g_handle->data = talloc_steal(g_handle, a_state);
1803
1804         *r->out.group_handle = g_handle->wire_handle;
1805
1806         return NT_STATUS_OK;
1807 }
1808
1809 /*
1810   samr_QueryGroupInfo
1811 */
1812 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1813                        struct samr_QueryGroupInfo *r)
1814 {
1815         struct dcesrv_handle *h;
1816         struct samr_account_state *a_state;
1817         struct ldb_message *msg, **res;
1818         const char * const attrs[4] = { "sAMAccountName", "description",
1819                                         "numMembers", NULL };
1820         int ret;
1821         union samr_GroupInfo *info;
1822
1823         *r->out.info = NULL;
1824
1825         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1826
1827         a_state = h->data;
1828
1829         /* pull all the group attributes */
1830         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
1831                               a_state->account_dn, &res, attrs);
1832         if (ret == 0) {
1833                 return NT_STATUS_NO_SUCH_GROUP;
1834         }
1835         if (ret != 1) {
1836                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1837         }
1838         msg = res[0];
1839
1840         /* allocate the info structure */
1841         info = talloc_zero(mem_ctx, union samr_GroupInfo);
1842         if (info == NULL) {
1843                 return NT_STATUS_NO_MEMORY;
1844         }
1845
1846         /* Fill in the level */
1847         switch (r->in.level) {
1848         case GROUPINFOALL:
1849                 QUERY_STRING(msg, all.name,        "sAMAccountName");
1850                 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1851                 QUERY_UINT  (msg, all.num_members,      "numMembers")
1852                 QUERY_STRING(msg, all.description, "description");
1853                 break;
1854         case GROUPINFONAME:
1855                 QUERY_STRING(msg, name,            "sAMAccountName");
1856                 break;
1857         case GROUPINFOATTRIBUTES:
1858                 info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1859                 break;
1860         case GROUPINFODESCRIPTION:
1861                 QUERY_STRING(msg, description, "description");
1862                 break;
1863         case GROUPINFOALL2:
1864                 QUERY_STRING(msg, all2.name,        "sAMAccountName");
1865                 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1866                 QUERY_UINT  (msg, all2.num_members,      "numMembers")
1867                 QUERY_STRING(msg, all2.description, "description");
1868                 break;
1869         default:
1870                 talloc_free(info);
1871                 return NT_STATUS_INVALID_INFO_CLASS;
1872         }
1873
1874         *r->out.info = info;
1875
1876         return NT_STATUS_OK;
1877 }
1878
1879
1880 /*
1881   samr_SetGroupInfo
1882 */
1883 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1884                                   struct samr_SetGroupInfo *r)
1885 {
1886         struct dcesrv_handle *h;
1887         struct samr_account_state *g_state;
1888         struct ldb_message *msg;
1889         int ret;
1890
1891         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1892
1893         g_state = h->data;
1894
1895         msg = ldb_msg_new(mem_ctx);
1896         if (msg == NULL) {
1897                 return NT_STATUS_NO_MEMORY;
1898         }
1899
1900         msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
1901         if (!msg->dn) {
1902                 return NT_STATUS_NO_MEMORY;
1903         }
1904
1905         switch (r->in.level) {
1906         case GROUPINFODESCRIPTION:
1907                 SET_STRING(msg, description,         "description");
1908                 break;
1909         case GROUPINFONAME:
1910                 /* On W2k3 this does not change the name, it changes the
1911                  * sAMAccountName attribute */
1912                 SET_STRING(msg, name,                "sAMAccountName");
1913                 break;
1914         case GROUPINFOATTRIBUTES:
1915                 /* This does not do anything obviously visible in W2k3 LDAP */
1916                 return NT_STATUS_OK;
1917         default:
1918                 return NT_STATUS_INVALID_INFO_CLASS;
1919         }
1920
1921         /* modify the samdb record */
1922         ret = ldb_modify(g_state->sam_ctx, msg);
1923         if (ret != LDB_SUCCESS) {
1924                 return dsdb_ldb_err_to_ntstatus(ret);
1925         }
1926
1927         return NT_STATUS_OK;
1928 }
1929
1930
1931 /*
1932   samr_AddGroupMember
1933 */
1934 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1935                        struct samr_AddGroupMember *r)
1936 {
1937         struct dcesrv_handle *h;
1938         struct samr_account_state *a_state;
1939         struct samr_domain_state *d_state;
1940         struct ldb_message *mod;
1941         struct dom_sid *membersid;
1942         const char *memberdn;
1943         struct ldb_result *res;
1944         const char * const attrs[] = { NULL };
1945         int ret;
1946
1947         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1948
1949         a_state = h->data;
1950         d_state = a_state->domain_state;
1951
1952         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1953         if (membersid == NULL) {
1954                 return NT_STATUS_NO_MEMORY;
1955         }
1956
1957         /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
1958         ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
1959                          d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
1960                          "(objectSid=%s)",
1961                          ldap_encode_ndr_dom_sid(mem_ctx, membersid));
1962
1963         if (ret != LDB_SUCCESS) {
1964                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1965         }
1966
1967         if (res->count == 0) {
1968                 return NT_STATUS_NO_SUCH_USER;
1969         }
1970
1971         if (res->count > 1) {
1972                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1973         }
1974
1975         memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
1976
1977         if (memberdn == NULL)
1978                 return NT_STATUS_NO_MEMORY;
1979
1980         mod = ldb_msg_new(mem_ctx);
1981         if (mod == NULL) {
1982                 return NT_STATUS_NO_MEMORY;
1983         }
1984
1985         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
1986
1987         ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
1988                                                                 memberdn);
1989         if (ret != LDB_SUCCESS) {
1990                 return dsdb_ldb_err_to_ntstatus(ret);
1991         }
1992
1993         ret = ldb_modify(a_state->sam_ctx, mod);
1994         switch (ret) {
1995         case LDB_SUCCESS:
1996                 return NT_STATUS_OK;
1997         case LDB_ERR_ENTRY_ALREADY_EXISTS:
1998                 return NT_STATUS_MEMBER_IN_GROUP;
1999         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2000                 return NT_STATUS_ACCESS_DENIED;
2001         default:
2002                 return dsdb_ldb_err_to_ntstatus(ret);
2003         }
2004 }
2005
2006
2007 /*
2008   samr_DeleteDomainGroup
2009 */
2010 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2011                        struct samr_DeleteDomainGroup *r)
2012 {
2013         struct dcesrv_handle *h;
2014         struct samr_account_state *a_state;
2015         int ret;
2016
2017         *r->out.group_handle = *r->in.group_handle;
2018
2019         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2020
2021         a_state = h->data;
2022
2023         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2024         if (ret != LDB_SUCCESS) {
2025                 return dsdb_ldb_err_to_ntstatus(ret);
2026         }
2027
2028         talloc_free(h);
2029         ZERO_STRUCTP(r->out.group_handle);
2030
2031         return NT_STATUS_OK;
2032 }
2033
2034
2035 /*
2036   samr_DeleteGroupMember
2037 */
2038 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2039                        struct samr_DeleteGroupMember *r)
2040 {
2041         struct dcesrv_handle *h;
2042         struct samr_account_state *a_state;
2043         struct samr_domain_state *d_state;
2044         struct ldb_message *mod;
2045         struct dom_sid *membersid;
2046         const char *memberdn;
2047         struct ldb_result *res;
2048         const char * const attrs[] = { NULL };
2049         int ret;
2050
2051         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2052
2053         a_state = h->data;
2054         d_state = a_state->domain_state;
2055
2056         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2057         if (membersid == NULL) {
2058                 return NT_STATUS_NO_MEMORY;
2059         }
2060
2061         /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
2062         ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2063                          d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2064                          "(objectSid=%s)",
2065                          ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2066
2067         if (ret != LDB_SUCCESS) {
2068                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2069         }
2070
2071         if (res->count == 0) {
2072                 return NT_STATUS_NO_SUCH_USER;
2073         }
2074
2075         if (res->count > 1) {
2076                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2077         }
2078
2079         memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2080
2081         if (memberdn == NULL)
2082                 return NT_STATUS_NO_MEMORY;
2083
2084         mod = ldb_msg_new(mem_ctx);
2085         if (mod == NULL) {
2086                 return NT_STATUS_NO_MEMORY;
2087         }
2088
2089         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2090
2091         ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2092                                                                 memberdn);
2093         if (ret != LDB_SUCCESS) {
2094                 return NT_STATUS_NO_MEMORY;
2095         }
2096
2097         ret = ldb_modify(a_state->sam_ctx, mod);
2098         switch (ret) {
2099         case LDB_SUCCESS:
2100                 return NT_STATUS_OK;
2101         case LDB_ERR_UNWILLING_TO_PERFORM:
2102                 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2103         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2104                 return NT_STATUS_ACCESS_DENIED;
2105         default:
2106                 return dsdb_ldb_err_to_ntstatus(ret);
2107         }
2108 }
2109
2110
2111 /*
2112   samr_QueryGroupMember
2113 */
2114 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2115                                       struct samr_QueryGroupMember *r)
2116 {
2117         struct dcesrv_handle *h;
2118         struct samr_account_state *a_state;
2119         struct samr_domain_state *d_state;
2120         struct samr_RidAttrArray *array;
2121         unsigned int i, num_members;
2122         struct dom_sid *members;
2123         NTSTATUS status;
2124
2125         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2126
2127         a_state = h->data;
2128         d_state = a_state->domain_state;
2129
2130         status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
2131                                      a_state->account_dn, &members,
2132                                      &num_members);
2133         if (!NT_STATUS_IS_OK(status)) {
2134                 return status;
2135         }
2136
2137         array = talloc_zero(mem_ctx, struct samr_RidAttrArray);
2138         if (array == NULL) {
2139                 return NT_STATUS_NO_MEMORY;
2140         }
2141
2142         if (num_members == 0) {
2143                 *r->out.rids = array;
2144
2145                 return NT_STATUS_OK;
2146         }
2147
2148         array->rids = talloc_array(array, uint32_t, num_members);
2149         if (array->rids == NULL) {
2150                 return NT_STATUS_NO_MEMORY;
2151         }
2152
2153         array->attributes = talloc_array(array, uint32_t, num_members);
2154         if (array->attributes == NULL) {
2155                 return NT_STATUS_NO_MEMORY;
2156         }
2157
2158         array->count = 0;
2159         for (i=0; i<num_members; i++) {
2160                 if (!dom_sid_in_domain(d_state->domain_sid, &members[i])) {
2161                         continue;
2162                 }
2163
2164                 status = dom_sid_split_rid(NULL, &members[i], NULL,
2165                                            &array->rids[array->count]);
2166                 if (!NT_STATUS_IS_OK(status)) {
2167                         return status;
2168                 }
2169
2170                 array->attributes[array->count] = SE_GROUP_MANDATORY |
2171                                                   SE_GROUP_ENABLED_BY_DEFAULT |
2172                                                   SE_GROUP_ENABLED;
2173                 array->count++;
2174         }
2175
2176         *r->out.rids = array;
2177
2178         return NT_STATUS_OK;
2179 }
2180
2181
2182 /*
2183   samr_SetMemberAttributesOfGroup
2184 */
2185 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2186                        struct samr_SetMemberAttributesOfGroup *r)
2187 {
2188         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2189 }
2190
2191
2192 /*
2193   samr_OpenAlias
2194 */
2195 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2196                        struct samr_OpenAlias *r)
2197 {
2198         struct samr_domain_state *d_state;
2199         struct samr_account_state *a_state;
2200         struct dcesrv_handle *h;
2201         const char *alias_name;
2202         struct dom_sid *sid;
2203         struct ldb_message **msgs;
2204         struct dcesrv_handle *g_handle;
2205         const char * const attrs[2] = { "sAMAccountName", NULL };
2206         int ret;
2207
2208         ZERO_STRUCTP(r->out.alias_handle);
2209
2210         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2211
2212         d_state = h->data;
2213
2214         /* form the alias SID */
2215         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2216         if (sid == NULL)
2217                 return NT_STATUS_NO_MEMORY;
2218
2219         /* search for the group record */
2220         ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL, &msgs, attrs,
2221                            "(&(objectSid=%s)(objectclass=group)"
2222                            "(|(grouptype=%d)(grouptype=%d)))",
2223                            ldap_encode_ndr_dom_sid(mem_ctx, sid),
2224                            GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2225                            GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2226         if (ret == 0) {
2227                 return NT_STATUS_NO_SUCH_ALIAS;
2228         }
2229         if (ret != 1) {
2230                 DEBUG(0,("Found %d records matching sid %s\n",
2231                          ret, dom_sid_string(mem_ctx, sid)));
2232                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2233         }
2234
2235         alias_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2236         if (alias_name == NULL) {
2237                 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2238                          dom_sid_string(mem_ctx, sid)));
2239                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2240         }
2241
2242         a_state = talloc(mem_ctx, struct samr_account_state);
2243         if (!a_state) {
2244                 return NT_STATUS_NO_MEMORY;
2245         }
2246         a_state->sam_ctx = d_state->sam_ctx;
2247         a_state->access_mask = r->in.access_mask;
2248         a_state->domain_state = talloc_reference(a_state, d_state);
2249         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2250         a_state->account_sid = talloc_steal(a_state, sid);
2251         a_state->account_name = talloc_strdup(a_state, alias_name);
2252         if (!a_state->account_name) {
2253                 return NT_STATUS_NO_MEMORY;
2254         }
2255
2256         /* create the policy handle */
2257         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2258         if (!g_handle) {
2259                 return NT_STATUS_NO_MEMORY;
2260         }
2261
2262         g_handle->data = talloc_steal(g_handle, a_state);
2263
2264         *r->out.alias_handle = g_handle->wire_handle;
2265
2266         return NT_STATUS_OK;
2267 }
2268
2269
2270 /*
2271   samr_QueryAliasInfo
2272 */
2273 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2274                        struct samr_QueryAliasInfo *r)
2275 {
2276         struct dcesrv_handle *h;
2277         struct samr_account_state *a_state;
2278         struct ldb_message *msg, **res;
2279         const char * const attrs[4] = { "sAMAccountName", "description",
2280                                         "numMembers", NULL };
2281         int ret;
2282         union samr_AliasInfo *info;
2283
2284         *r->out.info = NULL;
2285
2286         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2287
2288         a_state = h->data;
2289
2290         /* pull all the alias attributes */
2291         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2292                               a_state->account_dn, &res, attrs);
2293         if (ret == 0) {
2294                 return NT_STATUS_NO_SUCH_ALIAS;
2295         }
2296         if (ret != 1) {
2297                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2298         }
2299         msg = res[0];
2300
2301         /* allocate the info structure */
2302         info = talloc_zero(mem_ctx, union samr_AliasInfo);
2303         if (info == NULL) {
2304                 return NT_STATUS_NO_MEMORY;
2305         }
2306
2307         switch(r->in.level) {
2308         case ALIASINFOALL:
2309                 QUERY_STRING(msg, all.name, "sAMAccountName");
2310                 QUERY_UINT  (msg, all.num_members, "numMembers");
2311                 QUERY_STRING(msg, all.description, "description");
2312                 break;
2313         case ALIASINFONAME:
2314                 QUERY_STRING(msg, name, "sAMAccountName");
2315                 break;
2316         case ALIASINFODESCRIPTION:
2317                 QUERY_STRING(msg, description, "description");
2318                 break;
2319         default:
2320                 talloc_free(info);
2321                 return NT_STATUS_INVALID_INFO_CLASS;
2322         }
2323
2324         *r->out.info = info;
2325
2326         return NT_STATUS_OK;
2327 }
2328
2329
2330 /*
2331   samr_SetAliasInfo
2332 */
2333 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2334                        struct samr_SetAliasInfo *r)
2335 {
2336         struct dcesrv_handle *h;
2337         struct samr_account_state *a_state;
2338         struct ldb_message *msg;
2339         int ret;
2340
2341         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2342
2343         a_state = h->data;
2344
2345         msg = ldb_msg_new(mem_ctx);
2346         if (msg == NULL) {
2347                 return NT_STATUS_NO_MEMORY;
2348         }
2349
2350         msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2351         if (!msg->dn) {
2352                 return NT_STATUS_NO_MEMORY;
2353         }
2354
2355         switch (r->in.level) {
2356         case ALIASINFODESCRIPTION:
2357                 SET_STRING(msg, description,         "description");
2358                 break;
2359         case ALIASINFONAME:
2360                 /* On W2k3 this does not change the name, it changes the
2361                  * sAMAccountName attribute */
2362                 SET_STRING(msg, name,                "sAMAccountName");
2363                 break;
2364         default:
2365                 return NT_STATUS_INVALID_INFO_CLASS;
2366         }
2367
2368         /* modify the samdb record */
2369         ret = ldb_modify(a_state->sam_ctx, msg);
2370         if (ret != LDB_SUCCESS) {
2371                 return dsdb_ldb_err_to_ntstatus(ret);
2372         }
2373
2374         return NT_STATUS_OK;
2375 }
2376
2377
2378 /*
2379   samr_DeleteDomAlias
2380 */
2381 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2382                        struct samr_DeleteDomAlias *r)
2383 {
2384         struct dcesrv_handle *h;
2385         struct samr_account_state *a_state;
2386         int ret;
2387
2388         *r->out.alias_handle = *r->in.alias_handle;
2389
2390         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2391
2392         a_state = h->data;
2393
2394         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2395         if (ret != LDB_SUCCESS) {
2396                 return dsdb_ldb_err_to_ntstatus(ret);
2397         }
2398
2399         talloc_free(h);
2400         ZERO_STRUCTP(r->out.alias_handle);
2401
2402         return NT_STATUS_OK;
2403 }
2404
2405
2406 /*
2407   samr_AddAliasMember
2408 */
2409 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2410                        struct samr_AddAliasMember *r)
2411 {
2412         struct dcesrv_handle *h;
2413         struct samr_account_state *a_state;
2414         struct samr_domain_state *d_state;
2415         struct ldb_message *mod;
2416         struct ldb_message **msgs;
2417         const char * const attrs[] = { NULL };
2418         struct ldb_dn *memberdn = NULL;
2419         int ret;
2420         NTSTATUS status;
2421
2422         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2423
2424         a_state = h->data;
2425         d_state = a_state->domain_state;
2426
2427         ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2428                            &msgs, attrs, "(objectsid=%s)",
2429                            ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2430
2431         if (ret == 1) {
2432                 memberdn = msgs[0]->dn;
2433         } else if (ret == 0) {
2434                 status = samdb_create_foreign_security_principal(
2435                         d_state->sam_ctx, mem_ctx, r->in.sid, &memberdn);
2436                 if (!NT_STATUS_IS_OK(status)) {
2437                         return status;
2438                 }
2439         } else {
2440                 DEBUG(0,("Found %d records matching sid %s\n",
2441                          ret, dom_sid_string(mem_ctx, r->in.sid)));
2442                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2443         }
2444
2445         if (memberdn == NULL) {
2446                 DEBUG(0, ("Could not find memberdn\n"));
2447                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2448         }
2449
2450         mod = ldb_msg_new(mem_ctx);
2451         if (mod == NULL) {
2452                 return NT_STATUS_NO_MEMORY;
2453         }
2454
2455         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2456
2457         ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2458                                  ldb_dn_alloc_linearized(mem_ctx, memberdn));
2459         if (ret != LDB_SUCCESS) {
2460                 return dsdb_ldb_err_to_ntstatus(ret);
2461         }
2462
2463         ret = ldb_modify(a_state->sam_ctx, mod);
2464         switch (ret) {
2465         case LDB_SUCCESS:
2466                 return NT_STATUS_OK;
2467         case LDB_ERR_ENTRY_ALREADY_EXISTS:
2468                 return NT_STATUS_MEMBER_IN_GROUP;
2469         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2470                 return NT_STATUS_ACCESS_DENIED;
2471         default:
2472                 return dsdb_ldb_err_to_ntstatus(ret);
2473         }
2474 }
2475
2476
2477 /*
2478   samr_DeleteAliasMember
2479 */
2480 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2481                        struct samr_DeleteAliasMember *r)
2482 {
2483         struct dcesrv_handle *h;
2484         struct samr_account_state *a_state;
2485         struct samr_domain_state *d_state;
2486         struct ldb_message *mod;
2487         const char *memberdn;
2488         int ret;
2489
2490         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2491
2492         a_state = h->data;
2493         d_state = a_state->domain_state;
2494
2495         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2496                                        "distinguishedName", "(objectSid=%s)",
2497                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2498         if (memberdn == NULL) {
2499                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2500         }
2501
2502         mod = ldb_msg_new(mem_ctx);
2503         if (mod == NULL) {
2504                 return NT_STATUS_NO_MEMORY;
2505         }
2506
2507         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2508
2509         ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2510                                                                  memberdn);
2511         if (ret != LDB_SUCCESS) {
2512                 return dsdb_ldb_err_to_ntstatus(ret);
2513         }
2514
2515         ret = ldb_modify(a_state->sam_ctx, mod);
2516         switch (ret) {
2517         case LDB_SUCCESS:
2518                 return NT_STATUS_OK;
2519         case LDB_ERR_UNWILLING_TO_PERFORM:
2520                 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2521         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2522                 return NT_STATUS_ACCESS_DENIED;
2523         default:
2524                 return dsdb_ldb_err_to_ntstatus(ret);
2525         }
2526 }
2527
2528
2529 /*
2530   samr_GetMembersInAlias
2531 */
2532 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2533                        struct samr_GetMembersInAlias *r)
2534 {
2535         struct dcesrv_handle *h;
2536         struct samr_account_state *a_state;
2537         struct samr_domain_state *d_state;
2538         struct lsa_SidPtr *array;
2539         unsigned int i, num_members;
2540         struct dom_sid *members;
2541         NTSTATUS status;
2542
2543         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2544
2545         a_state = h->data;
2546         d_state = a_state->domain_state;
2547
2548         status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
2549                                      a_state->account_dn, &members,
2550                                      &num_members);
2551         if (!NT_STATUS_IS_OK(status)) {
2552                 return status;
2553         }
2554
2555         if (num_members == 0) {
2556                 r->out.sids->sids = NULL;
2557
2558                 return NT_STATUS_OK;
2559         }
2560
2561         array = talloc_array(mem_ctx, struct lsa_SidPtr, num_members);
2562         if (array == NULL) {
2563                 return NT_STATUS_NO_MEMORY;
2564         }
2565
2566         for (i=0; i<num_members; i++) {
2567                 array[i].sid = &members[i];
2568         }
2569
2570         r->out.sids->num_sids = num_members;
2571         r->out.sids->sids = array;
2572
2573         return NT_STATUS_OK;
2574 }
2575
2576 /*
2577   samr_OpenUser
2578 */
2579 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2580                               struct samr_OpenUser *r)
2581 {
2582         struct samr_domain_state *d_state;
2583         struct samr_account_state *a_state;
2584         struct dcesrv_handle *h;
2585         const char *account_name;
2586         struct dom_sid *sid;
2587         struct ldb_message **msgs;
2588         struct dcesrv_handle *u_handle;
2589         const char * const attrs[2] = { "sAMAccountName", NULL };
2590         int ret;
2591
2592         ZERO_STRUCTP(r->out.user_handle);
2593
2594         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2595
2596         d_state = h->data;
2597
2598         /* form the users SID */
2599         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2600         if (!sid) {
2601                 return NT_STATUS_NO_MEMORY;
2602         }
2603
2604         /* search for the user record */
2605         ret = gendb_search(d_state->sam_ctx,
2606                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2607                            "(&(objectSid=%s)(objectclass=user))",
2608                            ldap_encode_ndr_dom_sid(mem_ctx, sid));
2609         if (ret == 0) {
2610                 return NT_STATUS_NO_SUCH_USER;
2611         }
2612         if (ret != 1) {
2613                 DEBUG(0,("Found %d records matching sid %s\n", ret,
2614                          dom_sid_string(mem_ctx, sid)));
2615                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2616         }
2617
2618         account_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2619         if (account_name == NULL) {
2620                 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2621                          dom_sid_string(mem_ctx, sid)));
2622                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2623         }
2624
2625         a_state = talloc(mem_ctx, struct samr_account_state);
2626         if (!a_state) {
2627                 return NT_STATUS_NO_MEMORY;
2628         }
2629         a_state->sam_ctx = d_state->sam_ctx;
2630         a_state->access_mask = r->in.access_mask;
2631         a_state->domain_state = talloc_reference(a_state, d_state);
2632         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2633         a_state->account_sid = talloc_steal(a_state, sid);
2634         a_state->account_name = talloc_strdup(a_state, account_name);
2635         if (!a_state->account_name) {
2636                 return NT_STATUS_NO_MEMORY;
2637         }
2638
2639         /* create the policy handle */
2640         u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2641         if (!u_handle) {
2642                 return NT_STATUS_NO_MEMORY;
2643         }
2644
2645         u_handle->data = talloc_steal(u_handle, a_state);
2646
2647         *r->out.user_handle = u_handle->wire_handle;
2648
2649         return NT_STATUS_OK;
2650
2651 }
2652
2653
2654 /*
2655   samr_DeleteUser
2656 */
2657 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2658                                 struct samr_DeleteUser *r)
2659 {
2660         struct dcesrv_handle *h;
2661         struct samr_account_state *a_state;
2662         int ret;
2663
2664         *r->out.user_handle = *r->in.user_handle;
2665
2666         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2667
2668         a_state = h->data;
2669
2670         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2671         if (ret != LDB_SUCCESS) {
2672                 DEBUG(1, ("Failed to delete user: %s: %s\n",
2673                           ldb_dn_get_linearized(a_state->account_dn),
2674                           ldb_errstring(a_state->sam_ctx)));
2675                 return dsdb_ldb_err_to_ntstatus(ret);
2676         }
2677
2678         talloc_free(h);
2679         ZERO_STRUCTP(r->out.user_handle);
2680
2681         return NT_STATUS_OK;
2682 }
2683
2684
2685 /*
2686   samr_QueryUserInfo
2687 */
2688 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2689                                    struct samr_QueryUserInfo *r)
2690 {
2691         struct dcesrv_handle *h;
2692         struct samr_account_state *a_state;
2693         struct ldb_message *msg, **res;
2694         int ret;
2695         struct ldb_context *sam_ctx;
2696
2697         const char * const *attrs = NULL;
2698         union samr_UserInfo *info;
2699
2700         NTSTATUS status;
2701
2702         *r->out.info = NULL;
2703
2704         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2705
2706         a_state = h->data;
2707         sam_ctx = a_state->sam_ctx;
2708
2709         /* fill in the reply */
2710         switch (r->in.level) {
2711         case 1:
2712         {
2713                 static const char * const attrs2[] = {"sAMAccountName",
2714                                                       "displayName",
2715                                                       "primaryGroupID",
2716                                                       "description",
2717                                                       "comment",
2718                                                       NULL};
2719                 attrs = attrs2;
2720                 break;
2721         }
2722         case 2:
2723         {
2724                 static const char * const attrs2[] = {"comment",
2725                                                       "countryCode",
2726                                                       "codePage",
2727                                                       NULL};
2728                 attrs = attrs2;
2729                 break;
2730         }
2731         case 3:
2732         {
2733                 static const char * const attrs2[] = {"sAMAccountName",
2734                                                       "displayName",
2735                                                       "objectSid",
2736                                                       "primaryGroupID",
2737                                                       "homeDirectory",
2738                                                       "homeDrive",
2739                                                       "scriptPath",
2740                                                       "profilePath",
2741                                                       "userWorkstations",
2742                                                       "lastLogon",
2743                                                       "lastLogoff",
2744                                                       "pwdLastSet",
2745                                                       "logonHours",
2746                                                       "badPwdCount",
2747                                                       "badPasswordTime",
2748                                                       "logonCount",
2749                                                       "userAccountControl",
2750                                                       "msDS-User-Account-Control-Computed",
2751                                                       NULL};
2752                 attrs = attrs2;
2753                 break;
2754         }
2755         case 4:
2756         {
2757                 static const char * const attrs2[] = {"logonHours",
2758                                                       NULL};
2759                 attrs = attrs2;
2760                 break;
2761         }
2762         case 5:
2763         {
2764                 static const char * const attrs2[] = {"sAMAccountName",
2765                                                       "displayName",
2766                                                       "objectSid",
2767                                                       "primaryGroupID",
2768                                                       "homeDirectory",
2769                                                       "homeDrive",
2770                                                       "scriptPath",
2771                                                       "profilePath",
2772                                                       "description",
2773                                                       "userWorkstations",
2774                                                       "lastLogon",
2775                                                       "lastLogoff",
2776                                                       "logonHours",
2777                                                       "badPwdCount",
2778                                                       "badPasswordTime",
2779                                                       "logonCount",
2780                                                       "pwdLastSet",
2781                                                       "accountExpires",
2782                                                       "userAccountControl",
2783                                                       "msDS-User-Account-Control-Computed",
2784                                                       NULL};
2785                 attrs = attrs2;
2786                 break;
2787         }
2788         case 6:
2789         {
2790                 static const char * const attrs2[] = {"sAMAccountName",
2791                                                       "displayName",
2792                                                       NULL};
2793                 attrs = attrs2;
2794                 break;
2795         }
2796         case 7:
2797         {
2798                 static const char * const attrs2[] = {"sAMAccountName",
2799                                                       NULL};
2800                 attrs = attrs2;
2801                 break;
2802         }
2803         case 8:
2804         {
2805                 static const char * const attrs2[] = {"displayName",
2806                                                       NULL};
2807                 attrs = attrs2;
2808                 break;
2809         }
2810         case 9:
2811         {
2812                 static const char * const attrs2[] = {"primaryGroupID",
2813                                                       NULL};
2814                 attrs = attrs2;
2815                 break;
2816         }
2817         case 10:
2818         {
2819                 static const char * const attrs2[] = {"homeDirectory",
2820                                                       "homeDrive",
2821                                                       NULL};
2822                 attrs = attrs2;
2823                 break;
2824         }
2825         case 11:
2826         {
2827                 static const char * const attrs2[] = {"scriptPath",
2828                                                       NULL};
2829                 attrs = attrs2;
2830                 break;
2831         }
2832         case 12:
2833         {
2834                 static const char * const attrs2[] = {"profilePath",
2835                                                       NULL};
2836                 attrs = attrs2;
2837                 break;
2838         }
2839         case 13:
2840         {
2841                 static const char * const attrs2[] = {"description",
2842                                                       NULL};
2843                 attrs = attrs2;
2844                 break;
2845         }
2846         case 14:
2847         {
2848                 static const char * const attrs2[] = {"userWorkstations",
2849                                                       NULL};
2850                 attrs = attrs2;
2851                 break;
2852         }
2853         case 16:
2854         {
2855                 static const char * const attrs2[] = {"userAccountControl",
2856                                                       "msDS-User-Account-Control-Computed",
2857                                                       "pwdLastSet",
2858                                                       NULL};
2859                 attrs = attrs2;
2860                 break;
2861         }
2862         case 17:
2863         {
2864                 static const char * const attrs2[] = {"accountExpires",
2865                                                       NULL};
2866                 attrs = attrs2;
2867                 break;
2868         }
2869         case 18:
2870         {
2871                 return NT_STATUS_NOT_SUPPORTED;
2872         }
2873         case 20:
2874         {
2875                 static const char * const attrs2[] = {"userParameters",
2876                                                       NULL};
2877                 attrs = attrs2;
2878                 break;
2879         }
2880         case 21:
2881         {
2882                 static const char * const attrs2[] = {"lastLogon",
2883                                                       "lastLogoff",
2884                                                       "pwdLastSet",
2885                                                       "accountExpires",
2886                                                       "sAMAccountName",
2887                                                       "displayName",
2888                                                       "homeDirectory",
2889                                                       "homeDrive",
2890                                                       "scriptPath",
2891                                                       "profilePath",
2892                                                       "description",
2893                                                       "userWorkstations",
2894                                                       "comment",
2895                                                       "userParameters",
2896                                                       "objectSid",
2897                                                       "primaryGroupID",
2898                                                       "userAccountControl",
2899                                                       "msDS-User-Account-Control-Computed",
2900                                                       "logonHours",
2901                                                       "badPwdCount",
2902                                                       "badPasswordTime",
2903                                                       "logonCount",
2904                                                       "countryCode",
2905                                                       "codePage",
2906                                                       NULL};
2907                 attrs = attrs2;
2908                 break;
2909         }
2910         case 23:
2911         case 24:
2912         case 25:
2913         case 26:
2914         {
2915                 return NT_STATUS_NOT_SUPPORTED;
2916         }
2917         default:
2918         {
2919                 return NT_STATUS_INVALID_INFO_CLASS;
2920         }
2921         }
2922
2923         /* pull all the user attributes */
2924         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2925                               a_state->account_dn, &res, attrs);
2926         if (ret == 0) {
2927                 return NT_STATUS_NO_SUCH_USER;
2928         }
2929         if (ret != 1) {
2930                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2931         }
2932         msg = res[0];
2933
2934         /* allocate the info structure */
2935         info = talloc_zero(mem_ctx, union samr_UserInfo);
2936         if (info == NULL) {
2937                 return NT_STATUS_NO_MEMORY;
2938         }
2939
2940         /* fill in the reply */
2941         switch (r->in.level) {
2942         case 1:
2943                 QUERY_STRING(msg, info1.account_name,          "sAMAccountName");
2944                 QUERY_STRING(msg, info1.full_name,             "displayName");
2945                 QUERY_UINT  (msg, info1.primary_gid,           "primaryGroupID");
2946                 QUERY_STRING(msg, info1.description,           "description");
2947                 QUERY_STRING(msg, info1.comment,               "comment");
2948                 break;
2949
2950         case 2:
2951                 QUERY_STRING(msg, info2.comment,               "comment");
2952                 QUERY_UINT  (msg, info2.country_code,          "countryCode");
2953                 QUERY_UINT  (msg, info2.code_page,             "codePage");
2954                 break;
2955
2956         case 3:
2957                 QUERY_STRING(msg, info3.account_name,          "sAMAccountName");
2958                 QUERY_STRING(msg, info3.full_name,             "displayName");
2959                 QUERY_RID   (msg, info3.rid,                   "objectSid");
2960                 QUERY_UINT  (msg, info3.primary_gid,           "primaryGroupID");
2961                 QUERY_STRING(msg, info3.home_directory,        "homeDirectory");
2962                 QUERY_STRING(msg, info3.home_drive,            "homeDrive");
2963                 QUERY_STRING(msg, info3.logon_script,          "scriptPath");
2964                 QUERY_STRING(msg, info3.profile_path,          "profilePath");
2965                 QUERY_STRING(msg, info3.workstations,          "userWorkstations");
2966                 QUERY_UINT64(msg, info3.last_logon,            "lastLogon");
2967                 QUERY_UINT64(msg, info3.last_logoff,           "lastLogoff");
2968                 QUERY_UINT64(msg, info3.last_password_change,  "pwdLastSet");
2969                 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
2970                 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
2971                 QUERY_LHOURS(msg, info3.logon_hours,           "logonHours");
2972                 /* level 3 gives the raw badPwdCount value */
2973                 QUERY_UINT  (msg, info3.bad_password_count,    "badPwdCount");
2974                 QUERY_UINT  (msg, info3.logon_count,           "logonCount");
2975                 QUERY_AFLAGS(msg, info3.acct_flags,            "msDS-User-Account-Control-Computed");
2976                 break;
2977
2978         case 4:
2979                 QUERY_LHOURS(msg, info4.logon_hours,           "logonHours");
2980                 break;
2981
2982         case 5:
2983                 QUERY_STRING(msg, info5.account_name,          "sAMAccountName");
2984                 QUERY_STRING(msg, info5.full_name,             "displayName");
2985                 QUERY_RID   (msg, info5.rid,                   "objectSid");
2986                 QUERY_UINT  (msg, info5.primary_gid,           "primaryGroupID");
2987                 QUERY_STRING(msg, info5.home_directory,        "homeDirectory");
2988                 QUERY_STRING(msg, info5.home_drive,            "homeDrive");
2989                 QUERY_STRING(msg, info5.logon_script,          "scriptPath");
2990                 QUERY_STRING(msg, info5.profile_path,          "profilePath");
2991                 QUERY_STRING(msg, info5.description,           "description");
2992                 QUERY_STRING(msg, info5.workstations,          "userWorkstations");
2993                 QUERY_UINT64(msg, info5.last_logon,            "lastLogon");
2994                 QUERY_UINT64(msg, info5.last_logoff,           "lastLogoff");
2995                 QUERY_LHOURS(msg, info5.logon_hours,           "logonHours");
2996                 QUERY_BPWDCT(msg, info5.bad_password_count,    "badPwdCount");
2997                 QUERY_UINT  (msg, info5.logon_count,           "logonCount");
2998                 QUERY_UINT64(msg, info5.last_password_change,  "pwdLastSet");
2999                 QUERY_UINT64(msg, info5.acct_expiry,           "accountExpires");
3000                 QUERY_AFLAGS(msg, info5.acct_flags,            "msDS-User-Account-Control-Computed");
3001                 break;
3002
3003         case 6:
3004                 QUERY_STRING(msg, info6.account_name,   "sAMAccountName");
3005                 QUERY_STRING(msg, info6.full_name,      "displayName");
3006                 break;
3007
3008         case 7:
3009                 QUERY_STRING(msg, info7.account_name,   "sAMAccountName");
3010                 break;
3011
3012         case 8:
3013                 QUERY_STRING(msg, info8.full_name,      "displayName");
3014                 break;
3015
3016         case 9:
3017                 QUERY_UINT  (msg, info9.primary_gid,    "primaryGroupID");
3018                 break;
3019
3020         case 10:
3021                 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3022                 QUERY_STRING(msg, info10.home_drive,    "homeDrive");
3023                 break;
3024
3025         case 11:
3026                 QUERY_STRING(msg, info11.logon_script,  "scriptPath");
3027                 break;
3028
3029         case 12:
3030                 QUERY_STRING(msg, info12.profile_path,  "profilePath");
3031                 break;
3032
3033         case 13:
3034                 QUERY_STRING(msg, info13.description,   "description");
3035                 break;
3036
3037         case 14:
3038                 QUERY_STRING(msg, info14.workstations,  "userWorkstations");
3039                 break;
3040
3041         case 16:
3042                 QUERY_AFLAGS(msg, info16.acct_flags,    "msDS-User-Account-Control-Computed");
3043                 break;
3044
3045         case 17:
3046                 QUERY_UINT64(msg, info17.acct_expiry,   "accountExpires");
3047                 break;
3048
3049         case 20:
3050                 status = samdb_result_parameters(mem_ctx, msg, "userParameters", &info->info20.parameters);
3051                 if (!NT_STATUS_IS_OK(status)) {
3052                         talloc_free(info);
3053                         return status;
3054                 }
3055                 break;
3056
3057         case 21:
3058                 QUERY_UINT64(msg, info21.last_logon,           "lastLogon");
3059                 QUERY_UINT64(msg, info21.last_logoff,          "lastLogoff");
3060                 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3061                 QUERY_UINT64(msg, info21.acct_expiry,          "accountExpires");
3062                 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3063                 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3064                 QUERY_STRING(msg, info21.account_name,         "sAMAccountName");
3065                 QUERY_STRING(msg, info21.full_name,            "displayName");
3066                 QUERY_STRING(msg, info21.home_directory,       "homeDirectory");
3067                 QUERY_STRING(msg, info21.home_drive,           "homeDrive");
3068                 QUERY_STRING(msg, info21.logon_script,         "scriptPath");
3069                 QUERY_STRING(msg, info21.profile_path,         "profilePath");
3070                 QUERY_STRING(msg, info21.description,          "description");
3071                 QUERY_STRING(msg, info21.workstations,         "userWorkstations");
3072                 QUERY_STRING(msg, info21.comment,              "comment");
3073                 status = samdb_result_parameters(mem_ctx, msg, "userParameters", &info->info21.parameters);
3074                 if (!NT_STATUS_IS_OK(status)) {
3075                         talloc_free(info);
3076                         return status;
3077                 }
3078
3079                 QUERY_RID   (msg, info21.rid,                  "objectSid");
3080                 QUERY_UINT  (msg, info21.primary_gid,          "primaryGroupID");
3081                 QUERY_AFLAGS(msg, info21.acct_flags,           "msDS-User-Account-Control-Computed");
3082                 info->info21.fields_present = 0x08FFFFFF;
3083                 QUERY_LHOURS(msg, info21.logon_hours,          "logonHours");
3084                 QUERY_BPWDCT(msg, info21.bad_password_count,   "badPwdCount");
3085                 QUERY_UINT  (msg, info21.logon_count,          "logonCount");
3086                 if ((info->info21.acct_flags & ACB_PW_EXPIRED) != 0) {
3087                         info->info21.password_expired = PASS_MUST_CHANGE_AT_NEXT_LOGON;
3088                 } else {
3089                         info->info21.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
3090                 }
3091                 QUERY_UINT  (msg, info21.country_code,         "countryCode");
3092                 QUERY_UINT  (msg, info21.code_page,            "codePage");
3093                 break;
3094
3095
3096         default:
3097                 talloc_free(info);
3098                 return NT_STATUS_INVALID_INFO_CLASS;
3099         }
3100
3101         *r->out.info = info;
3102
3103         return NT_STATUS_OK;
3104 }
3105
3106
3107 /*
3108   samr_SetUserInfo
3109 */
3110 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3111                                  struct samr_SetUserInfo *r)
3112 {
3113         struct dcesrv_handle *h;
3114         struct samr_account_state *a_state;
3115         struct ldb_message *msg;
3116         int ret;
3117         NTSTATUS status = NT_STATUS_OK;
3118         struct ldb_context *sam_ctx;
3119
3120         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3121
3122         a_state = h->data;
3123         sam_ctx = a_state->sam_ctx;
3124
3125         msg = ldb_msg_new(mem_ctx);
3126         if (msg == NULL) {
3127                 return NT_STATUS_NO_MEMORY;
3128         }
3129
3130         msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3131         if (!msg->dn) {
3132                 return NT_STATUS_NO_MEMORY;
3133         }
3134
3135         switch (r->in.level) {
3136         case 2:
3137                 SET_STRING(msg, info2.comment,          "comment");
3138                 SET_UINT  (msg, info2.country_code,     "countryCode");
3139                 SET_UINT  (msg, info2.code_page,        "codePage");
3140                 break;
3141
3142         case 4:
3143                 SET_LHOURS(msg, info4.logon_hours,      "logonHours");
3144                 break;
3145
3146         case 6:
3147                 SET_STRING(msg, info6.account_name,     "samAccountName");
3148                 SET_STRING(msg, info6.full_name,        "displayName");
3149                 break;
3150
3151         case 7:
3152                 SET_STRING(msg, info7.account_name,     "samAccountName");
3153                 break;
3154
3155         case 8:
3156                 SET_STRING(msg, info8.full_name,        "displayName");
3157                 break;
3158
3159         case 9:
3160                 SET_UINT(msg, info9.primary_gid,        "primaryGroupID");
3161                 break;
3162
3163         case 10:
3164                 SET_STRING(msg, info10.home_directory,  "homeDirectory");
3165                 SET_STRING(msg, info10.home_drive,      "homeDrive");
3166                 break;
3167
3168         case 11:
3169                 SET_STRING(msg, info11.logon_script,    "scriptPath");
3170                 break;
3171
3172         case 12:
3173                 SET_STRING(msg, info12.profile_path,    "profilePath");
3174                 break;
3175
3176         case 13:
3177                 SET_STRING(msg, info13.description,     "description");
3178                 break;
3179
3180         case 14:
3181                 SET_STRING(msg, info14.workstations,    "userWorkstations");
3182                 break;
3183
3184         case 16:
3185                 SET_AFLAGS(msg, info16.acct_flags,      "userAccountControl");
3186                 break;
3187
3188         case 17:
3189                 SET_UINT64(msg, info17.acct_expiry,     "accountExpires");
3190                 break;
3191
3192         case 18:
3193                 status = samr_set_password_buffers(dce_call,
3194                                                    a_state->sam_ctx,
3195                                                    a_state->account_dn,
3196                                                    a_state->domain_state->domain_dn,
3197                                                    mem_ctx,
3198                                                    r->in.info->info18.lm_pwd_active ? r->in.info->info18.lm_pwd.hash : NULL,
3199                                                    r->in.info->info18.nt_pwd_active ? r->in.info->info18.nt_pwd.hash : NULL);
3200                 if (!NT_STATUS_IS_OK(status)) {
3201                         return status;
3202                 }
3203
3204                 if (r->in.info->info18.password_expired > 0) {
3205                         struct ldb_message_element *set_el;
3206                         if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3207                                 return NT_STATUS_NO_MEMORY;
3208                         }
3209                         set_el = ldb_msg_find_element(msg, "pwdLastSet");
3210                         set_el->flags = LDB_FLAG_MOD_REPLACE;
3211                 }
3212                 break;
3213
3214         case 20:
3215                 SET_PARAMETERS(msg, info20.parameters,      "userParameters");
3216                 break;
3217
3218         case 21:
3219                 if (r->in.info->info21.fields_present == 0)
3220                         return NT_STATUS_INVALID_PARAMETER;
3221
3222 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3223                 IFSET(SAMR_FIELD_LAST_LOGON)
3224                         SET_UINT64(msg, info21.last_logon,     "lastLogon");
3225                 IFSET(SAMR_FIELD_LAST_LOGOFF)
3226                         SET_UINT64(msg, info21.last_logoff,    "lastLogoff");
3227                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3228                         SET_UINT64(msg, info21.acct_expiry,    "accountExpires");
3229                 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3230                         SET_STRING(msg, info21.account_name,   "samAccountName");
3231                 IFSET(SAMR_FIELD_FULL_NAME)
3232                         SET_STRING(msg, info21.full_name,      "displayName");
3233                 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3234                         SET_STRING(msg, info21.home_directory, "homeDirectory");
3235                 IFSET(SAMR_FIELD_HOME_DRIVE)
3236                         SET_STRING(msg, info21.home_drive,     "homeDrive");
3237                 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3238                         SET_STRING(msg, info21.logon_script,   "scriptPath");
3239                 IFSET(SAMR_FIELD_PROFILE_PATH)
3240                         SET_STRING(msg, info21.profile_path,   "profilePath");
3241                 IFSET(SAMR_FIELD_DESCRIPTION)
3242                         SET_STRING(msg, info21.description,    "description");
3243                 IFSET(SAMR_FIELD_WORKSTATIONS)
3244                         SET_STRING(msg, info21.workstations,   "userWorkstations");
3245                 IFSET(SAMR_FIELD_COMMENT)
3246                         SET_STRING(msg, info21.comment,        "comment");
3247                 IFSET(SAMR_FIELD_PARAMETERS)
3248                         SET_PARAMETERS(msg, info21.parameters, "userParameters");
3249                 IFSET(SAMR_FIELD_PRIMARY_GID)
3250                         SET_UINT(msg, info21.primary_gid,      "primaryGroupID");
3251                 IFSET(SAMR_FIELD_ACCT_FLAGS)
3252                         SET_AFLAGS(msg, info21.acct_flags,     "userAccountControl");
3253                 IFSET(SAMR_FIELD_LOGON_HOURS)
3254                         SET_LHOURS(msg, info21.logon_hours,    "logonHours");
3255                 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3256                         SET_UINT  (msg, info21.bad_password_count, "badPwdCount");
3257                 IFSET(SAMR_FIELD_NUM_LOGONS)
3258                         SET_UINT  (msg, info21.logon_count,    "logonCount");
3259                 IFSET(SAMR_FIELD_COUNTRY_CODE)
3260                         SET_UINT  (msg, info21.country_code,   "countryCode");
3261                 IFSET(SAMR_FIELD_CODE_PAGE)
3262                         SET_UINT  (msg, info21.code_page,      "codePage");
3263
3264                 /* password change fields */
3265                 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3266                         return NT_STATUS_ACCESS_DENIED;
3267
3268                 IFSET((SAMR_FIELD_LM_PASSWORD_PRESENT
3269                                         | SAMR_FIELD_NT_PASSWORD_PRESENT)) {
3270                         uint8_t *lm_pwd_hash = NULL, *nt_pwd_hash = NULL;
3271
3272                         if (r->in.info->info21.lm_password_set) {
3273                                 if ((r->in.info->info21.lm_owf_password.length != 16)
3274                                  || (r->in.info->info21.lm_owf_password.size != 16)) {
3275                                         return NT_STATUS_INVALID_PARAMETER;
3276                                 }
3277
3278                                 lm_pwd_hash = (uint8_t *) r->in.info->info21.lm_owf_password.array;
3279                         }
3280                         if (r->in.info->info21.nt_password_set) {
3281                                 if ((r->in.info->info21.nt_owf_password.length != 16)
3282                                  || (r->in.info->info21.nt_owf_password.size != 16)) {
3283                                         return NT_STATUS_INVALID_PARAMETER;
3284                                 }
3285
3286                                 nt_pwd_hash = (uint8_t *) r->in.info->info21.nt_owf_password.array;
3287                         }
3288                         status = samr_set_password_buffers(dce_call,
3289                                                            a_state->sam_ctx,
3290                                                            a_state->account_dn,
3291                                                            a_state->domain_state->domain_dn,
3292                                                            mem_ctx,
3293                                                            lm_pwd_hash,
3294                                                            nt_pwd_hash);
3295                         if (!NT_STATUS_IS_OK(status)) {
3296                                 return status;
3297                         }
3298                 }
3299
3300
3301                 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3302                         NTTIME t = 0;
3303                         struct ldb_message_element *set_el;
3304                         if (r->in.info->info21.password_expired
3305                                         == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3306                                 unix_to_nt_time(&t, time(NULL));
3307                         }
3308                         if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3309                                                  "pwdLastSet", t) != LDB_SUCCESS) {
3310                                 return NT_STATUS_NO_MEMORY;
3311                         }
3312                         set_el = ldb_msg_find_element(msg, "pwdLastSet");
3313                         set_el->flags = LDB_FLAG_MOD_REPLACE;
3314                 }
3315 #undef IFSET
3316                 break;
3317
3318         case 23:
3319                 if (r->in.info->info23.info.fields_present == 0)
3320                         return NT_STATUS_INVALID_PARAMETER;
3321
3322 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3323                 IFSET(SAMR_FIELD_LAST_LOGON)
3324                         SET_UINT64(msg, info23.info.last_logon,     "lastLogon");
3325                 IFSET(SAMR_FIELD_LAST_LOGOFF)
3326                         SET_UINT64(msg, info23.info.last_logoff,    "lastLogoff");
3327                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3328                         SET_UINT64(msg, info23.info.acct_expiry,    "accountExpires");
3329                 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3330                         SET_STRING(msg, info23.info.account_name,   "samAccountName");
3331                 IFSET(SAMR_FIELD_FULL_NAME)
3332                         SET_STRING(msg, info23.info.full_name,      "displayName");
3333                 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3334                         SET_STRING(msg, info23.info.home_directory, "homeDirectory");
3335                 IFSET(SAMR_FIELD_HOME_DRIVE)
3336                         SET_STRING(msg, info23.info.home_drive,     "homeDrive");
3337                 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3338                         SET_STRING(msg, info23.info.logon_script,   "scriptPath");
3339                 IFSET(SAMR_FIELD_PROFILE_PATH)
3340                         SET_STRING(msg, info23.info.profile_path,   "profilePath");
3341                 IFSET(SAMR_FIELD_DESCRIPTION)
3342                         SET_STRING(msg, info23.info.description,    "description");
3343                 IFSET(SAMR_FIELD_WORKSTATIONS)
3344                         SET_STRING(msg, info23.info.workstations,   "userWorkstations");
3345                 IFSET(SAMR_FIELD_COMMENT)
3346                         SET_STRING(msg, info23.info.comment,        "comment");
3347                 IFSET(SAMR_FIELD_PARAMETERS)
3348                         SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3349                 IFSET(SAMR_FIELD_PRIMARY_GID)
3350                         SET_UINT(msg, info23.info.primary_gid,      "primaryGroupID");
3351                 IFSET(SAMR_FIELD_ACCT_FLAGS)
3352                         SET_AFLAGS(msg, info23.info.acct_flags,     "userAccountControl");
3353                 IFSET(SAMR_FIELD_LOGON_HOURS)
3354                         SET_LHOURS(msg, info23.info.logon_hours,    "logonHours");
3355                 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3356                         SET_UINT  (msg, info23.info.bad_password_count, "badPwdCount");
3357                 IFSET(SAMR_FIELD_NUM_LOGONS)
3358                         SET_UINT  (msg, info23.info.logon_count,    "logonCount");
3359
3360                 IFSET(SAMR_FIELD_COUNTRY_CODE)
3361                         SET_UINT  (msg, info23.info.country_code,   "countryCode");
3362                 IFSET(SAMR_FIELD_CODE_PAGE)
3363                         SET_UINT  (msg, info23.info.code_page,      "codePage");
3364
3365                 /* password change fields */
3366                 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3367                         return NT_STATUS_ACCESS_DENIED;
3368
3369                 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3370                         status = samr_set_password(dce_call,
3371                                                    a_state->sam_ctx,
3372                                                    a_state->account_dn,
3373                                                    a_state->domain_state->domain_dn,
3374                                                    mem_ctx,
3375                                                    &r->in.info->info23.password);
3376                 } else IFSET(SAMR_FIELD_LM_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                 }
3384                 if (!NT_STATUS_IS_OK(status)) {
3385                         return status;
3386                 }
3387
3388                 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3389                         NTTIME t = 0;
3390                         struct ldb_message_element *set_el;
3391                         if (r->in.info->info23.info.password_expired
3392                                         == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3393                                 unix_to_nt_time(&t, time(NULL));
3394                         }
3395                         if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3396                                                  "pwdLastSet", t) != LDB_SUCCESS) {
3397                                 return NT_STATUS_NO_MEMORY;
3398                         }
3399                         set_el = ldb_msg_find_element(msg, "pwdLastSet");
3400                         set_el->flags = LDB_FLAG_MOD_REPLACE;
3401                 }
3402 #undef IFSET
3403                 break;
3404
3405                 /* the set password levels are handled separately */
3406         case 24:
3407                 status = samr_set_password(dce_call,
3408                                            a_state->sam_ctx,
3409                                            a_state->account_dn,
3410                                            a_state->domain_state->domain_dn,
3411                                            mem_ctx,
3412                                            &r->in.info->info24.password);
3413                 if (!NT_STATUS_IS_OK(status)) {
3414                         return status;
3415                 }
3416
3417                 if (r->in.info->info24.password_expired > 0) {
3418                         struct ldb_message_element *set_el;
3419                         if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3420                                 return NT_STATUS_NO_MEMORY;
3421                         }
3422                         set_el = ldb_msg_find_element(msg, "pwdLastSet");
3423                         set_el->flags = LDB_FLAG_MOD_REPLACE;
3424                 }
3425                 break;
3426
3427         case 25:
3428                 if (r->in.info->info25.info.fields_present == 0)
3429                         return NT_STATUS_INVALID_PARAMETER;
3430
3431 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3432                 IFSET(SAMR_FIELD_LAST_LOGON)
3433                         SET_UINT64(msg, info25.info.last_logon,     "lastLogon");
3434                 IFSET(SAMR_FIELD_LAST_LOGOFF)
3435                         SET_UINT64(msg, info25.info.last_logoff,    "lastLogoff");
3436                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3437                         SET_UINT64(msg, info25.info.acct_expiry,    "accountExpires");
3438                 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3439                         SET_STRING(msg, info25.info.account_name,   "samAccountName");
3440                 IFSET(SAMR_FIELD_FULL_NAME)
3441                         SET_STRING(msg, info25.info.full_name,      "displayName");
3442                 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3443                         SET_STRING(msg, info25.info.home_directory, "homeDirectory");
3444                 IFSET(SAMR_FIELD_HOME_DRIVE)
3445                         SET_STRING(msg, info25.info.home_drive,     "homeDrive");
3446                 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3447                         SET_STRING(msg, info25.info.logon_script,   "scriptPath");
3448                 IFSET(SAMR_FIELD_PROFILE_PATH)
3449                         SET_STRING(msg, info25.info.profile_path,   "profilePath");
3450                 IFSET(SAMR_FIELD_DESCRIPTION)
3451                         SET_STRING(msg, info25.info.description,    "description");
3452                 IFSET(SAMR_FIELD_WORKSTATIONS)
3453                         SET_STRING(msg, info25.info.workstations,   "userWorkstations");
3454                 IFSET(SAMR_FIELD_COMMENT)
3455                         SET_STRING(msg, info25.info.comment,        "comment");
3456                 IFSET(SAMR_FIELD_PARAMETERS)
3457                         SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
3458                 IFSET(SAMR_FIELD_PRIMARY_GID)
3459                         SET_UINT(msg, info25.info.primary_gid,      "primaryGroupID");
3460                 IFSET(SAMR_FIELD_ACCT_FLAGS)
3461                         SET_AFLAGS(msg, info25.info.acct_flags,     "userAccountControl");
3462                 IFSET(SAMR_FIELD_LOGON_HOURS)
3463                         SET_LHOURS(msg, info25.info.logon_hours,    "logonHours");
3464                 IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3465                         SET_UINT  (msg, info25.info.bad_password_count, "badPwdCount");
3466                 IFSET(SAMR_FIELD_NUM_LOGONS)
3467                         SET_UINT  (msg, info25.info.logon_count,    "logonCount");
3468                 IFSET(SAMR_FIELD_COUNTRY_CODE)
3469                         SET_UINT  (msg, info25.info.country_code,   "countryCode");
3470                 IFSET(SAMR_FIELD_CODE_PAGE)
3471                         SET_UINT  (msg, info25.info.code_page,      "codePage");
3472
3473                 /* password change fields */
3474                 IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
3475                         return NT_STATUS_ACCESS_DENIED;
3476
3477                 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3478                         status = samr_set_password_ex(dce_call,
3479                                                       a_state->sam_ctx,
3480                                                       a_state->account_dn,
3481                                                       a_state->domain_state->domain_dn,
3482                                                       mem_ctx,
3483                                                       &r->in.info->info25.password);
3484                 } else IFSET(SAMR_FIELD_LM_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                 }
3492                 if (!NT_STATUS_IS_OK(status)) {
3493                         return status;
3494                 }
3495
3496                 IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3497                         NTTIME t = 0;
3498                         struct ldb_message_element *set_el;
3499                         if (r->in.info->info25.info.password_expired
3500                                         == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3501                                 unix_to_nt_time(&t, time(NULL));
3502                         }
3503                         if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3504                                                  "pwdLastSet", t) != LDB_SUCCESS) {
3505                                 return NT_STATUS_NO_MEMORY;
3506                         }
3507                         set_el = ldb_msg_find_element(msg, "pwdLastSet");
3508                         set_el->flags = LDB_FLAG_MOD_REPLACE;
3509                 }
3510 #undef IFSET
3511                 break;
3512
3513                 /* the set password levels are handled separately */
3514         case 26:
3515                 status = samr_set_password_ex(dce_call,
3516                                               a_state->sam_ctx,
3517                                               a_state->account_dn,
3518                                               a_state->domain_state->domain_dn,
3519                                               mem_ctx,
3520                                               &r->in.info->info26.password);
3521                 if (!NT_STATUS_IS_OK(status)) {
3522                         return status;
3523                 }
3524
3525                 if (r->in.info->info26.password_expired > 0) {
3526                         NTTIME t = 0;
3527                         struct ldb_message_element *set_el;
3528                         if (r->in.info->info26.password_expired
3529                                         == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3530                                 unix_to_nt_time(&t, time(NULL));
3531                         }
3532                         if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg,
3533                                                  "pwdLastSet", t) != LDB_SUCCESS) {
3534                                 return NT_STATUS_NO_MEMORY;
3535                         }
3536                         set_el = ldb_msg_find_element(msg, "pwdLastSet");
3537                         set_el->flags = LDB_FLAG_MOD_REPLACE;
3538                 }
3539                 break;
3540
3541         default:
3542                 /* many info classes are not valid for SetUserInfo */
3543                 return NT_STATUS_INVALID_INFO_CLASS;
3544         }
3545
3546         if (!NT_STATUS_IS_OK(status)) {
3547                 return status;
3548         }
3549
3550         /* modify the samdb record */
3551         if (msg->num_elements > 0) {
3552                 ret = ldb_modify(a_state->sam_ctx, msg);
3553                 if (ret != LDB_SUCCESS) {
3554                         DEBUG(1,("Failed to modify record %s: %s\n",
3555                                  ldb_dn_get_linearized(a_state->account_dn),
3556                                  ldb_errstring(a_state->sam_ctx)));
3557
3558                         return dsdb_ldb_err_to_ntstatus(ret);
3559                 }
3560         }
3561
3562         return NT_STATUS_OK;
3563 }
3564
3565
3566 /*
3567   samr_GetGroupsForUser
3568 */
3569 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3570                        struct samr_GetGroupsForUser *r)
3571 {
3572         struct dcesrv_handle *h;
3573         struct samr_account_state *a_state;
3574         struct samr_domain_state *d_state;
3575         struct ldb_message **res;
3576         const char * const attrs[2] = { "objectSid", NULL };
3577         struct samr_RidWithAttributeArray *array;
3578         int i, count;
3579         char membersidstr[DOM_SID_STR_BUFLEN];
3580
3581         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3582
3583         a_state = h->data;
3584         d_state = a_state->domain_state;
3585
3586         dom_sid_string_buf(a_state->account_sid,
3587                            membersidstr, sizeof(membersidstr)),
3588
3589         count = samdb_search_domain(a_state->sam_ctx, mem_ctx,
3590                                     d_state->domain_dn, &res,
3591                                     attrs, d_state->domain_sid,
3592                                     "(&(member=<SID=%s>)"
3593                                      "(|(grouptype=%d)(grouptype=%d))"
3594                                      "(objectclass=group))",
3595                                     membersidstr,
3596                                     GTYPE_SECURITY_UNIVERSAL_GROUP,
3597                                     GTYPE_SECURITY_GLOBAL_GROUP);
3598         if (count < 0)
3599                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3600
3601         array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3602         if (array == NULL)
3603                 return NT_STATUS_NO_MEMORY;
3604
3605         array->count = 0;
3606         array->rids = NULL;
3607
3608         array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3609                                             count + 1);
3610         if (array->rids == NULL)
3611                 return NT_STATUS_NO_MEMORY;
3612
3613         /* Adds the primary group */
3614         array->rids[0].rid = samdb_search_uint(a_state->sam_ctx, mem_ctx,
3615                                                ~0, a_state->account_dn,
3616                                                "primaryGroupID", NULL);
3617         array->rids[0].attributes = SE_GROUP_MANDATORY
3618                         | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3619         array->count += 1;
3620
3621         /* Adds the additional groups */
3622         for (i = 0; i < count; i++) {
3623                 struct dom_sid *group_sid;
3624
3625                 group_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
3626                 if (group_sid == NULL) {
3627                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
3628                 }
3629
3630                 array->rids[i + 1].rid =
3631                         group_sid->sub_auths[group_sid->num_auths-1];
3632                 array->rids[i + 1].attributes = SE_GROUP_MANDATORY
3633                         | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3634                 array->count += 1;
3635         }
3636
3637         *r->out.rids = array;
3638
3639         return NT_STATUS_OK;
3640 }
3641
3642
3643 /*
3644   samr_QueryDisplayInfo
3645 */
3646 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3647                        struct samr_QueryDisplayInfo *r)
3648 {
3649         struct dcesrv_handle *h;
3650         struct samr_domain_state *d_state;
3651         struct ldb_result *res;
3652         unsigned int i;
3653         uint32_t count;
3654         const char * const attrs[] = { "objectSid", "sAMAccountName",
3655                 "displayName", "description", "userAccountControl",
3656                 "pwdLastSet", NULL };
3657         struct samr_DispEntryFull *entriesFull = NULL;
3658         struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3659         struct samr_DispEntryAscii *entriesAscii = NULL;
3660         struct samr_DispEntryGeneral *entriesGeneral = NULL;
3661         const char *filter;
3662         int ret;
3663
3664         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3665
3666         d_state = h->data;
3667
3668         switch (r->in.level) {
3669         case 1:
3670         case 4:
3671                 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3672                                          "(sAMAccountType=%d))",
3673                                          ATYPE_NORMAL_ACCOUNT);
3674                 break;
3675         case 2:
3676                 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3677                                          "(sAMAccountType=%d))",
3678                                          ATYPE_WORKSTATION_TRUST);
3679                 break;
3680         case 3:
3681         case 5:
3682                 filter = talloc_asprintf(mem_ctx,
3683                                          "(&(|(groupType=%d)(groupType=%d))"
3684                                          "(objectClass=group))",
3685                                          GTYPE_SECURITY_UNIVERSAL_GROUP,
3686                                          GTYPE_SECURITY_GLOBAL_GROUP);
3687                 break;
3688         default:
3689                 return NT_STATUS_INVALID_INFO_CLASS;
3690         }
3691
3692         /* search for all requested objects in all domains. This could
3693            possibly be cached and resumed based on resume_key */
3694         ret = dsdb_search(d_state->sam_ctx, mem_ctx, &res, ldb_get_default_basedn(d_state->sam_ctx),
3695                           LDB_SCOPE_SUBTREE, attrs, 0, "%s", filter);
3696         if (ret != LDB_SUCCESS) {
3697                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3698         }
3699         if ((res->count == 0) || (r->in.max_entries == 0)) {
3700                 return NT_STATUS_OK;
3701         }
3702
3703         switch (r->in.level) {
3704         case 1:
3705                 entriesGeneral = talloc_array(mem_ctx,
3706                                               struct samr_DispEntryGeneral,
3707                                               res->count);
3708                 break;
3709         case 2:
3710                 entriesFull = talloc_array(mem_ctx,
3711                                            struct samr_DispEntryFull,
3712                                            res->count);
3713                 break;
3714         case 3:
3715                 entriesFullGroup = talloc_array(mem_ctx,
3716                                                 struct samr_DispEntryFullGroup,
3717                                                 res->count);
3718                 break;
3719         case 4:
3720         case 5:
3721                 entriesAscii = talloc_array(mem_ctx,
3722                                             struct samr_DispEntryAscii,
3723                                             res->count);
3724                 break;
3725         }
3726
3727         if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3728             (entriesAscii == NULL) && (entriesFullGroup == NULL))
3729                 return NT_STATUS_NO_MEMORY;
3730
3731         count = 0;
3732
3733         for (i = 0; i < res->count; i++) {
3734                 struct dom_sid *objectsid;
3735
3736                 objectsid = samdb_result_dom_sid(mem_ctx, res->msgs[i],
3737                                                  "objectSid");
3738                 if (objectsid == NULL)
3739                         continue;
3740
3741                 switch(r->in.level) {
3742                 case 1:
3743                         entriesGeneral[count].idx = count + 1;
3744                         entriesGeneral[count].rid =
3745                                 objectsid->sub_auths[objectsid->num_auths-1];
3746                         entriesGeneral[count].acct_flags =
3747                                 samdb_result_acct_flags(res->msgs[i], NULL);
3748                         entriesGeneral[count].account_name.string =
3749                                 ldb_msg_find_attr_as_string(res->msgs[i],
3750                                                             "sAMAccountName", "");
3751                         entriesGeneral[count].full_name.string =
3752                                 ldb_msg_find_attr_as_string(res->msgs[i],
3753                                                             "displayName", "");
3754                         entriesGeneral[count].description.string =
3755                                 ldb_msg_find_attr_as_string(res->msgs[i],
3756                                                             "description", "");
3757                         break;
3758                 case 2:
3759                         entriesFull[count].idx = count + 1;
3760                         entriesFull[count].rid =
3761                                 objectsid->sub_auths[objectsid->num_auths-1];
3762
3763                         /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3764                         entriesFull[count].acct_flags =
3765                                 samdb_result_acct_flags(res->msgs[i],
3766                                                         NULL) | ACB_NORMAL;
3767                         entriesFull[count].account_name.string =
3768                                 ldb_msg_find_attr_as_string(res->msgs[i],
3769                                                             "sAMAccountName", "");
3770                         entriesFull[count].description.string =
3771                                 ldb_msg_find_attr_as_string(res->msgs[i],
3772                                                             "description", "");
3773                         break;
3774                 case 3:
3775                         entriesFullGroup[count].idx = count + 1;
3776                         entriesFullGroup[count].rid =
3777                                 objectsid->sub_auths[objectsid->num_auths-1];
3778                         /* We get a "7" here for groups */
3779                         entriesFullGroup[count].acct_flags
3780                                 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3781                         entriesFullGroup[count].account_name.string =
3782                                 ldb_msg_find_attr_as_string(res->msgs[i],
3783                                                             "sAMAccountName", "");
3784                         entriesFullGroup[count].description.string =
3785                                 ldb_msg_find_attr_as_string(res->msgs[i],
3786                                                             "description", "");
3787                         break;
3788                 case 4:
3789                 case 5:
3790                         entriesAscii[count].idx = count + 1;
3791                         entriesAscii[count].account_name.string =
3792                                 ldb_msg_find_attr_as_string(res->msgs[i],
3793                                                             "sAMAccountName", "");
3794                         break;
3795                 }
3796
3797                 count += 1;
3798         }
3799
3800         *r->out.total_size = count;
3801
3802         if (r->in.start_idx >= count) {
3803                 *r->out.returned_size = 0;
3804                 switch(r->in.level) {
3805                 case 1:
3806                         r->out.info->info1.count = *r->out.returned_size;
3807                         r->out.info->info1.entries = NULL;
3808                         break;
3809                 case 2:
3810                         r->out.info->info2.count = *r->out.returned_size;
3811                         r->out.info->info2.entries = NULL;
3812                         break;
3813                 case 3:
3814                         r->out.info->info3.count = *r->out.returned_size;
3815                         r->out.info->info3.entries = NULL;
3816                         break;
3817                 case 4:
3818                         r->out.info->info4.count = *r->out.returned_size;
3819                         r->out.info->info4.entries = NULL;
3820                         break;
3821                 case 5:
3822                         r->out.info->info5.count = *r->out.returned_size;
3823                         r->out.info->info5.entries = NULL;
3824                         break;
3825                 }
3826         } else {
3827                 *r->out.returned_size = MIN(count - r->in.start_idx,
3828                                            r->in.max_entries);
3829                 switch(r->in.level) {
3830                 case 1:
3831                         r->out.info->info1.count = *r->out.returned_size;
3832                         r->out.info->info1.entries =
3833                                 &(entriesGeneral[r->in.start_idx]);
3834                         break;
3835                 case 2:
3836                         r->out.info->info2.count = *r->out.returned_size;
3837                         r->out.info->info2.entries =
3838                                 &(entriesFull[r->in.start_idx]);
3839                         break;
3840                 case 3:
3841                         r->out.info->info3.count = *r->out.returned_size;
3842                         r->out.info->info3.entries =
3843                                 &(entriesFullGroup[r->in.start_idx]);
3844                         break;
3845                 case 4:
3846                         r->out.info->info4.count = *r->out.returned_size;
3847                         r->out.info->info4.entries =
3848                                 &(entriesAscii[r->in.start_idx]);
3849                         break;
3850                 case 5:
3851                         r->out.info->info5.count = *r->out.returned_size;
3852                         r->out.info->info5.entries =
3853                                 &(entriesAscii[r->in.start_idx]);
3854                         break;
3855                 }
3856         }
3857
3858         return (*r->out.returned_size < (count - r->in.start_idx)) ?
3859                 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3860 }
3861
3862
3863 /*
3864   samr_GetDisplayEnumerationIndex
3865 */
3866 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3867                        struct samr_GetDisplayEnumerationIndex *r)
3868 {
3869         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3870 }
3871
3872
3873 /*
3874   samr_TestPrivateFunctionsDomain
3875 */
3876 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3877                        struct samr_TestPrivateFunctionsDomain *r)
3878 {
3879         return NT_STATUS_NOT_IMPLEMENTED;
3880 }
3881
3882
3883 /*
3884   samr_TestPrivateFunctionsUser
3885 */
3886 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3887                        struct samr_TestPrivateFunctionsUser *r)
3888 {
3889         return NT_STATUS_NOT_IMPLEMENTED;
3890 }
3891
3892
3893 /*
3894   samr_GetUserPwInfo
3895 */
3896 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3897                                    struct samr_GetUserPwInfo *r)
3898 {
3899         struct dcesrv_handle *h;
3900         struct samr_account_state *a_state;
3901
3902         ZERO_STRUCTP(r->out.info);
3903
3904         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3905
3906         a_state = h->data;
3907
3908         r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx,
3909                 mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength",
3910                 NULL);
3911         r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx,
3912                 mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL);
3913
3914         return NT_STATUS_OK;
3915 }
3916
3917
3918 /*
3919   samr_RemoveMemberFromForeignDomain
3920 */
3921 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call,
3922                                                           TALLOC_CTX *mem_ctx,
3923                                                           struct samr_RemoveMemberFromForeignDomain *r)
3924 {
3925         struct dcesrv_handle *h;
3926         struct samr_domain_state *d_state;
3927         const char *memberdn;
3928         struct ldb_message **res;
3929         const char *no_attrs[] = { NULL };
3930         int i, count;
3931
3932         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3933
3934         d_state = h->data;
3935
3936         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3937                                        "distinguishedName", "(objectSid=%s)",
3938                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3939         /* Nothing to do */
3940         if (memberdn == NULL) {
3941                 return NT_STATUS_OK;
3942         }
3943
3944         count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3945                                     d_state->domain_dn, &res, no_attrs,
3946                                     d_state->domain_sid,
3947                                     "(&(member=%s)(objectClass=group)"
3948                                     "(|(groupType=%d)(groupType=%d)))",
3949                                     memberdn,
3950                                     GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
3951                                     GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
3952
3953         if (count < 0)
3954                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3955
3956         for (i=0; i<count; i++) {
3957                 struct ldb_message *mod;
3958                 int ret;
3959
3960                 mod = ldb_msg_new(mem_ctx);
3961                 if (mod == NULL) {
3962                         return NT_STATUS_NO_MEMORY;
3963                 }
3964
3965                 mod->dn = res[i]->dn;
3966
3967                 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
3968                                          "member", memberdn) != LDB_SUCCESS)
3969                         return NT_STATUS_NO_MEMORY;
3970
3971                 ret = ldb_modify(d_state->sam_ctx, mod);
3972                 talloc_free(mod);
3973                 if (ret != LDB_SUCCESS) {
3974                         return dsdb_ldb_err_to_ntstatus(ret);
3975                 }
3976         }
3977
3978         return NT_STATUS_OK;
3979 }
3980
3981
3982 /*
3983   samr_QueryDomainInfo2
3984
3985   just an alias for samr_QueryDomainInfo
3986 */
3987 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3988                        struct samr_QueryDomainInfo2 *r)
3989 {
3990         struct samr_QueryDomainInfo r1;
3991         NTSTATUS status;
3992
3993         ZERO_STRUCT(r1.out);
3994         r1.in.domain_handle = r->in.domain_handle;
3995         r1.in.level  = r->in.level;
3996         r1.out.info  = r->out.info;
3997
3998         status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
3999
4000         return status;
4001 }
4002
4003
4004 /*
4005   samr_QueryUserInfo2
4006
4007   just an alias for samr_QueryUserInfo
4008 */
4009 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4010                                     struct samr_QueryUserInfo2 *r)
4011 {
4012         struct samr_QueryUserInfo r1;
4013         NTSTATUS status;
4014
4015         r1 = (struct samr_QueryUserInfo) {
4016                 .in.user_handle = r->in.user_handle,
4017                 .in.level  = r->in.level,
4018                 .out.info  = r->out.info
4019         };
4020
4021         status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
4022
4023         return status;
4024 }
4025
4026
4027 /*
4028   samr_QueryDisplayInfo2
4029 */
4030 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4031                                        struct samr_QueryDisplayInfo2 *r)
4032 {
4033         struct samr_QueryDisplayInfo q;
4034         NTSTATUS result;
4035
4036         q.in.domain_handle = r->in.domain_handle;
4037         q.in.level = r->in.level;
4038         q.in.start_idx = r->in.start_idx;
4039         q.in.max_entries = r->in.max_entries;
4040         q.in.buf_size = r->in.buf_size;
4041         q.out.total_size = r->out.total_size;
4042         q.out.returned_size = r->out.returned_size;
4043         q.out.info = r->out.info;
4044
4045         result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4046
4047         return result;
4048 }
4049
4050
4051 /*
4052   samr_GetDisplayEnumerationIndex2
4053 */
4054 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4055                        struct samr_GetDisplayEnumerationIndex2 *r)
4056 {
4057         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4058 }
4059
4060
4061 /*
4062   samr_QueryDisplayInfo3
4063 */
4064 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4065                        struct samr_QueryDisplayInfo3 *r)
4066 {
4067         struct samr_QueryDisplayInfo q;
4068         NTSTATUS result;
4069
4070         q.in.domain_handle = r->in.domain_handle;
4071         q.in.level = r->in.level;
4072         q.in.start_idx = r->in.start_idx;
4073         q.in.max_entries = r->in.max_entries;
4074         q.in.buf_size = r->in.buf_size;
4075         q.out.total_size = r->out.total_size;
4076         q.out.returned_size = r->out.returned_size;
4077         q.out.info = r->out.info;
4078
4079         result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4080
4081         return result;
4082 }
4083
4084
4085 /*
4086   samr_AddMultipleMembersToAlias
4087 */
4088 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4089                        struct samr_AddMultipleMembersToAlias *r)
4090 {
4091         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4092 }
4093
4094
4095 /*
4096   samr_RemoveMultipleMembersFromAlias
4097 */
4098 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4099                        struct samr_RemoveMultipleMembersFromAlias *r)
4100 {
4101         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4102 }
4103
4104
4105 /*
4106   samr_GetDomPwInfo
4107
4108   this fetches the default password properties for a domain
4109
4110   note that w2k3 completely ignores the domain name in this call, and
4111   always returns the information for the servers primary domain
4112 */
4113 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4114                                   struct samr_GetDomPwInfo *r)
4115 {
4116         struct ldb_message **msgs;
4117         int ret;
4118         const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4119         struct ldb_context *sam_ctx;
4120
4121         ZERO_STRUCTP(r->out.info);
4122
4123         sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
4124                                          dce_call->conn->dce_ctx->lp_ctx,
4125                                          dce_call->conn->auth_state.session_info, 0);
4126         if (sam_ctx == NULL) {
4127                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4128         }
4129
4130         /* The domain name in this call is ignored */
4131         ret = gendb_search_dn(sam_ctx,
4132                            mem_ctx, NULL, &msgs, attrs);
4133         if (ret <= 0) {
4134                 talloc_free(sam_ctx);
4135
4136                 return NT_STATUS_NO_SUCH_DOMAIN;
4137         }
4138         if (ret > 1) {
4139                 talloc_free(msgs);
4140                 talloc_free(sam_ctx);
4141
4142                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4143         }
4144
4145         r->out.info->min_password_length = ldb_msg_find_attr_as_uint(msgs[0],
4146                 "minPwdLength", 0);
4147         r->out.info->password_properties = ldb_msg_find_attr_as_uint(msgs[0],
4148                 "pwdProperties", 1);
4149
4150         talloc_free(msgs);
4151         talloc_unlink(mem_ctx, sam_ctx);
4152
4153         return NT_STATUS_OK;
4154 }
4155
4156
4157 /*
4158   samr_Connect2
4159 */
4160 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4161                               struct samr_Connect2 *r)
4162 {
4163         struct samr_Connect c;
4164
4165         c.in.system_name = NULL;
4166         c.in.access_mask = r->in.access_mask;
4167         c.out.connect_handle = r->out.connect_handle;
4168
4169         return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4170 }
4171
4172
4173 /*
4174   samr_SetUserInfo2
4175
4176   just an alias for samr_SetUserInfo
4177 */
4178 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4179                                   struct samr_SetUserInfo2 *r)
4180 {
4181         struct samr_SetUserInfo r2;
4182
4183         r2.in.user_handle = r->in.user_handle;
4184         r2.in.level = r->in.level;
4185         r2.in.info = r->in.info;
4186
4187         return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
4188 }
4189
4190
4191 /*
4192   samr_SetBootKeyInformation
4193 */
4194 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4195                        struct samr_SetBootKeyInformation *r)
4196 {
4197         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4198 }
4199
4200
4201 /*
4202   samr_GetBootKeyInformation
4203 */
4204 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4205                        struct samr_GetBootKeyInformation *r)
4206 {
4207         /* Windows Server 2008 returns this */
4208         return NT_STATUS_NOT_SUPPORTED;
4209 }
4210
4211
4212 /*
4213   samr_Connect3
4214 */
4215 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4216                        struct samr_Connect3 *r)
4217 {
4218         struct samr_Connect c;
4219
4220         c.in.system_name = NULL;
4221         c.in.access_mask = r->in.access_mask;
4222         c.out.connect_handle = r->out.connect_handle;
4223
4224         return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4225 }
4226
4227
4228 /*
4229   samr_Connect4
4230 */
4231 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4232                        struct samr_Connect4 *r)
4233 {
4234         struct samr_Connect c;
4235
4236         c.in.system_name = NULL;
4237         c.in.access_mask = r->in.access_mask;
4238         c.out.connect_handle = r->out.connect_handle;
4239
4240         return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4241 }
4242
4243
4244 /*
4245   samr_Connect5
4246 */
4247 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4248                               struct samr_Connect5 *r)
4249 {
4250         struct samr_Connect c;
4251         NTSTATUS status;
4252
4253         c.in.system_name = NULL;
4254         c.in.access_mask = r->in.access_mask;
4255         c.out.connect_handle = r->out.connect_handle;
4256
4257         status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4258
4259         r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
4260         r->out.info_out->info1.unknown2 = 0;
4261         *r->out.level_out = r->in.level_in;
4262
4263         return status;
4264 }
4265
4266
4267 /*
4268   samr_RidToSid
4269 */
4270 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4271                               struct samr_RidToSid *r)
4272 {
4273         struct samr_domain_state *d_state;
4274         struct dcesrv_handle *h;
4275
4276         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4277
4278         d_state = h->data;
4279
4280         /* form the users SID */
4281         *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4282         if (!*r->out.sid) {
4283                 return NT_STATUS_NO_MEMORY;
4284         }
4285
4286         return NT_STATUS_OK;
4287 }
4288
4289
4290 /*
4291   samr_SetDsrmPassword
4292 */
4293 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4294                        struct samr_SetDsrmPassword *r)
4295 {
4296         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4297 }
4298
4299
4300 /*
4301   samr_ValidatePassword
4302
4303   For now the call checks the password complexity (if active) and the minimum
4304   password length on level 2 and 3. Level 1 is ignored for now.
4305 */
4306 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
4307                                              TALLOC_CTX *mem_ctx,
4308                                              struct samr_ValidatePassword *r)
4309 {
4310         struct samr_GetDomPwInfo r2;
4311         struct samr_PwInfo pwInfo;
4312         DATA_BLOB password;
4313         enum samr_ValidationStatus res;
4314         NTSTATUS status;
4315         enum dcerpc_transport_t transport =
4316                 dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description);
4317
4318         if (transport != NCACN_IP_TCP && transport != NCALRPC) {
4319                 DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
4320         }
4321
4322         if (dce_call->conn->auth_state.auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
4323                 DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
4324         }
4325
4326         (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
4327
4328         r2.in.domain_name = NULL;
4329         r2.out.info = &pwInfo;
4330         status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2);
4331         if (!NT_STATUS_IS_OK(status)) {
4332                 return status;
4333         }
4334
4335         switch (r->in.level) {
4336         case NetValidateAuthentication:
4337                 /* we don't support this yet */
4338                 return NT_STATUS_NOT_SUPPORTED;
4339         break;
4340         case NetValidatePasswordChange:
4341                 password = data_blob_const(r->in.req->req2.password.string,
4342                                            r->in.req->req2.password.length);
4343                 res = samdb_check_password(&password,
4344                                            pwInfo.password_properties,
4345                                            pwInfo.min_password_length);
4346                 (*r->out.rep)->ctr2.status = res;
4347         break;
4348         case NetValidatePasswordReset:
4349                 password = data_blob_const(r->in.req->req3.password.string,
4350                                            r->in.req->req3.password.length);
4351                 res = samdb_check_password(&password,
4352                                            pwInfo.password_properties,
4353                                            pwInfo.min_password_length);
4354                 (*r->out.rep)->ctr3.status = res;
4355         break;
4356         default:
4357                 return NT_STATUS_INVALID_INFO_CLASS;
4358         break;
4359         }
4360
4361         return NT_STATUS_OK;
4362 }
4363
4364
4365 /* include the generated boilerplate */
4366 #include "librpc/gen_ndr/ndr_samr_s.c"