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