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