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