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