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