s4-dsdb Add ability to force a particular SID in the upgrade case
[amitay/samba.git] / source4 / rpc_server / samr / dcesrv_samr.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    endpoint server for the samr pipe
5
6    Copyright (C) Andrew Tridgell 2004
7    Copyright (C) Volker Lendecke 2004
8    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
9    Copyright (C) Matthias Dieter Wallnöfer 2009
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26 #include "librpc/gen_ndr/ndr_samr.h"
27 #include "rpc_server/dcerpc_server.h"
28 #include "rpc_server/common/common.h"
29 #include "rpc_server/samr/dcesrv_samr.h"
30 #include "system/time.h"
31 #include <ldb.h>
32 #include <ldb_errors.h>
33 #include "../libds/common/flags.h"
34 #include "dsdb/samdb/samdb.h"
35 #include "dsdb/common/util.h"
36 #include "libcli/ldap/ldap_ndr.h"
37 #include "libcli/security/security.h"
38 #include "rpc_server/samr/proto.h"
39 #include "../lib/util/util_ldb.h"
40 #include "param/param.h"
41 #include "lib/util/tsort.h"
42 #include "libds/common/flag_mapping.h"
43
44 /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
45
46 #define QUERY_STRING(msg, field, attr) \
47         info->field.string = ldb_msg_find_attr_as_string(msg, attr, "");
48 #define QUERY_UINT(msg, field, attr) \
49         info->field = ldb_msg_find_attr_as_uint(msg, attr, 0);
50 #define QUERY_RID(msg, field, attr) \
51         info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
52 #define QUERY_UINT64(msg, field, attr) \
53         info->field = ldb_msg_find_attr_as_uint64(msg, attr, 0);
54 #define QUERY_APASSC(msg, field, attr) \
55         info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
56                                                          a_state->domain_state->domain_dn, msg, attr);
57 #define QUERY_FPASSC(msg, field, attr) \
58         info->field = samdb_result_force_password_change(sam_ctx, mem_ctx, \
59                                                          a_state->domain_state->domain_dn, msg);
60 #define QUERY_LHOURS(msg, field, attr) \
61         info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
62 #define QUERY_AFLAGS(msg, field, attr) \
63         info->field = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, a_state->domain_state->domain_dn);
64 #define QUERY_PARAMETERS(msg, field, attr) \
65         info->field = samdb_result_parameters(mem_ctx, msg, attr);
66
67
68 /* these are used to make the Set[User|Group]Info code easier to follow */
69
70 #define SET_STRING(msg, field, attr) do {                               \
71         struct ldb_message_element *set_el;                             \
72         if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
73         if (r->in.info->field.string[0] == '\0') {                      \
74                 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL) != LDB_SUCCESS) { \
75                         return NT_STATUS_NO_MEMORY;                     \
76                 }                                                       \
77         }                                                               \
78         if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != LDB_SUCCESS) { \
79                 return NT_STATUS_NO_MEMORY;                             \
80         }                                                               \
81         set_el = ldb_msg_find_element(msg, attr);                       \
82         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
83 } while (0)
84
85 #define SET_UINT(msg, field, attr) do {                                 \
86         struct ldb_message_element *set_el;                             \
87         if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
88                 return NT_STATUS_NO_MEMORY;                             \
89         }                                                               \
90         set_el = ldb_msg_find_element(msg, attr);                       \
91         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
92 } while (0)
93
94 #define SET_INT64(msg, field, attr) do {                                \
95         struct ldb_message_element *set_el;                             \
96         if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
97                 return NT_STATUS_NO_MEMORY;                             \
98         }                                                               \
99         set_el = ldb_msg_find_element(msg, attr);                       \
100         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
101 } while (0)
102
103 #define SET_UINT64(msg, field, attr) do {                               \
104         struct ldb_message_element *set_el;                             \
105         if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
106                 return NT_STATUS_NO_MEMORY;                             \
107         }                                                               \
108         set_el = ldb_msg_find_element(msg, attr);                       \
109         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
110 } while (0)
111
112 #define CHECK_FOR_MULTIPLES(value, flag, poss_flags)    \
113         do { \
114                 if ((value & flag) && ((value & flag) != (value & (poss_flags)))) { \
115                         return NT_STATUS_INVALID_PARAMETER;             \
116                 }                                                       \
117         } while (0)                                                     \
118
119 /* Set account flags, discarding flags that cannot be set with SAMR */
120 #define SET_AFLAGS(msg, field, attr) do {                               \
121         struct ldb_message_element *set_el;                             \
122         if ((r->in.info->field & (ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST)) == 0) { \
123                 return NT_STATUS_INVALID_PARAMETER; \
124         }                                                               \
125         CHECK_FOR_MULTIPLES(r->in.info->field, ACB_NORMAL, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
126         CHECK_FOR_MULTIPLES(r->in.info->field, ACB_DOMTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
127         CHECK_FOR_MULTIPLES(r->in.info->field, ACB_WSTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
128         CHECK_FOR_MULTIPLES(r->in.info->field, ACB_SVRTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
129         if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, (r->in.info->field & ~(ACB_AUTOLOCK|ACB_PW_EXPIRED))) != 0) { \
130                 return NT_STATUS_NO_MEMORY;                             \
131         }                                                               \
132         set_el = ldb_msg_find_element(msg, attr);                       \
133         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
134 } while (0)
135
136 #define SET_LHOURS(msg, field, attr) do {                               \
137         struct ldb_message_element *set_el;                             \
138         if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
139                 return NT_STATUS_NO_MEMORY;                             \
140         }                                                               \
141         set_el = ldb_msg_find_element(msg, attr);                       \
142         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
143 } while (0)
144
145 #define SET_PARAMETERS(msg, field, attr) do {                           \
146         struct ldb_message_element *set_el;                             \
147         if (r->in.info->field.length != 0) {                            \
148                 if (samdb_msg_add_parameters(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
149                         return NT_STATUS_NO_MEMORY;                     \
150                 }                                                       \
151                 set_el = ldb_msg_find_element(msg, attr);               \
152                 set_el->flags = LDB_FLAG_MOD_REPLACE;                   \
153         }                                                               \
154 } while (0)
155
156
157
158 /*
159   samr_Connect
160
161   create a connection to the SAM database
162 */
163 static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
164                              struct samr_Connect *r)
165 {
166         struct samr_connect_state *c_state;
167         struct dcesrv_handle *handle;
168
169         ZERO_STRUCTP(r->out.connect_handle);
170
171         c_state = talloc(mem_ctx, struct samr_connect_state);
172         if (!c_state) {
173                 return NT_STATUS_NO_MEMORY;
174         }
175
176         /* make sure the sam database is accessible */
177         c_state->sam_ctx = samdb_connect(c_state, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info, 0);
178         if (c_state->sam_ctx == NULL) {
179                 talloc_free(c_state);
180                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
181         }
182
183
184         handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_CONNECT);
185         if (!handle) {
186                 talloc_free(c_state);
187                 return NT_STATUS_NO_MEMORY;
188         }
189
190         handle->data = talloc_steal(handle, c_state);
191
192         c_state->access_mask = r->in.access_mask;
193         *r->out.connect_handle = handle->wire_handle;
194
195         return NT_STATUS_OK;
196 }
197
198
199 /*
200   samr_Close
201 */
202 static NTSTATUS dcesrv_samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
203                            struct samr_Close *r)
204 {
205         struct dcesrv_handle *h;
206
207         *r->out.handle = *r->in.handle;
208
209         DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
210
211         talloc_free(h);
212
213         ZERO_STRUCTP(r->out.handle);
214
215         return NT_STATUS_OK;
216 }
217
218
219 /*
220   samr_SetSecurity
221 */
222 static NTSTATUS dcesrv_samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
223                                  struct samr_SetSecurity *r)
224 {
225         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
226 }
227
228
229 /*
230   samr_QuerySecurity
231 */
232 static NTSTATUS dcesrv_samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
233                                    struct samr_QuerySecurity *r)
234 {
235         struct dcesrv_handle *h;
236         struct sec_desc_buf *sd;
237
238         *r->out.sdbuf = NULL;
239
240         DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
241
242         sd = talloc(mem_ctx, struct sec_desc_buf);
243         if (sd == NULL) {
244                 return NT_STATUS_NO_MEMORY;
245         }
246
247         sd->sd = samdb_default_security_descriptor(mem_ctx);
248
249         *r->out.sdbuf = sd;
250
251         return NT_STATUS_OK;
252 }
253
254
255 /*
256   samr_Shutdown
257
258   we refuse this operation completely. If a admin wants to shutdown samr
259   in Samba then they should use the samba admin tools to disable the samr pipe
260 */
261 static NTSTATUS dcesrv_samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
262                               struct samr_Shutdown *r)
263 {
264         return NT_STATUS_ACCESS_DENIED;
265 }
266
267
268 /*
269   samr_LookupDomain
270
271   this maps from a domain name to a SID
272 */
273 static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
274                                   struct samr_LookupDomain *r)
275 {
276         struct samr_connect_state *c_state;
277         struct dcesrv_handle *h;
278         struct dom_sid *sid;
279         const char * const dom_attrs[] = { "objectSid", NULL};
280         struct ldb_message **dom_msgs;
281         int ret;
282
283         *r->out.sid = NULL;
284
285         DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
286
287         c_state = h->data;
288
289         if (r->in.domain_name->string == NULL) {
290                 return NT_STATUS_INVALID_PARAMETER;
291         }
292
293         if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
294                 ret = gendb_search(c_state->sam_ctx,
295                                    mem_ctx, NULL, &dom_msgs, dom_attrs,
296                                    "(objectClass=builtinDomain)");
297         } else if (strcasecmp_m(r->in.domain_name->string, lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx)) == 0) {
298                 ret = gendb_search_dn(c_state->sam_ctx,
299                                       mem_ctx, ldb_get_default_basedn(c_state->sam_ctx),
300                                       &dom_msgs, dom_attrs);
301         } else {
302                 return NT_STATUS_NO_SUCH_DOMAIN;
303         }
304         if (ret != 1) {
305                 return NT_STATUS_NO_SUCH_DOMAIN;
306         }
307
308         sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
309                                    "objectSid");
310
311         if (sid == NULL) {
312                 return NT_STATUS_NO_SUCH_DOMAIN;
313         }
314
315         *r->out.sid = sid;
316
317         return NT_STATUS_OK;
318 }
319
320
321 /*
322   samr_EnumDomains
323
324   list the domains in the SAM
325 */
326 static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
327                                  struct samr_EnumDomains *r)
328 {
329         struct samr_connect_state *c_state;
330         struct dcesrv_handle *h;
331         struct samr_SamArray *array;
332         uint32_t i, start_i;
333
334         *r->out.resume_handle = 0;
335         *r->out.sam = NULL;
336         *r->out.num_entries = 0;
337
338         DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
339
340         c_state = h->data;
341
342         *r->out.resume_handle = 2;
343
344         start_i = *r->in.resume_handle;
345
346         if (start_i >= 2) {
347                 /* search past end of list is not an error for this call */
348                 return NT_STATUS_OK;
349         }
350
351         array = talloc(mem_ctx, struct samr_SamArray);
352         if (array == NULL) {
353                 return NT_STATUS_NO_MEMORY;
354         }
355
356         array->count = 0;
357         array->entries = NULL;
358
359         array->entries = talloc_array(mem_ctx, struct samr_SamEntry, 2 - start_i);
360         if (array->entries == NULL) {
361                 return NT_STATUS_NO_MEMORY;
362         }
363
364         for (i=0;i<2-start_i;i++) {
365                 array->entries[i].idx = start_i + i;
366                 if (i == 0) {
367                         array->entries[i].name.string = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx);
368                 } else {
369                         array->entries[i].name.string = "BUILTIN";
370                 }
371         }
372
373         *r->out.sam = array;
374         *r->out.num_entries = i;
375         array->count = *r->out.num_entries;
376
377         return NT_STATUS_OK;
378 }
379
380
381 /*
382   samr_OpenDomain
383 */
384 static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
385                                 struct samr_OpenDomain *r)
386 {
387         struct dcesrv_handle *h_conn, *h_domain;
388         struct samr_connect_state *c_state;
389         struct samr_domain_state *d_state;
390         const char * const dom_attrs[] = { "cn", NULL};
391         struct ldb_message **dom_msgs;
392         int ret;
393
394         ZERO_STRUCTP(r->out.domain_handle);
395
396         DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
397
398         c_state = h_conn->data;
399
400         if (r->in.sid == NULL) {
401                 return NT_STATUS_INVALID_PARAMETER;
402         }
403
404         d_state = talloc(mem_ctx, struct samr_domain_state);
405         if (!d_state) {
406                 return NT_STATUS_NO_MEMORY;
407         }
408
409         d_state->domain_sid = talloc_steal(d_state, r->in.sid);
410
411         if (dom_sid_equal(d_state->domain_sid, dom_sid_parse_talloc(mem_ctx, SID_BUILTIN))) {
412                 d_state->builtin = true;
413                 d_state->domain_name = "BUILTIN";
414         } else {
415                 d_state->builtin = false;
416                 d_state->domain_name = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx);
417         }
418
419         ret = gendb_search(c_state->sam_ctx,
420                            mem_ctx, ldb_get_default_basedn(c_state->sam_ctx), &dom_msgs, dom_attrs,
421                            "(objectSid=%s)",
422                            ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
423
424         if (ret == 0) {
425                 talloc_free(d_state);
426                 return NT_STATUS_NO_SUCH_DOMAIN;
427         } else if (ret > 1) {
428                 talloc_free(d_state);
429                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
430         } else if (ret == -1) {
431                 talloc_free(d_state);
432                 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx)));
433                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
434         }
435
436         d_state->domain_dn = talloc_steal(d_state, dom_msgs[0]->dn);
437         d_state->role = lpcfg_server_role(dce_call->conn->dce_ctx->lp_ctx);
438         d_state->connect_state = talloc_reference(d_state, c_state);
439         d_state->sam_ctx = c_state->sam_ctx;
440         d_state->access_mask = r->in.access_mask;
441
442         d_state->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
443
444         h_domain = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_DOMAIN);
445         if (!h_domain) {
446                 talloc_free(d_state);
447                 return NT_STATUS_NO_MEMORY;
448         }
449
450         h_domain->data = talloc_steal(h_domain, d_state);
451
452         *r->out.domain_handle = h_domain->wire_handle;
453
454         return NT_STATUS_OK;
455 }
456
457 /*
458   return DomInfo1
459 */
460 static NTSTATUS dcesrv_samr_info_DomInfo1(struct samr_domain_state *state,
461                                           TALLOC_CTX *mem_ctx,
462                                           struct ldb_message **dom_msgs,
463                                           struct samr_DomInfo1 *info)
464 {
465         info->min_password_length =
466                 ldb_msg_find_attr_as_uint(dom_msgs[0], "minPwdLength", 0);
467         info->password_history_length =
468                 ldb_msg_find_attr_as_uint(dom_msgs[0], "pwdHistoryLength", 0);
469         info->password_properties =
470                 ldb_msg_find_attr_as_uint(dom_msgs[0], "pwdProperties", 0);
471         info->max_password_age =
472                 ldb_msg_find_attr_as_int64(dom_msgs[0], "maxPwdAge", 0);
473         info->min_password_age =
474                 ldb_msg_find_attr_as_int64(dom_msgs[0], "minPwdAge", 0);
475
476         return NT_STATUS_OK;
477 }
478
479 /*
480   return DomInfo2
481 */
482 static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state *state,
483                                                        TALLOC_CTX *mem_ctx,
484                                                        struct ldb_message **dom_msgs,
485                                                        struct samr_DomGeneralInformation *info)
486 {
487         /* MS-SAMR 2.2.4.1 - ReplicaSourceNodeName: "domainReplica" attribute */
488         info->primary.string = ldb_msg_find_attr_as_string(dom_msgs[0],
489                                                            "domainReplica",
490                                                            "");
491
492         info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
493                                                             0x8000000000000000LL);
494
495         info->oem_information.string = ldb_msg_find_attr_as_string(dom_msgs[0],
496                                                                    "oEMInformation",
497                                                                    "");
498         info->domain_name.string  = state->domain_name;
499
500         info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
501                                                  0);
502         switch (state->role) {
503         case ROLE_DOMAIN_CONTROLLER:
504                 /* This pulls the NetBIOS name from the
505                    cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
506                    string */
507                 if (samdb_is_pdc(state->sam_ctx)) {
508                         info->role = SAMR_ROLE_DOMAIN_PDC;
509                 } else {
510                         info->role = SAMR_ROLE_DOMAIN_BDC;
511                 }
512                 break;
513         case ROLE_DOMAIN_PDC:
514                 info->role = SAMR_ROLE_DOMAIN_PDC;
515                 break;
516         case ROLE_DOMAIN_MEMBER:
517                 info->role = SAMR_ROLE_DOMAIN_MEMBER;
518                 break;
519         case ROLE_STANDALONE:
520                 info->role = SAMR_ROLE_STANDALONE;
521                 break;
522         }
523
524         info->num_users = samdb_search_count(state->sam_ctx, mem_ctx,
525                                              state->domain_dn,
526                                              "(objectClass=user)");
527         info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx,
528                                               state->domain_dn,
529                                               "(&(objectClass=group)(|(groupType=%d)(groupType=%d)))",
530                                               GTYPE_SECURITY_UNIVERSAL_GROUP,
531                                               GTYPE_SECURITY_GLOBAL_GROUP);
532         info->num_aliases = samdb_search_count(state->sam_ctx, mem_ctx,
533                                                state->domain_dn,
534                                                "(&(objectClass=group)(|(groupType=%d)(groupType=%d)))",
535                                                GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
536                                                GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
537
538         return NT_STATUS_OK;
539 }
540
541 /*
542   return DomInfo3
543 */
544 static NTSTATUS dcesrv_samr_info_DomInfo3(struct samr_domain_state *state,
545                                           TALLOC_CTX *mem_ctx,
546                                           struct ldb_message **dom_msgs,
547                                           struct samr_DomInfo3 *info)
548 {
549         info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
550                                                       0x8000000000000000LL);
551
552         return NT_STATUS_OK;
553 }
554
555 /*
556   return DomInfo4
557 */
558 static NTSTATUS dcesrv_samr_info_DomOEMInformation(struct samr_domain_state *state,
559                                    TALLOC_CTX *mem_ctx,
560                                     struct ldb_message **dom_msgs,
561                                    struct samr_DomOEMInformation *info)
562 {
563         info->oem_information.string = ldb_msg_find_attr_as_string(dom_msgs[0],
564                                                                    "oEMInformation",
565                                                                    "");
566
567         return NT_STATUS_OK;
568 }
569
570 /*
571   return DomInfo5
572 */
573 static NTSTATUS dcesrv_samr_info_DomInfo5(struct samr_domain_state *state,
574                                           TALLOC_CTX *mem_ctx,
575                                           struct ldb_message **dom_msgs,
576                                           struct samr_DomInfo5 *info)
577 {
578         info->domain_name.string  = state->domain_name;
579
580         return NT_STATUS_OK;
581 }
582
583 /*
584   return DomInfo6
585 */
586 static NTSTATUS dcesrv_samr_info_DomInfo6(struct samr_domain_state *state,
587                                           TALLOC_CTX *mem_ctx,
588                                           struct ldb_message **dom_msgs,
589                                           struct samr_DomInfo6 *info)
590 {
591         /* MS-SAMR 2.2.4.1 - ReplicaSourceNodeName: "domainReplica" attribute */
592         info->primary.string = ldb_msg_find_attr_as_string(dom_msgs[0],
593                                                            "domainReplica",
594                                                            "");
595
596         return NT_STATUS_OK;
597 }
598
599 /*
600   return DomInfo7
601 */
602 static NTSTATUS dcesrv_samr_info_DomInfo7(struct samr_domain_state *state,
603                                           TALLOC_CTX *mem_ctx,
604                                           struct ldb_message **dom_msgs,
605                                           struct samr_DomInfo7 *info)
606 {
607
608         switch (state->role) {
609         case ROLE_DOMAIN_CONTROLLER:
610                 /* This pulls the NetBIOS name from the
611                    cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
612                    string */
613                 if (samdb_is_pdc(state->sam_ctx)) {
614                         info->role = SAMR_ROLE_DOMAIN_PDC;
615                 } else {
616                         info->role = SAMR_ROLE_DOMAIN_BDC;
617                 }
618                 break;
619         case ROLE_DOMAIN_PDC:
620                 info->role = SAMR_ROLE_DOMAIN_PDC;
621                 break;
622         case ROLE_DOMAIN_MEMBER:
623                 info->role = SAMR_ROLE_DOMAIN_MEMBER;
624                 break;
625         case ROLE_STANDALONE:
626                 info->role = SAMR_ROLE_STANDALONE;
627                 break;
628         }
629
630         return NT_STATUS_OK;
631 }
632
633 /*
634   return DomInfo8
635 */
636 static NTSTATUS dcesrv_samr_info_DomInfo8(struct samr_domain_state *state,
637                                           TALLOC_CTX *mem_ctx,
638                                           struct ldb_message **dom_msgs,
639                                           struct samr_DomInfo8 *info)
640 {
641         info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
642                                                time(NULL));
643
644         info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
645                                                      0x0LL);
646
647         return NT_STATUS_OK;
648 }
649
650 /*
651   return DomInfo9
652 */
653 static NTSTATUS dcesrv_samr_info_DomInfo9(struct samr_domain_state *state,
654                                           TALLOC_CTX *mem_ctx,
655                                           struct ldb_message **dom_msgs,
656                                           struct samr_DomInfo9 *info)
657 {
658         info->domain_server_state = DOMAIN_SERVER_ENABLED;
659
660         return NT_STATUS_OK;
661 }
662
663 /*
664   return DomInfo11
665 */
666 static NTSTATUS dcesrv_samr_info_DomGeneralInformation2(struct samr_domain_state *state,
667                                                         TALLOC_CTX *mem_ctx,
668                                                         struct ldb_message **dom_msgs,
669                                                         struct samr_DomGeneralInformation2 *info)
670 {
671         NTSTATUS status;
672         status = dcesrv_samr_info_DomGeneralInformation(state, mem_ctx, dom_msgs, &info->general);
673         if (!NT_STATUS_IS_OK(status)) {
674                 return status;
675         }
676
677         info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
678                                                     -18000000000LL);
679         info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
680                                                     -18000000000LL);
681         info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
682
683         return NT_STATUS_OK;
684 }
685
686 /*
687   return DomInfo12
688 */
689 static NTSTATUS dcesrv_samr_info_DomInfo12(struct samr_domain_state *state,
690                                            TALLOC_CTX *mem_ctx,
691                                            struct ldb_message **dom_msgs,
692                                            struct samr_DomInfo12 *info)
693 {
694         info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
695                                                     -18000000000LL);
696         info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
697                                                     -18000000000LL);
698         info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
699
700         return NT_STATUS_OK;
701 }
702
703 /*
704   return DomInfo13
705 */
706 static NTSTATUS dcesrv_samr_info_DomInfo13(struct samr_domain_state *state,
707                                            TALLOC_CTX *mem_ctx,
708                                            struct ldb_message **dom_msgs,
709                                            struct samr_DomInfo13 *info)
710 {
711         info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
712                                                time(NULL));
713
714         info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
715                                                      0x0LL);
716
717         info->modified_count_at_last_promotion = 0;
718
719         return NT_STATUS_OK;
720 }
721
722 /*
723   samr_QueryDomainInfo
724 */
725 static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call,
726                                             TALLOC_CTX *mem_ctx,
727                                             struct samr_QueryDomainInfo *r)
728 {
729         struct dcesrv_handle *h;
730         struct samr_domain_state *d_state;
731         union samr_DomainInfo *info;
732
733         struct ldb_message **dom_msgs;
734         const char * const *attrs = NULL;
735
736         *r->out.info = NULL;
737
738         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
739
740         d_state = h->data;
741
742         switch (r->in.level) {
743         case 1:
744         {
745                 static const char * const attrs2[] = { "minPwdLength",
746                                                        "pwdHistoryLength",
747                                                        "pwdProperties",
748                                                        "maxPwdAge",
749                                                        "minPwdAge",
750                                                        NULL };
751                 attrs = attrs2;
752                 break;
753         }
754         case 2:
755         {
756                 static const char * const attrs2[] = {"forceLogoff",
757                                                       "oEMInformation",
758                                                       "modifiedCount",
759                                                       "domainReplica",
760                                                       NULL};
761                 attrs = attrs2;
762                 break;
763         }
764         case 3:
765         {
766                 static const char * const attrs2[] = {"forceLogoff",
767                                                       NULL};
768                 attrs = attrs2;
769                 break;
770         }
771         case 4:
772         {
773                 static const char * const attrs2[] = {"oEMInformation",
774                                                       NULL};
775                 attrs = attrs2;
776                 break;
777         }
778         case 5:
779         {
780                 attrs = NULL;
781                 break;
782         }
783         case 6:
784         {
785                 static const char * const attrs2[] = { "domainReplica",
786                                                        NULL };
787                 attrs = attrs2;
788                 break;
789         }
790         case 7:
791         {
792                 attrs = NULL;
793                 break;
794         }
795         case 8:
796         {
797                 static const char * const attrs2[] = { "modifiedCount",
798                                                        "creationTime",
799                                                        NULL };
800                 attrs = attrs2;
801                 break;
802         }
803         case 9:
804         {
805                 attrs = NULL;
806                 break;
807         }
808         case 11:
809         {
810                 static const char * const attrs2[] = { "oEMInformation",
811                                                        "forceLogoff",
812                                                        "modifiedCount",
813                                                        "lockoutDuration",
814                                                        "lockOutObservationWindow",
815                                                        "lockoutThreshold",
816                                                        NULL};
817                 attrs = attrs2;
818                 break;
819         }
820         case 12:
821         {
822                 static const char * const attrs2[] = { "lockoutDuration",
823                                                        "lockOutObservationWindow",
824                                                        "lockoutThreshold",
825                                                        NULL};
826                 attrs = attrs2;
827                 break;
828         }
829         case 13:
830         {
831                 static const char * const attrs2[] = { "modifiedCount",
832                                                        "creationTime",
833                                                        NULL };
834                 attrs = attrs2;
835                 break;
836         }
837         default:
838         {
839                 return NT_STATUS_INVALID_INFO_CLASS;
840         }
841         }
842
843         /* some levels don't need a search */
844         if (attrs) {
845                 int ret;
846                 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
847                                       d_state->domain_dn, &dom_msgs, attrs);
848                 if (ret == 0) {
849                         return NT_STATUS_NO_SUCH_DOMAIN;
850                 }
851                 if (ret != 1) {
852                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
853                 }
854         }
855
856         /* allocate the info structure */
857         info = talloc_zero(mem_ctx, union samr_DomainInfo);
858         if (info == NULL) {
859                 return NT_STATUS_NO_MEMORY;
860         }
861
862         *r->out.info = info;
863
864         switch (r->in.level) {
865         case 1:
866                 return dcesrv_samr_info_DomInfo1(d_state, mem_ctx, dom_msgs,
867                                                  &info->info1);
868         case 2:
869                 return dcesrv_samr_info_DomGeneralInformation(d_state, mem_ctx, dom_msgs,
870                                                               &info->general);
871         case 3:
872                 return dcesrv_samr_info_DomInfo3(d_state, mem_ctx, dom_msgs,
873                                                  &info->info3);
874         case 4:
875                 return dcesrv_samr_info_DomOEMInformation(d_state, mem_ctx, dom_msgs,
876                                                           &info->oem);
877         case 5:
878                 return dcesrv_samr_info_DomInfo5(d_state, mem_ctx, dom_msgs,
879                                                  &info->info5);
880         case 6:
881                 return dcesrv_samr_info_DomInfo6(d_state, mem_ctx, dom_msgs,
882                                                  &info->info6);
883         case 7:
884                 return dcesrv_samr_info_DomInfo7(d_state, mem_ctx, dom_msgs,
885                                                  &info->info7);
886         case 8:
887                 return dcesrv_samr_info_DomInfo8(d_state, mem_ctx, dom_msgs,
888                                                  &info->info8);
889         case 9:
890                 return dcesrv_samr_info_DomInfo9(d_state, mem_ctx, dom_msgs,
891                                                  &info->info9);
892         case 11:
893                 return dcesrv_samr_info_DomGeneralInformation2(d_state, mem_ctx, dom_msgs,
894                                                                &info->general2);
895         case 12:
896                 return dcesrv_samr_info_DomInfo12(d_state, mem_ctx, dom_msgs,
897                                                   &info->info12);
898         case 13:
899                 return dcesrv_samr_info_DomInfo13(d_state, mem_ctx, dom_msgs,
900                                                   &info->info13);
901         default:
902                 return NT_STATUS_INVALID_INFO_CLASS;
903         }
904 }
905
906
907 /*
908   samr_SetDomainInfo
909 */
910 static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
911                        struct samr_SetDomainInfo *r)
912 {
913         struct dcesrv_handle *h;
914         struct samr_domain_state *d_state;
915         struct ldb_message *msg;
916         int ret;
917         struct ldb_context *sam_ctx;
918
919         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
920
921         d_state = h->data;
922         sam_ctx = d_state->sam_ctx;
923
924         msg = ldb_msg_new(mem_ctx);
925         if (msg == NULL) {
926                 return NT_STATUS_NO_MEMORY;
927         }
928
929         msg->dn = talloc_reference(mem_ctx, d_state->domain_dn);
930         if (!msg->dn) {
931                 return NT_STATUS_NO_MEMORY;
932         }
933
934         switch (r->in.level) {
935         case 1:
936                 SET_UINT  (msg, info1.min_password_length,     "minPwdLength");
937                 SET_UINT  (msg, info1.password_history_length, "pwdHistoryLength");
938                 SET_UINT  (msg, info1.password_properties,     "pwdProperties");
939                 SET_INT64  (msg, info1.max_password_age,       "maxPwdAge");
940                 SET_INT64  (msg, info1.min_password_age,       "minPwdAge");
941                 break;
942         case 3:
943                 SET_UINT64  (msg, info3.force_logoff_time,     "forceLogoff");
944                 break;
945         case 4:
946                 SET_STRING(msg, oem.oem_information,           "oEMInformation");
947                 break;
948
949         case 6:
950         case 7:
951         case 9:
952                 /* No op, we don't know where to set these */
953                 return NT_STATUS_OK;
954
955         case 12:
956                 /*
957                  * It is not possible to set lockout_duration < lockout_window.
958                  * (The test is the other way around since the negative numbers
959                  *  are stored...)
960                  *
961                  * TODO:
962                  *   This check should be moved to the backend, i.e. to some
963                  *   ldb module under dsdb/samdb/ldb_modules/ .
964                  *
965                  * This constraint is documented here for the samr rpc service:
966                  * MS-SAMR 3.1.1.6 Attribute Constraints for Originating Updates
967                  * http://msdn.microsoft.com/en-us/library/cc245667%28PROT.10%29.aspx
968                  *
969                  * And here for the ldap backend:
970                  * MS-ADTS 3.1.1.5.3.2 Constraints
971                  * http://msdn.microsoft.com/en-us/library/cc223462(PROT.10).aspx
972                  */
973                 if (r->in.info->info12.lockout_duration >
974                     r->in.info->info12.lockout_window)
975                 {
976                         return NT_STATUS_INVALID_PARAMETER;
977                 }
978                 SET_INT64  (msg, info12.lockout_duration,      "lockoutDuration");
979                 SET_INT64  (msg, info12.lockout_window,        "lockOutObservationWindow");
980                 SET_INT64  (msg, info12.lockout_threshold,     "lockoutThreshold");
981                 break;
982
983         default:
984                 /* many info classes are not valid for SetDomainInfo */
985                 return NT_STATUS_INVALID_INFO_CLASS;
986         }
987
988         /* modify the samdb record */
989         ret = ldb_modify(sam_ctx, msg);
990         if (ret != LDB_SUCCESS) {
991                 DEBUG(1,("Failed to modify record %s: %s\n",
992                          ldb_dn_get_linearized(d_state->domain_dn),
993                          ldb_errstring(sam_ctx)));
994                 return dsdb_ldb_err_to_ntstatus(ret);
995         }
996
997         return NT_STATUS_OK;
998 }
999
1000 /*
1001   samr_CreateDomainGroup
1002 */
1003 static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1004                                        struct samr_CreateDomainGroup *r)
1005 {
1006         NTSTATUS status;
1007         struct samr_domain_state *d_state;
1008         struct samr_account_state *a_state;
1009         struct dcesrv_handle *h;
1010         const char *groupname;
1011         struct dom_sid *group_sid;
1012         struct ldb_dn *group_dn;
1013         struct dcesrv_handle *g_handle;
1014
1015         ZERO_STRUCTP(r->out.group_handle);
1016         *r->out.rid = 0;
1017
1018         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1019
1020         d_state = h->data;
1021
1022         if (d_state->builtin) {
1023                 DEBUG(5, ("Cannot create a domain group in the BUILTIN domain"));
1024                 return NT_STATUS_ACCESS_DENIED;
1025         }
1026
1027         groupname = r->in.name->string;
1028
1029         if (groupname == NULL) {
1030                 return NT_STATUS_INVALID_PARAMETER;
1031         }
1032
1033         status = dsdb_add_domain_group(d_state->sam_ctx, mem_ctx, groupname, &group_sid, &group_dn);
1034         if (!NT_STATUS_IS_OK(status)) {
1035                 return status;
1036         }
1037
1038         a_state = talloc(mem_ctx, struct samr_account_state);
1039         if (!a_state) {
1040                 return NT_STATUS_NO_MEMORY;
1041         }
1042         a_state->sam_ctx = d_state->sam_ctx;
1043         a_state->access_mask = r->in.access_mask;
1044         a_state->domain_state = talloc_reference(a_state, d_state);
1045         a_state->account_dn = talloc_steal(a_state, group_dn);
1046
1047         a_state->account_name = talloc_steal(a_state, groupname);
1048
1049         /* create the policy handle */
1050         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1051         if (!g_handle) {
1052                 return NT_STATUS_NO_MEMORY;
1053         }
1054
1055         g_handle->data = talloc_steal(g_handle, a_state);
1056
1057         *r->out.group_handle = g_handle->wire_handle;
1058         *r->out.rid = group_sid->sub_auths[group_sid->num_auths-1];
1059
1060         return NT_STATUS_OK;
1061 }
1062
1063
1064 /*
1065   comparison function for sorting SamEntry array
1066 */
1067 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
1068 {
1069         return e1->idx - e2->idx;
1070 }
1071
1072 /*
1073   samr_EnumDomainGroups
1074 */
1075 static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1076                                       struct samr_EnumDomainGroups *r)
1077 {
1078         struct dcesrv_handle *h;
1079         struct samr_domain_state *d_state;
1080         struct ldb_message **res;
1081         int i, ldb_cnt;
1082         uint32_t first, count;
1083         struct samr_SamEntry *entries;
1084         const char * const attrs[] = { "objectSid", "sAMAccountName", NULL };
1085         struct samr_SamArray *sam;
1086
1087         *r->out.resume_handle = 0;
1088         *r->out.sam = NULL;
1089         *r->out.num_entries = 0;
1090
1091         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1092
1093         d_state = h->data;
1094
1095         /* search for all domain groups in this domain. This could possibly be
1096            cached and resumed based on resume_key */
1097         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1098                                       d_state->domain_dn, &res, attrs,
1099                                       d_state->domain_sid,
1100                                       "(&(|(groupType=%d)(groupType=%d))(objectClass=group))",
1101                                       GTYPE_SECURITY_UNIVERSAL_GROUP,
1102                                       GTYPE_SECURITY_GLOBAL_GROUP);
1103         if (ldb_cnt < 0) {
1104                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1105         }
1106
1107         /* convert to SamEntry format */
1108         entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1109         if (!entries) {
1110                 return NT_STATUS_NO_MEMORY;
1111         }
1112
1113         count = 0;
1114
1115         for (i=0;i<ldb_cnt;i++) {
1116                 struct dom_sid *group_sid;
1117
1118                 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
1119                                                  "objectSid");
1120                 if (group_sid == NULL) {
1121                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1122                 }
1123
1124                 entries[count].idx =
1125                         group_sid->sub_auths[group_sid->num_auths-1];
1126                 entries[count].name.string =
1127                         ldb_msg_find_attr_as_string(res[i], "sAMAccountName", "");
1128                 count += 1;
1129         }
1130
1131         /* sort the results by rid */
1132         TYPESAFE_QSORT(entries, count, compare_SamEntry);
1133
1134         /* find the first entry to return */
1135         for (first=0;
1136              first<count && entries[first].idx <= *r->in.resume_handle;
1137              first++) ;
1138
1139         /* return the rest, limit by max_size. Note that we
1140            use the w2k3 element size value of 54 */
1141         *r->out.num_entries = count - first;
1142         *r->out.num_entries = MIN(*r->out.num_entries,
1143                                  1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1144
1145         sam = talloc(mem_ctx, struct samr_SamArray);
1146         if (!sam) {
1147                 return NT_STATUS_NO_MEMORY;
1148         }
1149
1150         sam->entries = entries+first;
1151         sam->count = *r->out.num_entries;
1152
1153         *r->out.sam = sam;
1154
1155         if (first == count) {
1156                 return NT_STATUS_OK;
1157         }
1158
1159         if (*r->out.num_entries < count - first) {
1160                 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1161                 return STATUS_MORE_ENTRIES;
1162         }
1163
1164         return NT_STATUS_OK;
1165 }
1166
1167
1168 /*
1169   samr_CreateUser2
1170
1171   This call uses transactions to ensure we don't get a new conflicting
1172   user while we are processing this, and to ensure the user either
1173   completly exists, or does not.
1174 */
1175 static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1176                                  struct samr_CreateUser2 *r)
1177 {
1178         NTSTATUS status;
1179         struct samr_domain_state *d_state;
1180         struct samr_account_state *a_state;
1181         struct dcesrv_handle *h;
1182         struct ldb_dn *dn;
1183         struct dom_sid *sid;
1184         struct dcesrv_handle *u_handle;
1185         const char *account_name;
1186
1187         ZERO_STRUCTP(r->out.user_handle);
1188         *r->out.access_granted = 0;
1189         *r->out.rid = 0;
1190
1191         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1192
1193         d_state = h->data;
1194
1195         if (d_state->builtin) {
1196                 DEBUG(5, ("Cannot create a user in the BUILTIN domain"));
1197                 return NT_STATUS_ACCESS_DENIED;
1198         } else if (r->in.acct_flags == ACB_DOMTRUST) {
1199                 /* Domain trust accounts must be created by the LSA calls */
1200                 return NT_STATUS_ACCESS_DENIED;
1201         }
1202         account_name = r->in.account_name->string;
1203
1204         if (account_name == NULL) {
1205                 return NT_STATUS_INVALID_PARAMETER;
1206         }
1207
1208         status = dsdb_add_user(d_state->sam_ctx, mem_ctx, account_name, r->in.acct_flags, NULL,
1209                                &sid, &dn);
1210         if (!NT_STATUS_IS_OK(status)) {
1211                 return status;
1212         }
1213         a_state = talloc(mem_ctx, struct samr_account_state);
1214         if (!a_state) {
1215                 return NT_STATUS_NO_MEMORY;
1216         }
1217         a_state->sam_ctx = d_state->sam_ctx;
1218         a_state->access_mask = r->in.access_mask;
1219         a_state->domain_state = talloc_reference(a_state, d_state);
1220         a_state->account_dn = talloc_steal(a_state, dn);
1221
1222         a_state->account_name = talloc_steal(a_state, account_name);
1223         if (!a_state->account_name) {
1224                 return NT_STATUS_NO_MEMORY;
1225         }
1226
1227         /* create the policy handle */
1228         u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
1229         if (!u_handle) {
1230                 return NT_STATUS_NO_MEMORY;
1231         }
1232
1233         u_handle->data = talloc_steal(u_handle, a_state);
1234
1235         *r->out.user_handle = u_handle->wire_handle;
1236         *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1237
1238         *r->out.rid = sid->sub_auths[sid->num_auths-1];
1239
1240         return NT_STATUS_OK;
1241 }
1242
1243
1244 /*
1245   samr_CreateUser
1246 */
1247 static NTSTATUS dcesrv_samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1248                                 struct samr_CreateUser *r)
1249 {
1250         struct samr_CreateUser2 r2;
1251         uint32_t access_granted = 0;
1252
1253
1254         /* a simple wrapper around samr_CreateUser2 works nicely */
1255         r2.in.domain_handle = r->in.domain_handle;
1256         r2.in.account_name = r->in.account_name;
1257         r2.in.acct_flags = ACB_NORMAL;
1258         r2.in.access_mask = r->in.access_mask;
1259         r2.out.user_handle = r->out.user_handle;
1260         r2.out.access_granted = &access_granted;
1261         r2.out.rid = r->out.rid;
1262
1263         return dcesrv_samr_CreateUser2(dce_call, mem_ctx, &r2);
1264 }
1265
1266 /*
1267   samr_EnumDomainUsers
1268 */
1269 static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1270                                      struct samr_EnumDomainUsers *r)
1271 {
1272         struct dcesrv_handle *h;
1273         struct samr_domain_state *d_state;
1274         struct ldb_message **res;
1275         int i, ldb_cnt;
1276         uint32_t first, count;
1277         struct samr_SamEntry *entries;
1278         const char * const attrs[] = { "objectSid", "sAMAccountName",
1279                 "userAccountControl", NULL };
1280         struct samr_SamArray *sam;
1281
1282         *r->out.resume_handle = 0;
1283         *r->out.sam = NULL;
1284         *r->out.num_entries = 0;
1285
1286         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1287
1288         d_state = h->data;
1289
1290         /* search for all domain users in this domain. This could possibly be
1291            cached and resumed on resume_key */
1292         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1293                                       d_state->domain_dn,
1294                                       &res, attrs,
1295                                       d_state->domain_sid,
1296                                       "(objectClass=user)");
1297         if (ldb_cnt < 0) {
1298                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1299         }
1300
1301         /* convert to SamEntry format */
1302         entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1303         if (!entries) {
1304                 return NT_STATUS_NO_MEMORY;
1305         }
1306
1307         count = 0;
1308
1309         for (i=0;i<ldb_cnt;i++) {
1310                 /* Check if a mask has been requested */
1311                 if (r->in.acct_flags
1312                     && ((samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
1313                                                  res[i], d_state->domain_dn) & r->in.acct_flags) == 0)) {
1314                         continue;
1315                 }
1316                 entries[count].idx = samdb_result_rid_from_sid(mem_ctx, res[i],
1317                                                                "objectSid", 0);
1318                 entries[count].name.string = ldb_msg_find_attr_as_string(res[i],
1319                                                                  "sAMAccountName", "");
1320                 count += 1;
1321         }
1322
1323         /* sort the results by rid */
1324         TYPESAFE_QSORT(entries, count, compare_SamEntry);
1325
1326         /* find the first entry to return */
1327         for (first=0;
1328              first<count && entries[first].idx <= *r->in.resume_handle;
1329              first++) ;
1330
1331         /* return the rest, limit by max_size. Note that we
1332            use the w2k3 element size value of 54 */
1333         *r->out.num_entries = count - first;
1334         *r->out.num_entries = MIN(*r->out.num_entries,
1335                                  1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1336
1337         sam = talloc(mem_ctx, struct samr_SamArray);
1338         if (!sam) {
1339                 return NT_STATUS_NO_MEMORY;
1340         }
1341
1342         sam->entries = entries+first;
1343         sam->count = *r->out.num_entries;
1344
1345         *r->out.sam = sam;
1346
1347         if (first == count) {
1348                 return NT_STATUS_OK;
1349         }
1350
1351         if (*r->out.num_entries < count - first) {
1352                 *r->out.resume_handle = entries[first+*r->out.num_entries-1].idx;
1353                 return STATUS_MORE_ENTRIES;
1354         }
1355
1356         return NT_STATUS_OK;
1357 }
1358
1359
1360 /*
1361   samr_CreateDomAlias
1362 */
1363 static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1364                        struct samr_CreateDomAlias *r)
1365 {
1366         struct samr_domain_state *d_state;
1367         struct samr_account_state *a_state;
1368         struct dcesrv_handle *h;
1369         const char *alias_name;
1370         struct dom_sid *sid;
1371         struct dcesrv_handle *a_handle;
1372         struct ldb_dn *dn;
1373         NTSTATUS status;
1374
1375         ZERO_STRUCTP(r->out.alias_handle);
1376         *r->out.rid = 0;
1377
1378         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1379
1380         d_state = h->data;
1381
1382         if (d_state->builtin) {
1383                 DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain"));
1384                 return NT_STATUS_ACCESS_DENIED;
1385         }
1386
1387         alias_name = r->in.alias_name->string;
1388
1389         if (alias_name == NULL) {
1390                 return NT_STATUS_INVALID_PARAMETER;
1391         }
1392
1393         status = dsdb_add_domain_alias(d_state->sam_ctx, mem_ctx, alias_name, &sid, &dn);
1394         if (!NT_STATUS_IS_OK(status)) {
1395                 return status;
1396         }
1397
1398         a_state = talloc(mem_ctx, struct samr_account_state);
1399         if (!a_state) {
1400                 return NT_STATUS_NO_MEMORY;
1401         }
1402
1403         a_state->sam_ctx = d_state->sam_ctx;
1404         a_state->access_mask = r->in.access_mask;
1405         a_state->domain_state = talloc_reference(a_state, d_state);
1406         a_state->account_dn = talloc_steal(a_state, dn);
1407
1408         a_state->account_name = talloc_steal(a_state, alias_name);
1409
1410         /* create the policy handle */
1411         a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1412         if (a_handle == NULL)
1413                 return NT_STATUS_NO_MEMORY;
1414
1415         a_handle->data = talloc_steal(a_handle, a_state);
1416
1417         *r->out.alias_handle = a_handle->wire_handle;
1418
1419         *r->out.rid = sid->sub_auths[sid->num_auths-1];
1420
1421         return NT_STATUS_OK;
1422 }
1423
1424
1425 /*
1426   samr_EnumDomainAliases
1427 */
1428 static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1429                        struct samr_EnumDomainAliases *r)
1430 {
1431         struct dcesrv_handle *h;
1432         struct samr_domain_state *d_state;
1433         struct ldb_message **res;
1434         int i, ldb_cnt;
1435         uint32_t first, count;
1436         struct samr_SamEntry *entries;
1437         const char * const attrs[] = { "objectSid", "sAMAccountName", NULL };
1438         struct samr_SamArray *sam;
1439
1440         *r->out.resume_handle = 0;
1441         *r->out.sam = NULL;
1442         *r->out.num_entries = 0;
1443
1444         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1445
1446         d_state = h->data;
1447
1448         /* search for all domain aliases in this domain. This could possibly be
1449            cached and resumed based on resume_key */
1450         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx, NULL,
1451                                       &res, attrs,
1452                                       d_state->domain_sid,
1453                                       "(&(|(grouptype=%d)(grouptype=%d)))"
1454                                       "(objectclass=group))",
1455                                       GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1456                                       GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1457         if (ldb_cnt < 0) {
1458                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1459         }
1460
1461         /* convert to SamEntry format */
1462         entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1463         if (!entries) {
1464                 return NT_STATUS_NO_MEMORY;
1465         }
1466
1467         count = 0;
1468
1469         for (i=0;i<ldb_cnt;i++) {
1470                 struct dom_sid *alias_sid;
1471
1472                 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1473                                                  "objectSid");
1474
1475                 if (alias_sid == NULL) {
1476                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1477                 }
1478
1479                 entries[count].idx =
1480                         alias_sid->sub_auths[alias_sid->num_auths-1];
1481                 entries[count].name.string =
1482                         ldb_msg_find_attr_as_string(res[i], "sAMAccountName", "");
1483                 count += 1;
1484         }
1485
1486         /* sort the results by rid */
1487         TYPESAFE_QSORT(entries, count, compare_SamEntry);
1488
1489         /* find the first entry to return */
1490         for (first=0;
1491              first<count && entries[first].idx <= *r->in.resume_handle;
1492              first++) ;
1493
1494         /* return the rest, limit by max_size. Note that we
1495            use the w2k3 element size value of 54 */
1496         *r->out.num_entries = count - first;
1497         *r->out.num_entries = MIN(*r->out.num_entries,
1498                                   1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1499
1500         sam = talloc(mem_ctx, struct samr_SamArray);
1501         if (!sam) {
1502                 return NT_STATUS_NO_MEMORY;
1503         }
1504
1505         sam->entries = entries+first;
1506         sam->count = *r->out.num_entries;
1507
1508         *r->out.sam = sam;
1509
1510         if (first == count) {
1511                 return NT_STATUS_OK;
1512         }
1513
1514         if (*r->out.num_entries < count - first) {
1515                 *r->out.resume_handle =
1516                         entries[first+*r->out.num_entries-1].idx;
1517                 return STATUS_MORE_ENTRIES;
1518         }
1519
1520         return NT_STATUS_OK;
1521 }
1522
1523
1524 /*
1525   samr_GetAliasMembership
1526 */
1527 static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1528                        struct samr_GetAliasMembership *r)
1529 {
1530         struct dcesrv_handle *h;
1531         struct samr_domain_state *d_state;
1532         const char *filter;
1533         const char * const attrs[] = { "objectSid", NULL };
1534         struct ldb_message **res;
1535         uint32_t i;
1536         int count = 0;
1537
1538         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1539
1540         d_state = h->data;
1541
1542         filter = talloc_asprintf(mem_ctx,
1543                                  "(&(|(grouptype=%d)(grouptype=%d))"
1544                                  "(objectclass=group)(|",
1545                                  GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1546                                  GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1547         if (filter == NULL) {
1548                 return NT_STATUS_NO_MEMORY;
1549         }
1550
1551         for (i=0; i<r->in.sids->num_sids; i++) {
1552                 const char *memberdn;
1553
1554                 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1555                                                "distinguishedName",
1556                                                "(objectSid=%s)",
1557                                                ldap_encode_ndr_dom_sid(mem_ctx,
1558                                                                        r->in.sids->sids[i].sid));
1559                 if (memberdn == NULL) {
1560                         continue;
1561                 }
1562
1563                 filter = talloc_asprintf(mem_ctx, "%s(member=%s)", filter,
1564                                          memberdn);
1565                 if (filter == NULL) {
1566                         return NT_STATUS_NO_MEMORY;
1567                 }
1568         }
1569
1570         /* Find out if we had at least one valid member SID passed - otherwise
1571          * just skip the search. */
1572         if (strstr(filter, "member") != NULL) {
1573                 count = samdb_search_domain(d_state->sam_ctx, mem_ctx, NULL,
1574                                             &res, attrs, d_state->domain_sid,
1575                                             "%s))", filter);
1576                 if (count < 0) {
1577                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1578                 }
1579         }
1580
1581         r->out.rids->count = 0;
1582         r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1583         if (r->out.rids->ids == NULL)
1584                 return NT_STATUS_NO_MEMORY;
1585
1586         for (i=0; i<count; i++) {
1587                 struct dom_sid *alias_sid;
1588
1589                 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1590                 if (alias_sid == NULL) {
1591                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1592                 }
1593
1594                 r->out.rids->ids[r->out.rids->count] =
1595                         alias_sid->sub_auths[alias_sid->num_auths-1];
1596                 r->out.rids->count += 1;
1597         }
1598
1599         return NT_STATUS_OK;
1600 }
1601
1602
1603 /*
1604   samr_LookupNames
1605 */
1606 static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1607                                  struct samr_LookupNames *r)
1608 {
1609         struct dcesrv_handle *h;
1610         struct samr_domain_state *d_state;
1611         uint32_t i, num_mapped;
1612         NTSTATUS status = NT_STATUS_OK;
1613         const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1614         int count;
1615
1616         ZERO_STRUCTP(r->out.rids);
1617         ZERO_STRUCTP(r->out.types);
1618
1619         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1620
1621         d_state = h->data;
1622
1623         if (r->in.num_names == 0) {
1624                 return NT_STATUS_OK;
1625         }
1626
1627         r->out.rids->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1628         r->out.types->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1629         if (!r->out.rids->ids || !r->out.types->ids) {
1630                 return NT_STATUS_NO_MEMORY;
1631         }
1632         r->out.rids->count = r->in.num_names;
1633         r->out.types->count = r->in.num_names;
1634
1635         num_mapped = 0;
1636
1637         for (i=0;i<r->in.num_names;i++) {
1638                 struct ldb_message **res;
1639                 struct dom_sid *sid;
1640                 uint32_t atype, rtype;
1641
1642                 r->out.rids->ids[i] = 0;
1643                 r->out.types->ids[i] = SID_NAME_UNKNOWN;
1644
1645                 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
1646                                      "sAMAccountName=%s",
1647                                      ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1648                 if (count != 1) {
1649                         status = STATUS_SOME_UNMAPPED;
1650                         continue;
1651                 }
1652
1653                 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1654                 if (sid == NULL) {
1655                         status = STATUS_SOME_UNMAPPED;
1656                         continue;
1657                 }
1658
1659                 atype = ldb_msg_find_attr_as_uint(res[0], "sAMAccountType", 0);
1660                 if (atype == 0) {
1661                         status = STATUS_SOME_UNMAPPED;
1662                         continue;
1663                 }
1664
1665                 rtype = ds_atype_map(atype);
1666
1667                 if (rtype == SID_NAME_UNKNOWN) {
1668                         status = STATUS_SOME_UNMAPPED;
1669                         continue;
1670                 }
1671
1672                 r->out.rids->ids[i] = sid->sub_auths[sid->num_auths-1];
1673                 r->out.types->ids[i] = rtype;
1674                 num_mapped++;
1675         }
1676
1677         if (num_mapped == 0) {
1678                 return NT_STATUS_NONE_MAPPED;
1679         }
1680         return status;
1681 }
1682
1683
1684 /*
1685   samr_LookupRids
1686 */
1687 static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1688                        struct samr_LookupRids *r)
1689 {
1690         NTSTATUS status;
1691         struct dcesrv_handle *h;
1692         struct samr_domain_state *d_state;
1693         const char **names;
1694         struct lsa_String *lsa_names;
1695         enum lsa_SidType *ids;
1696
1697         ZERO_STRUCTP(r->out.names);
1698         ZERO_STRUCTP(r->out.types);
1699
1700         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1701
1702         d_state = h->data;
1703
1704         if (r->in.num_rids == 0)
1705                 return NT_STATUS_OK;
1706
1707         lsa_names = talloc_zero_array(mem_ctx, struct lsa_String, r->in.num_rids);
1708         names = talloc_zero_array(mem_ctx, const char *, r->in.num_rids);
1709         ids = talloc_zero_array(mem_ctx, enum lsa_SidType, r->in.num_rids);
1710
1711         if ((lsa_names == NULL) || (names == NULL) || (ids == NULL))
1712                 return NT_STATUS_NO_MEMORY;
1713
1714         r->out.names->names = lsa_names;
1715         r->out.names->count = r->in.num_rids;
1716
1717         r->out.types->ids = (uint32_t *) ids;
1718         r->out.types->count = r->in.num_rids;
1719
1720         status = dsdb_lookup_rids(d_state->sam_ctx, mem_ctx, d_state->domain_sid,
1721                                   r->in.num_rids, r->in.rids, names, ids);
1722         if (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED) || NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
1723                 uint32_t i;
1724                 for (i = 0; i < r->in.num_rids; i++) {
1725                         lsa_names[i].string = names[i];
1726                 }
1727         }
1728         return status;
1729 }
1730
1731
1732 /*
1733   samr_OpenGroup
1734 */
1735 static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1736                        struct samr_OpenGroup *r)
1737 {
1738         struct samr_domain_state *d_state;
1739         struct samr_account_state *a_state;
1740         struct dcesrv_handle *h;
1741         const char *groupname;
1742         struct dom_sid *sid;
1743         struct ldb_message **msgs;
1744         struct dcesrv_handle *g_handle;
1745         const char * const attrs[2] = { "sAMAccountName", NULL };
1746         int ret;
1747
1748         ZERO_STRUCTP(r->out.group_handle);
1749
1750         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1751
1752         d_state = h->data;
1753
1754         /* form the group SID */
1755         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1756         if (!sid) {
1757                 return NT_STATUS_NO_MEMORY;
1758         }
1759
1760         /* search for the group record */
1761         ret = gendb_search(d_state->sam_ctx,
1762                            mem_ctx, d_state->domain_dn, &msgs, attrs,
1763                            "(&(objectSid=%s)(objectClass=group)"
1764                            "(|(groupType=%d)(groupType=%d)))",
1765                            ldap_encode_ndr_dom_sid(mem_ctx, sid),
1766                            GTYPE_SECURITY_UNIVERSAL_GROUP,
1767                            GTYPE_SECURITY_GLOBAL_GROUP);
1768         if (ret == 0) {
1769                 return NT_STATUS_NO_SUCH_GROUP;
1770         }
1771         if (ret != 1) {
1772                 DEBUG(0,("Found %d records matching sid %s\n",
1773                          ret, dom_sid_string(mem_ctx, sid)));
1774                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1775         }
1776
1777         groupname = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
1778         if (groupname == NULL) {
1779                 DEBUG(0,("sAMAccountName field missing for sid %s\n",
1780                          dom_sid_string(mem_ctx, sid)));
1781                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1782         }
1783
1784         a_state = talloc(mem_ctx, struct samr_account_state);
1785         if (!a_state) {
1786                 return NT_STATUS_NO_MEMORY;
1787         }
1788         a_state->sam_ctx = d_state->sam_ctx;
1789         a_state->access_mask = r->in.access_mask;
1790         a_state->domain_state = talloc_reference(a_state, d_state);
1791         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1792         a_state->account_sid = talloc_steal(a_state, sid);
1793         a_state->account_name = talloc_strdup(a_state, groupname);
1794         if (!a_state->account_name) {
1795                 return NT_STATUS_NO_MEMORY;
1796         }
1797
1798         /* create the policy handle */
1799         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1800         if (!g_handle) {
1801                 return NT_STATUS_NO_MEMORY;
1802         }
1803
1804         g_handle->data = talloc_steal(g_handle, a_state);
1805
1806         *r->out.group_handle = g_handle->wire_handle;
1807
1808         return NT_STATUS_OK;
1809 }
1810
1811 /*
1812   samr_QueryGroupInfo
1813 */
1814 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1815                        struct samr_QueryGroupInfo *r)
1816 {
1817         struct dcesrv_handle *h;
1818         struct samr_account_state *a_state;
1819         struct ldb_message *msg, **res;
1820         const char * const attrs[4] = { "sAMAccountName", "description",
1821                                         "numMembers", NULL };
1822         int ret;
1823         union samr_GroupInfo *info;
1824
1825         *r->out.info = NULL;
1826
1827         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1828
1829         a_state = h->data;
1830
1831         /* pull all the group attributes */
1832         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
1833                               a_state->account_dn, &res, attrs);
1834         if (ret == 0) {
1835                 return NT_STATUS_NO_SUCH_GROUP;
1836         }
1837         if (ret != 1) {
1838                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1839         }
1840         msg = res[0];
1841
1842         /* allocate the info structure */
1843         info = talloc_zero(mem_ctx, union samr_GroupInfo);
1844         if (info == NULL) {
1845                 return NT_STATUS_NO_MEMORY;
1846         }
1847
1848         /* Fill in the level */
1849         switch (r->in.level) {
1850         case GROUPINFOALL:
1851                 QUERY_STRING(msg, all.name,        "sAMAccountName");
1852                 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1853                 QUERY_UINT  (msg, all.num_members,      "numMembers")
1854                 QUERY_STRING(msg, all.description, "description");
1855                 break;
1856         case GROUPINFONAME:
1857                 QUERY_STRING(msg, name,            "sAMAccountName");
1858                 break;
1859         case GROUPINFOATTRIBUTES:
1860                 info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1861                 break;
1862         case GROUPINFODESCRIPTION:
1863                 QUERY_STRING(msg, description, "description");
1864                 break;
1865         case GROUPINFOALL2:
1866                 QUERY_STRING(msg, all2.name,        "sAMAccountName");
1867                 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
1868                 QUERY_UINT  (msg, all2.num_members,      "numMembers")
1869                 QUERY_STRING(msg, all2.description, "description");
1870                 break;
1871         default:
1872                 talloc_free(info);
1873                 return NT_STATUS_INVALID_INFO_CLASS;
1874         }
1875
1876         *r->out.info = info;
1877
1878         return NT_STATUS_OK;
1879 }
1880
1881
1882 /*
1883   samr_SetGroupInfo
1884 */
1885 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1886                                   struct samr_SetGroupInfo *r)
1887 {
1888         struct dcesrv_handle *h;
1889         struct samr_account_state *g_state;
1890         struct ldb_message *msg;
1891         struct ldb_context *sam_ctx;
1892         int ret;
1893
1894         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1895
1896         g_state = h->data;
1897         sam_ctx = g_state->sam_ctx;
1898
1899         msg = ldb_msg_new(mem_ctx);
1900         if (msg == NULL) {
1901                 return NT_STATUS_NO_MEMORY;
1902         }
1903
1904         msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
1905         if (!msg->dn) {
1906                 return NT_STATUS_NO_MEMORY;
1907         }
1908
1909         switch (r->in.level) {
1910         case GROUPINFODESCRIPTION:
1911                 SET_STRING(msg, description,         "description");
1912                 break;
1913         case GROUPINFONAME:
1914                 /* On W2k3 this does not change the name, it changes the
1915                  * sAMAccountName attribute */
1916                 SET_STRING(msg, name,                "sAMAccountName");
1917                 break;
1918         case GROUPINFOATTRIBUTES:
1919                 /* This does not do anything obviously visible in W2k3 LDAP */
1920                 return NT_STATUS_OK;
1921         default:
1922                 return NT_STATUS_INVALID_INFO_CLASS;
1923         }
1924
1925         /* modify the samdb record */
1926         ret = ldb_modify(g_state->sam_ctx, msg);
1927         if (ret != LDB_SUCCESS) {
1928                 return dsdb_ldb_err_to_ntstatus(ret);
1929         }
1930
1931         return NT_STATUS_OK;
1932 }
1933
1934
1935 /*
1936   samr_AddGroupMember
1937 */
1938 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1939                        struct samr_AddGroupMember *r)
1940 {
1941         struct dcesrv_handle *h;
1942         struct samr_account_state *a_state;
1943         struct samr_domain_state *d_state;
1944         struct ldb_message *mod;
1945         struct dom_sid *membersid;
1946         const char *memberdn;
1947         struct ldb_result *res;
1948         const char * const attrs[] = { NULL };
1949         int ret;
1950
1951         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1952
1953         a_state = h->data;
1954         d_state = a_state->domain_state;
1955
1956         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1957         if (membersid == NULL) {
1958                 return NT_STATUS_NO_MEMORY;
1959         }
1960
1961         /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
1962         ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
1963                          d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
1964                          "(objectSid=%s)",
1965                          ldap_encode_ndr_dom_sid(mem_ctx, membersid));
1966
1967         if (ret != LDB_SUCCESS) {
1968                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1969         }
1970
1971         if (res->count == 0) {
1972                 return NT_STATUS_NO_SUCH_USER;
1973         }
1974
1975         if (res->count > 1) {
1976                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1977         }
1978
1979         memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
1980
1981         if (memberdn == NULL)
1982                 return NT_STATUS_NO_MEMORY;
1983
1984         mod = ldb_msg_new(mem_ctx);
1985         if (mod == NULL) {
1986                 return NT_STATUS_NO_MEMORY;
1987         }
1988
1989         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
1990
1991         ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
1992                                                                 memberdn);
1993         if (ret != LDB_SUCCESS) {
1994                 return dsdb_ldb_err_to_ntstatus(ret);
1995         }
1996
1997         ret = ldb_modify(a_state->sam_ctx, mod);
1998         switch (ret) {
1999         case LDB_SUCCESS:
2000                 return NT_STATUS_OK;
2001         case LDB_ERR_ENTRY_ALREADY_EXISTS:
2002                 return NT_STATUS_MEMBER_IN_GROUP;
2003         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2004                 return NT_STATUS_ACCESS_DENIED;
2005         default:
2006                 return dsdb_ldb_err_to_ntstatus(ret);
2007         }
2008 }
2009
2010
2011 /*
2012   samr_DeleteDomainGroup
2013 */
2014 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2015                        struct samr_DeleteDomainGroup *r)
2016 {
2017         struct dcesrv_handle *h;
2018         struct samr_account_state *a_state;
2019         int ret;
2020
2021         *r->out.group_handle = *r->in.group_handle;
2022
2023         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2024
2025         a_state = h->data;
2026
2027         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2028         if (ret != LDB_SUCCESS) {
2029                 return dsdb_ldb_err_to_ntstatus(ret);
2030         }
2031
2032         talloc_free(h);
2033         ZERO_STRUCTP(r->out.group_handle);
2034
2035         return NT_STATUS_OK;
2036 }
2037
2038
2039 /*
2040   samr_DeleteGroupMember
2041 */
2042 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2043                        struct samr_DeleteGroupMember *r)
2044 {
2045         struct dcesrv_handle *h;
2046         struct samr_account_state *a_state;
2047         struct samr_domain_state *d_state;
2048         struct ldb_message *mod;
2049         struct dom_sid *membersid;
2050         const char *memberdn;
2051         struct ldb_result *res;
2052         const char * const attrs[] = { NULL };
2053         int ret;
2054
2055         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2056
2057         a_state = h->data;
2058         d_state = a_state->domain_state;
2059
2060         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2061         if (membersid == NULL) {
2062                 return NT_STATUS_NO_MEMORY;
2063         }
2064
2065         /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
2066         ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2067                          d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2068                          "(objectSid=%s)",
2069                          ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2070
2071         if (ret != LDB_SUCCESS) {
2072                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2073         }
2074
2075         if (res->count == 0) {
2076                 return NT_STATUS_NO_SUCH_USER;
2077         }
2078
2079         if (res->count > 1) {
2080                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2081         }
2082
2083         memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2084
2085         if (memberdn == NULL)
2086                 return NT_STATUS_NO_MEMORY;
2087
2088         mod = ldb_msg_new(mem_ctx);
2089         if (mod == NULL) {
2090                 return NT_STATUS_NO_MEMORY;
2091         }
2092
2093         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2094
2095         ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2096                                                                 memberdn);
2097         if (ret != LDB_SUCCESS) {
2098                 return NT_STATUS_NO_MEMORY;
2099         }
2100
2101         ret = ldb_modify(a_state->sam_ctx, mod);
2102         switch (ret) {
2103         case LDB_SUCCESS:
2104                 return NT_STATUS_OK;
2105         case LDB_ERR_UNWILLING_TO_PERFORM:
2106                 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2107         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2108                 return NT_STATUS_ACCESS_DENIED;
2109         default:
2110                 return dsdb_ldb_err_to_ntstatus(ret);
2111         }
2112 }
2113
2114
2115 /*
2116   samr_QueryGroupMember
2117 */
2118 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2119                                       struct samr_QueryGroupMember *r)
2120 {
2121         struct dcesrv_handle *h;
2122         struct samr_account_state *a_state;
2123         struct samr_domain_state *d_state;
2124         struct samr_RidAttrArray *array;
2125         unsigned int i, num_members;
2126         struct dom_sid *members;
2127         NTSTATUS status;
2128
2129         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2130
2131         a_state = h->data;
2132         d_state = a_state->domain_state;
2133
2134         status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
2135                                      a_state->account_dn, &members,
2136                                      &num_members);
2137         if (!NT_STATUS_IS_OK(status)) {
2138                 return status;
2139         }
2140
2141         array = talloc_zero(mem_ctx, struct samr_RidAttrArray);
2142         if (array == NULL) {
2143                 return NT_STATUS_NO_MEMORY;
2144         }
2145
2146         if (num_members == 0) {
2147                 *r->out.rids = array;
2148
2149                 return NT_STATUS_OK;
2150         }
2151
2152         array->rids = talloc_array(array, uint32_t, num_members);
2153         if (array->rids == NULL) {
2154                 return NT_STATUS_NO_MEMORY;
2155         }
2156
2157         array->attributes = talloc_array(array, uint32_t, num_members);
2158         if (array->attributes == NULL) {
2159                 return NT_STATUS_NO_MEMORY;
2160         }
2161
2162         array->count = 0;
2163         for (i=0; i<num_members; i++) {
2164                 if (!dom_sid_in_domain(d_state->domain_sid, &members[i])) {
2165                         continue;
2166                 }
2167
2168                 status = dom_sid_split_rid(NULL, &members[i], NULL,
2169                                            &array->rids[array->count]);
2170                 if (!NT_STATUS_IS_OK(status)) {
2171                         return status;
2172                 }
2173
2174                 array->attributes[array->count] = SE_GROUP_MANDATORY |
2175                                                   SE_GROUP_ENABLED_BY_DEFAULT |
2176                                                   SE_GROUP_ENABLED;
2177                 array->count++;
2178         }
2179
2180         *r->out.rids = array;
2181
2182         return NT_STATUS_OK;
2183 }
2184
2185
2186 /*
2187   samr_SetMemberAttributesOfGroup
2188 */
2189 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2190                        struct samr_SetMemberAttributesOfGroup *r)
2191 {
2192         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2193 }
2194
2195
2196 /*
2197   samr_OpenAlias
2198 */
2199 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2200                        struct samr_OpenAlias *r)
2201 {
2202         struct samr_domain_state *d_state;
2203         struct samr_account_state *a_state;
2204         struct dcesrv_handle *h;
2205         const char *alias_name;
2206         struct dom_sid *sid;
2207         struct ldb_message **msgs;
2208         struct dcesrv_handle *g_handle;
2209         const char * const attrs[2] = { "sAMAccountName", NULL };
2210         int ret;
2211
2212         ZERO_STRUCTP(r->out.alias_handle);
2213
2214         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2215
2216         d_state = h->data;
2217
2218         /* form the alias SID */
2219         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2220         if (sid == NULL)
2221                 return NT_STATUS_NO_MEMORY;
2222
2223         /* search for the group record */
2224         ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL, &msgs, attrs,
2225                            "(&(objectSid=%s)(objectclass=group)"
2226                            "(|(grouptype=%d)(grouptype=%d)))",
2227                            ldap_encode_ndr_dom_sid(mem_ctx, sid),
2228                            GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2229                            GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2230         if (ret == 0) {
2231                 return NT_STATUS_NO_SUCH_ALIAS;
2232         }
2233         if (ret != 1) {
2234                 DEBUG(0,("Found %d records matching sid %s\n",
2235                          ret, dom_sid_string(mem_ctx, sid)));
2236                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2237         }
2238
2239         alias_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2240         if (alias_name == NULL) {
2241                 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2242                          dom_sid_string(mem_ctx, sid)));
2243                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2244         }
2245
2246         a_state = talloc(mem_ctx, struct samr_account_state);
2247         if (!a_state) {
2248                 return NT_STATUS_NO_MEMORY;
2249         }
2250         a_state->sam_ctx = d_state->sam_ctx;
2251         a_state->access_mask = r->in.access_mask;
2252         a_state->domain_state = talloc_reference(a_state, d_state);
2253         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2254         a_state->account_sid = talloc_steal(a_state, sid);
2255         a_state->account_name = talloc_strdup(a_state, alias_name);
2256         if (!a_state->account_name) {
2257                 return NT_STATUS_NO_MEMORY;
2258         }
2259
2260         /* create the policy handle */
2261         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2262         if (!g_handle) {
2263                 return NT_STATUS_NO_MEMORY;
2264         }
2265
2266         g_handle->data = talloc_steal(g_handle, a_state);
2267
2268         *r->out.alias_handle = g_handle->wire_handle;
2269
2270         return NT_STATUS_OK;
2271 }
2272
2273
2274 /*
2275   samr_QueryAliasInfo
2276 */
2277 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2278                        struct samr_QueryAliasInfo *r)
2279 {
2280         struct dcesrv_handle *h;
2281         struct samr_account_state *a_state;
2282         struct ldb_message *msg, **res;
2283         const char * const attrs[4] = { "sAMAccountName", "description",
2284                                         "numMembers", NULL };
2285         int ret;
2286         union samr_AliasInfo *info;
2287
2288         *r->out.info = NULL;
2289
2290         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2291
2292         a_state = h->data;
2293
2294         /* pull all the alias attributes */
2295         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2296                               a_state->account_dn, &res, attrs);
2297         if (ret == 0) {
2298                 return NT_STATUS_NO_SUCH_ALIAS;
2299         }
2300         if (ret != 1) {
2301                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2302         }
2303         msg = res[0];
2304
2305         /* allocate the info structure */
2306         info = talloc_zero(mem_ctx, union samr_AliasInfo);
2307         if (info == NULL) {
2308                 return NT_STATUS_NO_MEMORY;
2309         }
2310
2311         switch(r->in.level) {
2312         case ALIASINFOALL:
2313                 QUERY_STRING(msg, all.name, "sAMAccountName");
2314                 QUERY_UINT  (msg, all.num_members, "numMembers");
2315                 QUERY_STRING(msg, all.description, "description");
2316                 break;
2317         case ALIASINFONAME:
2318                 QUERY_STRING(msg, name, "sAMAccountName");
2319                 break;
2320         case ALIASINFODESCRIPTION:
2321                 QUERY_STRING(msg, description, "description");
2322                 break;
2323         default:
2324                 talloc_free(info);
2325                 return NT_STATUS_INVALID_INFO_CLASS;
2326         }
2327
2328         *r->out.info = info;
2329
2330         return NT_STATUS_OK;
2331 }
2332
2333
2334 /*
2335   samr_SetAliasInfo
2336 */
2337 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2338                        struct samr_SetAliasInfo *r)
2339 {
2340         struct dcesrv_handle *h;
2341         struct samr_account_state *a_state;
2342         struct ldb_message *msg;
2343         struct ldb_context *sam_ctx;
2344         int ret;
2345
2346         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2347
2348         a_state = h->data;
2349         sam_ctx = a_state->sam_ctx;
2350
2351         msg = ldb_msg_new(mem_ctx);
2352         if (msg == NULL) {
2353                 return NT_STATUS_NO_MEMORY;
2354         }
2355
2356         msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2357         if (!msg->dn) {
2358                 return NT_STATUS_NO_MEMORY;
2359         }
2360
2361         switch (r->in.level) {
2362         case ALIASINFODESCRIPTION:
2363                 SET_STRING(msg, description,         "description");
2364                 break;
2365         case ALIASINFONAME:
2366                 /* On W2k3 this does not change the name, it changes the
2367                  * sAMAccountName attribute */
2368                 SET_STRING(msg, name,                "sAMAccountName");
2369                 break;
2370         default:
2371                 return NT_STATUS_INVALID_INFO_CLASS;
2372         }
2373
2374         /* modify the samdb record */
2375         ret = ldb_modify(a_state->sam_ctx, msg);
2376         if (ret != LDB_SUCCESS) {
2377                 return dsdb_ldb_err_to_ntstatus(ret);
2378         }
2379
2380         return NT_STATUS_OK;
2381 }
2382
2383
2384 /*
2385   samr_DeleteDomAlias
2386 */
2387 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2388                        struct samr_DeleteDomAlias *r)
2389 {
2390         struct dcesrv_handle *h;
2391         struct samr_account_state *a_state;
2392         int ret;
2393
2394         *r->out.alias_handle = *r->in.alias_handle;
2395
2396         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2397
2398         a_state = h->data;
2399
2400         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2401         if (ret != LDB_SUCCESS) {
2402                 return dsdb_ldb_err_to_ntstatus(ret);
2403         }
2404
2405         talloc_free(h);
2406         ZERO_STRUCTP(r->out.alias_handle);
2407
2408         return NT_STATUS_OK;
2409 }
2410
2411
2412 /*
2413   samr_AddAliasMember
2414 */
2415 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2416                        struct samr_AddAliasMember *r)
2417 {
2418         struct dcesrv_handle *h;
2419         struct samr_account_state *a_state;
2420         struct samr_domain_state *d_state;
2421         struct ldb_message *mod;
2422         struct ldb_message **msgs;
2423         const char * const attrs[] = { NULL };
2424         struct ldb_dn *memberdn = NULL;
2425         int ret;
2426         NTSTATUS status;
2427
2428         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2429
2430         a_state = h->data;
2431         d_state = a_state->domain_state;
2432
2433         ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2434                            &msgs, attrs, "(objectsid=%s)",
2435                            ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2436
2437         if (ret == 1) {
2438                 memberdn = msgs[0]->dn;
2439         } else if (ret == 0) {
2440                 status = samdb_create_foreign_security_principal(
2441                         d_state->sam_ctx, mem_ctx, r->in.sid, &memberdn);
2442                 if (!NT_STATUS_IS_OK(status)) {
2443                         return status;
2444                 }
2445         } else {
2446                 DEBUG(0,("Found %d records matching sid %s\n",
2447                          ret, dom_sid_string(mem_ctx, r->in.sid)));
2448                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2449         }
2450
2451         if (memberdn == NULL) {
2452                 DEBUG(0, ("Could not find memberdn\n"));
2453                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2454         }
2455
2456         mod = ldb_msg_new(mem_ctx);
2457         if (mod == NULL) {
2458                 return NT_STATUS_NO_MEMORY;
2459         }
2460
2461         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2462
2463         ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2464                                  ldb_dn_alloc_linearized(mem_ctx, memberdn));
2465         if (ret != LDB_SUCCESS) {
2466                 return dsdb_ldb_err_to_ntstatus(ret);
2467         }
2468
2469         ret = ldb_modify(a_state->sam_ctx, mod);
2470         switch (ret) {
2471         case LDB_SUCCESS:
2472                 return NT_STATUS_OK;
2473         case LDB_ERR_ENTRY_ALREADY_EXISTS:
2474                 return NT_STATUS_MEMBER_IN_GROUP;
2475         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2476                 return NT_STATUS_ACCESS_DENIED;
2477         default:
2478                 return dsdb_ldb_err_to_ntstatus(ret);
2479         }
2480 }
2481
2482
2483 /*
2484   samr_DeleteAliasMember
2485 */
2486 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2487                        struct samr_DeleteAliasMember *r)
2488 {
2489         struct dcesrv_handle *h;
2490         struct samr_account_state *a_state;
2491         struct samr_domain_state *d_state;
2492         struct ldb_message *mod;
2493         const char *memberdn;
2494         int ret;
2495
2496         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2497
2498         a_state = h->data;
2499         d_state = a_state->domain_state;
2500
2501         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2502                                        "distinguishedName", "(objectSid=%s)",
2503                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2504         if (memberdn == NULL) {
2505                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2506         }
2507
2508         mod = ldb_msg_new(mem_ctx);
2509         if (mod == NULL) {
2510                 return NT_STATUS_NO_MEMORY;
2511         }
2512
2513         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2514
2515         ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2516                                                                  memberdn);
2517         if (ret != LDB_SUCCESS) {
2518                 return dsdb_ldb_err_to_ntstatus(ret);
2519         }
2520
2521         ret = ldb_modify(a_state->sam_ctx, mod);
2522         switch (ret) {
2523         case LDB_SUCCESS:
2524                 return NT_STATUS_OK;
2525         case LDB_ERR_UNWILLING_TO_PERFORM:
2526                 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2527         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2528                 return NT_STATUS_ACCESS_DENIED;
2529         default:
2530                 return dsdb_ldb_err_to_ntstatus(ret);
2531         }
2532 }
2533
2534
2535 /*
2536   samr_GetMembersInAlias
2537 */
2538 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2539                        struct samr_GetMembersInAlias *r)
2540 {
2541         struct dcesrv_handle *h;
2542         struct samr_account_state *a_state;
2543         struct samr_domain_state *d_state;
2544         struct lsa_SidPtr *array;
2545         unsigned int i, num_members;
2546         struct dom_sid *members;
2547         NTSTATUS status;
2548
2549         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2550
2551         a_state = h->data;
2552         d_state = a_state->domain_state;
2553
2554         status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
2555                                      a_state->account_dn, &members,
2556                                      &num_members);
2557         if (!NT_STATUS_IS_OK(status)) {
2558                 return status;
2559         }
2560
2561         if (num_members == 0) {
2562                 r->out.sids->sids = NULL;
2563
2564                 return NT_STATUS_OK;
2565         }
2566
2567         array = talloc_array(mem_ctx, struct lsa_SidPtr, num_members);
2568         if (array == NULL) {
2569                 return NT_STATUS_NO_MEMORY;
2570         }
2571
2572         for (i=0; i<num_members; i++) {
2573                 array[i].sid = &members[i];
2574         }
2575
2576         r->out.sids->num_sids = num_members;
2577         r->out.sids->sids = array;
2578
2579         return NT_STATUS_OK;
2580 }
2581
2582 /*
2583   samr_OpenUser
2584 */
2585 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2586                               struct samr_OpenUser *r)
2587 {
2588         struct samr_domain_state *d_state;
2589         struct samr_account_state *a_state;
2590         struct dcesrv_handle *h;
2591         const char *account_name;
2592         struct dom_sid *sid;
2593         struct ldb_message **msgs;
2594         struct dcesrv_handle *u_handle;
2595         const char * const attrs[2] = { "sAMAccountName", NULL };
2596         int ret;
2597
2598         ZERO_STRUCTP(r->out.user_handle);
2599
2600         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2601
2602         d_state = h->data;
2603
2604         /* form the users SID */
2605         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2606         if (!sid) {
2607                 return NT_STATUS_NO_MEMORY;
2608         }
2609
2610         /* search for the user record */
2611         ret = gendb_search(d_state->sam_ctx,
2612                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2613                            "(&(objectSid=%s)(objectclass=user))",
2614                            ldap_encode_ndr_dom_sid(mem_ctx, sid));
2615         if (ret == 0) {
2616                 return NT_STATUS_NO_SUCH_USER;
2617         }
2618         if (ret != 1) {
2619                 DEBUG(0,("Found %d records matching sid %s\n", ret,
2620                          dom_sid_string(mem_ctx, sid)));
2621                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2622         }
2623
2624         account_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2625         if (account_name == NULL) {
2626                 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2627                          dom_sid_string(mem_ctx, sid)));
2628                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2629         }
2630
2631         a_state = talloc(mem_ctx, struct samr_account_state);
2632         if (!a_state) {
2633                 return NT_STATUS_NO_MEMORY;
2634         }
2635         a_state->sam_ctx = d_state->sam_ctx;
2636         a_state->access_mask = r->in.access_mask;
2637         a_state->domain_state = talloc_reference(a_state, d_state);
2638         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2639         a_state->account_sid = talloc_steal(a_state, sid);
2640         a_state->account_name = talloc_strdup(a_state, account_name);
2641         if (!a_state->account_name) {
2642                 return NT_STATUS_NO_MEMORY;
2643         }
2644
2645         /* create the policy handle */
2646         u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2647         if (!u_handle) {
2648                 return NT_STATUS_NO_MEMORY;
2649         }
2650
2651         u_handle->data = talloc_steal(u_handle, a_state);
2652
2653         *r->out.user_handle = u_handle->wire_handle;
2654
2655         return NT_STATUS_OK;
2656
2657 }
2658
2659
2660 /*
2661   samr_DeleteUser
2662 */
2663 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2664                                 struct samr_DeleteUser *r)
2665 {
2666         struct dcesrv_handle *h;
2667         struct samr_account_state *a_state;
2668         int ret;
2669
2670         *r->out.user_handle = *r->in.user_handle;
2671
2672         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2673
2674         a_state = h->data;
2675
2676         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2677         if (ret != LDB_SUCCESS) {
2678                 DEBUG(1, ("Failed to delete user: %s: %s\n",
2679                           ldb_dn_get_linearized(a_state->account_dn),
2680                           ldb_errstring(a_state->sam_ctx)));
2681                 return dsdb_ldb_err_to_ntstatus(ret);
2682         }
2683
2684         talloc_free(h);
2685         ZERO_STRUCTP(r->out.user_handle);
2686
2687         return NT_STATUS_OK;
2688 }
2689
2690
2691 /*
2692   samr_QueryUserInfo
2693 */
2694 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2695                                    struct samr_QueryUserInfo *r)
2696 {
2697         struct dcesrv_handle *h;
2698         struct samr_account_state *a_state;
2699         struct ldb_message *msg, **res;
2700         int ret;
2701         struct ldb_context *sam_ctx;
2702
2703         const char * const *attrs = NULL;
2704         union samr_UserInfo *info;
2705
2706         *r->out.info = NULL;
2707
2708         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2709
2710         a_state = h->data;
2711         sam_ctx = a_state->sam_ctx;
2712
2713         /* fill in the reply */
2714         switch (r->in.level) {
2715         case 1:
2716         {
2717                 static const char * const attrs2[] = {"sAMAccountName",
2718                                                       "displayName",
2719                                                       "primaryroupID",
2720                                                       "description",
2721                                                       "comment",
2722                                                       NULL};
2723                 attrs = attrs2;
2724                 break;
2725         }
2726         case 2:
2727         {
2728                 static const char * const attrs2[] = {"comment",
2729                                                       "countryCode",
2730                                                       "codePage",
2731                                                       NULL};
2732                 attrs = attrs2;
2733                 break;
2734         }
2735         case 3:
2736         {
2737                 static const char * const attrs2[] = {"sAMAccountName",
2738                                                       "displayName",
2739                                                       "objectSid",
2740                                                       "primaryGroupID",
2741                                                       "homeDirectory",
2742                                                       "homeDrive",
2743                                                       "scriptPath",
2744                                                       "profilePath",
2745                                                       "userWorkstations",
2746                                                       "lastLogon",
2747                                                       "lastLogoff",
2748                                                       "pwdLastSet",
2749                                                       "logonHours",
2750                                                       "badPwdCount",
2751                                                       "logonCount",
2752                                                       "userAccountControl",
2753                                                       NULL};
2754                 attrs = attrs2;
2755                 break;
2756         }
2757         case 4:
2758         {
2759                 static const char * const attrs2[] = {"logonHours",
2760                                                       NULL};
2761                 attrs = attrs2;
2762                 break;
2763         }
2764         case 5:
2765         {
2766                 static const char * const attrs2[] = {"sAMAccountName",
2767                                                       "displayName",
2768                                                       "objectSid",
2769                                                       "primaryGroupID",
2770                                                       "homeDirectory",
2771                                                       "homeDrive",
2772                                                       "scriptPath",
2773                                                       "profilePath",
2774                                                       "description",
2775                                                       "userWorkstations",
2776                                                       "lastLogon",
2777                                                       "lastLogoff",
2778                                                       "logonHours",
2779                                                       "badPwdCount",
2780                                                       "logonCount",
2781                                                       "pwdLastSet",
2782                                                       "accountExpires",
2783                                                       "userAccountControl",
2784                                                       NULL};
2785                 attrs = attrs2;
2786                 break;
2787         }
2788         case 6:
2789         {
2790                 static const char * const attrs2[] = {"sAMAccountName",
2791                                                       "displayName",
2792                                                       NULL};
2793                 attrs = attrs2;
2794                 break;
2795         }
2796         case 7:
2797         {
2798                 static const char * const attrs2[] = {"sAMAccountName",
2799                                                       NULL};
2800                 attrs = attrs2;
2801                 break;
2802         }
2803         case 8:
2804         {
2805                 static const char * const attrs2[] = {"displayName",
2806                                                       NULL};
2807                 attrs = attrs2;
2808                 break;
2809         }
2810         case 9:
2811         {
2812                 static const char * const attrs2[] = {"primaryGroupID",
2813                                                       NULL};
2814                 attrs = attrs2;
2815                 break;
2816         }
2817         case 10:
2818         {
2819                 static const char * const attrs2[] = {"homeDirectory",
2820                                                       "homeDrive",
2821                                                       NULL};
2822                 attrs = attrs2;
2823                 break;
2824         }
2825         case 11:
2826         {
2827                 static const char * const attrs2[] = {"scriptPath",
2828                                                       NULL};
2829                 attrs = attrs2;
2830                 break;
2831         }
2832         case 12:
2833         {
2834                 static const char * const attrs2[] = {"profilePath",
2835                                                       NULL};
2836                 attrs = attrs2;
2837                 break;
2838         }
2839         case 13:
2840         {
2841                 static const char * const attrs2[] = {"description",
2842                                                       NULL};
2843                 attrs = attrs2;
2844                 break;
2845         }
2846         case 14:
2847         {
2848                 static const char * const attrs2[] = {"userWorkstations",
2849                                                       NULL};
2850                 attrs = attrs2;
2851                 break;
2852         }
2853         case 16:
2854         {
2855                 static const char * const attrs2[] = {"userAccountControl",
2856                                                       "pwdLastSet",
2857                                                       NULL};
2858                 attrs = attrs2;
2859                 break;
2860         }
2861         case 17:
2862         {
2863                 static const char * const attrs2[] = {"accountExpires",
2864                                                       NULL};
2865                 attrs = attrs2;
2866                 break;
2867         }
2868         case 18:
2869         {
2870                 return NT_STATUS_NOT_SUPPORTED;
2871         }
2872         case 20:
2873         {
2874                 static const char * const attrs2[] = {"userParameters",
2875                                                       NULL};
2876                 attrs = attrs2;
2877                 break;
2878         }
2879         case 21:
2880         {
2881                 static const char * const attrs2[] = {"lastLogon",
2882                                                       "lastLogoff",
2883                                                       "pwdLastSet",
2884                                                       "accountExpires",
2885                                                       "sAMAccountName",
2886                                                       "displayName",
2887                                                       "homeDirectory",
2888                                                       "homeDrive",
2889                                                       "scriptPath",
2890                                                       "profilePath",
2891                                                       "description",
2892                                                       "userWorkstations",
2893                                                       "comment",
2894                                                       "userParameters",
2895                                                       "objectSid",
2896                                                       "primaryGroupID",
2897                                                       "userAccountControl",
2898                                                       "logonHours",
2899                                                       "badPwdCount",
2900                                                       "logonCount",
2901                                                       "countryCode",
2902                                                       "codePage",
2903                                                       NULL};
2904                 attrs = attrs2;
2905                 break;
2906         }
2907         case 23:
2908         case 24:
2909         case 25:
2910         case 26:
2911         {
2912                 return NT_STATUS_NOT_SUPPORTED;
2913         }
2914         default:
2915         {
2916                 return NT_STATUS_INVALID_INFO_CLASS;
2917         }
2918         }
2919
2920         /* pull all the user attributes */
2921         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2922                               a_state->account_dn, &res, attrs);
2923         if (ret == 0) {
2924                 return NT_STATUS_NO_SUCH_USER;
2925         }
2926         if (ret != 1) {
2927                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2928         }
2929         msg = res[0];
2930
2931         /* allocate the info structure */
2932         info = talloc_zero(mem_ctx, union samr_UserInfo);
2933         if (info == NULL) {
2934                 return NT_STATUS_NO_MEMORY;
2935         }
2936
2937         /* fill in the reply */
2938         switch (r->in.level) {
2939         case 1:
2940                 QUERY_STRING(msg, info1.account_name,          "sAMAccountName");
2941                 QUERY_STRING(msg, info1.full_name,             "displayName");
2942                 QUERY_UINT  (msg, info1.primary_gid,           "primaryGroupID");
2943                 QUERY_STRING(msg, info1.description,           "description");
2944                 QUERY_STRING(msg, info1.comment,               "comment");
2945                 break;
2946
2947         case 2:
2948                 QUERY_STRING(msg, info2.comment,               "comment");
2949                 QUERY_UINT  (msg, info2.country_code,          "countryCode");
2950                 QUERY_UINT  (msg, info2.code_page,             "codePage");
2951                 break;
2952
2953         case 3:
2954                 QUERY_STRING(msg, info3.account_name,          "sAMAccountName");
2955                 QUERY_STRING(msg, info3.full_name,             "displayName");
2956                 QUERY_RID   (msg, info3.rid,                   "objectSid");
2957                 QUERY_UINT  (msg, info3.primary_gid,           "primaryGroupID");
2958                 QUERY_STRING(msg, info3.home_directory,        "homeDirectory");
2959                 QUERY_STRING(msg, info3.home_drive,            "homeDrive");
2960                 QUERY_STRING(msg, info3.logon_script,          "scriptPath");
2961                 QUERY_STRING(msg, info3.profile_path,          "profilePath");
2962                 QUERY_STRING(msg, info3.workstations,          "userWorkstations");
2963                 QUERY_UINT64(msg, info3.last_logon,            "lastLogon");
2964                 QUERY_UINT64(msg, info3.last_logoff,           "lastLogoff");
2965                 QUERY_UINT64(msg, info3.last_password_change,  "pwdLastSet");
2966                 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
2967                 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
2968                 QUERY_LHOURS(msg, info3.logon_hours,           "logonHours");
2969                 QUERY_UINT  (msg, info3.bad_password_count,    "badPwdCount");
2970                 QUERY_UINT  (msg, info3.logon_count,           "logonCount");
2971                 QUERY_AFLAGS(msg, info3.acct_flags,            "userAccountControl");
2972                 break;
2973
2974         case 4:
2975                 QUERY_LHOURS(msg, info4.logon_hours,           "logonHours");
2976                 break;
2977
2978         case 5:
2979                 QUERY_STRING(msg, info5.account_name,          "sAMAccountName");
2980                 QUERY_STRING(msg, info5.full_name,             "displayName");
2981                 QUERY_RID   (msg, info5.rid,                   "objectSid");
2982                 QUERY_UINT  (msg, info5.primary_gid,           "primaryGroupID");
2983                 QUERY_STRING(msg, info5.home_directory,        "homeDirectory");
2984                 QUERY_STRING(msg, info5.home_drive,            "homeDrive");
2985                 QUERY_STRING(msg, info5.logon_script,          "scriptPath");
2986                 QUERY_STRING(msg, info5.profile_path,          "profilePath");
2987                 QUERY_STRING(msg, info5.description,           "description");
2988                 QUERY_STRING(msg, info5.workstations,          "userWorkstations");
2989                 QUERY_UINT64(msg, info5.last_logon,            "lastLogon");
2990                 QUERY_UINT64(msg, info5.last_logoff,           "lastLogoff");
2991                 QUERY_LHOURS(msg, info5.logon_hours,           "logonHours");
2992                 QUERY_UINT  (msg, info5.bad_password_count,    "badPwdCount");
2993                 QUERY_UINT  (msg, info5.logon_count,           "logonCount");
2994                 QUERY_UINT64(msg, info5.last_password_change,  "pwdLastSet");
2995                 QUERY_UINT64(msg, info5.acct_expiry,           "accountExpires");
2996                 QUERY_AFLAGS(msg, info5.acct_flags,            "userAccountControl");
2997                 break;
2998
2999         case 6:
3000                 QUERY_STRING(msg, info6.account_name,   "sAMAccountName");
3001                 QUERY_STRING(msg, info6.full_name,      "displayName");
3002                 break;
3003
3004         case 7:
3005                 QUERY_STRING(msg, info7.account_name,   "sAMAccountName");
3006                 break;
3007
3008         case 8:
3009                 QUERY_STRING(msg, info8.full_name,      "displayName");
3010                 break;
3011
3012         case 9:
3013                 QUERY_UINT  (msg, info9.primary_gid,    "primaryGroupID");
3014                 break;
3015
3016         case 10:
3017                 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3018                 QUERY_STRING(msg, info10.home_drive,    "homeDrive");
3019                 break;
3020
3021         case 11:
3022                 QUERY_STRING(msg, info11.logon_script,  "scriptPath");
3023                 break;
3024
3025         case 12:
3026                 QUERY_STRING(msg, info12.profile_path,  "profilePath");
3027                 break;
3028
3029         case 13:
3030                 QUERY_STRING(msg, info13.description,   "description");
3031                 break;
3032
3033         case 14:
3034                 QUERY_STRING(msg, info14.workstations,  "userWorkstations");
3035                 break;
3036
3037         case 16:
3038                 QUERY_AFLAGS(msg, info16.acct_flags,    "userAccountControl");
3039                 break;
3040
3041         case 17:
3042                 QUERY_UINT64(msg, info17.acct_expiry,   "accountExpires");
3043                 break;
3044
3045         case 20:
3046                 QUERY_PARAMETERS(msg, info20.parameters,    "userParameters");
3047                 break;
3048
3049         case 21:
3050                 QUERY_UINT64(msg, info21.last_logon,           "lastLogon");
3051                 QUERY_UINT64(msg, info21.last_logoff,          "lastLogoff");
3052                 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3053                 QUERY_UINT64(msg, info21.acct_expiry,          "accountExpires");
3054                 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3055                 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3056                 QUERY_STRING(msg, info21.account_name,         "sAMAccountName");
3057                 QUERY_STRING(msg, info21.full_name,            "displayName");
3058                 QUERY_STRING(msg, info21.home_directory,       "homeDirectory");
3059                 QUERY_STRING(msg, info21.home_drive,           "homeDrive");
3060                 QUERY_STRING(msg, info21.logon_script,         "scriptPath");
3061                 QUERY_STRING(msg, info21.profile_path,         "profilePath");
3062                 QUERY_STRING(msg, info21.description,          "description");
3063                 QUERY_STRING(msg, info21.workstations,         "userWorkstations");
3064                 QUERY_STRING(msg, info21.comment,              "comment");
3065                 QUERY_PARAMETERS(msg, info21.parameters,       "userParameters");
3066                 QUERY_RID   (msg, info21.rid,                  "objectSid");
3067                 QUERY_UINT  (msg, info21.primary_gid,          "primaryGroupID");
3068                 QUERY_AFLAGS(msg, info21.acct_flags,           "userAccountControl");
3069                 info->info21.fields_present = 0x08FFFFFF;
3070                 QUERY_LHOURS(msg, info21.logon_hours,          "logonHours");
3071                 QUERY_UINT  (msg, info21.bad_password_count,   "badPwdCount");
3072                 QUERY_UINT  (msg, info21.logon_count,          "logonCount");
3073                 if ((info->info21.acct_flags & ACB_PW_EXPIRED) != 0) {
3074                         info->info21.password_expired = PASS_MUST_CHANGE_AT_NEXT_LOGON;
3075                 } else {
3076                         info->info21.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
3077                 }
3078                 QUERY_UINT  (msg, info21.country_code,         "countryCode");
3079                 QUERY_UINT  (msg, info21.code_page,            "codePage");
3080                 break;
3081
3082
3083         default:
3084                 talloc_free(info);
3085                 return NT_STATUS_INVALID_INFO_CLASS;
3086         }
3087
3088         *r->out.info = info;
3089
3090         return NT_STATUS_OK;
3091 }
3092
3093
3094 /*
3095   samr_SetUserInfo
3096 */
3097 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3098                                  struct samr_SetUserInfo *r)
3099 {
3100         struct dcesrv_handle *h;
3101         struct samr_account_state *a_state;
3102         struct ldb_message *msg;
3103         int ret;
3104         NTSTATUS status = NT_STATUS_OK;
3105         struct ldb_context *sam_ctx;
3106
3107         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3108
3109         a_state = h->data;
3110         sam_ctx = a_state->sam_ctx;
3111
3112         msg = ldb_msg_new(mem_ctx);
3113         if (msg == NULL) {
3114                 return NT_STATUS_NO_MEMORY;
3115         }
3116
3117         msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3118         if (!msg->dn) {