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