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