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