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