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