s4:dcesrv_samr - Fix up "EnumDomainGroups" and "QueryDisplayInfo" calls
[obnox/samba/samba-obnox.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))",
2052                            ldap_encode_ndr_dom_sid(mem_ctx, sid),
2053                            GTYPE_SECURITY_GLOBAL_GROUP);
2054         if (ret == 0) {
2055                 return NT_STATUS_NO_SUCH_GROUP;
2056         }
2057         if (ret != 1) {
2058                 DEBUG(0,("Found %d records matching sid %s\n", 
2059                          ret, dom_sid_string(mem_ctx, sid)));
2060                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2061         }
2062
2063         groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2064         if (groupname == NULL) {
2065                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2066                          dom_sid_string(mem_ctx, sid)));
2067                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2068         }
2069
2070         a_state = talloc(mem_ctx, struct samr_account_state);
2071         if (!a_state) {
2072                 return NT_STATUS_NO_MEMORY;
2073         }
2074         a_state->sam_ctx = d_state->sam_ctx;
2075         a_state->access_mask = r->in.access_mask;
2076         a_state->domain_state = talloc_reference(a_state, d_state);
2077         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2078         a_state->account_sid = talloc_steal(a_state, sid);
2079         a_state->account_name = talloc_strdup(a_state, groupname);
2080         if (!a_state->account_name) {
2081                 return NT_STATUS_NO_MEMORY;
2082         }
2083
2084         /* create the policy handle */
2085         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
2086         if (!g_handle) {
2087                 return NT_STATUS_NO_MEMORY;
2088         }
2089
2090         g_handle->data = talloc_steal(g_handle, a_state);
2091
2092         *r->out.group_handle = g_handle->wire_handle;
2093
2094         return NT_STATUS_OK;
2095 }
2096
2097 /* 
2098   samr_QueryGroupInfo 
2099 */
2100 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2101                        struct samr_QueryGroupInfo *r)
2102 {
2103         struct dcesrv_handle *h;
2104         struct samr_account_state *a_state;
2105         struct ldb_message *msg;
2106         struct ldb_result *res;
2107         const char * const attrs[4] = { "sAMAccountName", "description",
2108                                         "numMembers", NULL };
2109         int ret;
2110         union samr_GroupInfo *info;
2111
2112         *r->out.info = NULL;
2113
2114         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2115
2116         a_state = h->data;
2117         
2118         ret = ldb_search(a_state->sam_ctx, mem_ctx, &res, a_state->account_dn,
2119                 LDB_SCOPE_SUBTREE, attrs, "objectClass=*");
2120         
2121         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2122                 return NT_STATUS_NO_SUCH_GROUP;
2123         } else if (ret != LDB_SUCCESS) {
2124                 DEBUG(2, ("Error reading group info: %s\n", ldb_errstring(a_state->sam_ctx)));
2125                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2126         }
2127
2128         if (res->count != 1) {
2129                 DEBUG(2, ("Error finding group info, got %d entries\n", res->count));
2130                 
2131                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2132         }
2133         msg = res->msgs[0];
2134
2135         /* allocate the info structure */
2136         info = talloc_zero(mem_ctx, union samr_GroupInfo);
2137         if (info == NULL) {
2138                 return NT_STATUS_NO_MEMORY;
2139         }
2140
2141         /* Fill in the level */
2142         switch (r->in.level) {
2143         case GROUPINFOALL:
2144                 QUERY_STRING(msg, all.name,        "sAMAccountName");
2145                 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2146                 QUERY_UINT  (msg, all.num_members,      "numMembers")
2147                 QUERY_STRING(msg, all.description, "description");
2148                 break;
2149         case GROUPINFONAME:
2150                 QUERY_STRING(msg, name,            "sAMAccountName");
2151                 break;
2152         case GROUPINFOATTRIBUTES:
2153                 info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2154                 break;
2155         case GROUPINFODESCRIPTION:
2156                 QUERY_STRING(msg, description, "description");
2157                 break;
2158         case GROUPINFOALL2:
2159                 QUERY_STRING(msg, all2.name,        "sAMAccountName");
2160                 info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2161                 QUERY_UINT  (msg, all2.num_members,      "numMembers")
2162                 QUERY_STRING(msg, all2.description, "description");
2163                 break;
2164         default:
2165                 talloc_free(info);
2166                 return NT_STATUS_INVALID_INFO_CLASS;
2167         }
2168
2169         *r->out.info = info;
2170
2171         return NT_STATUS_OK;
2172 }
2173
2174
2175 /* 
2176   samr_SetGroupInfo 
2177 */
2178 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2179                                   struct samr_SetGroupInfo *r)
2180 {
2181         struct dcesrv_handle *h;
2182         struct samr_account_state *g_state;
2183         struct ldb_message *msg;
2184         struct ldb_context *sam_ctx;
2185         int ret;
2186
2187         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2188
2189         g_state = h->data;
2190         sam_ctx = g_state->sam_ctx;
2191
2192         msg = ldb_msg_new(mem_ctx);
2193         if (msg == NULL) {
2194                 return NT_STATUS_NO_MEMORY;
2195         }       
2196
2197         msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
2198         if (!msg->dn) {
2199                 return NT_STATUS_NO_MEMORY;
2200         }
2201
2202         switch (r->in.level) {
2203         case GROUPINFODESCRIPTION:
2204                 SET_STRING(msg, description,         "description");
2205                 break;
2206         case GROUPINFONAME:
2207                 /* On W2k3 this does not change the name, it changes the
2208                  * sAMAccountName attribute */
2209                 SET_STRING(msg, name,                "sAMAccountName");
2210                 break;
2211         case GROUPINFOATTRIBUTES:
2212                 /* This does not do anything obviously visible in W2k3 LDAP */
2213                 return NT_STATUS_OK;
2214         default:
2215                 return NT_STATUS_INVALID_INFO_CLASS;
2216         }
2217
2218         /* modify the samdb record */
2219         ret = ldb_modify(g_state->sam_ctx, msg);
2220         if (ret != LDB_SUCCESS) {
2221                 /* we really need samdb.c to return NTSTATUS */
2222                 return NT_STATUS_UNSUCCESSFUL;
2223         }
2224
2225         return NT_STATUS_OK;
2226 }
2227
2228
2229 /* 
2230   samr_AddGroupMember 
2231 */
2232 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2233                        struct samr_AddGroupMember *r)
2234 {
2235         struct dcesrv_handle *h;
2236         struct samr_account_state *a_state;
2237         struct samr_domain_state *d_state;
2238         struct ldb_message *mod;
2239         struct dom_sid *membersid;
2240         const char *memberdn;
2241         struct ldb_result *res;
2242         const char * const attrs[] = { NULL };
2243         int ret;
2244
2245         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2246
2247         a_state = h->data;
2248         d_state = a_state->domain_state;
2249
2250         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2251         if (membersid == NULL) {
2252                 return NT_STATUS_NO_MEMORY;
2253         }
2254
2255         /* In native mode, AD can also nest domain groups. Not sure yet
2256          * whether this is also available via RPC. */
2257         ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2258                                  d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2259                                  "(&(objectSid=%s)(objectclass=user))",
2260                                  ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2261
2262         if (ret != LDB_SUCCESS) {
2263                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2264         }
2265
2266         if (res->count == 0) {
2267                 return NT_STATUS_NO_SUCH_USER;
2268         }
2269                 
2270         if (res->count > 1) {
2271                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2272         }
2273
2274         memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2275
2276         if (memberdn == NULL)
2277                 return NT_STATUS_NO_MEMORY;
2278
2279         mod = ldb_msg_new(mem_ctx);
2280         if (mod == NULL) {
2281                 return NT_STATUS_NO_MEMORY;
2282         }
2283
2284         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2285
2286         ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2287                                                                 memberdn);
2288         if (ret != LDB_SUCCESS) {
2289                 return NT_STATUS_UNSUCCESSFUL;
2290         }
2291
2292         ret = ldb_modify(a_state->sam_ctx, mod);
2293         switch (ret) {
2294         case LDB_SUCCESS:
2295                 return NT_STATUS_OK;
2296         case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
2297                 return NT_STATUS_MEMBER_IN_GROUP;
2298         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2299                 return NT_STATUS_ACCESS_DENIED;
2300         default:
2301                 return NT_STATUS_UNSUCCESSFUL;
2302         }
2303 }
2304
2305
2306 /* 
2307   samr_DeleteDomainGroup 
2308 */
2309 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2310                        struct samr_DeleteDomainGroup *r)
2311 {
2312         struct dcesrv_handle *h;
2313         struct samr_account_state *a_state;
2314         int ret;
2315
2316         *r->out.group_handle = *r->in.group_handle;
2317
2318         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2319
2320         a_state = h->data;
2321
2322         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2323         if (ret != LDB_SUCCESS) {
2324                 return NT_STATUS_UNSUCCESSFUL;
2325         }
2326
2327         talloc_free(h);
2328         ZERO_STRUCTP(r->out.group_handle);
2329
2330         return NT_STATUS_OK;
2331 }
2332
2333
2334 /* 
2335   samr_DeleteGroupMember 
2336 */
2337 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2338                        struct samr_DeleteGroupMember *r)
2339 {
2340         struct dcesrv_handle *h;
2341         struct samr_account_state *a_state;
2342         struct samr_domain_state *d_state;
2343         struct ldb_message *mod;
2344         struct dom_sid *membersid;
2345         const char *memberdn;
2346         struct ldb_result *res;
2347         const char * const attrs[] = { NULL };
2348         int ret;
2349
2350         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2351
2352         a_state = h->data;
2353         d_state = a_state->domain_state;
2354
2355         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2356         if (membersid == NULL)
2357                 return NT_STATUS_NO_MEMORY;
2358
2359         /* In native mode, AD can also nest domain groups. Not sure yet
2360          * whether this is also available via RPC. */
2361         ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2362                                  d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2363                                  "(&(objectSid=%s)(objectclass=user))",
2364                                  ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2365
2366         if (ret != LDB_SUCCESS) {
2367                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2368         }
2369
2370         if (res->count == 0) {
2371                 return NT_STATUS_NO_SUCH_USER;
2372         }
2373                 
2374         if (res->count > 1) {
2375                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2376         }
2377
2378         memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2379
2380         if (memberdn == NULL)
2381                 return NT_STATUS_NO_MEMORY;
2382
2383         mod = ldb_msg_new(mem_ctx);
2384         if (mod == NULL) {
2385                 return NT_STATUS_NO_MEMORY;
2386         }
2387
2388         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2389
2390         ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2391                                                                 memberdn);
2392         if (ret != LDB_SUCCESS) {
2393                 return NT_STATUS_NO_MEMORY;
2394         }
2395
2396         ret = ldb_modify(a_state->sam_ctx, mod);
2397         switch (ret) {
2398         case LDB_SUCCESS:
2399                 return NT_STATUS_OK;
2400         case LDB_ERR_NO_SUCH_ATTRIBUTE:
2401                 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2402         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2403                 return NT_STATUS_ACCESS_DENIED;
2404         default:
2405                 return NT_STATUS_UNSUCCESSFUL;
2406         }
2407 }
2408
2409
2410 /* 
2411   samr_QueryGroupMember 
2412 */
2413 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2414                                       struct samr_QueryGroupMember *r)
2415 {
2416         struct dcesrv_handle *h;
2417         struct samr_account_state *a_state;
2418         struct ldb_message **res;
2419         struct ldb_message_element *el;
2420         struct samr_RidTypeArray *array;
2421         const char * const attrs[2] = { "member", NULL };
2422         int ret;
2423
2424         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2425
2426         a_state = h->data;
2427
2428         /* pull the member attribute */
2429         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2430                               a_state->account_dn, &res, attrs);
2431
2432         if (ret != 1) {
2433                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2434         }
2435
2436         array = talloc(mem_ctx, struct samr_RidTypeArray);
2437
2438         if (array == NULL)
2439                 return NT_STATUS_NO_MEMORY;
2440
2441         ZERO_STRUCTP(array);
2442
2443         el = ldb_msg_find_element(res[0], "member");
2444
2445         if (el != NULL) {
2446                 int i;
2447
2448                 array->count = el->num_values;
2449
2450                 array->rids = talloc_array(mem_ctx, uint32_t,
2451                                              el->num_values);
2452                 if (array->rids == NULL)
2453                         return NT_STATUS_NO_MEMORY;
2454
2455                 array->types = talloc_array(mem_ctx, uint32_t,
2456                                             el->num_values);
2457                 if (array->types == NULL)
2458                         return NT_STATUS_NO_MEMORY;
2459
2460                 for (i=0; i<el->num_values; i++) {
2461                         struct ldb_message **res2;
2462                         const char * const attrs2[2] = { "objectSid", NULL };
2463                         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2464                                            ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2465                                            &res2, attrs2);
2466                         if (ret != 1)
2467                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2468
2469                         array->rids[i] =
2470                                 samdb_result_rid_from_sid(mem_ctx, res2[0],
2471                                                           "objectSid", 0);
2472
2473                         if (array->rids[i] == 0)
2474                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2475
2476                         array->types[i] = 7; /* RID type of some kind, not sure what the value means. */
2477                 }
2478         }
2479
2480         *r->out.rids = array;
2481
2482         return NT_STATUS_OK;
2483 }
2484
2485
2486 /* 
2487   samr_SetMemberAttributesOfGroup 
2488 */
2489 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2490                        struct samr_SetMemberAttributesOfGroup *r)
2491 {
2492         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2493 }
2494
2495
2496 /* 
2497   samr_OpenAlias 
2498 */
2499 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2500                        struct samr_OpenAlias *r)
2501 {
2502         struct samr_domain_state *d_state;
2503         struct samr_account_state *a_state;
2504         struct dcesrv_handle *h;
2505         const char *alias_name;
2506         struct dom_sid *sid;
2507         struct ldb_message **msgs;
2508         struct dcesrv_handle *g_handle;
2509         const char * const attrs[2] = { "sAMAccountName", NULL };
2510         int ret;
2511
2512         ZERO_STRUCTP(r->out.alias_handle);
2513
2514         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2515
2516         d_state = h->data;
2517
2518         /* form the alias SID */
2519         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2520         if (sid == NULL)
2521                 return NT_STATUS_NO_MEMORY;
2522
2523         /* search for the group record */
2524         ret = gendb_search(d_state->sam_ctx,
2525                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2526                            "(&(objectSid=%s)(objectclass=group)"
2527                            "(|(grouptype=%d)(grouptype=%d)))",
2528                            ldap_encode_ndr_dom_sid(mem_ctx, sid),
2529                            GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2530                            GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2531         if (ret == 0) {
2532                 return NT_STATUS_NO_SUCH_ALIAS;
2533         }
2534         if (ret != 1) {
2535                 DEBUG(0,("Found %d records matching sid %s\n", 
2536                          ret, dom_sid_string(mem_ctx, sid)));
2537                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2538         }
2539
2540         alias_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2541         if (alias_name == NULL) {
2542                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2543                          dom_sid_string(mem_ctx, sid)));
2544                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2545         }
2546
2547         a_state = talloc(mem_ctx, struct samr_account_state);
2548         if (!a_state) {
2549                 return NT_STATUS_NO_MEMORY;
2550         }
2551         a_state->sam_ctx = d_state->sam_ctx;
2552         a_state->access_mask = r->in.access_mask;
2553         a_state->domain_state = talloc_reference(a_state, d_state);
2554         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2555         a_state->account_sid = talloc_steal(a_state, sid);
2556         a_state->account_name = talloc_strdup(a_state, alias_name);
2557         if (!a_state->account_name) {
2558                 return NT_STATUS_NO_MEMORY;
2559         }
2560
2561         /* create the policy handle */
2562         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2563         if (!g_handle) {
2564                 return NT_STATUS_NO_MEMORY;
2565         }
2566
2567         g_handle->data = talloc_steal(g_handle, a_state);
2568
2569         *r->out.alias_handle = g_handle->wire_handle;
2570
2571         return NT_STATUS_OK;
2572 }
2573
2574
2575 /* 
2576   samr_QueryAliasInfo 
2577 */
2578 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2579                        struct samr_QueryAliasInfo *r)
2580 {
2581         struct dcesrv_handle *h;
2582         struct samr_account_state *a_state;
2583         struct ldb_message *msg, **res;
2584         const char * const attrs[4] = { "sAMAccountName", "description",
2585                                         "numMembers", NULL };
2586         int ret;
2587         union samr_AliasInfo *info;
2588
2589         *r->out.info = NULL;
2590
2591         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2592
2593         a_state = h->data;
2594
2595         /* pull all the alias attributes */
2596         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2597                               a_state->account_dn ,&res, attrs);
2598         if (ret != 1) {
2599                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2600         }
2601         msg = res[0];
2602
2603         /* allocate the info structure */
2604         info = talloc_zero(mem_ctx, union samr_AliasInfo);
2605         if (info == NULL) {
2606                 return NT_STATUS_NO_MEMORY;
2607         }
2608
2609         switch(r->in.level) {
2610         case ALIASINFOALL:
2611                 QUERY_STRING(msg, all.name, "sAMAccountName");
2612                 QUERY_UINT  (msg, all.num_members, "numMembers");
2613                 QUERY_STRING(msg, all.description, "description");
2614                 break;
2615         case ALIASINFONAME:
2616                 QUERY_STRING(msg, name, "sAMAccountName");
2617                 break;
2618         case ALIASINFODESCRIPTION:
2619                 QUERY_STRING(msg, description, "description");
2620                 break;
2621         default:
2622                 talloc_free(info);
2623                 return NT_STATUS_INVALID_INFO_CLASS;
2624         }
2625
2626         *r->out.info = info;
2627
2628         return NT_STATUS_OK;
2629 }
2630
2631
2632 /* 
2633   samr_SetAliasInfo 
2634 */
2635 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2636                        struct samr_SetAliasInfo *r)
2637 {
2638         struct dcesrv_handle *h;
2639         struct samr_account_state *a_state;
2640         struct ldb_message *msg;
2641         struct ldb_context *sam_ctx;
2642         int ret;
2643
2644         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2645
2646         a_state = h->data;
2647         sam_ctx = a_state->sam_ctx;
2648
2649         msg = ldb_msg_new(mem_ctx);
2650         if (msg == NULL) {
2651                 return NT_STATUS_NO_MEMORY;
2652         }
2653
2654         msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2655         if (!msg->dn) {
2656                 return NT_STATUS_NO_MEMORY;
2657         }
2658
2659         switch (r->in.level) {
2660         case ALIASINFODESCRIPTION:
2661                 SET_STRING(msg, description,         "description");
2662                 break;
2663         case ALIASINFONAME:
2664                 /* On W2k3 this does not change the name, it changes the
2665                  * sAMAccountName attribute */
2666                 SET_STRING(msg, name,                "sAMAccountName");
2667                 break;
2668         default:
2669                 return NT_STATUS_INVALID_INFO_CLASS;
2670         }
2671
2672         /* modify the samdb record */
2673         ret = ldb_modify(a_state->sam_ctx, msg);
2674         if (ret != LDB_SUCCESS) {
2675                 /* we really need samdb.c to return NTSTATUS */
2676                 return NT_STATUS_UNSUCCESSFUL;
2677         }
2678
2679         return NT_STATUS_OK;
2680 }
2681
2682
2683 /* 
2684   samr_DeleteDomAlias 
2685 */
2686 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2687                        struct samr_DeleteDomAlias *r)
2688 {
2689         struct dcesrv_handle *h;
2690         struct samr_account_state *a_state;
2691         int ret;
2692
2693         *r->out.alias_handle = *r->in.alias_handle;
2694
2695         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2696
2697         a_state = h->data;
2698
2699         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2700         if (ret != LDB_SUCCESS) {
2701                 return NT_STATUS_UNSUCCESSFUL;
2702         }
2703
2704         talloc_free(h);
2705         ZERO_STRUCTP(r->out.alias_handle);
2706
2707         return NT_STATUS_OK;
2708 }
2709
2710
2711 /* 
2712   samr_AddAliasMember 
2713 */
2714 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2715                        struct samr_AddAliasMember *r)
2716 {
2717         struct dcesrv_handle *h;
2718         struct samr_account_state *a_state;
2719         struct samr_domain_state *d_state;
2720         struct ldb_message *mod;
2721         struct ldb_message **msgs;
2722         const char * const attrs[] = { NULL };
2723         struct ldb_dn *memberdn = NULL;
2724         int ret;
2725         NTSTATUS status;
2726
2727         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2728
2729         a_state = h->data;
2730         d_state = a_state->domain_state;
2731
2732         ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2733                            &msgs, attrs, "(objectsid=%s)", 
2734                            ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2735
2736         if (ret == 1) {
2737                 memberdn = msgs[0]->dn;
2738         } else  if (ret > 1) {
2739                 DEBUG(0,("Found %d records matching sid %s\n", 
2740                          ret, dom_sid_string(mem_ctx, r->in.sid)));
2741                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2742         } else if (ret == 0) {
2743                 status = samdb_create_foreign_security_principal(
2744                         d_state->sam_ctx, mem_ctx, r->in.sid, &memberdn);
2745                 if (!NT_STATUS_IS_OK(status)) {
2746                         return status;
2747                 }
2748         } else {
2749                 DEBUG(0, ("samdb_search returned %d: %s\n", ret, ldb_errstring(d_state->sam_ctx)));
2750         }
2751
2752         if (memberdn == NULL) {
2753                 DEBUG(0, ("Could not find memberdn\n"));
2754                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2755         }
2756
2757         mod = ldb_msg_new(mem_ctx);
2758         if (mod == NULL) {
2759                 return NT_STATUS_NO_MEMORY;
2760         }
2761
2762         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2763
2764         ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2765                                  ldb_dn_alloc_linearized(mem_ctx, memberdn));
2766         if (ret != LDB_SUCCESS) {
2767                 return NT_STATUS_UNSUCCESSFUL;
2768         }
2769
2770         if (ldb_modify(a_state->sam_ctx, mod) != LDB_SUCCESS) {
2771                 return NT_STATUS_UNSUCCESSFUL;
2772         }
2773
2774         return NT_STATUS_OK;
2775 }
2776
2777
2778 /* 
2779   samr_DeleteAliasMember 
2780 */
2781 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2782                        struct samr_DeleteAliasMember *r)
2783 {
2784         struct dcesrv_handle *h;
2785         struct samr_account_state *a_state;
2786         struct samr_domain_state *d_state;
2787         struct ldb_message *mod;
2788         const char *memberdn;
2789         int ret;
2790
2791         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2792
2793         a_state = h->data;
2794         d_state = a_state->domain_state;
2795
2796         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2797                                        "distinguishedName", "(objectSid=%s)", 
2798                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2799
2800         if (memberdn == NULL)
2801                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2802
2803         mod = ldb_msg_new(mem_ctx);
2804         if (mod == NULL) {
2805                 return NT_STATUS_NO_MEMORY;
2806         }
2807
2808         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2809
2810         ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2811                                                                  memberdn);
2812         if (ret != LDB_SUCCESS)
2813                 return NT_STATUS_UNSUCCESSFUL;
2814
2815         if (ldb_modify(a_state->sam_ctx, mod) != LDB_SUCCESS)
2816                 return NT_STATUS_UNSUCCESSFUL;
2817
2818         return NT_STATUS_OK;
2819 }
2820
2821
2822 /* 
2823   samr_GetMembersInAlias 
2824 */
2825 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2826                        struct samr_GetMembersInAlias *r)
2827 {
2828         struct dcesrv_handle *h;
2829         struct samr_account_state *a_state;
2830         struct samr_domain_state *d_state;
2831         struct ldb_message **msgs;
2832         struct lsa_SidPtr *sids;
2833         struct ldb_message_element *el;
2834         const char * const attrs[2] = { "member", NULL};
2835         int ret;
2836
2837         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2838
2839         a_state = h->data;
2840         d_state = a_state->domain_state;
2841
2842         ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
2843                               a_state->account_dn, &msgs, attrs);
2844
2845         if (ret == -1) {
2846                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2847         } else if (ret == 0) {
2848                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2849         } else if (ret != 1) {
2850                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2851         }
2852
2853         r->out.sids->num_sids = 0;
2854         r->out.sids->sids = NULL;
2855
2856         el = ldb_msg_find_element(msgs[0], "member");
2857
2858         if (el != NULL) {
2859                 int i;
2860
2861                 sids = talloc_array(mem_ctx, struct lsa_SidPtr,
2862                                       el->num_values);
2863
2864                 if (sids == NULL)
2865                         return NT_STATUS_NO_MEMORY;
2866
2867                 for (i=0; i<el->num_values; i++) {
2868                         struct ldb_message **msgs2;
2869                         const char * const attrs2[2] = { "objectSid", NULL };
2870                         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2871                                               ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2872                                               &msgs2, attrs2);
2873                         if (ret != 1)
2874                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2875
2876                         sids[i].sid = samdb_result_dom_sid(mem_ctx, msgs2[0],
2877                                                            "objectSid");
2878
2879                         if (sids[i].sid == NULL)
2880                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2881                 }
2882                 r->out.sids->num_sids = el->num_values;
2883                 r->out.sids->sids = sids;
2884         }
2885
2886         return NT_STATUS_OK;
2887 }
2888
2889 /* 
2890   samr_OpenUser 
2891 */
2892 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2893                               struct samr_OpenUser *r)
2894 {
2895         struct samr_domain_state *d_state;
2896         struct samr_account_state *a_state;
2897         struct dcesrv_handle *h;
2898         const char *account_name;
2899         struct dom_sid *sid;
2900         struct ldb_message **msgs;
2901         struct dcesrv_handle *u_handle;
2902         const char * const attrs[2] = { "sAMAccountName", NULL };
2903         int ret;
2904
2905         ZERO_STRUCTP(r->out.user_handle);
2906
2907         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2908
2909         d_state = h->data;
2910
2911         /* form the users SID */
2912         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2913         if (!sid) {
2914                 return NT_STATUS_NO_MEMORY;
2915         }
2916
2917         /* search for the user record */
2918         ret = gendb_search(d_state->sam_ctx,
2919                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2920                            "(&(objectSid=%s)(objectclass=user))", 
2921                            ldap_encode_ndr_dom_sid(mem_ctx, sid));
2922         if (ret == 0) {
2923                 return NT_STATUS_NO_SUCH_USER;
2924         }
2925         if (ret != 1) {
2926                 DEBUG(0,("Found %d records matching sid %s\n", ret, 
2927                          dom_sid_string(mem_ctx, sid)));
2928                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2929         }
2930
2931         account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2932         if (account_name == NULL) {
2933                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2934                          dom_sid_string(mem_ctx, sid)));
2935                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2936         }
2937
2938         a_state = talloc(mem_ctx, struct samr_account_state);
2939         if (!a_state) {
2940                 return NT_STATUS_NO_MEMORY;
2941         }
2942         a_state->sam_ctx = d_state->sam_ctx;
2943         a_state->access_mask = r->in.access_mask;
2944         a_state->domain_state = talloc_reference(a_state, d_state);
2945         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2946         a_state->account_sid = talloc_steal(a_state, sid);
2947         a_state->account_name = talloc_strdup(a_state, account_name);
2948         if (!a_state->account_name) {
2949                 return NT_STATUS_NO_MEMORY;
2950         }
2951
2952         /* create the policy handle */
2953         u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2954         if (!u_handle) {
2955                 return NT_STATUS_NO_MEMORY;
2956         }
2957
2958         u_handle->data = talloc_steal(u_handle, a_state);
2959
2960         *r->out.user_handle = u_handle->wire_handle;
2961
2962         return NT_STATUS_OK;
2963
2964 }
2965
2966
2967 /* 
2968   samr_DeleteUser 
2969 */
2970 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2971                                 struct samr_DeleteUser *r)
2972 {
2973         struct dcesrv_handle *h;
2974         struct samr_account_state *a_state;
2975         int ret;
2976
2977         *r->out.user_handle = *r->in.user_handle;
2978
2979         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2980
2981         a_state = h->data;
2982
2983         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2984         if (ret != LDB_SUCCESS) {
2985                 DEBUG(1, ("Failed to delete user: %s: %s\n", 
2986                           ldb_dn_get_linearized(a_state->account_dn), 
2987                           ldb_errstring(a_state->sam_ctx)));
2988                 return NT_STATUS_UNSUCCESSFUL;
2989         }
2990
2991         talloc_free(h);
2992         ZERO_STRUCTP(r->out.user_handle);
2993
2994         return NT_STATUS_OK;
2995 }
2996
2997
2998 /* 
2999   samr_QueryUserInfo 
3000 */
3001 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3002                                    struct samr_QueryUserInfo *r)
3003 {
3004         struct dcesrv_handle *h;
3005         struct samr_account_state *a_state;
3006         struct ldb_message *msg, **res;
3007         int ret;
3008         struct ldb_context *sam_ctx;
3009
3010         const char * const *attrs = NULL;
3011         union samr_UserInfo *info;
3012
3013         *r->out.info = NULL;
3014
3015         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3016
3017         a_state = h->data;
3018         sam_ctx = a_state->sam_ctx;
3019
3020         /* fill in the reply */
3021         switch (r->in.level) {
3022         case 1:
3023         {
3024                 static const char * const attrs2[] = {"sAMAccountName",
3025                                                       "displayName",
3026                                                       "primaryroupID",
3027                                                       "description",
3028                                                       "comment",
3029                                                       NULL};
3030                 attrs = attrs2;
3031                 break;
3032         }
3033         case 2:
3034         {
3035                 static const char * const attrs2[] = {"comment",
3036                                                       "countryCode",
3037                                                       "codePage",
3038                                                       NULL};
3039                 attrs = attrs2;
3040                 break;
3041         }
3042         case 3:
3043         {
3044                 static const char * const attrs2[] = {"sAMAccountName",
3045                                                       "displayName",
3046                                                       "objectSid",
3047                                                       "primaryGroupID",
3048                                                       "homeDirectory",
3049                                                       "homeDrive",
3050                                                       "scriptPath",
3051                                                       "profilePath",
3052                                                       "userWorkstations",
3053                                                       "lastLogon",
3054                                                       "lastLogoff",
3055                                                       "pwdLastSet",
3056                                                       "logonHours",
3057                                                       "badPwdCount",
3058                                                       "logonCount",
3059                                                       "userAccountControl",
3060                                                       NULL};
3061                 attrs = attrs2;
3062                 break;
3063         }
3064         case 4:
3065         {
3066                 static const char * const attrs2[] = {"logonHours",
3067                                                       NULL};
3068                 attrs = attrs2;
3069                 break;
3070         }
3071         case 5:
3072         {
3073                 static const char * const attrs2[] = {"sAMAccountName", 
3074                                                       "displayName",
3075                                                       "objectSid",
3076                                                       "primaryGroupID",
3077                                                       "homeDirectory",
3078                                                       "homeDrive",
3079                                                       "scriptPath", 
3080                                                       "profilePath",
3081                                                       "description",
3082                                                       "userWorkstations",
3083                                                       "lastLogon",
3084                                                       "lastLogoff",
3085                                                       "logonHours",
3086                                                       "badPwdCount",
3087                                                       "logonCount",
3088                                                       "pwdLastSet",
3089                                                       "accountExpires",
3090                                                       "userAccountControl",
3091                                                       NULL};
3092                 attrs = attrs2;
3093                 break;
3094         }
3095         case 6:
3096         {
3097                 static const char * const attrs2[] = {"sAMAccountName",
3098                                                       "displayName",
3099                                                       NULL};
3100                 attrs = attrs2;
3101                 break;
3102         }
3103         case 7:
3104         {
3105                 static const char * const attrs2[] = {"sAMAccountName",
3106                                                       NULL};
3107                 attrs = attrs2;
3108                 break;
3109         }
3110         case 8:
3111         {
3112                 static const char * const attrs2[] = {"displayName",
3113                                                       NULL};
3114                 attrs = attrs2;
3115                 break;
3116         }
3117         case 9:
3118         {
3119                 static const char * const attrs2[] = {"primaryGroupID",
3120                                                       NULL};
3121                 attrs = attrs2;
3122                 break;
3123         }
3124         case 10:
3125         {
3126                 static const char * const attrs2[] = {"homeDirectory",
3127                                                       "homeDrive",
3128                                                       NULL};
3129                 attrs = attrs2;
3130                 break;
3131         }
3132         case 11:
3133         {
3134                 static const char * const attrs2[] = {"scriptPath",
3135                                                       NULL};
3136                 attrs = attrs2;
3137                 break;
3138         }
3139         case 12:
3140         {
3141                 static const char * const attrs2[] = {"profilePath",
3142                                                       NULL};
3143                 attrs = attrs2;
3144                 break;
3145         }
3146         case 13:
3147         {
3148                 static const char * const attrs2[] = {"description",
3149                                                       NULL};
3150                 attrs = attrs2;
3151                 break;
3152         }
3153         case 14:
3154         {
3155                 static const char * const attrs2[] = {"userWorkstations",
3156                                                       NULL};
3157                 attrs = attrs2;
3158                 break;
3159         }
3160         case 16:
3161         {
3162                 static const char * const attrs2[] = {"userAccountControl",
3163                                                       "pwdLastSet",
3164                                                       NULL};
3165                 attrs = attrs2;
3166                 break;
3167         }
3168         case 17:
3169         {
3170                 static const char * const attrs2[] = {"accountExpires",
3171                                                       NULL};
3172                 attrs = attrs2;
3173                 break;
3174         }
3175         case 18:
3176         {
3177                 return NT_STATUS_NOT_SUPPORTED;
3178         }
3179         case 20:
3180         {
3181                 static const char * const attrs2[] = {"userParameters",
3182                                                       NULL};
3183                 attrs = attrs2;
3184                 break;
3185         }
3186         case 21:
3187         {
3188                 static const char * const attrs2[] = {"lastLogon",
3189                                                       "lastLogoff",
3190                                                       "pwdLastSet",
3191                                                       "accountExpires",
3192                                                       "sAMAccountName",
3193                                                       "displayName",
3194                                                       "homeDirectory",
3195                                                       "homeDrive",
3196                                                       "scriptPath",
3197                                                       "profilePath",
3198                                                       "description",
3199                                                       "userWorkstations",
3200                                                       "comment",
3201                                                       "userParameters",
3202                                                       "objectSid",
3203                                                       "primaryGroupID",
3204                                                       "userAccountControl",
3205                                                       "logonHours",
3206                                                       "badPwdCount",
3207                                                       "logonCount",
3208                                                       "countryCode",
3209                                                       "codePage",
3210                                                       NULL};
3211                 attrs = attrs2;
3212                 break;
3213         }
3214         case 23:
3215         case 24:
3216         case 25:
3217         case 26:
3218         {
3219                 return NT_STATUS_NOT_SUPPORTED;
3220         }
3221         default:
3222         {
3223                 return NT_STATUS_INVALID_INFO_CLASS;
3224         }
3225         }
3226
3227         /* pull all the user attributes */
3228         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
3229                               a_state->account_dn ,&res, attrs);
3230         if (ret != 1) {
3231                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3232         }
3233         msg = res[0];
3234
3235         /* allocate the info structure */
3236         info = talloc_zero(mem_ctx, union samr_UserInfo);
3237         if (info == NULL) {
3238                 return NT_STATUS_NO_MEMORY;
3239         }
3240
3241         /* fill in the reply */
3242         switch (r->in.level) {
3243         case 1:
3244                 QUERY_STRING(msg, info1.account_name,          "sAMAccountName");
3245                 QUERY_STRING(msg, info1.full_name,             "displayName");
3246                 QUERY_UINT  (msg, info1.primary_gid,           "primaryGroupID");
3247                 QUERY_STRING(msg, info1.description,           "description");
3248                 QUERY_STRING(msg, info1.comment,               "comment");
3249                 break;
3250
3251         case 2:
3252                 QUERY_STRING(msg, info2.comment,               "comment");
3253                 QUERY_UINT  (msg, info2.country_code,          "countryCode");
3254                 QUERY_UINT  (msg, info2.code_page,             "codePage");
3255                 break;
3256
3257         case 3:
3258                 QUERY_STRING(msg, info3.account_name,          "sAMAccountName");
3259                 QUERY_STRING(msg, info3.full_name,             "displayName");
3260                 QUERY_RID   (msg, info3.rid,                   "objectSid");
3261                 QUERY_UINT  (msg, info3.primary_gid,           "primaryGroupID");
3262                 QUERY_STRING(msg, info3.home_directory,        "homeDirectory");
3263                 QUERY_STRING(msg, info3.home_drive,            "homeDrive");
3264                 QUERY_STRING(msg, info3.logon_script,          "scriptPath");
3265                 QUERY_STRING(msg, info3.profile_path,          "profilePath");
3266                 QUERY_STRING(msg, info3.workstations,          "userWorkstations");
3267                 QUERY_UINT64(msg, info3.last_logon,            "lastLogon");
3268                 QUERY_UINT64(msg, info3.last_logoff,           "lastLogoff");
3269                 QUERY_UINT64(msg, info3.last_password_change,  "pwdLastSet");
3270                 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
3271                 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
3272                 QUERY_LHOURS(msg, info3.logon_hours,           "logonHours");
3273                 QUERY_UINT  (msg, info3.bad_password_count,    "badPwdCount");
3274                 QUERY_UINT  (msg, info3.logon_count,           "logonCount");
3275                 QUERY_AFLAGS(msg, info3.acct_flags,            "userAccountControl");
3276                 break;
3277
3278         case 4:
3279                 QUERY_LHOURS(msg, info4.logon_hours,           "logonHours");
3280                 break;
3281
3282         case 5:
3283                 QUERY_STRING(msg, info5.account_name,          "sAMAccountName");
3284                 QUERY_STRING(msg, info5.full_name,             "displayName");
3285                 QUERY_RID   (msg, info5.rid,                   "objectSid");
3286                 QUERY_UINT  (msg, info5.primary_gid,           "primaryGroupID");
3287                 QUERY_STRING(msg, info5.home_directory,        "homeDirectory");
3288                 QUERY_STRING(msg, info5.home_drive,            "homeDrive");
3289                 QUERY_STRING(msg, info5.logon_script,          "scriptPath");
3290                 QUERY_STRING(msg, info5.profile_path,          "profilePath");
3291                 QUERY_STRING(msg, info5.description,           "description");
3292                 QUERY_STRING(msg, info5.workstations,          "userWorkstations");
3293                 QUERY_UINT64(msg, info5.last_logon,            "lastLogon");
3294                 QUERY_UINT64(msg, info5.last_logoff,           "lastLogoff");
3295                 QUERY_LHOURS(msg, info5.logon_hours,           "logonHours");
3296                 QUERY_UINT  (msg, info5.bad_password_count,    "badPwdCount");
3297                 QUERY_UINT  (msg, info5.logon_count,           "logonCount");
3298                 QUERY_UINT64(msg, info5.last_password_change,  "pwdLastSet");
3299                 QUERY_UINT64(msg, info5.acct_expiry,           "accountExpires");
3300                 QUERY_AFLAGS(msg, info5.acct_flags,            "userAccountControl");
3301                 break;
3302
3303         case 6:
3304                 QUERY_STRING(msg, info6.account_name,   "sAMAccountName");
3305                 QUERY_STRING(msg, info6.full_name,      "displayName");
3306                 break;
3307
3308         case 7:
3309                 QUERY_STRING(msg, info7.account_name,   "sAMAccountName");
3310                 break;
3311
3312         case 8:
3313                 QUERY_STRING(msg, info8.full_name,      "displayName");
3314                 break;
3315
3316         case 9:
3317                 QUERY_UINT  (msg, info9.primary_gid,    "primaryGroupID");
3318                 break;
3319
3320         case 10:
3321                 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3322                 QUERY_STRING(msg, info10.home_drive,    "homeDrive");
3323                 break;
3324
3325         case 11:
3326                 QUERY_STRING(msg, info11.logon_script,  "scriptPath");
3327                 break;
3328
3329         case 12:
3330                 QUERY_STRING(msg, info12.profile_path,  "profilePath");
3331                 break;
3332
3333         case 13:
3334                 QUERY_STRING(msg, info13.description,   "description");
3335                 break;
3336
3337         case 14:
3338                 QUERY_STRING(msg, info14.workstations,  "userWorkstations");
3339                 break;
3340
3341         case 16:
3342                 QUERY_AFLAGS(msg, info16.acct_flags,    "userAccountControl");
3343                 break;
3344
3345         case 17:
3346                 QUERY_UINT64(msg, info17.acct_expiry,   "accountExpires");
3347                 break;
3348
3349         case 20:
3350                 QUERY_PARAMETERS(msg, info20.parameters,    "userParameters");
3351                 break;
3352
3353         case 21:
3354                 QUERY_UINT64(msg, info21.last_logon,           "lastLogon");
3355                 QUERY_UINT64(msg, info21.last_logoff,          "lastLogoff");
3356                 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3357                 QUERY_UINT64(msg, info21.acct_expiry,          "accountExpires");
3358                 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3359                 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3360                 QUERY_STRING(msg, info21.account_name,         "sAMAccountName");
3361                 QUERY_STRING(msg, info21.full_name,            "displayName");
3362                 QUERY_STRING(msg, info21.home_directory,       "homeDirectory");
3363                 QUERY_STRING(msg, info21.home_drive,           "homeDrive");
3364                 QUERY_STRING(msg, info21.logon_script,         "scriptPath");
3365                 QUERY_STRING(msg, info21.profile_path,         "profilePath");
3366                 QUERY_STRING(msg, info21.description,          "description");
3367                 QUERY_STRING(msg, info21.workstations,         "userWorkstations");
3368                 QUERY_STRING(msg, info21.comment,              "comment");
3369                 QUERY_PARAMETERS(msg, info21.parameters,       "userParameters");
3370                 QUERY_RID   (msg, info21.rid,                  "objectSid");
3371                 QUERY_UINT  (msg, info21.primary_gid,          "primaryGroupID");
3372                 QUERY_AFLAGS(msg, info21.acct_flags,           "userAccountControl");
3373                 info->info21.fields_present = 0x00FFFFFF;
3374                 QUERY_LHOURS(msg, info21.logon_hours,          "logonHours");
3375                 QUERY_UINT  (msg, info21.bad_password_count,   "badPwdCount");
3376                 QUERY_UINT  (msg, info21.logon_count,          "logonCount");
3377                 QUERY_UINT  (msg, info21.country_code,         "countryCode");
3378                 QUERY_UINT  (msg, info21.code_page,            "codePage");
3379                 break;
3380                 
3381
3382         default:
3383                 talloc_free(info);
3384                 return NT_STATUS_INVALID_INFO_CLASS;
3385         }
3386
3387         *r->out.info = info;
3388
3389         return NT_STATUS_OK;
3390 }
3391
3392
3393 /* 
3394   samr_SetUserInfo 
3395 */
3396 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3397                                  struct samr_SetUserInfo *r)
3398 {
3399         struct dcesrv_handle *h;
3400         struct samr_account_state *a_state;
3401         struct ldb_message *msg;
3402         int ret;
3403         NTSTATUS status = NT_STATUS_OK;
3404         struct ldb_context *sam_ctx;
3405
3406         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3407
3408         a_state = h->data;
3409         sam_ctx = a_state->sam_ctx;
3410
3411         msg = ldb_msg_new(mem_ctx);
3412         if (msg == NULL) {
3413                 return NT_STATUS_NO_MEMORY;
3414         }
3415
3416         msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3417         if (!msg->dn) {
3418                 return NT_STATUS_NO_MEMORY;
3419         }
3420
3421         switch (r->in.level) {
3422         case 2:
3423                 SET_STRING(msg, info2.comment,          "comment");
3424                 SET_UINT  (msg, info2.country_code,     "countryCode");
3425                 SET_UINT  (msg, info2.code_page,        "codePage");
3426                 break;
3427
3428         case 4:
3429                 SET_LHOURS(msg, info4.logon_hours,      "logonHours");
3430                 break;
3431
3432         case 6:
3433                 SET_STRING(msg, info6.account_name,     "samAccountName");
3434                 SET_STRING(msg, info6.full_name,        "displayName");
3435                 break;
3436
3437         case 7:
3438                 SET_STRING(msg, info7.account_name,     "samAccountName");
3439                 break;
3440
3441         case 8:
3442                 SET_STRING(msg, info8.full_name,        "displayName");
3443                 break;
3444
3445         case 9:
3446                 SET_UINT(msg, info9.primary_gid,        "primaryGroupID");
3447                 break;
3448
3449         case 10:
3450                 SET_STRING(msg, info10.home_directory,  "homeDirectory");
3451                 SET_STRING(msg, info10.home_drive,      "homeDrive");
3452                 break;
3453
3454         case 11:
3455                 SET_STRING(msg, info11.logon_script,    "scriptPath");
3456                 break;
3457
3458         case 12:
3459                 SET_STRING(msg, info12.profile_path,    "profilePath");
3460                 break;
3461
3462         case 13:
3463                 SET_STRING(msg, info13.description,     "description");
3464                 break;
3465
3466         case 14:
3467                 SET_STRING(msg, info14.workstations,    "userWorkstations");
3468                 break;
3469
3470         case 16:
3471                 SET_AFLAGS(msg, info16.acct_flags,      "userAccountControl");
3472                 break;
3473
3474         case 17:
3475                 SET_UINT64(msg, info17.acct_expiry,     "accountExpires");
3476                 break;
3477
3478         case 20:
3479                 SET_PARAMETERS(msg, info20.parameters,      "userParameters");
3480                 break;
3481
3482         case 21:
3483 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3484                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3485                         SET_UINT64(msg, info21.acct_expiry,    "accountExpires");
3486                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
3487                         SET_STRING(msg, info21.account_name,   "samAccountName");
3488                 IFSET(SAMR_FIELD_FULL_NAME) 
3489                         SET_STRING(msg, info21.full_name,      "displayName");
3490                 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3491                         SET_STRING(msg, info21.home_directory, "homeDirectory");
3492                 IFSET(SAMR_FIELD_HOME_DRIVE)
3493                         SET_STRING(msg, info21.home_drive,     "homeDrive");
3494                 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3495                         SET_STRING(msg, info21.logon_script,   "scriptPath");
3496                 IFSET(SAMR_FIELD_PROFILE_PATH)
3497                         SET_STRING(msg, info21.profile_path,   "profilePath");
3498                 IFSET(SAMR_FIELD_DESCRIPTION)
3499                         SET_STRING(msg, info21.description,    "description");
3500                 IFSET(SAMR_FIELD_WORKSTATIONS)
3501                         SET_STRING(msg, info21.workstations,   "userWorkstations");
3502                 IFSET(SAMR_FIELD_COMMENT)
3503                         SET_STRING(msg, info21.comment,        "comment");
3504                 IFSET(SAMR_FIELD_PARAMETERS)   
3505                         SET_PARAMETERS(msg, info21.parameters, "userParameters");
3506                 IFSET(SAMR_FIELD_PRIMARY_GID)
3507                         SET_UINT(msg, info21.primary_gid,      "primaryGroupID");
3508                 IFSET(SAMR_FIELD_ACCT_FLAGS)
3509                         SET_AFLAGS(msg, info21.acct_flags,     "userAccountControl");
3510                 IFSET(SAMR_FIELD_LOGON_HOURS)
3511                         SET_LHOURS(msg, info21.logon_hours,    "logonHours");
3512                 IFSET(SAMR_FIELD_COUNTRY_CODE)
3513                         SET_UINT  (msg, info21.country_code,   "countryCode");
3514                 IFSET(SAMR_FIELD_CODE_PAGE)
3515                         SET_UINT  (msg, info21.code_page,      "codePage");
3516 #undef IFSET
3517                 break;
3518
3519         case 23:
3520 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3521                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3522                         SET_UINT64(msg, info23.info.acct_expiry,    "accountExpires");
3523                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
3524                         SET_STRING(msg, info23.info.account_name,   "samAccountName");
3525                 IFSET(SAMR_FIELD_FULL_NAME)
3526                         SET_STRING(msg, info23.info.full_name,      "displayName");
3527                 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3528                         SET_STRING(msg, info23.info.home_directory, "homeDirectory");
3529                 IFSET(SAMR_FIELD_HOME_DRIVE)
3530                         SET_STRING(msg, info23.info.home_drive,     "homeDrive");
3531                 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3532                         SET_STRING(msg, info23.info.logon_script,   "scriptPath");
3533                 IFSET(SAMR_FIELD_PROFILE_PATH)
3534                         SET_STRING(msg, info23.info.profile_path,   "profilePath");
3535                 IFSET(SAMR_FIELD_DESCRIPTION)
3536                         SET_STRING(msg, info23.info.description,    "description");
3537                 IFSET(SAMR_FIELD_WORKSTATIONS)
3538                         SET_STRING(msg, info23.info.workstations,   "userWorkstations");
3539                 IFSET(SAMR_FIELD_COMMENT)
3540                         SET_STRING(msg, info23.info.comment,        "comment");
3541                 IFSET(SAMR_FIELD_PARAMETERS)
3542                         SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3543                 IFSET(SAMR_FIELD_PRIMARY_GID)
3544                         SET_UINT(msg, info23.info.primary_gid,      "primaryGroupID");
3545                 IFSET(SAMR_FIELD_ACCT_FLAGS)
3546                         SET_AFLAGS(msg, info23.info.acct_flags,     "userAccountControl");
3547                 IFSET(SAMR_FIELD_LOGON_HOURS)
3548                         SET_LHOURS(msg, info23.info.logon_hours,    "logonHours");
3549                 IFSET(SAMR_FIELD_COUNTRY_CODE)
3550                         SET_UINT  (msg, info23.info.country_code,   "countryCode");
3551                 IFSET(SAMR_FIELD_CODE_PAGE)
3552                         SET_UINT  (msg, info23.info.code_page,      "codePage");
3553
3554                 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3555                         status = samr_set_password(dce_call,
3556                                                    a_state->sam_ctx,
3557                                                    a_state->account_dn,
3558                                                    a_state->domain_state->domain_dn,
3559                                                    mem_ctx, msg, 
3560                                                    &r->in.info->info23.password);
3561                 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3562                         status = samr_set_password(dce_call,
3563                                                    a_state->sam_ctx,
3564                                                    a_state->account_dn,
3565                                                    a_state->domain_state->domain_dn,
3566                                                    mem_ctx, msg, 
3567                                                    &r->in.info->info23.password);
3568                 }
3569 #undef IFSET
3570                 break;
3571
3572                 /* the set password levels are handled separately */
3573         case 24:
3574                 status = samr_set_password(dce_call,
3575                                            a_state->sam_ctx,
3576                                            a_state->account_dn,
3577                                            a_state->domain_state->domain_dn,
3578                                            mem_ctx, msg, 
3579                                            &r->in.info->info24.password);
3580                 break;
3581
3582         case 25:
3583 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3584                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3585                         SET_UINT64(msg, info25.info.acct_expiry,    "accountExpires");
3586                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
3587                         SET_STRING(msg, info25.info.account_name,   "samAccountName");
3588                 IFSET(SAMR_FIELD_FULL_NAME)
3589                         SET_STRING(msg, info25.info.full_name,      "displayName");
3590                 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3591                         SET_STRING(msg, info25.info.home_directory, "homeDirectory");
3592                 IFSET(SAMR_FIELD_HOME_DRIVE)
3593                         SET_STRING(msg, info25.info.home_drive,     "homeDrive");
3594                 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3595                         SET_STRING(msg, info25.info.logon_script,   "scriptPath");
3596                 IFSET(SAMR_FIELD_PROFILE_PATH)
3597                         SET_STRING(msg, info25.info.profile_path,   "profilePath");
3598                 IFSET(SAMR_FIELD_DESCRIPTION)
3599                         SET_STRING(msg, info25.info.description,    "description");
3600                 IFSET(SAMR_FIELD_WORKSTATIONS)
3601                         SET_STRING(msg, info25.info.workstations,   "userWorkstations");
3602                 IFSET(SAMR_FIELD_COMMENT)
3603                         SET_STRING(msg, info25.info.comment,        "comment");
3604                 IFSET(SAMR_FIELD_PARAMETERS)
3605                         SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
3606                 IFSET(SAMR_FIELD_PRIMARY_GID)
3607                         SET_UINT(msg, info25.info.primary_gid,      "primaryGroupID");
3608                 IFSET(SAMR_FIELD_ACCT_FLAGS)
3609                         SET_AFLAGS(msg, info25.info.acct_flags,     "userAccountControl");
3610                 IFSET(SAMR_FIELD_LOGON_HOURS)
3611                         SET_LHOURS(msg, info25.info.logon_hours,    "logonHours");
3612                 IFSET(SAMR_FIELD_COUNTRY_CODE)
3613                         SET_UINT  (msg, info25.info.country_code,   "countryCode");
3614                 IFSET(SAMR_FIELD_CODE_PAGE)
3615                         SET_UINT  (msg, info25.info.code_page,      "codePage");
3616
3617                 IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3618                         status = samr_set_password_ex(dce_call,
3619                                                       a_state->sam_ctx,
3620                                                       a_state->account_dn,
3621                                                       a_state->domain_state->domain_dn,
3622                                                       mem_ctx, msg, 
3623                                                       &r->in.info->info25.password);
3624                 } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3625                         status = samr_set_password_ex(dce_call,
3626                                                       a_state->sam_ctx,
3627                                                       a_state->account_dn,
3628                                                       a_state->domain_state->domain_dn,
3629                                                       mem_ctx, msg, 
3630                                                       &r->in.info->info25.password);
3631                 }
3632 #undef IFSET
3633                 break;
3634
3635                 /* the set password levels are handled separately */
3636         case 26:
3637                 status = samr_set_password_ex(dce_call,
3638                                               a_state->sam_ctx,
3639                                               a_state->account_dn,
3640                                               a_state->domain_state->domain_dn,
3641                                               mem_ctx, msg, 
3642                                               &r->in.info->info26.password);
3643                 break;
3644                 
3645
3646         default:
3647                 /* many info classes are not valid for SetUserInfo */
3648                 return NT_STATUS_INVALID_INFO_CLASS;
3649         }
3650
3651         if (!NT_STATUS_IS_OK(status)) {
3652                 return status;
3653         }
3654
3655         /* modify the samdb record */
3656         if (msg->num_elements > 0) {
3657                 ret = ldb_modify(a_state->sam_ctx, msg);
3658                 if (ret != LDB_SUCCESS) {
3659                         DEBUG(1,("Failed to modify record %s: %s\n",
3660                                  ldb_dn_get_linearized(a_state->account_dn),
3661                                  ldb_errstring(a_state->sam_ctx)));
3662
3663                         /* we really need samdb.c to return NTSTATUS */
3664                         return NT_STATUS_UNSUCCESSFUL;
3665                 }
3666         }
3667
3668         return NT_STATUS_OK;
3669 }
3670
3671
3672 /* 
3673   samr_GetGroupsForUser 
3674 */
3675 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3676                        struct samr_GetGroupsForUser *r)
3677 {
3678         struct dcesrv_handle *h;
3679         struct samr_account_state *a_state;
3680         struct samr_domain_state *d_state;
3681         struct ldb_message **res;
3682         const char * const attrs[2] = { "objectSid", NULL };
3683         struct samr_RidWithAttributeArray *array;
3684         int i, count;
3685
3686         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3687
3688         a_state = h->data;
3689         d_state = a_state->domain_state;
3690
3691         count = samdb_search_domain(a_state->sam_ctx, mem_ctx,
3692                                     d_state->domain_dn, &res,
3693                                     attrs, d_state->domain_sid,
3694                                     "(&(member=%s)(grouptype=%d)(objectclass=group))",
3695                                     ldb_dn_get_linearized(a_state->account_dn),
3696                                     GTYPE_SECURITY_GLOBAL_GROUP);
3697         if (count < 0)
3698                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3699
3700         array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3701         if (array == NULL)
3702                 return NT_STATUS_NO_MEMORY;
3703
3704         array->count = 0;
3705         array->rids = NULL;
3706
3707         array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3708                                             count + 1);
3709         if (array->rids == NULL)
3710                 return NT_STATUS_NO_MEMORY;
3711
3712         /* Adds the primary group */
3713         array->rids[0].rid = samdb_search_uint(a_state->sam_ctx, mem_ctx,
3714                                                ~0, a_state->account_dn,
3715                                                "primaryGroupID", NULL);
3716         array->rids[0].attributes = SE_GROUP_MANDATORY
3717                         | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3718         array->count += 1;
3719
3720         /* Adds the additional groups */
3721         for (i = 0; i < count; i++) {
3722                 struct dom_sid *group_sid;
3723
3724                 group_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
3725                 if (group_sid == NULL) {
3726                         DEBUG(0, ("Couldn't find objectSid attrib\n"));
3727                         continue;
3728                 }
3729
3730                 array->rids[i + 1].rid =
3731                         group_sid->sub_auths[group_sid->num_auths-1];
3732                 array->rids[i + 1].attributes = SE_GROUP_MANDATORY
3733                         | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3734                 array->count += 1;
3735         }
3736
3737         *r->out.rids = array;
3738
3739         return NT_STATUS_OK;
3740 }
3741
3742
3743 /* 
3744   samr_QueryDisplayInfo 
3745 */
3746 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3747                        struct samr_QueryDisplayInfo *r)
3748 {
3749         struct dcesrv_handle *h;
3750         struct samr_domain_state *d_state;
3751         struct ldb_message **res;
3752         int ldb_cnt, count, i;
3753         const char * const attrs[] = { "objectSid", "sAMAccountName",
3754                 "displayName", "description", "userAccountControl",
3755                 "pwdLastSet", NULL };
3756         struct samr_DispEntryFull *entriesFull = NULL;
3757         struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3758         struct samr_DispEntryAscii *entriesAscii = NULL;
3759         struct samr_DispEntryGeneral *entriesGeneral = NULL;
3760         const char *filter;
3761
3762         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3763
3764         d_state = h->data;
3765
3766         switch (r->in.level) {
3767         case 1:
3768         case 4:
3769                 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3770                                          "(sAMAccountType=%u))",
3771                                          ATYPE_NORMAL_ACCOUNT);
3772                 break;
3773         case 2:
3774                 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3775                                          "(sAMAccountType=%u))",
3776                                          ATYPE_WORKSTATION_TRUST);
3777                 break;
3778         case 3:
3779         case 5:
3780                 filter = talloc_asprintf(mem_ctx,
3781                                          "(&(|(groupType=%d)(groupType=%d))"
3782                                          "(objectClass=group))",
3783                                          GTYPE_SECURITY_UNIVERSAL_GROUP,
3784                                          GTYPE_SECURITY_GLOBAL_GROUP);
3785                 break;
3786         default:
3787                 return NT_STATUS_INVALID_INFO_CLASS;
3788         }
3789
3790         /* search for all requested objects in this domain. This could
3791            possibly be cached and resumed based on resume_key */
3792         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3793                                       d_state->domain_dn, &res, attrs,
3794                                       d_state->domain_sid, "%s", filter);
3795         if (ldb_cnt == -1) {
3796                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3797         }
3798         if (ldb_cnt == 0 || r->in.max_entries == 0) {
3799                 return NT_STATUS_OK;
3800         }
3801
3802         switch (r->in.level) {
3803         case 1:
3804                 entriesGeneral = talloc_array(mem_ctx,
3805                                              struct samr_DispEntryGeneral,
3806                                              ldb_cnt);
3807                 break;
3808         case 2:
3809                 entriesFull = talloc_array(mem_ctx,
3810                                              struct samr_DispEntryFull,
3811                                              ldb_cnt);
3812                 break;
3813         case 3:
3814                 entriesFullGroup = talloc_array(mem_ctx,
3815                                              struct samr_DispEntryFullGroup,
3816                                              ldb_cnt);
3817                 break;
3818         case 4:
3819         case 5:
3820                 entriesAscii = talloc_array(mem_ctx,
3821                                               struct samr_DispEntryAscii,
3822                                               ldb_cnt);
3823                 break;
3824         }
3825
3826         if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3827             (entriesAscii == NULL) && (entriesFullGroup == NULL))
3828                 return NT_STATUS_NO_MEMORY;
3829
3830         count = 0;
3831
3832         for (i=0; i<ldb_cnt; i++) {
3833                 struct dom_sid *objectsid;
3834
3835                 objectsid = samdb_result_dom_sid(mem_ctx, res[i],
3836                                                  "objectSid");
3837                 if (objectsid == NULL)
3838                         continue;
3839
3840                 switch(r->in.level) {
3841                 case 1:
3842                         entriesGeneral[count].idx = count + 1;
3843                         entriesGeneral[count].rid = 
3844                                 objectsid->sub_auths[objectsid->num_auths-1];
3845                         entriesGeneral[count].acct_flags =
3846                                 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3847                                                         res[i], 
3848                                                         d_state->domain_dn);
3849                         entriesGeneral[count].account_name.string =
3850                                 samdb_result_string(res[i],
3851                                                     "sAMAccountName", "");
3852                         entriesGeneral[count].full_name.string =
3853                                 samdb_result_string(res[i], "displayName", "");
3854                         entriesGeneral[count].description.string =
3855                                 samdb_result_string(res[i], "description", "");
3856                         break;
3857                 case 2:
3858                         entriesFull[count].idx = count + 1;
3859                         entriesFull[count].rid =
3860                                 objectsid->sub_auths[objectsid->num_auths-1];
3861
3862                         /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3863                         entriesFull[count].acct_flags =
3864                                 samdb_result_acct_flags(d_state->sam_ctx, mem_ctx,
3865                                                         res[i], 
3866                                                         d_state->domain_dn) | ACB_NORMAL;
3867                         entriesFull[count].account_name.string =
3868                                 samdb_result_string(res[i], "sAMAccountName",
3869                                                     "");
3870                         entriesFull[count].description.string =
3871                                 samdb_result_string(res[i], "description", "");
3872                         break;
3873                 case 3:
3874                         entriesFullGroup[count].idx = count + 1;
3875                         entriesFullGroup[count].rid =
3876                                 objectsid->sub_auths[objectsid->num_auths-1];
3877                         /* We get a "7" here for groups */
3878                         entriesFullGroup[count].acct_flags
3879                                 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3880                         entriesFullGroup[count].account_name.string =
3881                                 samdb_result_string(res[i], "sAMAccountName",
3882                                                     "");
3883                         entriesFullGroup[count].description.string =
3884                                 samdb_result_string(res[i], "description", "");
3885                         break;
3886                 case 4:
3887                 case 5:
3888                         entriesAscii[count].idx = count + 1;
3889                         entriesAscii[count].account_name.string =
3890                                 samdb_result_string(res[i], "sAMAccountName",
3891                                                     "");
3892                         break;
3893                 }
3894
3895                 count += 1;
3896         }
3897
3898         *r->out.total_size = count;
3899
3900         if (r->in.start_idx >= count) {
3901                 *r->out.returned_size = 0;
3902                 switch(r->in.level) {
3903                 case 1:
3904                         r->out.info->info1.count = *r->out.returned_size;
3905                         r->out.info->info1.entries = NULL;
3906                         break;
3907                 case 2:
3908                         r->out.info->info2.count = *r->out.returned_size;
3909                         r->out.info->info2.entries = NULL;
3910                         break;
3911                 case 3:
3912                         r->out.info->info3.count = *r->out.returned_size;
3913                         r->out.info->info3.entries = NULL;
3914                         break;
3915                 case 4:
3916                         r->out.info->info4.count = *r->out.returned_size;
3917                         r->out.info->info4.entries = NULL;
3918                         break;
3919                 case 5:
3920                         r->out.info->info5.count = *r->out.returned_size;
3921                         r->out.info->info5.entries = NULL;
3922                         break;
3923                 }
3924         } else {
3925                 *r->out.returned_size = MIN(count - r->in.start_idx,
3926                                            r->in.max_entries);
3927                 switch(r->in.level) {
3928                 case 1:
3929                         r->out.info->info1.count = *r->out.returned_size;
3930                         r->out.info->info1.entries =
3931                                 &(entriesGeneral[r->in.start_idx]);
3932                         break;
3933                 case 2:
3934                         r->out.info->info2.count = *r->out.returned_size;
3935                         r->out.info->info2.entries =
3936                                 &(entriesFull[r->in.start_idx]);
3937                         break;
3938                 case 3:
3939                         r->out.info->info3.count = *r->out.returned_size;
3940                         r->out.info->info3.entries =
3941                                 &(entriesFullGroup[r->in.start_idx]);
3942                         break;
3943                 case 4:
3944                         r->out.info->info4.count = *r->out.returned_size;
3945                         r->out.info->info4.entries =
3946                                 &(entriesAscii[r->in.start_idx]);
3947                         break;
3948                 case 5:
3949                         r->out.info->info5.count = *r->out.returned_size;
3950                         r->out.info->info5.entries =
3951                                 &(entriesAscii[r->in.start_idx]);
3952                         break;
3953                 }
3954         }
3955
3956         return (*r->out.returned_size < (count - r->in.start_idx)) ?
3957                 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3958 }
3959
3960
3961 /* 
3962   samr_GetDisplayEnumerationIndex 
3963 */
3964 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3965                        struct samr_GetDisplayEnumerationIndex *r)
3966 {
3967         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3968 }
3969
3970
3971 /* 
3972   samr_TestPrivateFunctionsDomain 
3973 */
3974 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3975                        struct samr_TestPrivateFunctionsDomain *r)
3976 {
3977         return NT_STATUS_NOT_IMPLEMENTED;
3978 }
3979
3980
3981 /* 
3982   samr_TestPrivateFunctionsUser 
3983 */
3984 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3985                        struct samr_TestPrivateFunctionsUser *r)
3986 {
3987         return NT_STATUS_NOT_IMPLEMENTED;
3988 }
3989
3990
3991 /* 
3992   samr_GetUserPwInfo 
3993 */
3994 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3995                                    struct samr_GetUserPwInfo *r)
3996 {
3997         struct dcesrv_handle *h;
3998         struct samr_account_state *a_state;
3999
4000         ZERO_STRUCTP(r->out.info);
4001
4002         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
4003
4004         a_state = h->data;
4005
4006         r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx,
4007                 mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength",
4008                 NULL);
4009         r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx,
4010                 mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL);
4011
4012         return NT_STATUS_OK;
4013 }
4014
4015
4016 /* 
4017   samr_RemoveMemberFromForeignDomain 
4018 */
4019 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4020                        struct samr_RemoveMemberFromForeignDomain *r)
4021 {
4022         struct dcesrv_handle *h;
4023         struct samr_domain_state *d_state;
4024         const char *memberdn;
4025         struct ldb_message **res;
4026         const char * const attrs[3] = { "distinguishedName", "objectSid", NULL };
4027         int i, count;
4028
4029         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4030
4031         d_state = h->data;
4032
4033         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
4034                                        "distinguishedName", "(objectSid=%s)", 
4035                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
4036         /* Nothing to do */
4037         if (memberdn == NULL) {
4038                 return NT_STATUS_OK;
4039         }
4040
4041         /* TODO: Does this call only remove alias members, or does it do this
4042          * for domain groups as well? */
4043
4044         count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
4045                                     d_state->domain_dn, &res, attrs,
4046                                     d_state->domain_sid,
4047                                     "(&(member=%s)(objectClass=group)"
4048                                     "(|(groupType=%d)(groupType=%d)))",
4049                                     memberdn,
4050                                     GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
4051                                     GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
4052
4053         if (count < 0)
4054                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4055
4056         for (i=0; i<count; i++) {
4057                 struct ldb_message *mod;
4058
4059                 mod = ldb_msg_new(mem_ctx);
4060                 if (mod == NULL) {
4061                         return NT_STATUS_NO_MEMORY;
4062                 }
4063
4064                 mod->dn = samdb_result_dn(d_state->sam_ctx, mod, res[i], "distinguishedName", NULL);
4065                 if (mod->dn == NULL) {
4066                         talloc_free(mod);
4067                         continue;
4068                 }
4069
4070                 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
4071                                          "member", memberdn) != LDB_SUCCESS)
4072                         return NT_STATUS_NO_MEMORY;
4073
4074                 if (ldb_modify(d_state->sam_ctx, mod) != LDB_SUCCESS)
4075                         return NT_STATUS_UNSUCCESSFUL;
4076
4077                 talloc_free(mod);
4078         }
4079
4080         return NT_STATUS_OK;
4081 }
4082
4083
4084 /* 
4085   samr_QueryDomainInfo2 
4086
4087   just an alias for samr_QueryDomainInfo
4088 */
4089 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4090                        struct samr_QueryDomainInfo2 *r)
4091 {
4092         struct samr_QueryDomainInfo r1;
4093         NTSTATUS status;
4094
4095         ZERO_STRUCT(r1.out);
4096         r1.in.domain_handle = r->in.domain_handle;
4097         r1.in.level  = r->in.level;
4098         r1.out.info  = r->out.info;
4099
4100         status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
4101         
4102         return status;
4103 }
4104
4105
4106 /* 
4107   samr_QueryUserInfo2 
4108
4109   just an alias for samr_QueryUserInfo
4110 */
4111 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4112                                     struct samr_QueryUserInfo2 *r)
4113 {
4114         struct samr_QueryUserInfo r1;
4115         NTSTATUS status;
4116
4117         r1.in.user_handle = r->in.user_handle;
4118         r1.in.level  = r->in.level;
4119         r1.out.info  = r->out.info;
4120         
4121         status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
4122
4123         return status;
4124 }
4125
4126
4127 /* 
4128   samr_QueryDisplayInfo2 
4129 */
4130 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4131                                        struct samr_QueryDisplayInfo2 *r)
4132 {
4133         struct samr_QueryDisplayInfo q;
4134         NTSTATUS result;
4135
4136         q.in.domain_handle = r->in.domain_handle;
4137         q.in.level = r->in.level;
4138         q.in.start_idx = r->in.start_idx;
4139         q.in.max_entries = r->in.max_entries;
4140         q.in.buf_size = r->in.buf_size;
4141         q.out.total_size = r->out.total_size;
4142         q.out.returned_size = r->out.returned_size;
4143         q.out.info = r->out.info;
4144
4145         result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4146
4147         return result;
4148 }
4149
4150
4151 /* 
4152   samr_GetDisplayEnumerationIndex2 
4153 */
4154 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4155                        struct samr_GetDisplayEnumerationIndex2 *r)
4156 {
4157         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4158 }
4159
4160
4161 /* 
4162   samr_QueryDisplayInfo3 
4163 */
4164 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4165                        struct samr_QueryDisplayInfo3 *r)
4166 {
4167         struct samr_QueryDisplayInfo q;
4168         NTSTATUS result;
4169
4170         q.in.domain_handle = r->in.domain_handle;
4171         q.in.level = r->in.level;
4172         q.in.start_idx = r->in.start_idx;
4173         q.in.max_entries = r->in.max_entries;
4174         q.in.buf_size = r->in.buf_size;
4175         q.out.total_size = r->out.total_size;
4176         q.out.returned_size = r->out.returned_size;
4177         q.out.info = r->out.info;
4178
4179         result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4180
4181         return result;
4182 }
4183
4184
4185 /* 
4186   samr_AddMultipleMembersToAlias 
4187 */
4188 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4189                        struct samr_AddMultipleMembersToAlias *r)
4190 {
4191         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4192 }
4193
4194
4195 /* 
4196   samr_RemoveMultipleMembersFromAlias 
4197 */
4198 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4199                        struct samr_RemoveMultipleMembersFromAlias *r)
4200 {
4201         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4202 }
4203
4204
4205 /* 
4206   samr_GetDomPwInfo 
4207
4208   this fetches the default password properties for a domain
4209
4210   note that w2k3 completely ignores the domain name in this call, and 
4211   always returns the information for the servers primary domain
4212 */
4213 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4214                                   struct samr_GetDomPwInfo *r)
4215 {
4216         struct ldb_message **msgs;
4217         int ret;
4218         const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4219         struct ldb_context *sam_ctx;
4220
4221         ZERO_STRUCTP(r->out.info);
4222
4223         sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
4224                                          dce_call->conn->dce_ctx->lp_ctx,
4225                                          dce_call->conn->auth_state.session_info);
4226         if (sam_ctx == NULL) {
4227                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4228         }
4229
4230         /* The domain name in this call is ignored */
4231         ret = gendb_search_dn(sam_ctx, 
4232                            mem_ctx, NULL, &msgs, attrs);
4233         if (ret <= 0) {
4234                 talloc_free(sam_ctx);
4235
4236                 return NT_STATUS_NO_SUCH_DOMAIN;
4237         }
4238         if (ret > 1) {
4239                 talloc_free(msgs);
4240                 talloc_free(sam_ctx);
4241
4242                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4243         }
4244
4245         r->out.info->min_password_length = samdb_result_uint(msgs[0],
4246                 "minPwdLength", 0);
4247         r->out.info->password_properties = samdb_result_uint(msgs[0],
4248                 "pwdProperties", 1);
4249
4250         talloc_free(msgs);
4251         talloc_unlink(mem_ctx, sam_ctx);
4252
4253         return NT_STATUS_OK;
4254 }
4255
4256
4257 /* 
4258   samr_Connect2 
4259 */
4260 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4261                               struct samr_Connect2 *r)
4262 {
4263         struct samr_Connect c;
4264
4265         c.in.system_name = NULL;
4266         c.in.access_mask = r->in.access_mask;
4267         c.out.connect_handle = r->out.connect_handle;
4268
4269         return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4270 }
4271
4272
4273 /* 
4274   samr_SetUserInfo2 
4275
4276   just an alias for samr_SetUserInfo
4277 */
4278 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4279                                   struct samr_SetUserInfo2 *r)
4280 {
4281         struct samr_SetUserInfo r2;
4282
4283         r2.in.user_handle = r->in.user_handle;
4284         r2.in.level = r->in.level;
4285         r2.in.info = r->in.info;
4286
4287         return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
4288 }
4289
4290
4291 /* 
4292   samr_SetBootKeyInformation 
4293 */
4294 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4295                        struct samr_SetBootKeyInformation *r)
4296 {
4297         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4298 }
4299
4300
4301 /* 
4302   samr_GetBootKeyInformation 
4303 */
4304 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4305                        struct samr_GetBootKeyInformation *r)
4306 {
4307         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4308 }
4309
4310
4311 /* 
4312   samr_Connect3 
4313 */
4314 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4315                        struct samr_Connect3 *r)
4316 {
4317         struct samr_Connect c;
4318
4319         c.in.system_name = NULL;
4320         c.in.access_mask = r->in.access_mask;
4321         c.out.connect_handle = r->out.connect_handle;
4322
4323         return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4324 }
4325
4326
4327 /* 
4328   samr_Connect4 
4329 */
4330 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4331                        struct samr_Connect4 *r)
4332 {
4333         struct samr_Connect c;
4334
4335         c.in.system_name = NULL;
4336         c.in.access_mask = r->in.access_mask;
4337         c.out.connect_handle = r->out.connect_handle;
4338
4339         return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4340 }
4341
4342
4343 /* 
4344   samr_Connect5 
4345 */
4346 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4347                               struct samr_Connect5 *r)
4348 {
4349         struct samr_Connect c;
4350         NTSTATUS status;
4351
4352         c.in.system_name = NULL;
4353         c.in.access_mask = r->in.access_mask;
4354         c.out.connect_handle = r->out.connect_handle;
4355
4356         status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4357
4358         r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
4359         r->out.info_out->info1.unknown2 = 0;
4360         *r->out.level_out = r->in.level_in;
4361
4362         return status;
4363 }
4364
4365
4366 /* 
4367   samr_RidToSid 
4368 */
4369 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4370                               struct samr_RidToSid *r)
4371 {
4372         struct samr_domain_state *d_state;
4373         struct dcesrv_handle *h;
4374
4375         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4376
4377         d_state = h->data;
4378
4379         /* form the users SID */
4380         *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4381         if (!*r->out.sid) {
4382                 return NT_STATUS_NO_MEMORY;
4383         }
4384
4385         return NT_STATUS_OK;
4386 }
4387
4388
4389 /* 
4390   samr_SetDsrmPassword 
4391 */
4392 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4393                        struct samr_SetDsrmPassword *r)
4394 {
4395         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4396 }
4397
4398
4399 /* 
4400   samr_ValidatePassword
4401
4402   For now the call checks the password complexity (if active) and the minimum
4403   password length on level 2 and 3. Level 1 is ignored for now.
4404 */
4405 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
4406                                              TALLOC_CTX *mem_ctx,
4407                                              struct samr_ValidatePassword *r)
4408 {
4409         struct samr_GetDomPwInfo r2;
4410         struct samr_PwInfo pwInfo;
4411         DATA_BLOB password;
4412         enum samr_ValidationStatus res;
4413         NTSTATUS status;
4414
4415         (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
4416
4417         r2.in.domain_name = NULL;
4418         r2.out.info = &pwInfo;
4419         status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2);
4420         if (!NT_STATUS_IS_OK(status)) {
4421                 return status;
4422         }
4423
4424         switch (r->in.level) {
4425         case NetValidateAuthentication:
4426                 /* we don't support this yet */
4427                 return NT_STATUS_NOT_SUPPORTED;
4428         break;
4429         case NetValidatePasswordChange:
4430                 password = data_blob_const(r->in.req->req2.password.string,
4431                                            r->in.req->req2.password.length);
4432                 res = samdb_check_password(&password,
4433                                            pwInfo.password_properties,
4434                                            pwInfo.min_password_length);
4435                 (*r->out.rep)->ctr2.status = res;
4436         break;
4437         case NetValidatePasswordReset:
4438                 password = data_blob_const(r->in.req->req3.password.string,
4439                                            r->in.req->req3.password.length);
4440                 res = samdb_check_password(&password,
4441                                            pwInfo.password_properties,
4442                                            pwInfo.min_password_length);
4443                 (*r->out.rep)->ctr3.status = res;
4444         break;
4445         default:
4446                 return NT_STATUS_INVALID_INFO_CLASS;
4447         break;
4448         }
4449
4450         return NT_STATUS_OK;
4451 }
4452
4453
4454 /* include the generated boilerplate */
4455 #include "librpc/gen_ndr/ndr_samr_s.c"