s4:dcesrv_samr - Also "OpenGroup" needs to support universal groups
[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, ldb_errstring(d_state->sam_ctx)));
2751         }
2752
2753         if (memberdn == NULL) {
2754                 DEBUG(0, ("Could not find memberdn\n"));
2755                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2756         }
2757
2758         mod = ldb_msg_new(mem_ctx);
2759         if (mod == NULL) {
2760                 return NT_STATUS_NO_MEMORY;
2761         }
2762
2763         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2764
2765         ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2766                                  ldb_dn_alloc_linearized(mem_ctx, memberdn));
2767         if (ret != LDB_SUCCESS) {
2768                 return NT_STATUS_UNSUCCESSFUL;
2769         }
2770
2771         if (ldb_modify(a_state->sam_ctx, mod) != LDB_SUCCESS) {
2772                 return NT_STATUS_UNSUCCESSFUL;
2773         }
2774
2775         return NT_STATUS_OK;
2776 }
2777
2778
2779 /* 
2780   samr_DeleteAliasMember 
2781 */
2782 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2783                        struct samr_DeleteAliasMember *r)
2784 {
2785         struct dcesrv_handle *h;
2786         struct samr_account_state *a_state;
2787         struct samr_domain_state *d_state;
2788         struct ldb_message *mod;
2789         const char *memberdn;
2790         int ret;
2791
2792         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2793
2794         a_state = h->data;
2795         d_state = a_state->domain_state;
2796
2797         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2798                                        "distinguishedName", "(objectSid=%s)", 
2799                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2800
2801         if (memberdn == NULL)
2802                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2803
2804         mod = ldb_msg_new(mem_ctx);
2805         if (mod == NULL) {
2806                 return NT_STATUS_NO_MEMORY;
2807         }
2808
2809         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2810
2811         ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2812                                                                  memberdn);
2813         if (ret != LDB_SUCCESS)
2814                 return NT_STATUS_UNSUCCESSFUL;
2815
2816         if (ldb_modify(a_state->sam_ctx, mod) != LDB_SUCCESS)
2817                 return NT_STATUS_UNSUCCESSFUL;
2818
2819         return NT_STATUS_OK;
2820 }
2821
2822
2823 /* 
2824   samr_GetMembersInAlias 
2825 */
2826 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2827                        struct samr_GetMembersInAlias *r)
2828 {
2829         struct dcesrv_handle *h;
2830         struct samr_account_state *a_state;
2831         struct samr_domain_state *d_state;
2832         struct ldb_message **msgs;
2833         struct lsa_SidPtr *sids;
2834         struct ldb_message_element *el;
2835         const char * const attrs[2] = { "member", NULL};
2836         int ret;
2837
2838         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2839
2840         a_state = h->data;
2841         d_state = a_state->domain_state;
2842
2843         ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
2844                               a_state->account_dn, &msgs, attrs);
2845
2846         if (ret == -1) {
2847                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2848         } else if (ret == 0) {
2849                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2850         } else if (ret != 1) {
2851                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2852         }
2853
2854         r->out.sids->num_sids = 0;
2855         r->out.sids->sids = NULL;
2856
2857         el = ldb_msg_find_element(msgs[0], "member");
2858
2859         if (el != NULL) {
2860                 int i;
2861
2862                 sids = talloc_array(mem_ctx, struct lsa_SidPtr,
2863                                       el->num_values);
2864
2865                 if (sids == NULL)
2866                         return NT_STATUS_NO_MEMORY;
2867
2868                 for (i=0; i<el->num_values; i++) {
2869                         struct ldb_message **msgs2;
2870                         const char * const attrs2[2] = { "objectSid", NULL };
2871                         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2872                                               ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2873                                               &msgs2, attrs2);
2874                         if (ret != 1)
2875                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2876
2877                         sids[i].sid = samdb_result_dom_sid(mem_ctx, msgs2[0],
2878                                                            "objectSid");
2879
2880                         if (sids[i].sid == NULL)
2881                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2882                 }
2883                 r->out.sids->num_sids = el->num_values;
2884                 r->out.sids->sids = sids;
2885         }
2886
2887         return NT_STATUS_OK;
2888 }
2889
2890 /* 
2891   samr_OpenUser 
2892 */
2893 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2894                               struct samr_OpenUser *r)
2895 {
2896         struct samr_domain_state *d_state;
2897         struct samr_account_state *a_state;
2898         struct dcesrv_handle *h;
2899         const char *account_name;
2900         struct dom_sid *sid;
2901         struct ldb_message **msgs;
2902         struct dcesrv_handle *u_handle;
2903         const char * const attrs[2] = { "sAMAccountName", NULL };
2904         int ret;
2905
2906         ZERO_STRUCTP(r->out.user_handle);
2907
2908         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2909
2910         d_state = h->data;
2911
2912         /* form the users SID */
2913         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2914         if (!sid) {
2915                 return NT_STATUS_NO_MEMORY;
2916         }
2917
2918         /* search for the user record */
2919         ret = gendb_search(d_state->sam_ctx,
2920                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2921                            "(&(objectSid=%s)(objectclass=user))", 
2922                            ldap_encode_ndr_dom_sid(mem_ctx, sid));
2923         if (ret == 0) {
2924                 return NT_STATUS_NO_SUCH_USER;
2925         }
2926         if (ret != 1) {
2927                 DEBUG(0,("Found %d records matching sid %s\n", ret, 
2928                          dom_sid_string(mem_ctx, sid)));
2929                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2930         }
2931
2932         account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2933         if (account_name == NULL) {
2934                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2935                          dom_sid_string(mem_ctx, sid)));
2936                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2937         }
2938
2939         a_state = talloc(mem_ctx, struct samr_account_state);
2940         if (!a_state) {
2941                 return NT_STATUS_NO_MEMORY;
2942         }
2943         a_state->sam_ctx = d_state->sam_ctx;
2944         a_state->access_mask = r->in.access_mask;
2945         a_state->domain_state = talloc_reference(a_state, d_state);
2946         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2947         a_state->account_sid = talloc_steal(a_state, sid);
2948         a_state->account_name = talloc_strdup(a_state, account_name);
2949         if (!a_state->account_name) {
2950                 return NT_STATUS_NO_MEMORY;
2951         }
2952
2953         /* create the policy handle */
2954         u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2955         if (!u_handle) {
2956                 return NT_STATUS_NO_MEMORY;
2957         }
2958
2959         u_handle->data = talloc_steal(u_handle, a_state);
2960
2961         *r->out.user_handle = u_handle->wire_handle;
2962
2963         return NT_STATUS_OK;
2964
2965 }
2966
2967
2968 /* 
2969   samr_DeleteUser 
2970 */
2971 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2972                                 struct samr_DeleteUser *r)
2973 {
2974         struct dcesrv_handle *h;
2975         struct samr_account_state *a_state;
2976         int ret;
2977
2978         *r->out.user_handle = *r->in.user_handle;
2979
2980         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2981
2982         a_state = h->data;
2983
2984         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2985         if (ret != LDB_SUCCESS) {
2986                 DEBUG(1, ("Failed to delete user: %s: %s\n", 
2987                           ldb_dn_get_linearized(a_state->account_dn), 
2988                           ldb_errstring(a_state->sam_ctx)));
2989                 return NT_STATUS_UNSUCCESSFUL;
2990         }
2991
2992         talloc_free(h);
2993         ZERO_STRUCTP(r->out.user_handle);
2994
2995         return NT_STATUS_OK;
2996 }
2997
2998
2999 /* 
3000   samr_QueryUserInfo 
3001 */
3002 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3003                                    struct samr_QueryUserInfo *r)
3004 {
3005         struct dcesrv_handle *h;
3006         struct samr_account_state *a_state;
3007         struct ldb_message *msg, **res;
3008         int ret;
3009         struct ldb_context *sam_ctx;
3010
3011         const char * const *attrs = NULL;
3012         union samr_UserInfo *info;
3013
3014         *r->out.info = NULL;
3015
3016         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3017
3018         a_state = h->data;
3019         sam_ctx = a_state->sam_ctx;
3020
3021         /* fill in the reply */
3022         switch (r->in.level) {
3023         case 1:
3024         {
3025                 static const char * const attrs2[] = {"sAMAccountName",
3026                                                       "displayName",
3027                                                       "primaryroupID",
3028                                                       "description",
3029                                                       "comment",
3030                                                       NULL};
3031                 attrs = attrs2;
3032                 break;
3033         }
3034         case 2:
3035         {
3036                 static const char * const attrs2[] = {"comment",
3037                                                       "countryCode",
3038                                                       "codePage",
3039                                                       NULL};
3040                 attrs = attrs2;
3041                 break;
3042         }
3043         case 3:
3044         {
3045                 static const char * const attrs2[] = {"sAMAccountName",
3046                                                       "displayName",
3047                                                       "objectSid",
3048                                                       "primaryGroupID",
3049                                                       "homeDirectory",
3050                                                       "homeDrive",
3051                                                       "scriptPath",
3052                                                       "profilePath",
3053                                                       "userWorkstations",
3054                                                       "lastLogon",
3055                                                       "lastLogoff",
3056                                                       "pwdLastSet",
3057                                                       "logonHours",
3058                                                       "badPwdCount",
3059                                                       "logonCount",
3060                                                       "userAccountControl",
3061                                                       NULL};
3062                 attrs = attrs2;
3063                 break;
3064         }
3065         case 4:
3066         {
3067                 static const char * const attrs2[] = {"logonHours",
3068                                                       NULL};
3069                 attrs = attrs2;
3070                 break;
3071         }
3072         case 5:
3073         {
3074                 static const char * const attrs2[] = {"sAMAccountName", 
3075                                                       "displayName",
3076                                                       "objectSid",
3077                                                       "primaryGroupID",
3078                                                       "homeDirectory",
3079                                                       "homeDrive",
3080                                                       "scriptPath", 
3081                                                       "profilePath",
3082                                                       "description",
3083                                                       "userWorkstations",
3084                                                       "lastLogon",
3085                                                       "lastLogoff",
3086                                                       "logonHours",
3087                                                       "badPwdCount",
3088                                                       "logonCount",
3089                                                       "pwdLastSet",
3090                                                       "accountExpires",
3091                                                       "userAccountControl",
3092                                                       NULL};
3093                 attrs = attrs2;
3094                 break;
3095         }
3096         case 6:
3097         {
3098                 static const char * const attrs2[] = {"sAMAccountName",
3099                                                       "displayName",
3100                                                       NULL};
3101                 attrs = attrs2;
3102                 break;
3103         }
3104         case 7:
3105         {
3106                 static const char * const attrs2[] = {"sAMAccountName",
3107                                                       NULL};
3108                 attrs = attrs2;
3109                 break;
3110         }
3111         case 8:
3112         {
3113                 static const char * const attrs2[] = {"displayName",
3114                                                       NULL};
3115                 attrs = attrs2;
3116                 break;
3117         }
3118         case 9:
3119         {
3120                 static const char * const attrs2[] = {"primaryGroupID",
3121                                                       NULL};
3122                 attrs = attrs2;
3123                 break;
3124         }
3125         case 10:
3126         {
3127                 static const char * const attrs2[] = {"homeDirectory",
3128                                                       "homeDrive",
3129                                                       NULL};
3130                 attrs = attrs2;
3131                 break;
3132         }
3133         case 11:
3134         {
3135                 static const char * const attrs2[] = {"scriptPath",
3136                                                       NULL};
3137                 attrs = attrs2;
3138                 break;
3139         }
3140         case 12:
3141         {
3142                 static const char * const attrs2[] = {"profilePath",
3143                                                       NULL};
3144                 attrs = attrs2;
3145                 break;
3146         }
3147         case 13:
3148         {
3149                 static const char * const attrs2[] = {"description",
3150                                                       NULL};
3151                 attrs = attrs2;
3152                 break;
3153         }
3154         case 14:
3155         {
3156                 static const char * const attrs2[] = {"userWorkstations",
3157                                                       NULL};
3158                 attrs = attrs2;
3159                 break;
3160         }
3161         case 16:
3162         {
3163                 static const char * const attrs2[] = {"userAccountControl",
3164                                                       "pwdLastSet",
3165                                                       NULL};
3166                 attrs = attrs2;
3167                 break;
3168         }
3169         case 17:
3170         {
3171                 static const char * const attrs2[] = {"accountExpires",
3172                                                       NULL};
3173                 attrs = attrs2;
3174                 break;
3175         }
3176         case 18:
3177         {
3178                 return NT_STATUS_NOT_SUPPORTED;
3179         }
3180         case 20:
3181         {
3182                 static const char * const attrs2[] = {"userParameters",
3183                                                       NULL};
3184                 attrs = attrs2;
3185                 break;
3186         }
3187         case 21:
3188         {
3189                 static const char * const attrs2[] = {"lastLogon",
3190                                                       "lastLogoff",
3191                                                       "pwdLastSet",
3192                                                       "accountExpires",
3193                                                       "sAMAccountName",
3194                                                       "displayName",
3195                                                       "homeDirectory",
3196                                                       "homeDrive",
3197                                                       "scriptPath",
3198                                                       "profilePath",
3199                                                       "description",
3200                                                       "userWorkstations",
3201                                                       "comment",
3202                                                       "userParameters",
3203                                                       "objectSid",
3204                                                       "primaryGroupID",
3205                                                       "userAccountControl",
3206                                                       "logonHours",
3207                                                       "badPwdCount",
3208                                                       "logonCount",
3209                                                       "countryCode",
3210                                                       "codePage",
3211                                                       NULL};
3212                 attrs = attrs2;
3213                 break;
3214         }
3215         case 23:
3216         case 24:
3217         case 25:
3218         case 26:
3219         {
3220                 return NT_STATUS_NOT_SUPPORTED;
3221         }
3222         default:
3223         {
3224                 return NT_STATUS_INVALID_INFO_CLASS;
3225         }
3226         }
3227
3228         /* pull all the user attributes */
3229         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
3230                               a_state->account_dn ,&res, attrs);
3231         if (ret != 1) {
3232                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3233         }
3234         msg = res[0];
3235
3236         /* allocate the info structure */
3237         info = talloc_zero(mem_ctx, union samr_UserInfo);
3238         if (info == NULL) {
3239                 return NT_STATUS_NO_MEMORY;
3240         }
3241
3242         /* fill in the reply */
3243         switch (r->in.level) {
3244         case 1:
3245                 QUERY_STRING(msg, info1.account_name,          "sAMAccountName");
3246                 QUERY_STRING(msg, info1.full_name,             "displayName");
3247                 QUERY_UINT  (msg, info1.primary_gid,           "primaryGroupID");
3248                 QUERY_STRING(msg, info1.description,           "description");
3249                 QUERY_STRING(msg, info1.comment,               "comment");
3250                 break;
3251
3252         case 2:
3253                 QUERY_STRING(msg, info2.comment,               "comment");
3254                 QUERY_UINT  (msg, info2.country_code,          "countryCode");
3255                 QUERY_UINT  (msg, info2.code_page,             "codePage");
3256                 break;
3257
3258         case 3:
3259                 QUERY_STRING(msg, info3.account_name,          "sAMAccountName");
3260                 QUERY_STRING(msg, info3.full_name,             "displayName");
3261                 QUERY_RID   (msg, info3.rid,                   "objectSid");
3262                 QUERY_UINT  (msg, info3.primary_gid,           "primaryGroupID");
3263                 QUERY_STRING(msg, info3.home_directory,        "homeDirectory");
3264                 QUERY_STRING(msg, info3.home_drive,            "homeDrive");
3265                 QUERY_STRING(msg, info3.logon_script,          "scriptPath");
3266                 QUERY_STRING(msg, info3.profile_path,          "profilePath");
3267                 QUERY_STRING(msg, info3.workstations,          "userWorkstations");
3268                 QUERY_UINT64(msg, info3.last_logon,            "lastLogon");
3269                 QUERY_UINT64(msg, info3.last_logoff,           "lastLogoff");
3270                 QUERY_UINT64(msg, info3.last_password_change,  "pwdLastSet");
3271                 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
3272                 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
3273                 QUERY_LHOURS(msg, info3.logon_hours,           "logonHours");
3274                 QUERY_UINT  (msg, info3.bad_password_count,    "badPwdCount");
3275                 QUERY_UINT  (msg, info3.logon_count,           "logonCount");
3276                 QUERY_AFLAGS(msg, info3.acct_flags,            "userAccountControl");
3277                 break;
3278
3279         case 4:
3280                 QUERY_LHOURS(msg, info4.logon_hours,           "logonHours");
3281                 break;
3282
3283         case 5:
3284                 QUERY_STRING(msg, info5.account_name,          "sAMAccountName");
3285                 QUERY_STRING(msg, info5.full_name,             "displayName");
3286                 QUERY_RID   (msg, info5.rid,                   "objectSid");
3287                 QUERY_UINT  (msg, info5.primary_gid,           "primaryGroupID");
3288                 QUERY_STRING(msg, info5.home_directory,        "homeDirectory");
3289                 QUERY_STRING(msg, info5.home_drive,            "homeDrive");
3290                 QUERY_STRING(msg, info5.logon_script,          "scriptPath");
3291                 QUERY_STRING(msg, info5.profile_path,          "profilePath");
3292                 QUERY_STRING(msg, info5.description,           "description");
3293                 QUERY_STRING(msg, info5.workstations,          "userWorkstations");
3294                 QUERY_UINT64(msg, info5.last_logon,            "lastLogon");
3295                 QUERY_UINT64(msg, info5.last_logoff,           "lastLogoff");
3296                 QUERY_LHOURS(msg, info5.logon_hours,           "logonHours");
3297                 QUERY_UINT  (msg, info5.bad_password_count,    "badPwdCount");
3298                 QUERY_UINT  (msg, info5.logon_count,           "logonCount");
3299                 QUERY_UINT64(msg, info5.last_password_change,  "pwdLastSet");
3300                 QUERY_UINT64(msg, info5.acct_expiry,           "accountExpires");
3301                 QUERY_AFLAGS(msg, info5.acct_flags,            "userAccountControl");
3302                 break;
3303
3304         case 6:
3305                 QUERY_STRING(msg, info6.account_name,   "sAMAccountName");
3306                 QUERY_STRING(msg, info6.full_name,      "displayName");
3307                 break;
3308
3309         case 7:
3310                 QUERY_STRING(msg, info7.account_name,   "sAMAccountName");
3311                 break;
3312
3313         case 8:
3314                 QUERY_STRING(msg, info8.full_name,      "displayName");
3315                 break;
3316
3317         case 9:
3318                 QUERY_UINT  (msg, info9.primary_gid,    "primaryGroupID");
3319                 break;
3320
3321         case 10:
3322                 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3323                 QUERY_STRING(msg, info10.home_drive,    "homeDrive");
3324                 break;
3325
3326         case 11:
3327                 QUERY_STRING(msg, info11.logon_script,  "scriptPath");
3328                 break;
3329
3330         case 12:
3331                 QUERY_STRING(msg, info12.profile_path,  "profilePath");
3332                 break;
3333
3334         case 13:
3335                 QUERY_STRING(msg, info13.description,   "description");
3336                 break;
3337
3338         case 14:
3339                 QUERY_STRING(msg, info14.workstations,  "userWorkstations");
3340                 break;
3341
3342         case 16:
3343                 QUERY_AFLAGS(msg, info16.acct_flags,    "userAccountControl");
3344                 break;
3345
3346         case 17:
3347                 QUERY_UINT64(msg, info17.acct_expiry,   "accountExpires");
3348                 break;
3349
3350         case 20:
3351                 QUERY_PARAMETERS(msg, info20.parameters,    "userParameters");
3352                 break;
3353
3354         case 21:
3355                 QUERY_UINT64(msg, info21.last_logon,           "lastLogon");
3356                 QUERY_UINT64(msg, info21.last_logoff,          "lastLogoff");
3357                 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3358                 QUERY_UINT64(msg, info21.acct_expiry,          "accountExpires");
3359                 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3360                 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3361                 QUERY_STRING(msg, info21.account_name,         "sAMAccountName");
3362                 QUERY_STRING(msg, info21.full_name,            "displayName");
3363                 QUERY_STRING(msg, info21.home_directory,       "homeDirectory");
3364                 QUERY_STRING(msg, info21.home_drive,           "homeDrive");
3365                 QUERY_STRING(msg, info21.logon_script,         "scriptPath");
3366                 QUERY_STRING(msg, info21.profile_path,         "profilePath");
3367                 QUERY_STRING(msg, info21.description,          "description");
3368                 QUERY_STRING(msg, info21.workstations,         "userWorkstations");
3369                 QUERY_STRING(msg, info21.comment,              "comment");
3370                 QUERY_PARAMETERS(msg, info21.parameters,       "userParameters");
3371                 QUERY_RID   (msg, info21.rid,                  "objectSid");
3372                 QUERY_UINT  (msg, info21.primary_gid,          "primaryGroupID");
3373                 QUERY_AFLAGS(msg, info21.acct_flags,           "userAccountControl");
3374                 info->info21.fields_present = 0x00FFFFFF;
3375                 QUERY_LHOURS(msg, info21.logon_hours,          "logonHours");
3376                 QUERY_UINT  (msg, info21.bad_password_count,   "badPwdCount");
3377                 QUERY_UINT  (msg, info21.logon_count,          "logonCount");
3378                 QUERY_UINT  (msg, info21.country_code,         "countryCode");
3379                 QUERY_UINT  (msg, info21.code_page,            "codePage");
3380                 break;
3381                 
3382
3383         default:
3384                 talloc_free(info);
3385                 return NT_STATUS_INVALID_INFO_CLASS;
3386         }
3387
3388         *r->out.info = info;
3389
3390         return NT_STATUS_OK;
3391 }
3392
3393
3394 /* 
3395   samr_SetUserInfo 
3396 */
3397 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3398                                  struct samr_SetUserInfo *r)
3399 {
3400         struct dcesrv_handle *h;
3401         struct samr_account_state *a_state;
3402         struct ldb_message *msg;
3403         int ret;
3404         NTSTATUS status = NT_STATUS_OK;
3405         struct ldb_context *sam_ctx;
3406
3407         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3408
3409         a_state = h->data;
3410         sam_ctx = a_state->sam_ctx;
3411
3412         msg = ldb_msg_new(mem_ctx);
3413         if (msg == NULL) {
3414                 return NT_STATUS_NO_MEMORY;
3415         }
3416
3417         msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3418         if (!msg->dn) {
3419                 return NT_STATUS_NO_MEMORY;
3420         }
3421
3422         switch (r->in.level) {
3423         case 2:
3424                 SET_STRING(msg, info2.comment,          "comment");
3425                 SET_UINT  (msg, info2.country_code,     "countryCode");
3426                 SET_UINT  (msg, info2.code_page,        "codePage");
3427                 break;
3428
3429         case 4:
3430                 SET_LHOURS(msg, info4.logon_hours,      "logonHours");
3431                 break;
3432
3433         case 6:
3434                 SET_STRING(msg, info6.account_name,     "samAccountName");
3435                 SET_STRING(msg, info6.full_name,        "displayName");
3436                 break;
3437
3438         case 7:
3439                 SET_STRING(msg, info7.account_name,     "samAccountName");
3440                 break;
3441
3442         case 8:
3443                 SET_STRING(msg, info8.full_name,        "displayName");
3444                 break;
3445
3446         case 9:
3447                 SET_UINT(msg, info9.primary_gid,        "primaryGroupID");
3448                 break;
3449
3450         case 10:
3451                 SET_STRING(msg, info10.home_directory,  "homeDirectory");
3452                 SET_STRING(msg, info10.home_drive,      "homeDrive");
3453                 break;
3454
3455         case 11:
3456                 SET_STRING(msg, info11.logon_script,    "scriptPath");
3457                 break;
3458
3459         case 12:
3460                 SET_STRING(msg, info12.profile_path,    "profilePath");
3461                 break;
3462
3463         case 13:
3464                 SET_STRING(msg, info13.description,     "description");
3465                 break;
3466
3467         case 14:
3468                 SET_STRING(msg, info14.workstations,    "userWorkstations");
3469                 break;
3470
3471         case 16:
3472                 SET_AFLAGS(msg, info16.acct_flags,      "userAccountControl");
3473                 break;
3474
3475         case 17:
3476                 SET_UINT64(msg, info17.acct_expiry,     "accountExpires");
3477                 break;
3478
3479         case 20:
3480                 SET_PARAMETERS(msg, info20.parameters,      "userParameters");
3481                 break;
3482
3483         case 21:
3484 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3485                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3486                         SET_UINT64(msg, info21.acct_expiry,    "accountExpires");
3487                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
3488                         SET_STRING(msg, info21.account_name,   "samAccountName");
3489                 IFSET(SAMR_FIELD_FULL_NAME) 
3490                         SET_STRING(msg, info21.full_name,      "displayName");
3491                 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3492                         SET_STRING(msg, info21.home_directory, "homeDirectory");
3493                 IFSET(SAMR_FIELD_HOME_DRIVE)
3494                         SET_STRING(msg, info21.home_drive,     "homeDrive");
3495                 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3496                         SET_STRING(msg, info21.logon_script,   "scriptPath");
3497                 IFSET(SAMR_FIELD_PROFILE_PATH)
3498                         SET_STRING(msg, info21.profile_path,   "profilePath");
3499                 IFSET(SAMR_FIELD_DESCRIPTION)
3500                         SET_STRING(msg, info21.description,    "description");
3501                 IFSET(SAMR_FIELD_WORKSTATIONS)
3502                         SET_STRING(msg, info21.workstations,   "userWorkstations");
3503                 IFSET(SAMR_FIELD_COMMENT)
3504                         SET_STRING(msg, info21.comment,        "comment");
3505                 IFSET(SAMR_FIELD_PARAMETERS)   
3506                         SET_PARAMETERS(msg, info21.parameters, "userParameters");
3507                 IFSET(SAMR_FIELD_PRIMARY_GID)
3508                         SET_UINT(msg, info21.primary_gid,      "primaryGroupID");
3509                 IFSET(SAMR_FIELD_ACCT_FLAGS)
3510                         SET_AFLAGS(msg, info21.acct_flags,     "userAccountControl");
3511                 IFSET(SAMR_FIELD_LOGON_HOURS)
3512                         SET_LHOURS(msg, info21.logon_hours,    "logonHours");
3513                 IFSET(SAMR_FIELD_COUNTRY_CODE)
3514                         SET_UINT  (msg, info21.country_code,   "countryCode");
3515                 IFSET(SAMR_FIELD_CODE_PAGE)
3516                         SET_UINT  (msg, info21.code_page,      "codePage");
3517 #undef IFSET
3518                 break;
3519
3520         case 23:
3521 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3522                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3523                         SET_UINT64(msg, info23.info.acct_expiry,    "accountExpires");
3524                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
3525                         SET_STRING(msg, info23.info.account_name,   "samAccountName");
3526                 IFSET(SAMR_FIELD_FULL_NAME)
3527                         SET_STRING(msg, info23.info.full_name,      "displayName");
3528                 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3529                         SET_STRING(msg, info23.info.home_directory, "homeDirectory");
3530                 IFSET(SAMR_FIELD_HOME_DRIVE)
3531                         SET_STRING(msg, info23.info.home_drive,     "homeDrive");
3532                 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3533                         SET_STRING(msg, info23.info.logon_script,   "scriptPath");
3534                 IFSET(SAMR_FIELD_PROFILE_PATH)
3535                         SET_STRING(msg, info23.info.profile_path,   "profilePath");
3536                 IFSET(SAMR_FIELD_DESCRIPTION)
3537                         SET_STRING(msg, info23.info.description,    "description");
3538                 IFSET(SAMR_FIELD_WORKSTATIONS)
3539                         SET_STRING(msg, info23.info.workstations,   "userWorkstations");
3540                 IFSET(SAMR_FIELD_COMMENT)
3541                         SET_STRING(msg, info23.info.comment,        "comment");
3542                 IFSET(SAMR_FIELD_PARAMETERS)
3543                         SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3544                 IFSET(SAMR_FIELD_PRIMARY_GID)
3545                         SET_UINT(msg, info23.info.primary_gid,      "primaryGroupID");
3546                 IFSET(SAMR_FIELD_ACCT_FLAGS)
3547                         SET_AFLAGS(msg, info23.info.acct_flags,     "userAccountControl");
3548                 IFSET(SAMR_FIELD_LOGON_HOURS)
3549                         SET_LHOURS(msg, info23.info.logon_hours,    "logonHours");
3550                 IFSET(SAMR_FIELD_COUNTRY_CODE)
3551                         SET_UINT  (msg, info23.info.country_code,   "countryCode");
3552                 IFSET(SAMR_FIELD_CODE_PAGE)
3553                         SET_UINT  (msg, info23.info.code_page,      "codePage");
3554
3555                 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3556                         status = samr_set_password(dce_call,
3557                                                    a_state->sam_ctx,
3558                                                    a_state->account_dn,
3559                                                    a_state->domain_state->domain_dn,
3560                                                    mem_ctx, msg, 
3561                                                    &r->in.info->info23.password);
3562                 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3563                         status = samr_set_password(dce_call,
3564                                                    a_state->sam_ctx,
3565                                                    a_state->account_dn,
3566                                                    a_state->domain_state->domain_dn,
3567                                                    mem_ctx, msg, 
3568                                                    &r->in.info->info23.password);
3569                 }
3570 #undef IFSET
3571                 break;
3572
3573                 /* the set password levels are handled separately */
3574         case 24:
3575                 status = samr_set_password(dce_call,
3576                                            a_state->sam_ctx,
3577                                            a_state->account_dn,
3578                                            a_state->domain_state->domain_dn,
3579                                            mem_ctx, msg, 
3580                                            &r->in.info->info24.password);
3581                 break;
3582
3583         case 25:
3584 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3585                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3586                         SET_UINT64(msg, info25.info.acct_expiry,    "accountExpires");
3587                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
3588                         SET_STRING(msg, info25.info.account_name,   "samAccountName");
3589                 IFSET(SAMR_FIELD_FULL_NAME)
3590                         SET_STRING(msg, info25.info.full_name,      "displayName");
3591                 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3592                         SET_STRING(msg, info25.info.home_directory, "homeDirectory");
3593                 IFSET(SAMR_FIELD_HOME_DRIVE)
3594                         SET_STRING(msg, info25.info.home_drive,     "homeDrive");
3595                 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3596                         SET_STRING(msg, info25.info.logon_script,   "scriptPath");
3597                 IFSET(SAMR_FIELD_PROFILE_PATH)
3598                         SET_STRING(msg, info25.info.profile_path,   "profilePath");
3599                 IFSET(SAMR_FIELD_DESCRIPTION)
3600                         SET_STRING(msg, info25.info.description,    "description");
3601                 IFSET(SAMR_FIELD_WORKSTATIONS)
3602                         SET_STRING(msg, info25.info.workstations,   "userWorkstations");
3603                 IFSET(SAMR_FIELD_COMMENT)
3604                         SET_STRING(msg, info25.info.comment,        "comment");
3605                 IFSET(SAMR_FIELD_PARAMETERS)
3606                         SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
3607                 IFSET(SAMR_FIELD_PRIMARY_GID)
3608                         SET_UINT(msg, info25.info.primary_gid,      "primaryGroupID");
3609                 IFSET(SAMR_FIELD_ACCT_FLAGS)
3610                         SET_AFLAGS(msg, info25.info.acct_flags,     "userAccountControl");
3611                 IFSET(SAMR_FIELD_LOGON_HOURS)
3612                         SET_LHOURS(msg, info25.info.logon_hours,    "logonHours");
3613                 IFSET(SAMR_FIELD_COUNTRY_CODE)
3614                         SET_UINT  (msg, info25.info.country_code,   "countryCode");
3615                 IFSET(SAMR_FIELD_CODE_PAGE)
3616                         SET_UINT  (msg, info25.info.code_page,      "codePage");
3617
3618                 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3619                         status = samr_set_password_ex(dce_call,
3620                                                       a_state->sam_ctx,
3621                                                       a_state->account_dn,
3622                                                       a_state->domain_state->domain_dn,
3623                                                       mem_ctx, msg, 
3624                                                       &r->in.info->info25.password);
3625                 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3626                         status = samr_set_password_ex(dce_call,
3627                                                       a_state->sam_ctx,
3628                                                       a_state->account_dn,
3629                                                       a_state->domain_state->domain_dn,
3630                                                       mem_ctx, msg, 
3631                                                       &r->in.info->info25.password);
3632                 }
3633 #undef IFSET
3634                 break;
3635
3636                 /* the set password levels are handled separately */
3637         case 26:
3638                 status = samr_set_password_ex(dce_call,
3639                                               a_state->sam_ctx,
3640                                               a_state->account_dn,
3641                                               a_state->domain_state->domain_dn,
3642                                               mem_ctx, msg, 
3643                                               &r->in.info->info26.password);
3644                 break;
3645                 
3646
3647         default:
3648                 /* many info classes are not valid for SetUserInfo */
3649                 return NT_STATUS_INVALID_INFO_CLASS;
3650         }
3651
3652         if (!NT_STATUS_IS_OK(status)) {
3653                 return status;
3654         }
3655
3656         /* modify the samdb record */
3657         if (msg->num_elements > 0) {
3658                 ret = ldb_modify(a_state->sam_ctx, msg);
3659                 if (ret != LDB_SUCCESS) {
3660                         DEBUG(1,("Failed to modify record %s: %s\n",
3661                                  ldb_dn_get_linearized(a_state->account_dn),
3662                                  ldb_errstring(a_state->sam_ctx)));
3663
3664                         /* we really need samdb.c to return NTSTATUS */
3665                         return NT_STATUS_UNSUCCESSFUL;
3666                 }
3667         }
3668
3669         return NT_STATUS_OK;
3670 }
3671
3672
3673 /* 
3674   samr_GetGroupsForUser 
3675 */
3676 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3677                        struct samr_GetGroupsForUser *r)
3678 {
3679         struct dcesrv_handle *h;
3680         struct samr_account_state *a_state;
3681         struct samr_domain_state *d_state;
3682         struct ldb_message **res;
3683         const char * const attrs[2] = { "objectSid", NULL };
3684         struct samr_RidWithAttributeArray *array;
3685         int i, count;
3686
3687         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3688
3689         a_state = h->data;
3690         d_state = a_state->domain_state;
3691
3692         count = samdb_search_domain(a_state->sam_ctx, mem_ctx,
3693                                     d_state->domain_dn, &res,
3694                                     attrs, d_state->domain_sid,
3695                                     "(&(member=%s)(grouptype=%d)(objectclass=group))",
3696                                     ldb_dn_get_linearized(a_state->account_dn),
3697                                     GTYPE_SECURITY_GLOBAL_GROUP);
3698         if (count < 0)
3699                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3700
3701         array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3702         if (array == NULL)
3703                 return NT_STATUS_NO_MEMORY;
3704
3705         array->count = 0;
3706         array->rids = NULL;
3707
3708         array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3709                                             count + 1);
3710         if (array->rids == NULL)
3711                 return NT_STATUS_NO_MEMORY;
3712
3713         /* Adds the primary group */
3714         array->rids[0].rid = samdb_search_uint(a_state->sam_ctx, mem_ctx,
3715                                                ~0, a_state->account_dn,
3716                                                "primaryGroupID", NULL);
3717         array->rids[0].attributes = SE_GROUP_MANDATORY
3718                         | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3719         array->count += 1;
3720
3721         /* Adds the additional groups */
3722         for (i = 0; i < count; i++) {
3723                 struct dom_sid *group_sid;
3724
3725                 group_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
3726                 if (group_sid == NULL) {
3727                         DEBUG(0, ("Couldn't find objectSid attrib\n"));
3728                         continue;
3729                 }
3730
3731                 array->rids[i + 1].rid =
3732                         group_sid->sub_auths[group_sid->num_auths-1];
3733                 array->rids[i + 1].attributes = SE_GROUP_MANDATORY
3734                         | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3735                 array->count += 1;
3736         }
3737
3738         *r->out.rids = array;
3739
3740         return NT_STATUS_OK;
3741 }
3742
3743
3744 /* 
3745   samr_QueryDisplayInfo 
3746 */
3747 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3748                        struct samr_QueryDisplayInfo *r)
3749 {
3750         struct dcesrv_handle *h;
3751         struct samr_domain_state *d_state;
3752         struct ldb_message **res;
3753         int ldb_cnt, count, i;
3754         const char * const attrs[] = { "objectSid", "sAMAccountName",
3755                 "displayName", "description", "userAccountControl",
3756                 "pwdLastSet", NULL };
3757         struct samr_DispEntryFull *entriesFull = NULL;
3758         struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3759         struct samr_DispEntryAscii *entriesAscii = NULL;
3760         struct samr_DispEntryGeneral *entriesGeneral = NULL;
3761         const char *filter;
3762
3763         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3764
3765         d_state = h->data;
3766
3767         switch (r->in.level) {
3768         case 1:
3769         case 4:
3770                 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3771                                          "(sAMAccountType=%u))",
3772                                          ATYPE_NORMAL_ACCOUNT);
3773                 break;
3774         case 2:
3775                 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3776                                          "(sAMAccountType=%u))",
3777                                          ATYPE_WORKSTATION_TRUST);
3778                 break;
3779         case 3:
3780         case 5:
3781                 filter = talloc_asprintf(mem_ctx,
3782                                          "(&(|(groupType=%d)(groupType=%d))"
3783                                          "(objectClass=group))",
3784                                          GTYPE_SECURITY_UNIVERSAL_GROUP,
3785                                          GTYPE_SECURITY_GLOBAL_GROUP);
3786                 break;
3787         default:
3788                 return NT_STATUS_INVALID_INFO_CLASS;
3789         }
3790
3791         /* search for all requested objects in this domain. This could
3792            possibly be cached and resumed based on resume_key */
3793         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3794                                       d_state->domain_dn, &res, attrs,
3795                                       d_state->domain_sid, "%s", filter);
3796         if (ldb_cnt == -1) {
3797                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3798         }
3799         if (ldb_cnt == 0 || r->in.max_entries == 0) {
3800                 return NT_STATUS_OK;
3801         }
3802
3803         switch (r->in.level) {
3804         case 1:
3805                 entriesGeneral = talloc_array(mem_ctx,
3806                                              struct samr_DispEntryGeneral,
3807                                              ldb_cnt);
3808                 break;
3809         case 2:
3810                 entriesFull = talloc_array(mem_ctx,
3811                                              struct samr_DispEntryFull,
3812                                              ldb_cnt);
3813                 break;
3814         case 3:
3815                 entriesFullGroup = talloc_array(mem_ctx,
3816                                              struct samr_DispEntryFullGroup,
3817                                              ldb_cnt);
3818                 break;
3819         case 4:
3820         case 5:
3821                 entriesAscii = talloc_array(mem_ctx,
3822                                               struct samr_DispEntryAscii,
3823                                               ldb_cnt);
3824                 break;
3825         }
3826
3827         if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3828             (entriesAscii == NULL) && (entriesFullGroup == NULL))
3829                 return NT_STATUS_NO_MEMORY;
3830
3831         count = 0;
3832
3833         for (i=0; i<ldb_cnt; i++) {
3834                 struct dom_sid *objectsid;
3835
3836                 objectsid = samdb_result_dom_sid(mem_ctx, res[i],
3837                                                  "objectSid");
3838                 if (objectsid == NULL)
3839                         continue;
3840
3841                 switch(r->in.level) {
3842                 case 1:
3843                         entriesGeneral[count].idx = count + 1;
3844                         entriesGeneral[count].rid = 
3845                                 objectsid->sub_auths[objectsid->num_auths-1];
3846                         entriesGeneral[count].acct_flags =
3847                                 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3848                                                         res[i], 
3849                                                         d_state->domain_dn);
3850                         entriesGeneral[count].account_name.string =
3851                                 samdb_result_string(res[i],
3852                                                     "sAMAccountName", "");
3853                         entriesGeneral[count].full_name.string =
3854                                 samdb_result_string(res[i], "displayName", "");
3855                         entriesGeneral[count].description.string =
3856                                 samdb_result_string(res[i], "description", "");
3857                         break;
3858                 case 2:
3859                         entriesFull[count].idx = count + 1;
3860                         entriesFull[count].rid =
3861                                 objectsid->sub_auths[objectsid->num_auths-1];
3862
3863                         /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3864                         entriesFull[count].acct_flags =
3865                                 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3866                                                         res[i], 
3867                                                         d_state->domain_dn) | ACB_NORMAL;
3868                         entriesFull[count].account_name.string =
3869                                 samdb_result_string(res[i], "sAMAccountName",
3870                                                     "");
3871                         entriesFull[count].description.string =
3872                                 samdb_result_string(res[i], "description", "");
3873                         break;
3874                 case 3:
3875                         entriesFullGroup[count].idx = count + 1;
3876                         entriesFullGroup[count].rid =
3877                                 objectsid->sub_auths[objectsid->num_auths-1];
3878                         /* We get a "7" here for groups */
3879                         entriesFullGroup[count].acct_flags
3880                                 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3881                         entriesFullGroup[count].account_name.string =
3882                                 samdb_result_string(res[i], "sAMAccountName",
3883                                                     "");
3884                         entriesFullGroup[count].description.string =
3885                                 samdb_result_string(res[i], "description", "");
3886                         break;
3887                 case 4:
3888                 case 5:
3889                         entriesAscii[count].idx = count + 1;
3890                         entriesAscii[count].account_name.string =
3891                                 samdb_result_string(res[i], "sAMAccountName",
3892                                                     "");
3893                         break;
3894                 }
3895
3896                 count += 1;
3897         }
3898
3899         *r->out.total_size = count;
3900
3901         if (r->in.start_idx >= count) {
3902                 *r->out.returned_size = 0;
3903                 switch(r->in.level) {
3904                 case 1:
3905                         r->out.info->info1.count = *r->out.returned_size;
3906                         r->out.info->info1.entries = NULL;
3907                         break;
3908                 case 2:
3909                         r->out.info->info2.count = *r->out.returned_size;
3910                         r->out.info->info2.entries = NULL;
3911                         break;
3912                 case 3:
3913                         r->out.info->info3.count = *r->out.returned_size;
3914                         r->out.info->info3.entries = NULL;
3915                         break;
3916                 case 4:
3917                         r->out.info->info4.count = *r->out.returned_size;
3918                         r->out.info->info4.entries = NULL;
3919                         break;
3920                 case 5:
3921                         r->out.info->info5.count = *r->out.returned_size;
3922                         r->out.info->info5.entries = NULL;
3923                         break;
3924                 }
3925         } else {
3926                 *r->out.returned_size = MIN(count - r->in.start_idx,
3927                                            r->in.max_entries);
3928                 switch(r->in.level) {
3929                 case 1:
3930                         r->out.info->info1.count = *r->out.returned_size;
3931                         r->out.info->info1.entries =
3932                                 &(entriesGeneral[r->in.start_idx]);
3933                         break;
3934                 case 2:
3935                         r->out.info->info2.count = *r->out.returned_size;
3936                         r->out.info->info2.entries =
3937                                 &(entriesFull[r->in.start_idx]);
3938                         break;
3939                 case 3:
3940                         r->out.info->info3.count = *r->out.returned_size;
3941                         r->out.info->info3.entries =
3942                                 &(entriesFullGroup[r->in.start_idx]);
3943                         break;
3944                 case 4:
3945                         r->out.info->info4.count = *r->out.returned_size;
3946                         r->out.info->info4.entries =
3947                                 &(entriesAscii[r->in.start_idx]);
3948                         break;
3949                 case 5:
3950                         r->out.info->info5.count = *r->out.returned_size;
3951                         r->out.info->info5.entries =
3952                                 &(entriesAscii[r->in.start_idx]);
3953                         break;
3954                 }
3955         }
3956
3957         return (*r->out.returned_size < (count - r->in.start_idx)) ?
3958                 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3959 }
3960
3961
3962 /* 
3963   samr_GetDisplayEnumerationIndex 
3964 */
3965 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3966                        struct samr_GetDisplayEnumerationIndex *r)
3967 {
3968         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3969 }
3970
3971
3972 /* 
3973   samr_TestPrivateFunctionsDomain 
3974 */
3975 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3976                        struct samr_TestPrivateFunctionsDomain *r)
3977 {
3978         return NT_STATUS_NOT_IMPLEMENTED;
3979 }
3980
3981
3982 /* 
3983   samr_TestPrivateFunctionsUser 
3984 */
3985 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3986                        struct samr_TestPrivateFunctionsUser *r)
3987 {
3988         return NT_STATUS_NOT_IMPLEMENTED;
3989 }
3990
3991
3992 /* 
3993   samr_GetUserPwInfo 
3994 */
3995 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3996                                    struct samr_GetUserPwInfo *r)
3997 {
3998         struct dcesrv_handle *h;
3999         struct samr_account_state *a_state;
4000
4001         ZERO_STRUCTP(r->out.info);
4002
4003         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
4004
4005         a_state = h->data;
4006
4007         r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx,
4008                 mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength",
4009                 NULL);
4010         r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx,
4011                 mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL);
4012
4013         return NT_STATUS_OK;
4014 }
4015
4016
4017 /* 
4018   samr_RemoveMemberFromForeignDomain 
4019 */
4020 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4021                        struct samr_RemoveMemberFromForeignDomain *r)
4022 {
4023         struct dcesrv_handle *h;
4024         struct samr_domain_state *d_state;
4025         const char *memberdn;
4026         struct ldb_message **res;
4027         const char * const attrs[3] = { "distinguishedName", "objectSid", NULL };
4028         int i, count;
4029
4030         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4031
4032         d_state = h->data;
4033
4034         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
4035                                        "distinguishedName", "(objectSid=%s)", 
4036                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
4037         /* Nothing to do */
4038         if (memberdn == NULL) {
4039                 return NT_STATUS_OK;
4040         }
4041
4042         /* TODO: Does this call only remove alias members, or does it do this
4043          * for domain groups as well? */
4044
4045         count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
4046                                     d_state->domain_dn, &res, attrs,
4047                                     d_state->domain_sid,
4048                                     "(&(member=%s)(objectClass=group)"
4049                                     "(|(groupType=%d)(groupType=%d)))",
4050                                     memberdn,
4051                                     GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
4052                                     GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
4053
4054         if (count < 0)
4055                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4056
4057         for (i=0; i<count; i++) {
4058                 struct ldb_message *mod;
4059
4060                 mod = ldb_msg_new(mem_ctx);
4061                 if (mod == NULL) {
4062                         return NT_STATUS_NO_MEMORY;
4063                 }
4064
4065                 mod->dn = samdb_result_dn(d_state->sam_ctx, mod, res[i], "distinguishedName", NULL);
4066                 if (mod->dn == NULL) {
4067                         talloc_free(mod);
4068                         continue;
4069                 }
4070
4071                 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
4072                                          "member", memberdn) != LDB_SUCCESS)
4073                         return NT_STATUS_NO_MEMORY;
4074
4075                 if (ldb_modify(d_state->sam_ctx, mod) != LDB_SUCCESS)
4076                         return NT_STATUS_UNSUCCESSFUL;
4077
4078                 talloc_free(mod);
4079         }
4080
4081         return NT_STATUS_OK;
4082 }
4083
4084
4085 /* 
4086   samr_QueryDomainInfo2 
4087
4088   just an alias for samr_QueryDomainInfo
4089 */
4090 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4091                        struct samr_QueryDomainInfo2 *r)
4092 {
4093         struct samr_QueryDomainInfo r1;
4094         NTSTATUS status;
4095
4096         ZERO_STRUCT(r1.out);
4097         r1.in.domain_handle = r->in.domain_handle;
4098         r1.in.level  = r->in.level;
4099         r1.out.info  = r->out.info;
4100
4101         status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
4102         
4103         return status;
4104 }
4105
4106
4107 /* 
4108   samr_QueryUserInfo2 
4109
4110   just an alias for samr_QueryUserInfo
4111 */
4112 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4113                                     struct samr_QueryUserInfo2 *r)
4114 {
4115         struct samr_QueryUserInfo r1;
4116         NTSTATUS status;
4117
4118         r1.in.user_handle = r->in.user_handle;
4119         r1.in.level  = r->in.level;
4120         r1.out.info  = r->out.info;
4121         
4122         status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
4123
4124         return status;
4125 }
4126
4127
4128 /* 
4129   samr_QueryDisplayInfo2 
4130 */
4131 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4132                                        struct samr_QueryDisplayInfo2 *r)
4133 {
4134         struct samr_QueryDisplayInfo q;
4135         NTSTATUS result;
4136
4137         q.in.domain_handle = r->in.domain_handle;
4138         q.in.level = r->in.level;
4139         q.in.start_idx = r->in.start_idx;
4140         q.in.max_entries = r->in.max_entries;
4141         q.in.buf_size = r->in.buf_size;
4142         q.out.total_size = r->out.total_size;
4143         q.out.returned_size = r->out.returned_size;
4144         q.out.info = r->out.info;
4145
4146         result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4147
4148         return result;
4149 }
4150
4151
4152 /* 
4153   samr_GetDisplayEnumerationIndex2 
4154 */
4155 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4156                        struct samr_GetDisplayEnumerationIndex2 *r)
4157 {
4158         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4159 }
4160
4161
4162 /* 
4163   samr_QueryDisplayInfo3 
4164 */
4165 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4166                        struct samr_QueryDisplayInfo3 *r)
4167 {
4168         struct samr_QueryDisplayInfo q;
4169         NTSTATUS result;
4170
4171         q.in.domain_handle = r->in.domain_handle;
4172         q.in.level = r->in.level;
4173         q.in.start_idx = r->in.start_idx;
4174         q.in.max_entries = r->in.max_entries;
4175         q.in.buf_size = r->in.buf_size;
4176         q.out.total_size = r->out.total_size;
4177         q.out.returned_size = r->out.returned_size;
4178         q.out.info = r->out.info;
4179
4180         result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4181
4182         return result;
4183 }
4184
4185
4186 /* 
4187   samr_AddMultipleMembersToAlias 
4188 */
4189 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4190                        struct samr_AddMultipleMembersToAlias *r)
4191 {
4192         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4193 }
4194
4195
4196 /* 
4197   samr_RemoveMultipleMembersFromAlias 
4198 */
4199 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4200                        struct samr_RemoveMultipleMembersFromAlias *r)
4201 {
4202         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4203 }
4204
4205
4206 /* 
4207   samr_GetDomPwInfo 
4208
4209   this fetches the default password properties for a domain
4210
4211   note that w2k3 completely ignores the domain name in this call, and 
4212   always returns the information for the servers primary domain
4213 */
4214 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4215                                   struct samr_GetDomPwInfo *r)
4216 {
4217         struct ldb_message **msgs;
4218         int ret;
4219         const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4220         struct ldb_context *sam_ctx;
4221
4222         ZERO_STRUCTP(r->out.info);
4223
4224         sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
4225                                          dce_call->conn->dce_ctx->lp_ctx,
4226                                          dce_call->conn->auth_state.session_info);
4227         if (sam_ctx == NULL) {
4228                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4229         }
4230
4231         /* The domain name in this call is ignored */
4232         ret = gendb_search_dn(sam_ctx, 
4233                            mem_ctx, NULL, &msgs, attrs);
4234         if (ret <= 0) {
4235                 talloc_free(sam_ctx);
4236
4237                 return NT_STATUS_NO_SUCH_DOMAIN;
4238         }
4239         if (ret > 1) {
4240                 talloc_free(msgs);
4241                 talloc_free(sam_ctx);
4242
4243                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4244         }
4245
4246         r->out.info->min_password_length = samdb_result_uint(msgs[0],
4247                 "minPwdLength", 0);
4248         r->out.info->password_properties = samdb_result_uint(msgs[0],
4249                 "pwdProperties", 1);
4250
4251         talloc_free(msgs);
4252         talloc_unlink(mem_ctx, sam_ctx);
4253
4254         return NT_STATUS_OK;
4255 }
4256
4257
4258 /* 
4259   samr_Connect2 
4260 */
4261 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4262                               struct samr_Connect2 *r)
4263 {
4264         struct samr_Connect c;
4265
4266         c.in.system_name = NULL;
4267         c.in.access_mask = r->in.access_mask;
4268         c.out.connect_handle = r->out.connect_handle;
4269
4270         return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4271 }
4272
4273
4274 /* 
4275   samr_SetUserInfo2 
4276
4277   just an alias for samr_SetUserInfo
4278 */
4279 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4280                                   struct samr_SetUserInfo2 *r)
4281 {
4282         struct samr_SetUserInfo r2;
4283
4284         r2.in.user_handle = r->in.user_handle;
4285         r2.in.level = r->in.level;
4286         r2.in.info = r->in.info;
4287
4288         return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
4289 }
4290
4291
4292 /* 
4293   samr_SetBootKeyInformation 
4294 */
4295 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4296                        struct samr_SetBootKeyInformation *r)
4297 {
4298         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4299 }
4300
4301
4302 /* 
4303   samr_GetBootKeyInformation 
4304 */
4305 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4306                        struct samr_GetBootKeyInformation *r)
4307 {
4308         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4309 }
4310
4311
4312 /* 
4313   samr_Connect3 
4314 */
4315 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4316                        struct samr_Connect3 *r)
4317 {
4318         struct samr_Connect c;
4319
4320         c.in.system_name = NULL;
4321         c.in.access_mask = r->in.access_mask;
4322         c.out.connect_handle = r->out.connect_handle;
4323
4324         return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4325 }
4326
4327
4328 /* 
4329   samr_Connect4 
4330 */
4331 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4332                        struct samr_Connect4 *r)
4333 {
4334         struct samr_Connect c;
4335
4336         c.in.system_name = NULL;
4337         c.in.access_mask = r->in.access_mask;
4338         c.out.connect_handle = r->out.connect_handle;
4339
4340         return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4341 }
4342
4343
4344 /* 
4345   samr_Connect5 
4346 */
4347 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4348                               struct samr_Connect5 *r)
4349 {
4350         struct samr_Connect c;
4351         NTSTATUS status;
4352
4353         c.in.system_name = NULL;
4354         c.in.access_mask = r->in.access_mask;
4355         c.out.connect_handle = r->out.connect_handle;
4356
4357         status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4358
4359         r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
4360         r->out.info_out->info1.unknown2 = 0;
4361         *r->out.level_out = r->in.level_in;
4362
4363         return status;
4364 }
4365
4366
4367 /* 
4368   samr_RidToSid 
4369 */
4370 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4371                               struct samr_RidToSid *r)
4372 {
4373         struct samr_domain_state *d_state;
4374         struct dcesrv_handle *h;
4375
4376         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4377
4378         d_state = h->data;
4379
4380         /* form the users SID */
4381         *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4382         if (!*r->out.sid) {
4383                 return NT_STATUS_NO_MEMORY;
4384         }
4385
4386         return NT_STATUS_OK;
4387 }
4388
4389
4390 /* 
4391   samr_SetDsrmPassword 
4392 */
4393 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4394                        struct samr_SetDsrmPassword *r)
4395 {
4396         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4397 }
4398
4399
4400 /* 
4401   samr_ValidatePassword
4402
4403   For now the call checks the password complexity (if active) and the minimum
4404   password length on level 2 and 3. Level 1 is ignored for now.
4405 */
4406 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
4407                                              TALLOC_CTX *mem_ctx,
4408                                              struct samr_ValidatePassword *r)
4409 {
4410         struct samr_GetDomPwInfo r2;
4411         struct samr_PwInfo pwInfo;
4412         DATA_BLOB password;
4413         enum samr_ValidationStatus res;
4414         NTSTATUS status;
4415
4416         (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
4417
4418         r2.in.domain_name = NULL;
4419         r2.out.info = &pwInfo;
4420         status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2);
4421         if (!NT_STATUS_IS_OK(status)) {
4422                 return status;
4423         }
4424
4425         switch (r->in.level) {
4426         case NetValidateAuthentication:
4427                 /* we don't support this yet */
4428                 return NT_STATUS_NOT_SUPPORTED;
4429         break;
4430         case NetValidatePasswordChange:
4431                 password = data_blob_const(r->in.req->req2.password.string,
4432                                            r->in.req->req2.password.length);
4433                 res = samdb_check_password(&password,
4434                                            pwInfo.password_properties,
4435                                            pwInfo.min_password_length);
4436                 (*r->out.rep)->ctr2.status = res;
4437         break;
4438         case NetValidatePasswordReset:
4439                 password = data_blob_const(r->in.req->req3.password.string,
4440                                            r->in.req->req3.password.length);
4441                 res = samdb_check_password(&password,
4442                                            pwInfo.password_properties,
4443                                            pwInfo.min_password_length);
4444                 (*r->out.rep)->ctr3.status = res;
4445         break;
4446         default:
4447                 return NT_STATUS_INVALID_INFO_CLASS;
4448         break;
4449         }
4450
4451         return NT_STATUS_OK;
4452 }
4453
4454
4455 /* include the generated boilerplate */
4456 #include "librpc/gen_ndr/ndr_samr_s.c"