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