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