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