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