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