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