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