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