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