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