fc2d623160dea81879a3e37ff6b10c7b515ab34f
[kai/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]Info a bit easier to read */
41
42 #define QUERY_STRING(msg, field, attr) \
43         r->out.info->field.string = samdb_result_string(msg, attr, "");
44 #define QUERY_UINT(msg, field, attr) \
45         r->out.info->field = samdb_result_uint(msg, attr, 0);
46 #define QUERY_RID(msg, field, attr) \
47         r->out.info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
48 #define QUERY_UINT64(msg, field, attr) \
49         r->out.info->field = samdb_result_uint64(msg, attr, 0);
50 #define QUERY_APASSC(msg, field, attr) \
51         r->out.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         r->out.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         r->out.info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
58 #define QUERY_AFLAGS(msg, field, attr) \
59         r->out.info->field = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, a_state->domain_state->domain_dn);
60
61
62 /* these are used to make the Set[User|Group]Info code easier to follow */
63
64 #define SET_STRING(msg, field, attr) do {                               \
65         struct ldb_message_element *set_el;                             \
66         if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
67         if (r->in.info->field.string[0] == '\0') {                      \
68                 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL)) { \
69                         return NT_STATUS_NO_MEMORY;                     \
70                 }                                                       \
71         }                                                               \
72         if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != 0) { \
73                 return NT_STATUS_NO_MEMORY;                             \
74         }                                                               \
75         set_el = ldb_msg_find_element(msg, attr);                       \
76         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
77 } while (0)
78
79 #define SET_UINT(msg, field, attr) do {                                 \
80         struct ldb_message_element *set_el;                             \
81         if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
82                 return NT_STATUS_NO_MEMORY;                             \
83         }                                                               \
84         set_el = ldb_msg_find_element(msg, attr);                       \
85         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
86 } while (0)                                                             
87                                                                         
88 #define SET_INT64(msg, field, attr) do {                                \
89         struct ldb_message_element *set_el;                             \
90         if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
91                 return NT_STATUS_NO_MEMORY;                             \
92         }                                                               \
93         set_el = ldb_msg_find_element(msg, attr);                       \
94         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
95 } while (0)                                                             
96                                                                         
97 #define SET_UINT64(msg, field, attr) do {                               \
98         struct ldb_message_element *set_el;                             \
99         if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
100                 return NT_STATUS_NO_MEMORY;                             \
101         }                                                               \
102         set_el = ldb_msg_find_element(msg, attr);                       \
103         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
104 } while (0)                                                             
105
106 #define CHECK_FOR_MULTIPLES(value, flag, poss_flags)    \
107         do { \
108                 if ((value & flag) && ((value & flag) != (value & (poss_flags)))) { \
109                         return NT_STATUS_INVALID_PARAMETER;             \
110                 }                                                       \
111         } while (0)                                                     \
112         
113 /* Set account flags, discarding flags that cannot be set with SAMR */                                                          
114 #define SET_AFLAGS(msg, field, attr) do {                               \
115         struct ldb_message_element *set_el;                             \
116         if ((r->in.info->field & (ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST)) == 0) { \
117                 return NT_STATUS_INVALID_PARAMETER; \
118         }                                                               \
119         CHECK_FOR_MULTIPLES(r->in.info->field, ACB_NORMAL, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
120         CHECK_FOR_MULTIPLES(r->in.info->field, ACB_DOMTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
121         CHECK_FOR_MULTIPLES(r->in.info->field, ACB_WSTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
122         CHECK_FOR_MULTIPLES(r->in.info->field, ACB_SVRTRUST, ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); \
123         if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, (r->in.info->field & ~(ACB_AUTOLOCK|ACB_PW_EXPIRED))) != 0) { \
124                 return NT_STATUS_NO_MEMORY;                             \
125         }                                                               \
126         set_el = ldb_msg_find_element(msg, attr);                       \
127         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
128 } while (0)                                                             
129                                                                         
130 #define SET_LHOURS(msg, field, attr) do {                               \
131         struct ldb_message_element *set_el;                             \
132         if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
133                 return NT_STATUS_NO_MEMORY;                             \
134         }                                                               \
135         set_el = ldb_msg_find_element(msg, attr);                       \
136         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
137 } while (0)
138
139
140 /* 
141   samr_Connect 
142
143   create a connection to the SAM database
144 */
145 static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
146                              struct samr_Connect *r)
147 {
148         struct samr_connect_state *c_state;
149         struct dcesrv_handle *handle;
150
151         ZERO_STRUCTP(r->out.connect_handle);
152
153         c_state = talloc(dce_call->conn, struct samr_connect_state);
154         if (!c_state) {
155                 return NT_STATUS_NO_MEMORY;
156         }
157
158         /* make sure the sam database is accessible */
159         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); 
160         if (c_state->sam_ctx == NULL) {
161                 talloc_free(c_state);
162                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
163         }
164
165
166         handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_CONNECT);
167         if (!handle) {
168                 talloc_free(c_state);
169                 return NT_STATUS_NO_MEMORY;
170         }
171
172         handle->data = talloc_steal(handle, c_state);
173
174         c_state->access_mask = r->in.access_mask;
175         *r->out.connect_handle = handle->wire_handle;
176
177         return NT_STATUS_OK;
178 }
179
180
181 /* 
182   samr_Close 
183 */
184 static NTSTATUS dcesrv_samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
185                            struct samr_Close *r)
186 {
187         struct dcesrv_handle *h;
188
189         *r->out.handle = *r->in.handle;
190
191         DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
192
193         talloc_free(h);
194
195         ZERO_STRUCTP(r->out.handle);
196
197         return NT_STATUS_OK;
198 }
199
200
201 /* 
202   samr_SetSecurity 
203 */
204 static NTSTATUS dcesrv_samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
205                                  struct samr_SetSecurity *r)
206 {
207         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
208 }
209
210
211 /* 
212   samr_QuerySecurity 
213 */
214 static NTSTATUS dcesrv_samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
215                                    struct samr_QuerySecurity *r)
216 {
217         struct dcesrv_handle *h;
218         struct sec_desc_buf *sd;
219
220         r->out.sdbuf = NULL;
221
222         DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
223
224         sd = talloc(mem_ctx, struct sec_desc_buf);
225         if (sd == NULL) {
226                 return NT_STATUS_NO_MEMORY;
227         }
228
229         sd->sd = samdb_default_security_descriptor(mem_ctx);
230
231         r->out.sdbuf = sd;
232
233         return NT_STATUS_OK;
234 }
235
236
237 /* 
238   samr_Shutdown 
239
240   we refuse this operation completely. If a admin wants to shutdown samr
241   in Samba then they should use the samba admin tools to disable the samr pipe
242 */
243 static NTSTATUS dcesrv_samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
244                               struct samr_Shutdown *r)
245 {
246         return NT_STATUS_ACCESS_DENIED;
247 }
248
249
250 /* 
251   samr_LookupDomain 
252
253   this maps from a domain name to a SID
254 */
255 static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
256                                   struct samr_LookupDomain *r)
257 {
258         struct samr_connect_state *c_state;
259         struct dcesrv_handle *h;
260         struct dom_sid *sid;
261         const char * const dom_attrs[] = { "objectSid", NULL};
262         const char * const ref_attrs[] = { "ncName", NULL};
263         struct ldb_message **dom_msgs;
264         struct ldb_message **ref_msgs;
265         int ret;
266         struct ldb_dn *partitions_basedn;
267
268         r->out.sid = NULL;
269
270         DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
271
272         c_state = h->data;
273
274         if (r->in.domain_name->string == NULL) {
275                 return NT_STATUS_INVALID_PARAMETER;
276         }
277
278         partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx);
279
280         if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
281                 ret = gendb_search(c_state->sam_ctx,
282                                    mem_ctx, NULL, &dom_msgs, dom_attrs,
283                                    "(objectClass=builtinDomain)");
284         } else {
285                 ret = gendb_search(c_state->sam_ctx,
286                                    mem_ctx, partitions_basedn, &ref_msgs, ref_attrs,
287                                    "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))", 
288                                    ldb_binary_encode_string(mem_ctx, r->in.domain_name->string));
289                 if (ret != 1) {
290                         return NT_STATUS_NO_SUCH_DOMAIN;
291                 }
292                 
293                 ret = gendb_search_dn(c_state->sam_ctx, mem_ctx, 
294                                       samdb_result_dn(c_state->sam_ctx, mem_ctx,
295                                                       ref_msgs[0], "ncName", NULL), 
296                                       &dom_msgs, dom_attrs);
297         }
298
299         if (ret != 1) {
300                 return NT_STATUS_NO_SUCH_DOMAIN;
301         }
302         
303         sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
304                                    "objectSid");
305                 
306         if (sid == NULL) {
307                 return NT_STATUS_NO_SUCH_DOMAIN;
308         }
309
310         r->out.sid = sid;
311
312         return NT_STATUS_OK;
313 }
314
315
316 /* 
317   samr_EnumDomains 
318
319   list the domains in the SAM
320 */
321 static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
322                                  struct samr_EnumDomains *r)
323 {
324         struct samr_connect_state *c_state;
325         struct dcesrv_handle *h;
326         struct samr_SamArray *array;
327         int i, start_i, ret;
328         const char * const dom_attrs[] = { "cn", NULL};
329         const char * const ref_attrs[] = { "nETBIOSName", NULL};
330         struct ldb_result *dom_res;
331         struct ldb_result *ref_res;
332         struct ldb_dn *partitions_basedn;
333
334         *r->out.resume_handle = 0;
335         r->out.sam = NULL;
336         r->out.num_entries = 0;
337
338         DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
339
340         c_state = h->data;
341
342         partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx);
343
344         ret = ldb_search(c_state->sam_ctx, mem_ctx, &dom_res, ldb_get_default_basedn(c_state->sam_ctx),
345                                  LDB_SCOPE_SUBTREE, dom_attrs, "(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain))");
346         if (ret != LDB_SUCCESS) {
347                 DEBUG(0,("samdb: unable to find domains: %s\n", ldb_errstring(c_state->sam_ctx)));
348                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
349         }
350
351         *r->out.resume_handle = dom_res->count;
352
353         start_i = *r->in.resume_handle;
354
355         if (start_i >= dom_res->count) {
356                 /* search past end of list is not an error for this call */
357                 return NT_STATUS_OK;
358         }
359
360         array = talloc(mem_ctx, struct samr_SamArray);
361         if (array == NULL) {
362                 return NT_STATUS_NO_MEMORY;
363         }
364                 
365         array->count = 0;
366         array->entries = NULL;
367
368         array->entries = talloc_array(mem_ctx, struct samr_SamEntry, dom_res->count - start_i);
369         if (array->entries == NULL) {
370                 return NT_STATUS_NO_MEMORY;
371         }
372
373         for (i=0;i<dom_res->count-start_i;i++) {
374                 array->entries[i].idx = start_i + i;
375                 /* try and find the domain */
376                 ret = ldb_search(c_state->sam_ctx, mem_ctx, &ref_res, partitions_basedn,
377                                          LDB_SCOPE_SUBTREE, ref_attrs, "(&(objectClass=crossRef)(ncName=%s))", 
378                                          ldb_dn_get_linearized(dom_res->msgs[i]->dn));
379
380                 if (ret != LDB_SUCCESS) {
381                         DEBUG(0,("samdb: unable to find domains: %s\n", ldb_errstring(c_state->sam_ctx)));
382                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
383                 }
384
385                 if (ref_res->count == 1) {
386                         array->entries[i].name.string = samdb_result_string(ref_res->msgs[0], "nETBIOSName", NULL);
387                 } else {
388                         array->entries[i].name.string = samdb_result_string(dom_res->msgs[i], "cn", NULL);
389                 }
390         }
391
392         r->out.sam = array;
393         r->out.num_entries = i;
394         array->count = r->out.num_entries;
395
396         return NT_STATUS_OK;
397 }
398
399
400 /* 
401   samr_OpenDomain 
402 */
403 static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
404                                 struct samr_OpenDomain *r)
405 {
406         struct dcesrv_handle *h_conn, *h_domain;
407         const char *domain_name;
408         struct samr_connect_state *c_state;
409         struct samr_domain_state *d_state;
410         const char * const dom_attrs[] = { "cn", NULL};
411         const char * const ref_attrs[] = { "nETBIOSName", NULL};
412         struct ldb_message **dom_msgs;
413         struct ldb_message **ref_msgs;
414         int ret;
415         struct ldb_dn *partitions_basedn;
416
417         ZERO_STRUCTP(r->out.domain_handle);
418
419         DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
420
421         c_state = h_conn->data;
422
423         if (r->in.sid == NULL) {
424                 return NT_STATUS_INVALID_PARAMETER;
425         }
426
427         partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx);
428
429         ret = gendb_search(c_state->sam_ctx,
430                            mem_ctx, NULL, &dom_msgs, dom_attrs,
431                            "(&(objectSid=%s)(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain)))", 
432                            ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
433         if (ret == 0) {
434                 return NT_STATUS_NO_SUCH_DOMAIN;
435         } else if (ret > 1) {
436                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
437         } else if (ret == -1) {
438                 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx)));
439                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
440         } else {
441                 ret = gendb_search(c_state->sam_ctx,
442                                    mem_ctx, partitions_basedn, &ref_msgs, ref_attrs,
443                                    "(&(&(nETBIOSName=*)(objectclass=crossRef))(ncName=%s))", 
444                                    ldb_dn_get_linearized(dom_msgs[0]->dn));
445                 if (ret == 0) {
446                         domain_name = ldb_msg_find_attr_as_string(dom_msgs[0], "cn", NULL);
447                         if (domain_name == NULL) {
448                                 return NT_STATUS_NO_SUCH_DOMAIN;
449                         }
450                 } else if (ret == 1) {
451                 
452                         domain_name = ldb_msg_find_attr_as_string(ref_msgs[0], "nETBIOSName", NULL);
453                         if (domain_name == NULL) {
454                                 return NT_STATUS_NO_SUCH_DOMAIN;
455                         }
456                 } else {
457                         return NT_STATUS_NO_SUCH_DOMAIN;
458                 }
459         }
460
461         d_state = talloc(c_state, struct samr_domain_state);
462         if (!d_state) {
463                 return NT_STATUS_NO_MEMORY;
464         }
465
466         d_state->role = lp_server_role(dce_call->conn->dce_ctx->lp_ctx);
467         d_state->connect_state = talloc_reference(d_state, c_state);
468         d_state->sam_ctx = c_state->sam_ctx;
469         d_state->domain_sid = dom_sid_dup(d_state, r->in.sid);
470         d_state->domain_name = talloc_strdup(d_state, domain_name);
471         d_state->domain_dn = ldb_dn_copy(d_state, dom_msgs[0]->dn);
472         if (!d_state->domain_sid || !d_state->domain_name || !d_state->domain_dn) {
473                 talloc_free(d_state);
474                 return NT_STATUS_NO_MEMORY;             
475         }
476         d_state->access_mask = r->in.access_mask;
477
478         if (dom_sid_equal(d_state->domain_sid, dom_sid_parse_talloc(mem_ctx, SID_BUILTIN))) {
479                 d_state->builtin = true;
480         } else {
481                 d_state->builtin = false;
482         }
483
484         d_state->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
485
486         h_domain = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_DOMAIN);
487         if (!h_domain) {
488                 talloc_free(d_state);
489                 return NT_STATUS_NO_MEMORY;
490         }
491         
492         h_domain->data = talloc_steal(h_domain, d_state);
493
494         *r->out.domain_handle = h_domain->wire_handle;
495
496         return NT_STATUS_OK;
497 }
498
499 /*
500   return DomInfo1
501 */
502 static NTSTATUS dcesrv_samr_info_DomInfo1(struct samr_domain_state *state,
503                                    TALLOC_CTX *mem_ctx,
504                                     struct ldb_message **dom_msgs,
505                                    struct samr_DomInfo1 *info)
506 {
507         info->min_password_length =
508                 samdb_result_uint(dom_msgs[0], "minPwdLength", 0);
509         info->password_history_length =
510                 samdb_result_uint(dom_msgs[0], "pwdHistoryLength", 0);
511         info->password_properties = 
512                 samdb_result_uint(dom_msgs[0], "pwdProperties", 0);
513         info->max_password_age = 
514                 samdb_result_int64(dom_msgs[0], "maxPwdAge", 0);
515         info->min_password_age = 
516                 samdb_result_int64(dom_msgs[0], "minPwdAge", 0);
517
518         return NT_STATUS_OK;
519 }
520
521 /*
522   return DomInfo2
523 */
524 static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state *state, 
525                                                        TALLOC_CTX *mem_ctx,
526                                                        struct ldb_message **dom_msgs,
527                                                        struct samr_DomGeneralInformation *info)
528 {
529         /* This pulls the NetBIOS name from the 
530            cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
531            string */
532         info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx, dom_msgs[0], "fSMORoleOwner");
533
534         if (!info->primary.string) {
535                 info->primary.string = lp_netbios_name(state->lp_ctx);
536         }
537
538         info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff", 
539                                                             0x8000000000000000LL);
540
541         info->oem_information.string = samdb_result_string(dom_msgs[0], "oEMInformation", NULL);
542         info->domain_name.string  = state->domain_name;
543
544         info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount", 
545                                                  0);
546         switch (state->role) {
547         case ROLE_DOMAIN_CONTROLLER:
548                 /* This pulls the NetBIOS name from the 
549                    cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
550                    string */
551                 if (samdb_is_pdc(state->sam_ctx)) {
552                         info->role = SAMR_ROLE_DOMAIN_PDC;
553                 } else {
554                         info->role = SAMR_ROLE_DOMAIN_BDC;
555                 }
556                 break;
557         case ROLE_DOMAIN_MEMBER:
558                 info->role = SAMR_ROLE_DOMAIN_MEMBER;
559                 break;
560         case ROLE_STANDALONE:
561                 info->role = SAMR_ROLE_STANDALONE;
562                 break;
563         }
564
565         /* No users in BUILTIN, and the LOCAL group types are only in builtin, and the global group type is never in BUILTIN */
566         info->num_users = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn, 
567                                              "(objectClass=user)");
568         info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
569                                               "(&(objectClass=group)(sAMAccountType=%u))",
570                                               ATYPE_GLOBAL_GROUP);
571         info->num_aliases = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
572                                                "(&(objectClass=group)(sAMAccountType=%u))",
573                                                ATYPE_LOCAL_GROUP);
574
575         return NT_STATUS_OK;
576 }
577
578 /*
579   return DomInfo3
580 */
581 static NTSTATUS dcesrv_samr_info_DomInfo3(struct samr_domain_state *state,
582                                    TALLOC_CTX *mem_ctx,
583                                     struct ldb_message **dom_msgs,
584                                    struct samr_DomInfo3 *info)
585 {
586         info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff", 
587                                                       0x8000000000000000LL);
588
589         return NT_STATUS_OK;
590 }
591
592 /*
593   return DomInfo4
594 */
595 static NTSTATUS dcesrv_samr_info_DomOEMInformation(struct samr_domain_state *state,
596                                    TALLOC_CTX *mem_ctx,
597                                     struct ldb_message **dom_msgs,
598                                    struct samr_DomOEMInformation *info)
599 {
600         info->oem_information.string = samdb_result_string(dom_msgs[0], "oEMInformation", NULL);
601
602         return NT_STATUS_OK;
603 }
604
605 /*
606   return DomInfo5
607 */
608 static NTSTATUS dcesrv_samr_info_DomInfo5(struct samr_domain_state *state,
609                                    TALLOC_CTX *mem_ctx,
610                                     struct ldb_message **dom_msgs,
611                                    struct samr_DomInfo5 *info)
612 {
613         info->domain_name.string  = state->domain_name;
614
615         return NT_STATUS_OK;
616 }
617
618 /*
619   return DomInfo6
620 */
621 static NTSTATUS dcesrv_samr_info_DomInfo6(struct samr_domain_state *state,
622                                    TALLOC_CTX *mem_ctx,
623                                    struct ldb_message **dom_msgs,
624                                    struct samr_DomInfo6 *info)
625 {
626         /* This pulls the NetBIOS name from the 
627            cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
628            string */
629         info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx, 
630                                                       dom_msgs[0], "fSMORoleOwner");
631
632         if (!info->primary.string) {
633                 info->primary.string = lp_netbios_name(state->lp_ctx);
634         }
635
636         return NT_STATUS_OK;
637 }
638
639 /*
640   return DomInfo7
641 */
642 static NTSTATUS dcesrv_samr_info_DomInfo7(struct samr_domain_state *state,
643                                    TALLOC_CTX *mem_ctx,
644                                     struct ldb_message **dom_msgs,
645                                    struct samr_DomInfo7 *info)
646 {
647
648         switch (state->role) {
649         case ROLE_DOMAIN_CONTROLLER:
650                 /* This pulls the NetBIOS name from the 
651                    cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
652                    string */
653                 if (samdb_is_pdc(state->sam_ctx)) {
654                         info->role = SAMR_ROLE_DOMAIN_PDC;
655                 } else {
656                         info->role = SAMR_ROLE_DOMAIN_BDC;
657                 }
658                 break;
659         case ROLE_DOMAIN_MEMBER:
660                 info->role = SAMR_ROLE_DOMAIN_MEMBER;
661                 break;
662         case ROLE_STANDALONE:
663                 info->role = SAMR_ROLE_STANDALONE;
664                 break;
665         }
666
667         return NT_STATUS_OK;
668 }
669
670 /*
671   return DomInfo8
672 */
673 static NTSTATUS dcesrv_samr_info_DomInfo8(struct samr_domain_state *state,
674                                    TALLOC_CTX *mem_ctx,
675                                     struct ldb_message **dom_msgs,
676                                    struct samr_DomInfo8 *info)
677 {
678         info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount", 
679                                                time(NULL));
680
681         info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
682                                                      0x0LL);
683
684         return NT_STATUS_OK;
685 }
686
687 /*
688   return DomInfo9
689 */
690 static NTSTATUS dcesrv_samr_info_DomInfo9(struct samr_domain_state *state,
691                                    TALLOC_CTX *mem_ctx,
692                                     struct ldb_message **dom_msgs,
693                                    struct samr_DomInfo9 *info)
694 {
695         info->unknown = 1;
696
697         return NT_STATUS_OK;
698 }
699
700 /*
701   return DomInfo11
702 */
703 static NTSTATUS dcesrv_samr_info_DomGeneralInformation2(struct samr_domain_state *state,
704                                     TALLOC_CTX *mem_ctx,
705                                     struct ldb_message **dom_msgs,
706                                     struct samr_DomGeneralInformation2 *info)
707 {
708         NTSTATUS status;
709         status = dcesrv_samr_info_DomGeneralInformation(state, mem_ctx, dom_msgs, &info->general);
710         if (!NT_STATUS_IS_OK(status)) {
711                 return status;
712         }
713         
714         info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration", 
715                                                     -18000000000LL);
716         info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
717                                                     -18000000000LL);
718         info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
719
720         return NT_STATUS_OK;
721 }
722
723 /*
724   return DomInfo12
725 */
726 static NTSTATUS dcesrv_samr_info_DomInfo12(struct samr_domain_state *state,
727                                    TALLOC_CTX *mem_ctx,
728                                     struct ldb_message **dom_msgs,
729                                    struct samr_DomInfo12 *info)
730 {
731         info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration", 
732                                                     -18000000000LL);
733         info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
734                                                     -18000000000LL);
735         info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
736
737         return NT_STATUS_OK;
738 }
739
740 /*
741   return DomInfo13
742 */
743 static NTSTATUS dcesrv_samr_info_DomInfo13(struct samr_domain_state *state,
744                                     TALLOC_CTX *mem_ctx,
745                                     struct ldb_message **dom_msgs,
746                                     struct samr_DomInfo13 *info)
747 {
748         info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount", 
749                                                time(NULL));
750
751         info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
752                                                      0x0LL);
753
754         info->unknown1 = 0;
755         info->unknown2 = 0;
756
757         return NT_STATUS_OK;
758 }
759
760 /* 
761   samr_QueryDomainInfo 
762 */
763 static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
764                                      struct samr_QueryDomainInfo *r)
765 {
766         struct dcesrv_handle *h;
767         struct samr_domain_state *d_state;
768
769         struct ldb_message **dom_msgs;
770         const char * const *attrs = NULL;
771         
772         r->out.info = NULL;
773
774         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
775
776         d_state = h->data;
777
778         r->out.info = talloc(mem_ctx, union samr_DomainInfo);
779         if (!r->out.info) {
780                 return NT_STATUS_NO_MEMORY;
781         }
782
783         switch (r->in.level) {
784         case 1: 
785         {
786                 static const char * const attrs2[] = { "minPwdLength", "pwdHistoryLength",
787                                                        "pwdProperties", "maxPwdAge",
788                                                        "minPwdAge", NULL };
789                 attrs = attrs2;
790                 break;
791         }
792         case 2:
793         {
794                 static const char * const attrs2[] = {"forceLogoff",
795                                                       "oEMInformation", 
796                                                       "modifiedCount", 
797                                                       "fSMORoleOwner",
798                                                       NULL};
799                 attrs = attrs2;
800                 break;
801         }
802         case 3:
803         {
804                 static const char * const attrs2[] = {"forceLogoff", 
805                                                       NULL};
806                 attrs = attrs2;
807                 break;
808         }
809         case 4:
810         {
811                 static const char * const attrs2[] = {"oEMInformation", 
812                                                       NULL};
813                 attrs = attrs2;
814                 break;
815         }
816         case 5:
817         {
818                 attrs = NULL;
819                 break;
820         }
821         case 6:
822         {
823                 static const char * const attrs2[] = {"fSMORoleOwner", 
824                                                       NULL};
825                 attrs = attrs2;
826                 break;
827         }
828         case 7:
829         {
830                 attrs = NULL;
831                 break;
832         }
833         case 8:
834         {
835                 static const char * const attrs2[] = { "modifiedCount", 
836                                                        "creationTime", 
837                                                        NULL };
838                 attrs = attrs2;
839                 break;
840         }
841         case 9:
842                 attrs = NULL;
843                 break;          
844         case 11:
845         {
846                 static const char * const attrs2[] = { "oEMInformation", "forceLogoff", 
847                                                        "modifiedCount", 
848                                                        "lockoutDuration", 
849                                                        "lockOutObservationWindow", 
850                                                        "lockoutThreshold", 
851                                                        NULL};
852                 attrs = attrs2;
853                 break;
854         }
855         case 12:
856         {
857                 static const char * const attrs2[] = { "lockoutDuration", 
858                                                        "lockOutObservationWindow", 
859                                                        "lockoutThreshold", 
860                                                        NULL};
861                 attrs = attrs2;
862                 break;
863         }
864         case 13:
865         {
866                 static const char * const attrs2[] = { "modifiedCount", 
867                                                        "creationTime", 
868                                                        NULL };
869                 attrs = attrs2;
870                 break;
871         }
872         }
873
874         /* some levels don't need a search */
875         if (attrs) {
876                 int ret;
877                 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
878                                       d_state->domain_dn, &dom_msgs, attrs);
879                 if (ret != 1) {
880                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
881                 }
882         }
883
884         ZERO_STRUCTP(r->out.info);
885
886         switch (r->in.level) {
887         case 1:
888                 return dcesrv_samr_info_DomInfo1(d_state, mem_ctx, dom_msgs, 
889                                                  &r->out.info->info1);
890         case 2:
891                 return dcesrv_samr_info_DomGeneralInformation(d_state, mem_ctx, dom_msgs, 
892                                                               &r->out.info->general);
893         case 3:
894                 return dcesrv_samr_info_DomInfo3(d_state, mem_ctx, dom_msgs, 
895                                                  &r->out.info->info3);
896         case 4:
897                 return dcesrv_samr_info_DomOEMInformation(d_state, mem_ctx, dom_msgs, 
898                                                           &r->out.info->oem);
899         case 5:
900                 return dcesrv_samr_info_DomInfo5(d_state, mem_ctx, dom_msgs, 
901                                                  &r->out.info->info5);
902         case 6:
903                 return dcesrv_samr_info_DomInfo6(d_state, mem_ctx, dom_msgs, 
904                                                  &r->out.info->info6);
905         case 7:
906                 return dcesrv_samr_info_DomInfo7(d_state, mem_ctx, dom_msgs, 
907                                                  &r->out.info->info7);
908         case 8:
909                 return dcesrv_samr_info_DomInfo8(d_state, mem_ctx, dom_msgs, 
910                                                  &r->out.info->info8);
911         case 9:
912                 return dcesrv_samr_info_DomInfo9(d_state, mem_ctx, dom_msgs, 
913                                                  &r->out.info->info9);
914         case 11:
915                 return dcesrv_samr_info_DomGeneralInformation2(d_state, mem_ctx, dom_msgs, 
916                                                                &r->out.info->general2);
917         case 12:
918                 return dcesrv_samr_info_DomInfo12(d_state, mem_ctx, dom_msgs, 
919                                                   &r->out.info->info12);
920         case 13:
921                 return dcesrv_samr_info_DomInfo13(d_state, mem_ctx, dom_msgs, 
922                                                   &r->out.info->info13);
923         }
924         
925         return NT_STATUS_INVALID_INFO_CLASS;
926 }
927
928
929 /* 
930   samr_SetDomainInfo 
931 */
932 static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
933                        struct samr_SetDomainInfo *r)
934 {
935         struct dcesrv_handle *h;
936         struct samr_domain_state *d_state;
937         struct ldb_message *msg;
938         int ret;
939         struct ldb_context *sam_ctx;
940
941         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
942
943         d_state = h->data;
944         sam_ctx = d_state->sam_ctx;
945
946         msg = ldb_msg_new(mem_ctx);
947         if (msg == NULL) {
948                 return NT_STATUS_NO_MEMORY;
949         }
950
951         msg->dn = talloc_reference(mem_ctx, d_state->domain_dn);
952         if (!msg->dn) {
953                 return NT_STATUS_NO_MEMORY;
954         }
955
956         switch (r->in.level) {
957         case 1:
958                 SET_UINT  (msg, info1.min_password_length,     "minPwdLength");
959                 SET_UINT  (msg, info1.password_history_length, "pwdHistoryLength");
960                 SET_UINT  (msg, info1.password_properties,     "pwdProperties");
961                 SET_INT64  (msg, info1.max_password_age,       "maxPwdAge");
962                 SET_INT64  (msg, info1.min_password_age,       "minPwdAge");
963                 break;
964         case 3:
965                 SET_UINT64  (msg, info3.force_logoff_time,     "forceLogoff");
966                 break;
967         case 4:
968                 SET_STRING(msg, oem.oem_information,           "oEMInformation");
969                 break;
970
971         case 6:
972         case 7:
973         case 9:
974                 /* No op, we don't know where to set these */
975                 return NT_STATUS_OK;
976
977         case 12:
978                 
979                 SET_INT64  (msg, info12.lockout_duration,      "lockoutDuration");
980                 SET_INT64  (msg, info12.lockout_window,        "lockOutObservationWindow");
981                 SET_INT64  (msg, info12.lockout_threshold,     "lockoutThreshold");
982                 break;
983
984         default:
985                 /* many info classes are not valid for SetDomainInfo */
986                 return NT_STATUS_INVALID_INFO_CLASS;
987         }
988
989         /* modify the samdb record */
990         ret = ldb_modify(sam_ctx, msg);
991         if (ret != 0) {
992                 DEBUG(1,("Failed to modify record %s: %s\n",
993                          ldb_dn_get_linearized(d_state->domain_dn),
994                          ldb_errstring(sam_ctx)));
995
996                 /* we really need samdb.c to return NTSTATUS */
997                 return NT_STATUS_UNSUCCESSFUL;
998         }
999
1000         return NT_STATUS_OK;
1001 }
1002
1003 /* 
1004   samr_CreateDomainGroup 
1005 */
1006 static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1007                                        struct samr_CreateDomainGroup *r)
1008 {
1009         struct samr_domain_state *d_state;
1010         struct samr_account_state *a_state;
1011         struct dcesrv_handle *h;
1012         const char *name;
1013         struct ldb_message *msg;
1014         struct dom_sid *sid;
1015         const char *groupname;
1016         struct dcesrv_handle *g_handle;
1017         int ret;
1018
1019         ZERO_STRUCTP(r->out.group_handle);
1020         *r->out.rid = 0;
1021
1022         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1023
1024         d_state = h->data;
1025
1026         if (d_state->builtin) {
1027                 DEBUG(5, ("Cannot create a domain group in the BUILTIN domain"));
1028                 return NT_STATUS_ACCESS_DENIED;
1029         }
1030
1031         groupname = r->in.name->string;
1032
1033         if (groupname == NULL) {
1034                 return NT_STATUS_INVALID_PARAMETER;
1035         }
1036
1037         /* check if the group already exists */
1038         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL, 
1039                                    "sAMAccountName",
1040                                    "(&(sAMAccountName=%s)(objectclass=group))",
1041                                    ldb_binary_encode_string(mem_ctx, groupname));
1042         if (name != NULL) {
1043                 return NT_STATUS_GROUP_EXISTS;
1044         }
1045
1046         msg = ldb_msg_new(mem_ctx);
1047         if (msg == NULL) {
1048                 return NT_STATUS_NO_MEMORY;
1049         }
1050
1051         /* add core elements to the ldb_message for the user */
1052         msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1053         ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", groupname);
1054         if (!msg->dn) {
1055                 return NT_STATUS_NO_MEMORY;
1056         }
1057         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", groupname);
1058         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1059                              
1060         /* create the group */
1061         ret = ldb_add(d_state->sam_ctx, msg);
1062         switch (ret) {
1063         case  LDB_SUCCESS:
1064                 break;
1065         case  LDB_ERR_ENTRY_ALREADY_EXISTS:
1066                 DEBUG(0,("Failed to create group record %s: %s\n",
1067                          ldb_dn_get_linearized(msg->dn),
1068                          ldb_errstring(d_state->sam_ctx)));
1069                 return NT_STATUS_GROUP_EXISTS;
1070         case  LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1071                 DEBUG(0,("Failed to create group record %s: %s\n",
1072                          ldb_dn_get_linearized(msg->dn),
1073                          ldb_errstring(d_state->sam_ctx)));
1074                 return NT_STATUS_ACCESS_DENIED;
1075         default:
1076                 DEBUG(0,("Failed to create group record %s: %s\n",
1077                          ldb_dn_get_linearized(msg->dn),
1078                          ldb_errstring(d_state->sam_ctx)));
1079                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1080         }
1081
1082         a_state = talloc(d_state, struct samr_account_state);
1083         if (!a_state) {
1084                 return NT_STATUS_NO_MEMORY;
1085         }
1086         a_state->sam_ctx = d_state->sam_ctx;
1087         a_state->access_mask = r->in.access_mask;
1088         a_state->domain_state = talloc_reference(a_state, d_state);
1089         a_state->account_dn = talloc_steal(a_state, msg->dn);
1090
1091         /* retrieve the sid for the group just created */
1092         sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1093                                    msg->dn, "objectSid", NULL);
1094         if (sid == NULL) {
1095                 return NT_STATUS_UNSUCCESSFUL;
1096         }
1097
1098         a_state->account_name = talloc_strdup(a_state, groupname);
1099         if (!a_state->account_name) {
1100                 return NT_STATUS_NO_MEMORY;
1101         }
1102
1103         /* create the policy handle */
1104         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1105         if (!g_handle) {
1106                 return NT_STATUS_NO_MEMORY;
1107         }
1108
1109         g_handle->data = talloc_steal(g_handle, a_state);
1110
1111         *r->out.group_handle = g_handle->wire_handle;
1112         *r->out.rid = sid->sub_auths[sid->num_auths-1];
1113
1114         return NT_STATUS_OK;
1115 }
1116
1117
1118 /*
1119   comparison function for sorting SamEntry array
1120 */
1121 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
1122 {
1123         return e1->idx - e2->idx;
1124 }
1125
1126 /* 
1127   samr_EnumDomainGroups 
1128 */
1129 static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1130                                       struct samr_EnumDomainGroups *r)
1131 {
1132         struct dcesrv_handle *h;
1133         struct samr_domain_state *d_state;
1134         struct ldb_message **res;
1135         int ldb_cnt, count, i, first;
1136         struct samr_SamEntry *entries;
1137         const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1138
1139         *r->out.resume_handle = 0;
1140         r->out.sam = NULL;
1141         r->out.num_entries = 0;
1142
1143         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1144
1145         d_state = h->data;
1146
1147         /* search for all domain groups in this domain. This could possibly be
1148            cached and resumed based on resume_key */
1149         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1150                                       d_state->domain_dn, &res, attrs,
1151                                       d_state->domain_sid,
1152                                       "(&(grouptype=%d)(objectclass=group))",
1153                                       GTYPE_SECURITY_GLOBAL_GROUP);
1154         if (ldb_cnt == -1) {
1155                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1156         }
1157
1158         /* convert to SamEntry format */
1159         entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1160         if (!entries) {
1161                 return NT_STATUS_NO_MEMORY;
1162         }
1163
1164         count = 0;
1165
1166         for (i=0;i<ldb_cnt;i++) {
1167                 struct dom_sid *group_sid;
1168
1169                 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
1170                                                  "objectSid");
1171                 if (group_sid == NULL)
1172                         continue;
1173
1174                 entries[count].idx =
1175                         group_sid->sub_auths[group_sid->num_auths-1];
1176                 entries[count].name.string =
1177                         samdb_result_string(res[i], "sAMAccountName", "");
1178                 count += 1;
1179         }
1180
1181         /* sort the results by rid */
1182         qsort(entries, count, sizeof(struct samr_SamEntry), 
1183               (comparison_fn_t)compare_SamEntry);
1184
1185         /* find the first entry to return */
1186         for (first=0;
1187              first<count && entries[first].idx <= *r->in.resume_handle;
1188              first++) ;
1189
1190         /* return the rest, limit by max_size. Note that we 
1191            use the w2k3 element size value of 54 */
1192         r->out.num_entries = count - first;
1193         r->out.num_entries = MIN(r->out.num_entries, 
1194                                  1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1195
1196         r->out.sam = talloc(mem_ctx, struct samr_SamArray);
1197         if (!r->out.sam) {
1198                 return NT_STATUS_NO_MEMORY;
1199         }
1200
1201         r->out.sam->entries = entries+first;
1202         r->out.sam->count = r->out.num_entries;
1203
1204         if (r->out.num_entries < count - first) {
1205                 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
1206                 return STATUS_MORE_ENTRIES;
1207         }
1208
1209         return NT_STATUS_OK;
1210 }
1211
1212
1213 /* 
1214   samr_CreateUser2 
1215
1216   This call uses transactions to ensure we don't get a new conflicting
1217   user while we are processing this, and to ensure the user either
1218   completly exists, or does not.
1219 */
1220 static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1221                                  struct samr_CreateUser2 *r)
1222 {
1223         struct samr_domain_state *d_state;
1224         struct samr_account_state *a_state;
1225         struct dcesrv_handle *h;
1226         const char *name;
1227         struct ldb_message *msg;
1228         struct dom_sid *sid;
1229         const char *account_name;
1230         struct dcesrv_handle *u_handle;
1231         int ret;
1232         const char *container, *obj_class=NULL;
1233         char *cn_name;
1234         int cn_name_len;
1235
1236         const char *attrs[] = {
1237                 "objectSid", 
1238                 "userAccountControl",
1239                 NULL
1240         };
1241
1242         uint32_t user_account_control;
1243
1244         struct ldb_message **msgs;
1245
1246         ZERO_STRUCTP(r->out.user_handle);
1247         *r->out.access_granted = 0;
1248         *r->out.rid = 0;
1249
1250         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1251
1252         d_state = h->data;
1253
1254         if (d_state->builtin) {
1255                 DEBUG(5, ("Cannot create a user in the BUILTIN domain"));
1256                 return NT_STATUS_ACCESS_DENIED;
1257         }
1258         account_name = r->in.account_name->string;
1259
1260         if (account_name == NULL) {
1261                 return NT_STATUS_INVALID_PARAMETER;
1262         }
1263
1264         ret = ldb_transaction_start(d_state->sam_ctx);
1265         if (ret != 0) {
1266                 DEBUG(0,("Failed to start a transaction for user creation: %s\n",
1267                          ldb_errstring(d_state->sam_ctx)));
1268                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1269         }
1270
1271         /* check if the user already exists */
1272         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL, 
1273                                    "sAMAccountName", 
1274                                    "(&(sAMAccountName=%s)(objectclass=user))", 
1275                                    ldb_binary_encode_string(mem_ctx, account_name));
1276         if (name != NULL) {
1277                 ldb_transaction_cancel(d_state->sam_ctx);
1278                 return NT_STATUS_USER_EXISTS;
1279         }
1280
1281         msg = ldb_msg_new(mem_ctx);
1282         if (msg == NULL) {
1283                 ldb_transaction_cancel(d_state->sam_ctx);
1284                 return NT_STATUS_NO_MEMORY;
1285         }
1286
1287         cn_name   = talloc_strdup(mem_ctx, account_name);
1288         if (!cn_name) {
1289                 ldb_transaction_cancel(d_state->sam_ctx);
1290                 return NT_STATUS_NO_MEMORY;
1291         }
1292
1293         cn_name_len = strlen(cn_name);
1294
1295         /* This must be one of these values *only* */
1296         if (r->in.acct_flags == ACB_NORMAL) {
1297                 container = "CN=Users";
1298                 obj_class = "user";
1299
1300         } else if (r->in.acct_flags == ACB_WSTRUST) {
1301                 if (cn_name[cn_name_len - 1] != '$') {
1302                         return NT_STATUS_FOOBAR;
1303                 }
1304                 cn_name[cn_name_len - 1] = '\0';
1305                 container = "CN=Computers";
1306                 obj_class = "computer";
1307                 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "primaryGroupID", DOMAIN_RID_DOMAIN_MEMBERS);
1308
1309         } else if (r->in.acct_flags == ACB_SVRTRUST) {
1310                 if (cn_name[cn_name_len - 1] != '$') {
1311                         return NT_STATUS_FOOBAR;                
1312                 }
1313                 cn_name[cn_name_len - 1] = '\0';
1314                 container = "OU=Domain Controllers";
1315                 obj_class = "computer";
1316                 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "primaryGroupID", DOMAIN_RID_DCS);
1317
1318         } else if (r->in.acct_flags == ACB_DOMTRUST) {
1319                 container = "CN=Users";
1320                 obj_class = "user";
1321
1322         } else {
1323                 ldb_transaction_cancel(d_state->sam_ctx);
1324                 return NT_STATUS_INVALID_PARAMETER;
1325         }
1326
1327         /* add core elements to the ldb_message for the user */
1328         msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1329         if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s,%s", cn_name, container)) {
1330                 ldb_transaction_cancel(d_state->sam_ctx);
1331                 return NT_STATUS_FOOBAR;
1332         }
1333
1334         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", account_name);
1335         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", obj_class);
1336         
1337         /* Start a transaction, so we can query and do a subsequent atomic modify */
1338         
1339         /* create the user */
1340         ret = ldb_add(d_state->sam_ctx, msg);
1341         switch (ret) {
1342         case LDB_SUCCESS:
1343                 break;
1344         case LDB_ERR_ENTRY_ALREADY_EXISTS:
1345                 ldb_transaction_cancel(d_state->sam_ctx);
1346                 DEBUG(0,("Failed to create user record %s: %s\n",
1347                          ldb_dn_get_linearized(msg->dn),
1348                          ldb_errstring(d_state->sam_ctx)));
1349                 return NT_STATUS_USER_EXISTS;
1350         case LDB_ERR_UNWILLING_TO_PERFORM:
1351         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1352                 ldb_transaction_cancel(d_state->sam_ctx);
1353                 DEBUG(0,("Failed to create user record %s: %s\n",
1354                          ldb_dn_get_linearized(msg->dn),
1355                          ldb_errstring(d_state->sam_ctx)));
1356                 return NT_STATUS_ACCESS_DENIED;
1357         default:
1358                 ldb_transaction_cancel(d_state->sam_ctx);
1359                 DEBUG(0,("Failed to create user record %s: %s\n",
1360                          ldb_dn_get_linearized(msg->dn),
1361                          ldb_errstring(d_state->sam_ctx)));
1362                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1363         }
1364
1365         a_state = talloc(d_state, struct samr_account_state);
1366         if (!a_state) {
1367                 ldb_transaction_cancel(d_state->sam_ctx);
1368                 return NT_STATUS_NO_MEMORY;
1369         }
1370         a_state->sam_ctx = d_state->sam_ctx;
1371         a_state->access_mask = r->in.access_mask;
1372         a_state->domain_state = talloc_reference(a_state, d_state);
1373         a_state->account_dn = talloc_steal(a_state, msg->dn);
1374
1375         /* retrieve the sid and account control bits for the user just created */
1376         ret = gendb_search_dn(d_state->sam_ctx, a_state,
1377                               msg->dn, &msgs, attrs);
1378
1379         if (ret != 1) {
1380                 ldb_transaction_cancel(d_state->sam_ctx);
1381                 DEBUG(0,("Apparently we failed to create an account record, as %s now doesn't exist\n",
1382                          ldb_dn_get_linearized(msg->dn)));
1383                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1384         }
1385         sid = samdb_result_dom_sid(mem_ctx, msgs[0], "objectSid");
1386         if (sid == NULL) {
1387                 ldb_transaction_cancel(d_state->sam_ctx);
1388                 DEBUG(0,("Apparently we failed to get the objectSid of the just created account record %s\n",
1389                          ldb_dn_get_linearized(msg->dn)));
1390                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1391         }
1392
1393         /* Change the account control to be the correct account type.
1394          * The default is for a workstation account */
1395         user_account_control = samdb_result_uint(msgs[0], "userAccountControl", 0);
1396         user_account_control = (user_account_control & 
1397                                 ~(UF_NORMAL_ACCOUNT |
1398                                   UF_INTERDOMAIN_TRUST_ACCOUNT | 
1399                                   UF_WORKSTATION_TRUST_ACCOUNT | 
1400                                   UF_SERVER_TRUST_ACCOUNT));
1401         user_account_control |= samdb_acb2uf(r->in.acct_flags);
1402
1403         talloc_free(msg);
1404         msg = ldb_msg_new(mem_ctx);
1405         if (msg == NULL) {
1406                 ldb_transaction_cancel(d_state->sam_ctx);
1407                 return NT_STATUS_NO_MEMORY;
1408         }
1409
1410         msg->dn = ldb_dn_copy(msg, a_state->account_dn);
1411
1412         if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, msg, 
1413                                "userAccountControl", 
1414                                user_account_control) != 0) { 
1415                 ldb_transaction_cancel(d_state->sam_ctx);
1416                 return NT_STATUS_NO_MEMORY; 
1417         }
1418
1419         /* modify the samdb record */
1420         ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
1421         if (ret != 0) {
1422                 DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n",
1423                          ldb_dn_get_linearized(msg->dn),
1424                          ldb_errstring(d_state->sam_ctx)));
1425                 ldb_transaction_cancel(d_state->sam_ctx);
1426
1427                 /* we really need samdb.c to return NTSTATUS */
1428                 return NT_STATUS_UNSUCCESSFUL;
1429         }
1430
1431         ret = ldb_transaction_commit(d_state->sam_ctx);
1432         if (ret != 0) {
1433                 DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n",
1434                          ldb_dn_get_linearized(msg->dn),
1435                          ldb_errstring(d_state->sam_ctx)));
1436                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1437         }
1438
1439         a_state->account_name = talloc_steal(a_state, account_name);
1440         if (!a_state->account_name) {
1441                 return NT_STATUS_NO_MEMORY;
1442         }
1443
1444         /* create the policy handle */
1445         u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
1446         if (!u_handle) {
1447                 return NT_STATUS_NO_MEMORY;
1448         }
1449
1450         u_handle->data = talloc_steal(u_handle, a_state);
1451
1452         *r->out.user_handle = u_handle->wire_handle;
1453         *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1454
1455         *r->out.rid = sid->sub_auths[sid->num_auths-1];
1456
1457         return NT_STATUS_OK;
1458 }
1459
1460
1461 /* 
1462   samr_CreateUser 
1463 */
1464 static NTSTATUS dcesrv_samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1465                                 struct samr_CreateUser *r)
1466 {
1467         struct samr_CreateUser2 r2;
1468         uint32_t access_granted = 0;
1469
1470
1471         /* a simple wrapper around samr_CreateUser2 works nicely */
1472         r2.in.domain_handle = r->in.domain_handle;
1473         r2.in.account_name = r->in.account_name;
1474         r2.in.acct_flags = ACB_NORMAL;
1475         r2.in.access_mask = r->in.access_mask;
1476         r2.out.user_handle = r->out.user_handle;
1477         r2.out.access_granted = &access_granted;
1478         r2.out.rid = r->out.rid;
1479
1480         return dcesrv_samr_CreateUser2(dce_call, mem_ctx, &r2);
1481 }
1482
1483 /* 
1484   samr_EnumDomainUsers 
1485 */
1486 static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1487                                      struct samr_EnumDomainUsers *r)
1488 {
1489         struct dcesrv_handle *h;
1490         struct samr_domain_state *d_state;
1491         struct ldb_result *res;
1492         int ret, num_filtered_entries, i, first;
1493         struct samr_SamEntry *entries;
1494         const char * const attrs[] = { "objectSid", "sAMAccountName", "userAccountControl", NULL };
1495
1496         *r->out.resume_handle = 0;
1497         r->out.sam = NULL;
1498         r->out.num_entries = 0;
1499
1500         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1501
1502         d_state = h->data;
1503         
1504         /* don't have to worry about users in the builtin domain, as there are none */
1505         ret = ldb_search(d_state->sam_ctx, mem_ctx, &res, d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs, "objectClass=user");
1506
1507         if (ret != LDB_SUCCESS) {
1508                 DEBUG(3, ("Failed to search for Domain Users in %s: %s\n", 
1509                           ldb_dn_get_linearized(d_state->domain_dn), ldb_errstring(d_state->sam_ctx)));
1510                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1511         }
1512
1513         /* convert to SamEntry format */
1514         entries = talloc_array(mem_ctx, struct samr_SamEntry, res->count);
1515         if (!entries) {
1516                 return NT_STATUS_NO_MEMORY;
1517         }
1518         num_filtered_entries = 0;
1519         for (i=0;i<res->count;i++) {
1520                 /* Check if a mask has been requested */
1521                 if (r->in.acct_flags
1522                     && ((samdb_result_acct_flags(d_state->sam_ctx, mem_ctx, res->msgs[i], 
1523                                                  d_state->domain_dn) & r->in.acct_flags) == 0)) {
1524                         continue;
1525                 }
1526                 entries[num_filtered_entries].idx = samdb_result_rid_from_sid(mem_ctx, res->msgs[i], "objectSid", 0);
1527                 entries[num_filtered_entries].name.string = samdb_result_string(res->msgs[i], "sAMAccountName", "");
1528                 num_filtered_entries++;
1529         }
1530
1531         /* sort the results by rid */
1532         qsort(entries, num_filtered_entries, sizeof(struct samr_SamEntry), 
1533               (comparison_fn_t)compare_SamEntry);
1534
1535         /* find the first entry to return */
1536         for (first=0;
1537              first<num_filtered_entries && entries[first].idx <= *r->in.resume_handle;
1538              first++) ;
1539
1540         /* return the rest, limit by max_size. Note that we 
1541            use the w2k3 element size value of 54 */
1542         r->out.num_entries = num_filtered_entries - first;
1543         r->out.num_entries = MIN(r->out.num_entries, 
1544                                  1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1545
1546         r->out.sam = talloc(mem_ctx, struct samr_SamArray);
1547         if (!r->out.sam) {
1548                 return NT_STATUS_NO_MEMORY;
1549         }
1550
1551         r->out.sam->entries = entries+first;
1552         r->out.sam->count = r->out.num_entries;
1553
1554         if (first == num_filtered_entries) {
1555                 return NT_STATUS_OK;
1556         }
1557
1558         if (r->out.num_entries < num_filtered_entries - first) {
1559                 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
1560                 return STATUS_MORE_ENTRIES;
1561         }
1562
1563         return NT_STATUS_OK;
1564 }
1565
1566
1567 /* 
1568   samr_CreateDomAlias 
1569 */
1570 static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1571                        struct samr_CreateDomAlias *r)
1572 {
1573         struct samr_domain_state *d_state;
1574         struct samr_account_state *a_state;
1575         struct dcesrv_handle *h;
1576         const char *alias_name, *name;
1577         struct ldb_message *msg;
1578         struct dom_sid *sid;
1579         struct dcesrv_handle *a_handle;
1580         int ret;
1581
1582         ZERO_STRUCTP(r->out.alias_handle);
1583         *r->out.rid = 0;
1584
1585         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1586
1587         d_state = h->data;
1588
1589         if (d_state->builtin) {
1590                 DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain"));
1591                 return NT_STATUS_ACCESS_DENIED;
1592         }
1593
1594         alias_name = r->in.alias_name->string;
1595
1596         if (alias_name == NULL) {
1597                 return NT_STATUS_INVALID_PARAMETER;
1598         }
1599
1600         /* Check if alias already exists */
1601         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1602                                    "sAMAccountName",
1603                                    "(sAMAccountName=%s)(objectclass=group))",
1604                                    ldb_binary_encode_string(mem_ctx, alias_name));
1605
1606         if (name != NULL) {
1607                 return NT_STATUS_ALIAS_EXISTS;
1608         }
1609
1610         msg = ldb_msg_new(mem_ctx);
1611         if (msg == NULL) {
1612                 return NT_STATUS_NO_MEMORY;
1613         }
1614
1615         /* add core elements to the ldb_message for the alias */
1616         msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1617         ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", alias_name);
1618         if (!msg->dn) {
1619                 return NT_STATUS_NO_MEMORY;
1620         }
1621
1622         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", alias_name);
1623         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1624         samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "groupType", GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1625
1626         /* create the alias */
1627         ret = ldb_add(d_state->sam_ctx, msg);
1628         switch (ret) {
1629         case LDB_SUCCESS:
1630                 break;
1631         case LDB_ERR_ENTRY_ALREADY_EXISTS:
1632                 return NT_STATUS_ALIAS_EXISTS;
1633         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1634                 return NT_STATUS_ACCESS_DENIED;
1635         default:
1636                 DEBUG(0,("Failed to create alias record %s: %s\n",
1637                          ldb_dn_get_linearized(msg->dn),
1638                          ldb_errstring(d_state->sam_ctx)));
1639                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1640         }
1641
1642         a_state = talloc(d_state, struct samr_account_state);
1643         if (!a_state) {
1644                 return NT_STATUS_NO_MEMORY;
1645         }
1646
1647         a_state->sam_ctx = d_state->sam_ctx;
1648         a_state->access_mask = r->in.access_mask;
1649         a_state->domain_state = talloc_reference(a_state, d_state);
1650         a_state->account_dn = talloc_steal(a_state, msg->dn);
1651
1652         /* retrieve the sid for the alias just created */
1653         sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1654                                    msg->dn, "objectSid", NULL);
1655
1656         a_state->account_name = talloc_strdup(a_state, alias_name);
1657         if (!a_state->account_name) {
1658                 return NT_STATUS_NO_MEMORY;
1659         }
1660
1661         /* create the policy handle */
1662         a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1663         if (a_handle == NULL)
1664                 return NT_STATUS_NO_MEMORY;
1665
1666         a_handle->data = talloc_steal(a_handle, a_state);
1667
1668         *r->out.alias_handle = a_handle->wire_handle;
1669
1670         *r->out.rid = sid->sub_auths[sid->num_auths-1];
1671
1672         return NT_STATUS_OK;
1673 }
1674
1675
1676 /* 
1677   samr_EnumDomainAliases 
1678 */
1679 static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1680                        struct samr_EnumDomainAliases *r)
1681 {
1682         struct dcesrv_handle *h;
1683         struct samr_domain_state *d_state;
1684         struct ldb_message **res;
1685         int ldb_cnt, count, i, first;
1686         struct samr_SamEntry *entries;
1687         const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1688
1689         *r->out.resume_handle = 0;
1690         r->out.sam = NULL;
1691         r->out.num_entries = 0;
1692
1693         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1694
1695         d_state = h->data;
1696
1697         /* search for all domain groups in this domain. This could possibly be
1698            cached and resumed based on resume_key */
1699         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1700                                       d_state->domain_dn,
1701                                       &res, attrs, 
1702                                       d_state->domain_sid,
1703                                       "(&(|(grouptype=%d)(grouptype=%d)))"
1704                                       "(objectclass=group))",
1705                                       GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1706                                       GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1707         if (ldb_cnt == -1) {
1708                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1709         }
1710         if (ldb_cnt == 0) {
1711                 return NT_STATUS_OK;
1712         }
1713
1714         /* convert to SamEntry format */
1715         entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1716         if (!entries) {
1717                 return NT_STATUS_NO_MEMORY;
1718         }
1719
1720         count = 0;
1721
1722         for (i=0;i<ldb_cnt;i++) {
1723                 struct dom_sid *alias_sid;
1724
1725                 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1726                                                  "objectSid");
1727
1728                 if (alias_sid == NULL)
1729                         continue;
1730
1731                 entries[count].idx =
1732                         alias_sid->sub_auths[alias_sid->num_auths-1];
1733                 entries[count].name.string =
1734                         samdb_result_string(res[i], "sAMAccountName", "");
1735                 count += 1;
1736         }
1737
1738         /* sort the results by rid */
1739         qsort(entries, count, sizeof(struct samr_SamEntry), 
1740               (comparison_fn_t)compare_SamEntry);
1741
1742         /* find the first entry to return */
1743         for (first=0;
1744              first<count && entries[first].idx <= *r->in.resume_handle;
1745              first++) ;
1746
1747         if (first == count) {
1748                 return NT_STATUS_OK;
1749         }
1750
1751         r->out.num_entries = count - first;
1752         r->out.num_entries = MIN(r->out.num_entries, 1000);
1753
1754         r->out.sam = talloc(mem_ctx, struct samr_SamArray);
1755         if (!r->out.sam) {
1756                 return NT_STATUS_NO_MEMORY;
1757         }
1758
1759         r->out.sam->entries = entries+first;
1760         r->out.sam->count = r->out.num_entries;
1761
1762         if (r->out.num_entries < count - first) {
1763                 *r->out.resume_handle =
1764                         entries[first+r->out.num_entries-1].idx;
1765                 return STATUS_MORE_ENTRIES;
1766         }
1767
1768         return NT_STATUS_OK;
1769 }
1770
1771
1772 /* 
1773   samr_GetAliasMembership 
1774 */
1775 static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1776                        struct samr_GetAliasMembership *r)
1777 {
1778         struct dcesrv_handle *h;
1779         struct samr_domain_state *d_state;
1780         struct ldb_message **res;
1781         int i, count = 0;
1782
1783         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1784
1785         d_state = h->data;
1786
1787         if (r->in.sids->num_sids > 0) {
1788                 const char *filter;
1789                 const char * const attrs[2] = { "objectSid", NULL };
1790
1791                 filter = talloc_asprintf(mem_ctx,
1792                                          "(&(|(grouptype=%d)(grouptype=%d))"
1793                                          "(objectclass=group)(|",
1794                                          GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1795                                          GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1796                 if (filter == NULL)
1797                         return NT_STATUS_NO_MEMORY;
1798
1799                 for (i=0; i<r->in.sids->num_sids; i++) {
1800                         const char *memberdn;
1801
1802                         memberdn = 
1803                                 samdb_search_string(d_state->sam_ctx,
1804                                                     mem_ctx, NULL, "distinguishedName",
1805                                                     "(objectSid=%s)",
1806                                                     ldap_encode_ndr_dom_sid(mem_ctx, 
1807                                                                             r->in.sids->sids[i].sid));
1808
1809                         if (memberdn == NULL)
1810                                 continue;
1811
1812                         filter = talloc_asprintf(mem_ctx, "%s(member=%s)",
1813                                                  filter, memberdn);
1814                         if (filter == NULL)
1815                                 return NT_STATUS_NO_MEMORY;
1816                 }
1817
1818                 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1819                                             d_state->domain_dn, &res, attrs,
1820                                             d_state->domain_sid, "%s))", filter);
1821                 if (count < 0)
1822                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1823         }
1824
1825         r->out.rids->count = 0;
1826         r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1827         if (r->out.rids->ids == NULL)
1828                 return NT_STATUS_NO_MEMORY;
1829
1830         for (i=0; i<count; i++) {
1831                 struct dom_sid *alias_sid;
1832
1833                 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1834
1835                 if (alias_sid == NULL) {
1836                         DEBUG(0, ("Could not find objectSid\n"));
1837                         continue;
1838                 }
1839
1840                 r->out.rids->ids[r->out.rids->count] =
1841                         alias_sid->sub_auths[alias_sid->num_auths-1];
1842                 r->out.rids->count += 1;
1843         }
1844
1845         return NT_STATUS_OK;
1846 }
1847
1848
1849 /* 
1850   samr_LookupNames 
1851 */
1852 static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1853                                  struct samr_LookupNames *r)
1854 {
1855         struct dcesrv_handle *h;
1856         struct samr_domain_state *d_state;
1857         int i, num_mapped;
1858         NTSTATUS status = NT_STATUS_OK;
1859         const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1860         int count;
1861
1862         ZERO_STRUCT(r->out.rids);
1863         ZERO_STRUCT(r->out.types);
1864
1865         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1866
1867         d_state = h->data;
1868
1869         if (r->in.num_names == 0) {
1870                 return NT_STATUS_OK;
1871         }
1872
1873         r->out.rids.ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1874         r->out.types.ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1875         if (!r->out.rids.ids || !r->out.types.ids) {
1876                 return NT_STATUS_NO_MEMORY;
1877         }
1878         r->out.rids.count = r->in.num_names;
1879         r->out.types.count = r->in.num_names;
1880
1881         num_mapped = 0;
1882
1883         for (i=0;i<r->in.num_names;i++) {
1884                 struct ldb_message **res;
1885                 struct dom_sid *sid;
1886                 uint32_t atype, rtype;
1887
1888                 r->out.rids.ids[i] = 0;
1889                 r->out.types.ids[i] = SID_NAME_UNKNOWN;
1890
1891                 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs, 
1892                                      "sAMAccountName=%s", 
1893                                      ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1894                 if (count != 1) {
1895                         status = STATUS_SOME_UNMAPPED;
1896                         continue;
1897                 }
1898
1899                 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1900                 if (sid == NULL) {
1901                         status = STATUS_SOME_UNMAPPED;
1902                         continue;
1903                 }
1904                 
1905                 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1906                 if (atype == 0) {
1907                         status = STATUS_SOME_UNMAPPED;
1908                         continue;
1909                 }
1910
1911                 rtype = samdb_atype_map(atype);
1912                 
1913                 if (rtype == SID_NAME_UNKNOWN) {
1914                         status = STATUS_SOME_UNMAPPED;
1915                         continue;
1916                 }
1917
1918                 r->out.rids.ids[i] = sid->sub_auths[sid->num_auths-1];
1919                 r->out.types.ids[i] = rtype;
1920                 num_mapped++;
1921         }
1922         
1923         if (num_mapped == 0) {
1924                 return NT_STATUS_NONE_MAPPED;
1925         }
1926         return status;
1927 }
1928
1929
1930 /* 
1931   samr_LookupRids 
1932 */
1933 static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1934                        struct samr_LookupRids *r)
1935 {
1936         struct dcesrv_handle *h;
1937         struct samr_domain_state *d_state;
1938         int i, total;
1939         NTSTATUS status = NT_STATUS_OK;
1940         struct lsa_String *names;
1941         uint32_t *ids;
1942
1943         ZERO_STRUCT(r->out.names);
1944         ZERO_STRUCT(r->out.types);
1945
1946         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1947
1948         d_state = h->data;
1949
1950         if (r->in.num_rids == 0)
1951                 return NT_STATUS_OK;
1952
1953         names = talloc_array(mem_ctx, struct lsa_String, r->in.num_rids);
1954         ids = talloc_array(mem_ctx, uint32_t, r->in.num_rids);
1955
1956         if ((names == NULL) || (ids == NULL))
1957                 return NT_STATUS_NO_MEMORY;
1958
1959         total = 0;
1960
1961         for (i=0; i<r->in.num_rids; i++) {
1962                 struct ldb_message **res;
1963                 int count;
1964                 const char * const attrs[] = {  "sAMAccountType",
1965                                                 "sAMAccountName", NULL };
1966                 uint32_t atype;
1967                 struct dom_sid *sid;
1968
1969                 ids[i] = SID_NAME_UNKNOWN;
1970
1971                 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rids[i]);
1972                 if (sid == NULL) {
1973                         names[i].string = NULL;
1974                         status = STATUS_SOME_UNMAPPED;
1975                         continue;
1976                 }
1977                 
1978                 count = gendb_search(d_state->sam_ctx, mem_ctx,
1979                                      d_state->domain_dn, &res, attrs,
1980                                      "(objectSid=%s)", 
1981                                      ldap_encode_ndr_dom_sid(mem_ctx, sid));
1982                 if (count != 1) {
1983                         names[i].string = NULL;
1984                         status = STATUS_SOME_UNMAPPED;
1985                         continue;
1986                 }
1987
1988                 names[i].string = samdb_result_string(res[0], "sAMAccountName",
1989                                                       NULL);
1990
1991                 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1992                 if (atype == 0) {
1993                         status = STATUS_SOME_UNMAPPED;
1994                         continue;
1995                 }
1996
1997                 ids[i] = samdb_atype_map(atype);
1998                 
1999                 if (ids[i] == SID_NAME_UNKNOWN) {
2000                         status = STATUS_SOME_UNMAPPED;
2001                         continue;
2002                 }
2003         }
2004
2005         r->out.names.names = names;
2006         r->out.names.count = r->in.num_rids;
2007
2008         r->out.types.ids = ids;
2009         r->out.types.count = r->in.num_rids;
2010
2011         return status;
2012 }
2013
2014
2015 /* 
2016   samr_OpenGroup 
2017 */
2018 static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2019                        struct samr_OpenGroup *r)
2020 {
2021         struct samr_domain_state *d_state;
2022         struct samr_account_state *a_state;
2023         struct dcesrv_handle *h;
2024         const char *groupname;
2025         struct dom_sid *sid;
2026         struct ldb_message **msgs;
2027         struct dcesrv_handle *g_handle;
2028         const char * const attrs[2] = { "sAMAccountName", NULL };
2029         int ret;
2030
2031         ZERO_STRUCTP(r->out.group_handle);
2032
2033         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2034
2035         d_state = h->data;
2036
2037         /* form the group SID */
2038         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2039         if (!sid) {
2040                 return NT_STATUS_NO_MEMORY;
2041         }
2042
2043         /* search for the group record */
2044         ret = gendb_search(d_state->sam_ctx,
2045                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2046                            "(&(objectSid=%s)(objectclass=group)"
2047                            "(grouptype=%d))",
2048                            ldap_encode_ndr_dom_sid(mem_ctx, sid),
2049                            GTYPE_SECURITY_GLOBAL_GROUP);
2050         if (ret == 0) {
2051                 return NT_STATUS_NO_SUCH_GROUP;
2052         }
2053         if (ret != 1) {
2054                 DEBUG(0,("Found %d records matching sid %s\n", 
2055                          ret, dom_sid_string(mem_ctx, sid)));
2056                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2057         }
2058
2059         groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2060         if (groupname == NULL) {
2061                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2062                          dom_sid_string(mem_ctx, sid)));
2063                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2064         }
2065
2066         a_state = talloc(d_state, struct samr_account_state);
2067         if (!a_state) {
2068                 return NT_STATUS_NO_MEMORY;
2069         }
2070         a_state->sam_ctx = d_state->sam_ctx;
2071         a_state->access_mask = r->in.access_mask;
2072         a_state->domain_state = talloc_reference(a_state, d_state);
2073         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2074         a_state->account_sid = talloc_steal(a_state, sid);
2075         a_state->account_name = talloc_strdup(a_state, groupname);
2076         if (!a_state->account_name) {
2077                 return NT_STATUS_NO_MEMORY;
2078         }
2079
2080         /* create the policy handle */
2081         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
2082         if (!g_handle) {
2083                 return NT_STATUS_NO_MEMORY;
2084         }
2085
2086         g_handle->data = talloc_steal(g_handle, a_state);
2087
2088         *r->out.group_handle = g_handle->wire_handle;
2089
2090         return NT_STATUS_OK;
2091 }
2092
2093 /* 
2094   samr_QueryGroupInfo 
2095 */
2096 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2097                        struct samr_QueryGroupInfo *r)
2098 {
2099         struct dcesrv_handle *h;
2100         struct samr_account_state *a_state;
2101         struct ldb_message *msg;
2102         struct ldb_result *res;
2103         const char * const attrs[4] = { "sAMAccountName", "description",
2104                                         "numMembers", NULL };
2105         int ret;
2106
2107         r->out.info = NULL;
2108
2109         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2110
2111         a_state = h->data;
2112         
2113         ret = ldb_search(a_state->sam_ctx, mem_ctx, &res, a_state->account_dn, LDB_SCOPE_SUBTREE, attrs, "objectClass=*");
2114         
2115         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
2116                 return NT_STATUS_NO_SUCH_GROUP;
2117         } else if (ret != LDB_SUCCESS) {
2118                 DEBUG(2, ("Error reading group info: %s\n", ldb_errstring(a_state->sam_ctx)));
2119                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2120         }
2121
2122         if (res->count != 1) {
2123                 DEBUG(2, ("Error finding group info, got %d entries\n", res->count));
2124                 
2125                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2126         }
2127         msg = res->msgs[0];
2128
2129         /* allocate the info structure */
2130         r->out.info = talloc(mem_ctx, union samr_GroupInfo);
2131         if (r->out.info == NULL) {
2132                 return NT_STATUS_NO_MEMORY;
2133         }
2134         ZERO_STRUCTP(r->out.info);
2135
2136         /* Fill in the level */
2137         switch (r->in.level) {
2138         case GROUPINFOALL:
2139                 QUERY_STRING(msg, all.name,        "sAMAccountName");
2140                 r->out.info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2141                 QUERY_UINT  (msg, all.num_members,      "numMembers")
2142                 QUERY_STRING(msg, all.description, "description");
2143                 break;
2144         case GROUPINFONAME:
2145                 QUERY_STRING(msg, name,            "sAMAccountName");
2146                 break;
2147         case GROUPINFOATTRIBUTES:
2148                 r->out.info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2149                 break;
2150         case GROUPINFODESCRIPTION:
2151                 QUERY_STRING(msg, description, "description");
2152                 break;
2153         case GROUPINFOALL2:
2154                 QUERY_STRING(msg, all2.name,        "sAMAccountName");
2155                 r->out.info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2156                 QUERY_UINT  (msg, all2.num_members,      "numMembers")
2157                 QUERY_STRING(msg, all2.description, "description");
2158                 break;
2159         default:
2160                 r->out.info = NULL;
2161                 return NT_STATUS_INVALID_INFO_CLASS;
2162         }
2163         
2164         return NT_STATUS_OK;
2165 }
2166
2167
2168 /* 
2169   samr_SetGroupInfo 
2170 */
2171 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2172                                   struct samr_SetGroupInfo *r)
2173 {
2174         struct dcesrv_handle *h;
2175         struct samr_account_state *g_state;
2176         struct ldb_message *msg;
2177         struct ldb_context *sam_ctx;
2178         int ret;
2179
2180         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2181
2182         g_state = h->data;
2183         sam_ctx = g_state->sam_ctx;
2184
2185         msg = ldb_msg_new(mem_ctx);
2186         if (msg == NULL) {
2187                 return NT_STATUS_NO_MEMORY;
2188         }       
2189
2190         msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
2191         if (!msg->dn) {
2192                 return NT_STATUS_NO_MEMORY;
2193         }
2194
2195         switch (r->in.level) {
2196         case GROUPINFODESCRIPTION:
2197                 SET_STRING(msg, description,         "description");
2198                 break;
2199         case GROUPINFONAME:
2200                 /* On W2k3 this does not change the name, it changes the
2201                  * sAMAccountName attribute */
2202                 SET_STRING(msg, name,                "sAMAccountName");
2203                 break;
2204         case GROUPINFOATTRIBUTES:
2205                 /* This does not do anything obviously visible in W2k3 LDAP */
2206                 return NT_STATUS_OK;
2207         default:
2208                 return NT_STATUS_INVALID_INFO_CLASS;
2209         }
2210
2211         /* modify the samdb record */
2212         ret = ldb_modify(g_state->sam_ctx, msg);
2213         if (ret != 0) {
2214                 /* we really need samdb.c to return NTSTATUS */
2215                 return NT_STATUS_UNSUCCESSFUL;
2216         }
2217
2218         return NT_STATUS_OK;
2219 }
2220
2221
2222 /* 
2223   samr_AddGroupMember 
2224 */
2225 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2226                        struct samr_AddGroupMember *r)
2227 {
2228         struct dcesrv_handle *h;
2229         struct samr_account_state *a_state;
2230         struct samr_domain_state *d_state;
2231         struct ldb_message *mod;
2232         struct dom_sid *membersid;
2233         const char *memberdn;
2234         struct ldb_result *res;
2235         const char * const attrs[] = { NULL };
2236         int ret;
2237
2238         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2239
2240         a_state = h->data;
2241         d_state = a_state->domain_state;
2242
2243         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2244         if (membersid == NULL)
2245                 return NT_STATUS_NO_MEMORY;
2246
2247         /* In native mode, AD can also nest domain groups. Not sure yet
2248          * whether this is also available via RPC. */
2249         ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2250                                  d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2251                                  "(&(objectSid=%s)(objectclass=user))",
2252                                  ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2253
2254         if (ret != 0) {
2255                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2256         }
2257
2258         if (res->count == 0) {
2259                 return NT_STATUS_NO_SUCH_USER;
2260         }
2261                 
2262         if (res->count > 1) {
2263                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2264         }
2265
2266         memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2267
2268         if (memberdn == NULL)
2269                 return NT_STATUS_NO_MEMORY;
2270
2271         mod = ldb_msg_new(mem_ctx);
2272         if (mod == NULL) {
2273                 return NT_STATUS_NO_MEMORY;
2274         }
2275
2276         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2277
2278         if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2279                                  memberdn) != 0)
2280                 return NT_STATUS_UNSUCCESSFUL;
2281
2282         ret = ldb_modify(a_state->sam_ctx, mod);
2283         switch (ret) {
2284         case LDB_SUCCESS:
2285                 return NT_STATUS_OK;
2286         case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
2287                 return NT_STATUS_MEMBER_IN_GROUP;
2288         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2289                 return NT_STATUS_ACCESS_DENIED;
2290         default:
2291                 return NT_STATUS_UNSUCCESSFUL;
2292         }
2293
2294 }
2295
2296
2297 /* 
2298   samr_DeleteDomainGroup 
2299 */
2300 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2301                        struct samr_DeleteDomainGroup *r)
2302 {
2303         struct dcesrv_handle *h;
2304         struct samr_account_state *a_state;
2305         int ret;
2306
2307         *r->out.group_handle = *r->in.group_handle;
2308
2309         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2310
2311         a_state = h->data;
2312
2313         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2314         if (ret != 0) {
2315                 return NT_STATUS_UNSUCCESSFUL;
2316         }
2317
2318         ZERO_STRUCTP(r->out.group_handle);
2319
2320         return NT_STATUS_OK;
2321 }
2322
2323
2324 /* 
2325   samr_DeleteGroupMember 
2326 */
2327 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2328                        struct samr_DeleteGroupMember *r)
2329 {
2330         struct dcesrv_handle *h;
2331         struct samr_account_state *a_state;
2332         struct samr_domain_state *d_state;
2333         struct ldb_message *mod;
2334         struct dom_sid *membersid;
2335         const char *memberdn;
2336         struct ldb_result *res;
2337         const char * const attrs[] = { NULL };
2338         int ret;
2339
2340         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2341
2342         a_state = h->data;
2343         d_state = a_state->domain_state;
2344
2345         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2346         if (membersid == NULL)
2347                 return NT_STATUS_NO_MEMORY;
2348
2349         /* In native mode, AD can also nest domain groups. Not sure yet
2350          * whether this is also available via RPC. */
2351         ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2352                                  d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2353                                  "(&(objectSid=%s)(objectclass=user))",
2354                                  ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2355
2356         if (ret != 0) {
2357                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2358         }
2359
2360         if (res->count == 0) {
2361                 return NT_STATUS_NO_SUCH_USER;
2362         }
2363                 
2364         if (res->count > 1) {
2365                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2366         }
2367
2368         memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2369
2370         if (memberdn == NULL)
2371                 return NT_STATUS_NO_MEMORY;
2372
2373         mod = ldb_msg_new(mem_ctx);
2374         if (mod == NULL) {
2375                 return NT_STATUS_NO_MEMORY;
2376         }
2377
2378         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2379
2380         if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2381                                  memberdn) != 0) {
2382                 return NT_STATUS_NO_MEMORY;
2383         }
2384
2385         ret = ldb_modify(a_state->sam_ctx, mod);
2386         switch (ret) {
2387         case LDB_SUCCESS:
2388                 return NT_STATUS_OK;
2389         case LDB_ERR_NO_SUCH_ATTRIBUTE:
2390                 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2391         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2392                 return NT_STATUS_ACCESS_DENIED;
2393         default:
2394                 return NT_STATUS_UNSUCCESSFUL;
2395         }
2396
2397 }
2398
2399
2400 /* 
2401   samr_QueryGroupMember 
2402 */
2403 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2404                                       struct samr_QueryGroupMember *r)
2405 {
2406         struct dcesrv_handle *h;
2407         struct samr_account_state *a_state;
2408         struct ldb_message **res;
2409         struct ldb_message_element *el;
2410         struct samr_RidTypeArray *array;
2411         const char * const attrs[2] = { "member", NULL };
2412         int ret;
2413
2414         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2415
2416         a_state = h->data;
2417
2418         /* pull the member attribute */
2419         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2420                               a_state->account_dn, &res, attrs);
2421
2422         if (ret != 1) {
2423                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2424         }
2425
2426         array = talloc(mem_ctx, struct samr_RidTypeArray);
2427
2428         if (array == NULL)
2429                 return NT_STATUS_NO_MEMORY;
2430
2431         ZERO_STRUCTP(array);
2432
2433         el = ldb_msg_find_element(res[0], "member");
2434
2435         if (el != NULL) {
2436                 int i;
2437
2438                 array->count = el->num_values;
2439
2440                 array->rids = talloc_array(mem_ctx, uint32_t,
2441                                              el->num_values);
2442                 if (array->rids == NULL)
2443                         return NT_STATUS_NO_MEMORY;
2444
2445                 array->types = talloc_array(mem_ctx, uint32_t,
2446                                             el->num_values);
2447                 if (array->types == NULL)
2448                         return NT_STATUS_NO_MEMORY;
2449
2450                 for (i=0; i<el->num_values; i++) {
2451                         struct ldb_message **res2;
2452                         const char * const attrs2[2] = { "objectSid", NULL };
2453                         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2454                                            ldb_dn_from_ldb_val(mem_ctx, a_state->sam_ctx, &el->values[i]),
2455                                            &res2, attrs2);
2456                         if (ret != 1)
2457                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2458
2459                         array->rids[i] =
2460                                 samdb_result_rid_from_sid(mem_ctx, res2[0],
2461                                                           "objectSid", 0);
2462
2463                         if (array->rids[i] == 0)
2464                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2465
2466                         array->types[i] = 7; /* RID type of some kind, not sure what the value means. */
2467                 }
2468         }
2469
2470         r->out.rids = array;
2471
2472         return NT_STATUS_OK;
2473 }
2474
2475
2476 /* 
2477   samr_SetMemberAttributesOfGroup 
2478 */
2479 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2480                        struct samr_SetMemberAttributesOfGroup *r)
2481 {
2482         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2483 }
2484
2485
2486 /* 
2487   samr_OpenAlias 
2488 */
2489 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2490                        struct samr_OpenAlias *r)
2491 {
2492         struct samr_domain_state *d_state;
2493         struct samr_account_state *a_state;
2494         struct dcesrv_handle *h;
2495         const char *alias_name;
2496         struct dom_sid *sid;
2497         struct ldb_message **msgs;
2498         struct dcesrv_handle *g_handle;
2499         const char * const attrs[2] = { "sAMAccountName", NULL };
2500         int ret;
2501
2502         ZERO_STRUCTP(r->out.alias_handle);
2503
2504         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2505
2506         d_state = h->data;
2507
2508         /* form the alias SID */
2509         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2510         if (sid == NULL)
2511                 return NT_STATUS_NO_MEMORY;
2512
2513         /* search for the group record */
2514         ret = gendb_search(d_state->sam_ctx,
2515                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2516                            "(&(objectSid=%s)(objectclass=group)"
2517                            "(|(grouptype=%d)(grouptype=%d)))",
2518                            ldap_encode_ndr_dom_sid(mem_ctx, sid),
2519                            GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2520                            GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2521         if (ret == 0) {
2522                 return NT_STATUS_NO_SUCH_ALIAS;
2523         }
2524         if (ret != 1) {
2525                 DEBUG(0,("Found %d records matching sid %s\n", 
2526                          ret, dom_sid_string(mem_ctx, sid)));
2527                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2528         }
2529
2530         alias_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2531         if (alias_name == NULL) {
2532                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2533                          dom_sid_string(mem_ctx, sid)));
2534                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2535         }
2536
2537         a_state = talloc(d_state, struct samr_account_state);
2538         if (!a_state) {
2539                 return NT_STATUS_NO_MEMORY;
2540         }
2541         a_state->sam_ctx = d_state->sam_ctx;
2542         a_state->access_mask = r->in.access_mask;
2543         a_state->domain_state = talloc_reference(a_state, d_state);
2544         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2545         a_state->account_sid = talloc_steal(a_state, sid);
2546         a_state->account_name = talloc_strdup(a_state, alias_name);
2547         if (!a_state->account_name) {
2548                 return NT_STATUS_NO_MEMORY;
2549         }
2550
2551         /* create the policy handle */
2552         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2553         if (!g_handle) {
2554                 return NT_STATUS_NO_MEMORY;
2555         }
2556
2557         g_handle->data = talloc_steal(g_handle, a_state);
2558
2559         *r->out.alias_handle = g_handle->wire_handle;
2560
2561         return NT_STATUS_OK;
2562 }
2563
2564
2565 /* 
2566   samr_QueryAliasInfo 
2567 */
2568 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2569                        struct samr_QueryAliasInfo *r)
2570 {
2571         struct dcesrv_handle *h;
2572         struct samr_account_state *a_state;
2573         struct ldb_message *msg, **res;
2574         const char * const attrs[4] = { "sAMAccountName", "description",
2575                                         "numMembers", NULL };
2576         int ret;
2577
2578         r->out.info = NULL;
2579
2580         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2581
2582         a_state = h->data;
2583
2584         /* pull all the alias attributes */
2585         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2586                               a_state->account_dn ,&res, attrs);
2587         if (ret != 1) {
2588                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2589         }
2590         msg = res[0];
2591
2592         /* allocate the info structure */
2593         r->out.info = talloc(mem_ctx, union samr_AliasInfo);
2594         if (r->out.info == NULL) {
2595                 return NT_STATUS_NO_MEMORY;
2596         }
2597         ZERO_STRUCTP(r->out.info);
2598
2599         switch(r->in.level) {
2600         case ALIASINFOALL:
2601                 QUERY_STRING(msg, all.name, "sAMAccountName");
2602                 QUERY_UINT  (msg, all.num_members, "numMembers");
2603                 QUERY_STRING(msg, all.description, "description");
2604                 break;
2605         case ALIASINFONAME:
2606                 QUERY_STRING(msg, name, "sAMAccountName");
2607                 break;
2608         case ALIASINFODESCRIPTION:
2609                 QUERY_STRING(msg, description, "description");
2610                 break;
2611         default:
2612                 r->out.info = NULL;
2613                 return NT_STATUS_INVALID_INFO_CLASS;
2614         }
2615         
2616         return NT_STATUS_OK;
2617 }
2618
2619
2620 /* 
2621   samr_SetAliasInfo 
2622 */
2623 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2624                        struct samr_SetAliasInfo *r)
2625 {
2626         struct dcesrv_handle *h;
2627         struct samr_account_state *a_state;
2628         struct ldb_message *msg;
2629         struct ldb_context *sam_ctx;
2630         int ret;
2631
2632         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2633
2634         a_state = h->data;
2635         sam_ctx = a_state->sam_ctx;
2636
2637         msg = ldb_msg_new(mem_ctx);
2638         if (msg == NULL) {
2639                 return NT_STATUS_NO_MEMORY;
2640         }
2641
2642         msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2643         if (!msg->dn) {
2644                 return NT_STATUS_NO_MEMORY;
2645         }
2646
2647         switch (r->in.level) {
2648         case ALIASINFODESCRIPTION:
2649                 SET_STRING(msg, description,         "description");
2650                 break;
2651         case ALIASINFONAME:
2652                 /* On W2k3 this does not change the name, it changes the
2653                  * sAMAccountName attribute */
2654                 SET_STRING(msg, name,                "sAMAccountName");
2655                 break;
2656         default:
2657                 return NT_STATUS_INVALID_INFO_CLASS;
2658         }
2659
2660         /* modify the samdb record */
2661         ret = ldb_modify(a_state->sam_ctx, msg);
2662         if (ret != 0) {
2663                 /* we really need samdb.c to return NTSTATUS */
2664                 return NT_STATUS_UNSUCCESSFUL;
2665         }
2666
2667         return NT_STATUS_OK;
2668 }
2669
2670
2671 /* 
2672   samr_DeleteDomAlias 
2673 */
2674 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2675                        struct samr_DeleteDomAlias *r)
2676 {
2677         struct dcesrv_handle *h;
2678         struct samr_account_state *a_state;
2679         int ret;
2680
2681         *r->out.alias_handle = *r->in.alias_handle;
2682
2683         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2684
2685         a_state = h->data;
2686
2687         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2688         if (ret != 0) {
2689                 return NT_STATUS_UNSUCCESSFUL;
2690         }
2691
2692         ZERO_STRUCTP(r->out.alias_handle);
2693
2694         return NT_STATUS_OK;
2695 }
2696
2697
2698 /* 
2699   samr_AddAliasMember 
2700 */
2701 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2702                        struct samr_AddAliasMember *r)
2703 {
2704         struct dcesrv_handle *h;
2705         struct samr_account_state *a_state;
2706         struct samr_domain_state *d_state;
2707         struct ldb_message *mod;
2708         struct ldb_message **msgs;
2709         const char * const attrs[] = { NULL };
2710         struct ldb_dn *memberdn = NULL;
2711         int ret;
2712         NTSTATUS status;
2713
2714         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2715
2716         a_state = h->data;
2717         d_state = a_state->domain_state;
2718
2719         ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2720                            &msgs, attrs, "(objectsid=%s)", 
2721                            ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2722
2723         if (ret == 1) {
2724                 memberdn = msgs[0]->dn;
2725         } else  if (ret > 1) {
2726                 DEBUG(0,("Found %d records matching sid %s\n", 
2727                          ret, dom_sid_string(mem_ctx, r->in.sid)));
2728                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2729         } else if (ret == 0) {
2730                 status = samdb_create_foreign_security_principal(d_state->sam_ctx, mem_ctx, 
2731                                                                  r->in.sid, &memberdn);
2732                 if (!NT_STATUS_IS_OK(status)) {
2733                         return status;
2734                 }
2735         } else {
2736                 DEBUG(0, ("samdb_search returned %d: %s\n", ret, ldb_errstring(d_state->sam_ctx)));
2737         }
2738
2739         if (memberdn == NULL) {
2740                 DEBUG(0, ("Could not find memberdn\n"));
2741                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2742         }
2743
2744         mod = ldb_msg_new(mem_ctx);
2745         if (mod == NULL) {
2746                 return NT_STATUS_NO_MEMORY;
2747         }
2748
2749         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2750
2751         if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2752                                  ldb_dn_alloc_linearized(mem_ctx, memberdn)) != 0)
2753                 return NT_STATUS_UNSUCCESSFUL;
2754
2755         if (ldb_modify(a_state->sam_ctx, mod) != 0)
2756                 return NT_STATUS_UNSUCCESSFUL;
2757
2758         return NT_STATUS_OK;
2759 }
2760
2761
2762 /* 
2763   samr_DeleteAliasMember 
2764 */
2765 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2766                        struct samr_DeleteAliasMember *r)
2767 {
2768         struct dcesrv_handle *h;
2769         struct samr_account_state *a_state;
2770         struct samr_domain_state *d_state;
2771         struct ldb_message *mod;
2772         const char *memberdn;
2773
2774         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2775
2776         a_state = h->data;
2777         d_state = a_state->domain_state;
2778
2779         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2780                                        "distinguishedName", "(objectSid=%s)", 
2781                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2782
2783         if (memberdn == NULL)
2784                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2785
2786         mod = ldb_msg_new(mem_ctx);
2787         if (mod == NULL) {
2788                 return NT_STATUS_NO_MEMORY;
2789         }
2790
2791         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2792
2793         if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2794                                  memberdn) != 0)
2795                 return NT_STATUS_UNSUCCESSFUL;
2796
2797         if (ldb_modify(a_state->sam_ctx, mod) != 0)
2798                 return NT_STATUS_UNSUCCESSFUL;
2799
2800         return NT_STATUS_OK;
2801 }
2802
2803
2804 /* 
2805   samr_GetMembersInAlias 
2806 */
2807 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2808                        struct samr_GetMembersInAlias *r)
2809 {
2810         struct dcesrv_handle *h;
2811         struct samr_account_state *a_state;
2812         struct samr_domain_state *d_state;
2813         struct ldb_message **msgs;
2814         struct lsa_SidPtr *sids;
2815         struct ldb_message_element *el;
2816         const char * const attrs[2] = { "member", NULL};
2817         int ret;
2818
2819         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2820
2821         a_state = h->data;
2822         d_state = a_state->domain_state;
2823
2824         ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
2825                               a_state->account_dn, &msgs, attrs);
2826
2827         if (ret != 1)
2828                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2829
2830         r->out.sids->num_sids = 0;
2831         r->out.sids->sids = NULL;
2832
2833         el = ldb_msg_find_element(msgs[0], "member");
2834
2835         if (el != NULL) {
2836                 int i;
2837
2838                 sids = talloc_array(mem_ctx, struct lsa_SidPtr,
2839                                       el->num_values);
2840
2841                 if (sids == NULL)
2842                         return NT_STATUS_NO_MEMORY;
2843
2844                 for (i=0; i<el->num_values; i++) {
2845                         struct ldb_message **msgs2;
2846                         const char * const attrs2[2] = { "objectSid", NULL };
2847                         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2848                                               ldb_dn_new(mem_ctx, a_state->sam_ctx, &el->values[i]),
2849                                               &msgs2, attrs2);
2850                         if (ret != 1)
2851                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2852
2853                         sids[i].sid = samdb_result_dom_sid(mem_ctx, msgs2[0],
2854                                                            "objectSid");
2855
2856                         if (sids[i].sid == NULL)
2857                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2858                 }
2859                 r->out.sids->num_sids = el->num_values;
2860                 r->out.sids->sids = sids;
2861         }
2862
2863         return NT_STATUS_OK;
2864 }
2865
2866 /* 
2867   samr_OpenUser 
2868 */
2869 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2870                               struct samr_OpenUser *r)
2871 {
2872         struct samr_domain_state *d_state;
2873         struct samr_account_state *a_state;
2874         struct dcesrv_handle *h;
2875         const char *account_name;
2876         struct dom_sid *sid;
2877         struct ldb_message **msgs;
2878         struct dcesrv_handle *u_handle;
2879         const char * const attrs[2] = { "sAMAccountName", NULL };
2880         int ret;
2881
2882         ZERO_STRUCTP(r->out.user_handle);
2883
2884         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2885
2886         d_state = h->data;
2887
2888         /* form the users SID */
2889         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2890         if (!sid) {
2891                 return NT_STATUS_NO_MEMORY;
2892         }
2893
2894         /* search for the user record */
2895         ret = gendb_search(d_state->sam_ctx,
2896                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2897                            "(&(objectSid=%s)(objectclass=user))", 
2898                            ldap_encode_ndr_dom_sid(mem_ctx, sid));
2899         if (ret == 0) {
2900                 return NT_STATUS_NO_SUCH_USER;
2901         }
2902         if (ret != 1) {
2903                 DEBUG(0,("Found %d records matching sid %s\n", ret, 
2904                          dom_sid_string(mem_ctx, sid)));
2905                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2906         }
2907
2908         account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2909         if (account_name == NULL) {
2910                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2911                          dom_sid_string(mem_ctx, sid)));
2912                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2913         }
2914
2915         a_state = talloc(mem_ctx, struct samr_account_state);
2916         if (!a_state) {
2917                 return NT_STATUS_NO_MEMORY;
2918         }
2919         a_state->sam_ctx = d_state->sam_ctx;
2920         a_state->access_mask = r->in.access_mask;
2921         a_state->domain_state = talloc_reference(a_state, d_state);
2922         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2923         a_state->account_sid = talloc_steal(a_state, sid);
2924         a_state->account_name = talloc_strdup(a_state, account_name);
2925         if (!a_state->account_name) {
2926                 return NT_STATUS_NO_MEMORY;
2927         }
2928
2929         /* create the policy handle */
2930         u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2931         if (!u_handle) {
2932                 return NT_STATUS_NO_MEMORY;
2933         }
2934
2935         u_handle->data = talloc_steal(u_handle, a_state);
2936
2937         *r->out.user_handle = u_handle->wire_handle;
2938
2939         return NT_STATUS_OK;
2940
2941 }
2942
2943
2944 /* 
2945   samr_DeleteUser 
2946 */
2947 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2948                                 struct samr_DeleteUser *r)
2949 {
2950         struct dcesrv_handle *h;
2951         struct samr_account_state *a_state;
2952         int ret;
2953
2954         *r->out.user_handle = *r->in.user_handle;
2955
2956         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2957
2958         a_state = h->data;
2959
2960         ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2961         if (ret != 0) {
2962                 DEBUG(1, ("Failed to delete user: %s: %s\n", 
2963                           ldb_dn_get_linearized(a_state->account_dn), 
2964                           ldb_errstring(a_state->sam_ctx)));
2965                 return NT_STATUS_UNSUCCESSFUL;
2966         }
2967
2968         ZERO_STRUCTP(r->out.user_handle);
2969
2970         return NT_STATUS_OK;
2971 }
2972
2973
2974 /* 
2975   samr_QueryUserInfo 
2976 */
2977 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2978                                    struct samr_QueryUserInfo *r)
2979 {
2980         struct dcesrv_handle *h;
2981         struct samr_account_state *a_state;
2982         struct ldb_message *msg, **res;
2983         int ret;
2984         struct ldb_context *sam_ctx;
2985
2986         const char * const *attrs = NULL;
2987
2988         r->out.info = NULL;
2989
2990         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2991
2992         a_state = h->data;
2993         sam_ctx = a_state->sam_ctx;
2994
2995         /* fill in the reply */
2996         switch (r->in.level) {
2997         case 1:
2998         {
2999                 static const char * const attrs2[] = {"sAMAccountName", "displayName",
3000                                                       "primaryroupID", "description",
3001                                                       "comment", NULL};
3002                 attrs = attrs2;
3003                 break;
3004         }
3005         case 2:
3006         {
3007                 static const char * const attrs2[] = {"comment", "countryCode", "codePage", NULL};
3008                 attrs = attrs2;
3009                 break;
3010         }
3011         case 3:
3012         {
3013                 static const char * const attrs2[] = {"sAMAccountName",
3014                                                       "displayName",
3015                                                       "objectSid",
3016                                                       "primaryGroupID",
3017                                                       "homeDirectory",
3018                                                       "homeDrive",
3019                                                       "scriptPath",
3020                                                       "profilePath",
3021                                                       "userWorkstations",
3022                                                       "lastLogon",
3023                                                       "lastLogoff",
3024                                                       "pwdLastSet",
3025                                                       "logonHours",
3026                                                       "badPwdCount",
3027                                                       "logonCount",
3028                                                       "userAccountControl", NULL};
3029                 attrs = attrs2;
3030                 break;
3031         }
3032         case 4:
3033         {
3034                 static const char * const attrs2[] = {"logonHours", NULL};
3035                 attrs = attrs2;
3036                 break;
3037         }
3038         case 5:
3039         {
3040                 static const char * const attrs2[] = {"sAMAccountName", 
3041                                                       "displayName",
3042                                                       "objectSid",
3043                                                       "primaryGroupID",
3044                                                       "homeDirectory",
3045                                                       "homeDrive",
3046                                                       "scriptPath", 
3047                                                       "profilePath",
3048                                                       "description",
3049                                                       "userWorkstations",
3050                                                       "lastLogon",
3051                                                       "lastLogoff",
3052                                                       "logonHours",
3053                                                       "badPwdCount",
3054                                                       "logonCount",
3055                                                       "pwdLastSet",
3056                                                       "accountExpires",
3057                                                       "userAccountControl",
3058                                                       NULL};
3059                 attrs = attrs2;
3060                 break;
3061         }
3062         case 6:
3063         {
3064                 static const char * const attrs2[] = {"sAMAccountName", "displayName", NULL};
3065                 attrs = attrs2;
3066                 break;
3067         }
3068         case 7:
3069         {
3070                 static const char * const attrs2[] = {"sAMAccountName", NULL};
3071                 attrs = attrs2;
3072                 break;
3073         }
3074         case 8:
3075         {
3076                 static const char * const attrs2[] = {"displayName", NULL};
3077                 attrs = attrs2;
3078                 break;
3079         }
3080         case 9:
3081         {
3082                 static const char * const attrs2[] = {"primaryGroupID", NULL};
3083                 attrs = attrs2;
3084                 break;
3085         }
3086         case 10:
3087         {
3088                 static const char * const attrs2[] = {"homeDirectory", "homeDrive", NULL};
3089                 attrs = attrs2;
3090                 break;
3091         }
3092         case 11:
3093         {
3094                 static const char * const attrs2[] = {"scriptPath", NULL};
3095                 attrs = attrs2;
3096                 break;
3097         }
3098         case 12:
3099         {
3100                 static const char * const attrs2[] = {"profilePath", NULL};
3101                 attrs = attrs2;
3102                 break;
3103         }
3104         case 13:
3105         {
3106                 static const char * const attrs2[] = {"description", NULL};
3107                 attrs = attrs2;
3108                 break;
3109         }
3110         case 14:
3111         {
3112                 static const char * const attrs2[] = {"userWorkstations", NULL};
3113                 attrs = attrs2;
3114                 break;
3115         }
3116         case 16:
3117         {
3118                 static const char * const attrs2[] = {"userAccountControl", "pwdLastSet", NULL};
3119                 attrs = attrs2;
3120                 break;
3121         }
3122         case 17:
3123         {
3124                 static const char * const attrs2[] = {"accountExpires", NULL};
3125                 attrs = attrs2;
3126                 break;
3127         }
3128         case 20:
3129         {
3130                 static const char * const attrs2[] = {"userParameters", NULL};
3131                 attrs = attrs2;
3132                 break;
3133         }
3134         case 21:
3135         {
3136                 static const char * const attrs2[] = {"lastLogon",
3137                                                       "lastLogoff",
3138                                                       "pwdLastSet",
3139                                                       "accountExpires",
3140                                                       "sAMAccountName",
3141                                                       "displayName",
3142                                                       "homeDirectory",
3143                                                       "homeDrive",
3144                                                       "scriptPath",
3145                                                       "profilePath",
3146                                                       "description",
3147                                                       "userWorkstations",
3148                                                       "comment",
3149                                                       "userParameters",
3150                                                       "objectSid",
3151                                                       "primaryGroupID",
3152                                                       "userAccountControl",
3153                                                       "logonHours",
3154                                                       "badPwdCount",
3155                                                       "logonCount",
3156                                                       "countryCode",
3157                                                       "codePage",
3158                                                       NULL};
3159                 attrs = attrs2;
3160                 break;
3161         }
3162         }
3163
3164         /* pull all the user attributes */
3165         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
3166                               a_state->account_dn ,&res, attrs);
3167         if (ret != 1) {
3168                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3169         }
3170         msg = res[0];
3171
3172         /* allocate the info structure */
3173         r->out.info = talloc(mem_ctx, union samr_UserInfo);
3174         if (r->out.info == NULL) {
3175                 return NT_STATUS_NO_MEMORY;
3176         }
3177         ZERO_STRUCTP(r->out.info);
3178
3179         /* fill in the reply */
3180         switch (r->in.level) {
3181         case 1:
3182                 QUERY_STRING(msg, info1.account_name,          "sAMAccountName");
3183                 QUERY_STRING(msg, info1.full_name,             "displayName");
3184                 QUERY_UINT  (msg, info1.primary_gid,           "primaryGroupID");
3185                 QUERY_STRING(msg, info1.description,           "description");
3186                 QUERY_STRING(msg, info1.comment,               "comment");
3187                 break;
3188
3189         case 2:
3190                 QUERY_STRING(msg, info2.comment,               "comment");
3191                 QUERY_UINT  (msg, info2.country_code,          "countryCode");
3192                 QUERY_UINT  (msg, info2.code_page,             "codePage");
3193                 break;
3194
3195         case 3:
3196                 QUERY_STRING(msg, info3.account_name,          "sAMAccountName");
3197                 QUERY_STRING(msg, info3.full_name,             "displayName");
3198                 QUERY_RID   (msg, info3.rid,                   "objectSid");
3199                 QUERY_UINT  (msg, info3.primary_gid,           "primaryGroupID");
3200                 QUERY_STRING(msg, info3.home_directory,        "homeDirectory");
3201                 QUERY_STRING(msg, info3.home_drive,            "homeDrive");
3202                 QUERY_STRING(msg, info3.logon_script,          "scriptPath");
3203                 QUERY_STRING(msg, info3.profile_path,          "profilePath");
3204                 QUERY_STRING(msg, info3.workstations,          "userWorkstations");
3205                 QUERY_UINT64(msg, info3.last_logon,            "lastLogon");
3206                 QUERY_UINT64(msg, info3.last_logoff,           "lastLogoff");
3207                 QUERY_UINT64(msg, info3.last_password_change,  "pwdLastSet");
3208                 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
3209                 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
3210                 QUERY_LHOURS(msg, info3.logon_hours,           "logonHours");
3211                 QUERY_UINT  (msg, info3.bad_password_count,    "badPwdCount");
3212                 QUERY_UINT  (msg, info3.logon_count,           "logonCount");
3213                 QUERY_AFLAGS(msg, info3.acct_flags,            "userAccountControl");
3214                 break;
3215
3216         case 4:
3217                 QUERY_LHOURS(msg, info4.logon_hours,           "logonHours");
3218                 break;
3219
3220         case 5:
3221                 QUERY_STRING(msg, info5.account_name,          "sAMAccountName");
3222                 QUERY_STRING(msg, info5.full_name,             "displayName");
3223                 QUERY_RID   (msg, info5.rid,                   "objectSid");
3224                 QUERY_UINT  (msg, info5.primary_gid,           "primaryGroupID");
3225                 QUERY_STRING(msg, info5.home_directory,        "homeDirectory");
3226                 QUERY_STRING(msg, info5.home_drive,            "homeDrive");
3227                 QUERY_STRING(msg, info5.logon_script,          "scriptPath");
3228                 QUERY_STRING(msg, info5.profile_path,          "profilePath");
3229                 QUERY_STRING(msg, info5.description,           "description");
3230                 QUERY_STRING(msg, info5.workstations,          "userWorkstations");
3231                 QUERY_UINT64(msg, info5.last_logon,            "lastLogon");
3232                 QUERY_UINT64(msg, info5.last_logoff,           "lastLogoff");
3233                 QUERY_LHOURS(msg, info5.logon_hours,           "logonHours");
3234                 QUERY_UINT  (msg, info5.bad_password_count,    "badPwdCount");
3235                 QUERY_UINT  (msg, info5.logon_count,           "logonCount");
3236                 QUERY_UINT64(msg, info5.last_password_change,  "pwdLastSet");
3237                 QUERY_UINT64(msg, info5.acct_expiry,           "accountExpires");
3238                 QUERY_AFLAGS(msg, info5.acct_flags,            "userAccountControl");
3239                 break;
3240
3241         case 6:
3242                 QUERY_STRING(msg, info6.account_name,   "sAMAccountName");
3243                 QUERY_STRING(msg, info6.full_name,      "displayName");
3244                 break;
3245
3246         case 7:
3247                 QUERY_STRING(msg, info7.account_name,   "sAMAccountName");
3248                 break;
3249
3250         case 8:
3251                 QUERY_STRING(msg, info8.full_name,      "displayName");
3252                 break;
3253
3254         case 9:
3255                 QUERY_UINT  (msg, info9.primary_gid,    "primaryGroupID");
3256                 break;
3257
3258         case 10:
3259                 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3260                 QUERY_STRING(msg, info10.home_drive,    "homeDrive");
3261                 break;
3262
3263         case 11:
3264                 QUERY_STRING(msg, info11.logon_script,  "scriptPath");
3265                 break;
3266
3267         case 12:
3268                 QUERY_STRING(msg, info12.profile_path,  "profilePath");
3269                 break;
3270
3271         case 13:
3272                 QUERY_STRING(msg, info13.description,   "description");
3273                 break;
3274
3275         case 14:
3276                 QUERY_STRING(msg, info14.workstations,  "userWorkstations");
3277                 break;
3278
3279         case 16:
3280                 QUERY_AFLAGS(msg, info16.acct_flags,    "userAccountControl");
3281                 break;
3282
3283         case 17:
3284                 QUERY_UINT64(msg, info17.acct_expiry,   "accountExpires");
3285                 break;
3286
3287         case 20:
3288                 QUERY_STRING(msg, info20.parameters,    "userParameters");
3289                 break;
3290
3291         case 21:
3292                 QUERY_UINT64(msg, info21.last_logon,           "lastLogon");
3293                 QUERY_UINT64(msg, info21.last_logoff,          "lastLogoff");
3294                 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3295                 QUERY_UINT64(msg, info21.acct_expiry,          "accountExpires");
3296                 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3297                 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3298                 QUERY_STRING(msg, info21.account_name,         "sAMAccountName");
3299                 QUERY_STRING(msg, info21.full_name,            "displayName");
3300                 QUERY_STRING(msg, info21.home_directory,       "homeDirectory");
3301                 QUERY_STRING(msg, info21.home_drive,           "homeDrive");
3302                 QUERY_STRING(msg, info21.logon_script,         "scriptPath");
3303                 QUERY_STRING(msg, info21.profile_path,         "profilePath");
3304                 QUERY_STRING(msg, info21.description,          "description");
3305                 QUERY_STRING(msg, info21.workstations,         "userWorkstations");
3306                 QUERY_STRING(msg, info21.comment,              "comment");
3307                 QUERY_STRING(msg, info21.parameters,           "userParameters");
3308                 QUERY_RID   (msg, info21.rid,                  "objectSid");
3309                 QUERY_UINT  (msg, info21.primary_gid,          "primaryGroupID");
3310                 QUERY_AFLAGS(msg, info21.acct_flags,           "userAccountControl");
3311                 r->out.info->info21.fields_present = 0x00FFFFFF;
3312                 QUERY_LHOURS(msg, info21.logon_hours,          "logonHours");
3313                 QUERY_UINT  (msg, info21.bad_password_count,   "badPwdCount");
3314                 QUERY_UINT  (msg, info21.logon_count,          "logonCount");
3315                 QUERY_UINT  (msg, info21.country_code,         "countryCode");
3316                 QUERY_UINT  (msg, info21.code_page,            "codePage");
3317                 break;
3318                 
3319
3320         default:
3321                 r->out.info = NULL;
3322                 return NT_STATUS_INVALID_INFO_CLASS;
3323         }
3324         
3325         return NT_STATUS_OK;
3326 }
3327
3328
3329 /* 
3330   samr_SetUserInfo 
3331 */
3332 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3333                                  struct samr_SetUserInfo *r)
3334 {
3335         struct dcesrv_handle *h;
3336         struct samr_account_state *a_state;
3337         struct ldb_message *msg;
3338         int ret;
3339         NTSTATUS status = NT_STATUS_OK;
3340         struct ldb_context *sam_ctx;
3341
3342         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3343
3344         a_state = h->data;
3345         sam_ctx = a_state->sam_ctx;
3346
3347         msg = ldb_msg_new(mem_ctx);
3348         if (msg == NULL) {
3349                 return NT_STATUS_NO_MEMORY;
3350         }
3351
3352         msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3353         if (!msg->dn) {
3354                 return NT_STATUS_NO_MEMORY;
3355         }
3356
3357         switch (r->in.level) {
3358         case 2:
3359                 SET_STRING(msg, info2.comment,          "comment");
3360                 SET_UINT  (msg, info2.country_code,     "countryCode");
3361                 SET_UINT  (msg, info2.code_page,        "codePage");
3362                 break;
3363
3364         case 4:
3365                 SET_LHOURS(msg, info4.logon_hours,      "logonHours");
3366                 break;
3367
3368         case 6:
3369                 SET_STRING(msg, info6.full_name,        "displayName");
3370                 break;
3371
3372         case 7:
3373                 SET_STRING(msg, info7.account_name,     "samAccountName");
3374                 break;
3375
3376         case 8:
3377                 SET_STRING(msg, info8.full_name,        "displayName");
3378                 break;
3379
3380         case 9:
3381                 SET_UINT(msg, info9.primary_gid,        "primaryGroupID");
3382                 break;
3383
3384         case 10:
3385                 SET_STRING(msg, info10.home_directory,  "homeDirectory");
3386                 SET_STRING(msg, info10.home_drive,      "homeDrive");
3387                 break;
3388
3389         case 11:
3390                 SET_STRING(msg, info11.logon_script,    "scriptPath");
3391                 break;
3392
3393         case 12:
3394                 SET_STRING(msg, info12.profile_path,    "profilePath");
3395                 break;
3396
3397         case 13:
3398                 SET_STRING(msg, info13.description,     "description");
3399                 break;
3400
3401         case 14:
3402                 SET_STRING(msg, info14.workstations,    "userWorkstations");
3403                 break;
3404
3405         case 16:
3406                 SET_AFLAGS(msg, info16.acct_flags,      "userAccountControl");
3407                 break;
3408
3409         case 17:
3410                 SET_UINT64(msg, info17.acct_expiry,     "accountExpires");
3411                 break;
3412
3413         case 20:
3414                 SET_STRING(msg, info20.parameters,      "userParameters");
3415                 break;
3416
3417         case 21:
3418 #define IFSET(bit) if (bit & r->in.info->info21.fields_present) 
3419                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3420                         SET_UINT64(msg, info21.acct_expiry,    "accountExpires");       
3421                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
3422                         SET_STRING(msg, info21.account_name,   "samAccountName");
3423                 IFSET(SAMR_FIELD_FULL_NAME) 
3424                         SET_STRING(msg, info21.full_name,      "displayName");
3425                 IFSET(SAMR_FIELD_DESCRIPTION)
3426                         SET_STRING(msg, info21.description,    "description");
3427                 IFSET(SAMR_FIELD_COMMENT)
3428                         SET_STRING(msg, info21.comment,        "comment");
3429                 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3430                         SET_STRING(msg, info21.logon_script,   "scriptPath");
3431                 IFSET(SAMR_FIELD_PROFILE_PATH)
3432                         SET_STRING(msg, info21.profile_path,   "profilePath");
3433                 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3434                         SET_STRING(msg, info21.home_directory, "homeDirectory");
3435                 IFSET(SAMR_FIELD_HOME_DRIVE)
3436                         SET_STRING(msg, info21.home_drive,     "homeDrive");
3437                 IFSET(SAMR_FIELD_WORKSTATIONS)
3438                         SET_STRING(msg, info21.workstations,   "userWorkstations");
3439                 IFSET(SAMR_FIELD_LOGON_HOURS)
3440                         SET_LHOURS(msg, info21.logon_hours,    "logonHours");
3441                 IFSET(SAMR_FIELD_ACCT_FLAGS)
3442                         SET_AFLAGS(msg, info21.acct_flags,     "userAccountControl");
3443                 IFSET(SAMR_FIELD_PARAMETERS)   
3444                         SET_STRING(msg, info21.parameters,     "userParameters");
3445                 IFSET(SAMR_FIELD_COUNTRY_CODE)
3446                         SET_UINT  (msg, info21.country_code,   "countryCode");
3447                 IFSET(SAMR_FIELD_CODE_PAGE)
3448                         SET_UINT  (msg, info21.code_page,      "codePage");     
3449 #undef IFSET
3450                 break;
3451
3452         case 23:
3453 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3454                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3455                         SET_UINT64(msg, info23.info.acct_expiry,  "accountExpires");    
3456                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
3457                         SET_STRING(msg, info23.info.account_name, "samAccountName");
3458                 IFSET(SAMR_FIELD_FULL_NAME)         
3459                         SET_STRING(msg, info23.info.full_name,    "displayName");
3460                 IFSET(SAMR_FIELD_DESCRIPTION)  
3461                         SET_STRING(msg, info23.info.description,  "description");
3462                 IFSET(SAMR_FIELD_COMMENT)      
3463                         SET_STRING(msg, info23.info.comment,      "comment");
3464                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
3465                         SET_STRING(msg, info23.info.logon_script, "scriptPath");
3466                 IFSET(SAMR_FIELD_PROFILE_PATH)      
3467                         SET_STRING(msg, info23.info.profile_path, "profilePath");
3468                 IFSET(SAMR_FIELD_WORKSTATIONS)  
3469                         SET_STRING(msg, info23.info.workstations, "userWorkstations");
3470                 IFSET(SAMR_FIELD_LOGON_HOURS)  
3471                         SET_LHOURS(msg, info23.info.logon_hours,  "logonHours");
3472                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
3473                         SET_AFLAGS(msg, info23.info.acct_flags,   "userAccountControl");
3474                 IFSET(SAMR_FIELD_PARAMETERS)     
3475                         SET_STRING(msg, info23.info.parameters,   "userParameters");
3476                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
3477                         SET_UINT  (msg, info23.info.country_code, "countryCode");
3478                 IFSET(SAMR_FIELD_CODE_PAGE)    
3479                         SET_UINT  (msg, info23.info.code_page,    "codePage");
3480                 IFSET(SAMR_FIELD_PASSWORD) {
3481                         status = samr_set_password(dce_call,
3482                                &