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