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