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