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