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