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