r24973: Try to make it really clear we are dealing with 64 bit numbers here.
[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_UINT64(msg, field, attr) \
48         r->out.info->field = samdb_result_uint64(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                 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "primaryGroupID", DOMAIN_RID_DOMAIN_MEMBERS);
1273
1274         } else if (r->in.acct_flags == ACB_SVRTRUST) {
1275                 if (cn_name[cn_name_len - 1] != '$') {
1276                         return NT_STATUS_FOOBAR;                
1277                 }
1278                 cn_name[cn_name_len - 1] = '\0';
1279                 container = "OU=Domain Controllers";
1280                 obj_class = "computer";
1281                 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "primaryGroupID", DOMAIN_RID_DCS);
1282
1283         } else if (r->in.acct_flags == ACB_DOMTRUST) {
1284                 container = "CN=Users";
1285                 obj_class = "user";
1286
1287         } else {
1288                 ldb_transaction_cancel(d_state->sam_ctx);
1289                 return NT_STATUS_INVALID_PARAMETER;
1290         }
1291
1292         /* add core elements to the ldb_message for the user */
1293         msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1294         if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s,%s", cn_name, container)) {
1295                 ldb_transaction_cancel(d_state->sam_ctx);
1296                 return NT_STATUS_FOOBAR;
1297         }
1298
1299         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", account_name);
1300         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", obj_class);
1301         
1302         /* Start a transaction, so we can query and do a subsequent atomic modify */
1303         
1304         /* create the user */
1305         ret = samdb_add(d_state->sam_ctx, mem_ctx, msg);
1306         switch (ret) {
1307         case  LDB_SUCCESS:
1308                 break;
1309         case  LDB_ERR_ENTRY_ALREADY_EXISTS:
1310                 ldb_transaction_cancel(d_state->sam_ctx);
1311                 DEBUG(0,("Failed to create user record %s: %s\n",
1312                          ldb_dn_get_linearized(msg->dn),
1313                          ldb_errstring(d_state->sam_ctx)));
1314                 return NT_STATUS_USER_EXISTS;
1315         case  LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1316                 ldb_transaction_cancel(d_state->sam_ctx);
1317                 DEBUG(0,("Failed to create user record %s: %s\n",
1318                          ldb_dn_get_linearized(msg->dn),
1319                          ldb_errstring(d_state->sam_ctx)));
1320                 return NT_STATUS_ACCESS_DENIED;
1321         default:
1322                 ldb_transaction_cancel(d_state->sam_ctx);
1323                 DEBUG(0,("Failed to create user record %s: %s\n",
1324                          ldb_dn_get_linearized(msg->dn),
1325                          ldb_errstring(d_state->sam_ctx)));
1326                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1327         }
1328
1329         a_state = talloc(d_state, struct samr_account_state);
1330         if (!a_state) {
1331                 ldb_transaction_cancel(d_state->sam_ctx);
1332                 return NT_STATUS_NO_MEMORY;
1333         }
1334         a_state->sam_ctx = d_state->sam_ctx;
1335         a_state->access_mask = r->in.access_mask;
1336         a_state->domain_state = talloc_reference(a_state, d_state);
1337         a_state->account_dn = talloc_steal(a_state, msg->dn);
1338
1339         /* retrieve the sid and account control bits for the user just created */
1340         ret = gendb_search_dn(d_state->sam_ctx, a_state,
1341                               msg->dn, &msgs, attrs);
1342
1343         if (ret != 1) {
1344                 ldb_transaction_cancel(d_state->sam_ctx);
1345                 DEBUG(0,("Apparently we failed to create an account record, as %s now doesn't exist\n",
1346                          ldb_dn_get_linearized(msg->dn)));
1347                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1348         }
1349         sid = samdb_result_dom_sid(mem_ctx, msgs[0], "objectSid");
1350         if (sid == NULL) {
1351                 ldb_transaction_cancel(d_state->sam_ctx);
1352                 DEBUG(0,("Apparently we failed to get the objectSid of the just created account record %s\n",
1353                          ldb_dn_get_linearized(msg->dn)));
1354                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1355         }
1356
1357         /* Change the account control to be the correct account type.
1358          * The default is for a workstation account */
1359         user_account_control = samdb_result_uint(msgs[0], "userAccountControl", 0);
1360         user_account_control = (user_account_control & 
1361                                 ~(UF_NORMAL_ACCOUNT |
1362                                   UF_INTERDOMAIN_TRUST_ACCOUNT | 
1363                                   UF_WORKSTATION_TRUST_ACCOUNT | 
1364                                   UF_SERVER_TRUST_ACCOUNT));
1365         user_account_control |= samdb_acb2uf(r->in.acct_flags);
1366
1367         talloc_free(msg);
1368         msg = ldb_msg_new(mem_ctx);
1369         if (msg == NULL) {
1370                 ldb_transaction_cancel(d_state->sam_ctx);
1371                 return NT_STATUS_NO_MEMORY;
1372         }
1373
1374         msg->dn = ldb_dn_copy(msg, a_state->account_dn);
1375
1376         if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, msg, 
1377                                "userAccountControl", 
1378                                user_account_control) != 0) { 
1379                 ldb_transaction_cancel(d_state->sam_ctx);
1380                 return NT_STATUS_NO_MEMORY; 
1381         }
1382
1383         /* modify the samdb record */
1384         ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
1385         if (ret != 0) {
1386                 DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n",
1387                          ldb_dn_get_linearized(msg->dn),
1388                          ldb_errstring(d_state->sam_ctx)));
1389                 ldb_transaction_cancel(d_state->sam_ctx);
1390
1391                 /* we really need samdb.c to return NTSTATUS */
1392                 return NT_STATUS_UNSUCCESSFUL;
1393         }
1394
1395         ret = ldb_transaction_commit(d_state->sam_ctx);
1396         if (ret != 0) {
1397                 DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n",
1398                          ldb_dn_get_linearized(msg->dn),
1399                          ldb_errstring(d_state->sam_ctx)));
1400                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1401         }
1402
1403         a_state->account_name = talloc_steal(a_state, account_name);
1404         if (!a_state->account_name) {
1405                 return NT_STATUS_NO_MEMORY;
1406         }
1407
1408         /* create the policy handle */
1409         u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
1410         if (!u_handle) {
1411                 return NT_STATUS_NO_MEMORY;
1412         }
1413
1414         u_handle->data = talloc_steal(u_handle, a_state);
1415
1416         *r->out.user_handle = u_handle->wire_handle;
1417         *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1418
1419         *r->out.rid = sid->sub_auths[sid->num_auths-1];
1420
1421         return NT_STATUS_OK;
1422 }
1423
1424
1425 /* 
1426   samr_CreateUser 
1427 */
1428 static NTSTATUS dcesrv_samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1429                                 struct samr_CreateUser *r)
1430 {
1431         struct samr_CreateUser2 r2;
1432         uint32_t access_granted = 0;
1433
1434
1435         /* a simple wrapper around samr_CreateUser2 works nicely */
1436         r2.in.domain_handle = r->in.domain_handle;
1437         r2.in.account_name = r->in.account_name;
1438         r2.in.acct_flags = ACB_NORMAL;
1439         r2.in.access_mask = r->in.access_mask;
1440         r2.out.user_handle = r->out.user_handle;
1441         r2.out.access_granted = &access_granted;
1442         r2.out.rid = r->out.rid;
1443
1444         return dcesrv_samr_CreateUser2(dce_call, mem_ctx, &r2);
1445 }
1446
1447 /* 
1448   samr_EnumDomainUsers 
1449 */
1450 static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1451                                      struct samr_EnumDomainUsers *r)
1452 {
1453         struct dcesrv_handle *h;
1454         struct samr_domain_state *d_state;
1455         struct ldb_message **res;
1456         int count, num_filtered_entries, i, first;
1457         struct samr_SamEntry *entries;
1458         const char * const attrs[] = { "objectSid", "sAMAccountName", "userAccountControl", NULL };
1459
1460         *r->out.resume_handle = 0;
1461         r->out.sam = NULL;
1462         r->out.num_entries = 0;
1463
1464         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1465
1466         d_state = h->data;
1467         
1468         /* search for all users in this domain. This could possibly be cached and 
1469            resumed based on resume_key */
1470         count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs, 
1471                              "objectclass=user");
1472         if (count == -1) {
1473                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1474         }
1475         if (count == 0 || r->in.max_size == 0) {
1476                 return NT_STATUS_OK;
1477         }
1478
1479         /* convert to SamEntry format */
1480         entries = talloc_array(mem_ctx, struct samr_SamEntry, count);
1481         if (!entries) {
1482                 return NT_STATUS_NO_MEMORY;
1483         }
1484         num_filtered_entries = 0;
1485         for (i=0;i<count;i++) {
1486                 /* Check if a mask has been requested */
1487                 if (r->in.acct_flags
1488                     && ((samdb_result_acct_flags(res[i], 
1489                                                  "userAccountControl") & r->in.acct_flags) == 0)) {
1490                         continue;
1491                 }
1492                 entries[num_filtered_entries].idx = samdb_result_rid_from_sid(mem_ctx, res[i], "objectSid", 0);
1493                 entries[num_filtered_entries].name.string = samdb_result_string(res[i], "sAMAccountName", "");
1494                 num_filtered_entries++;
1495         }
1496
1497         /* sort the results by rid */
1498         qsort(entries, num_filtered_entries, sizeof(struct samr_SamEntry), 
1499               (comparison_fn_t)compare_SamEntry);
1500
1501         /* find the first entry to return */
1502         for (first=0;
1503              first<num_filtered_entries && entries[first].idx <= *r->in.resume_handle;
1504              first++) ;
1505
1506         /* return the rest, limit by max_size. Note that we 
1507            use the w2k3 element size value of 54 */
1508         r->out.num_entries = num_filtered_entries - first;
1509         r->out.num_entries = MIN(r->out.num_entries, 
1510                                  1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1511
1512         r->out.sam = talloc(mem_ctx, struct samr_SamArray);
1513         if (!r->out.sam) {
1514                 return NT_STATUS_NO_MEMORY;
1515         }
1516
1517         r->out.sam->entries = entries+first;
1518         r->out.sam->count = r->out.num_entries;
1519
1520         if (first == num_filtered_entries) {
1521                 return NT_STATUS_OK;
1522         }
1523
1524         if (r->out.num_entries < num_filtered_entries - first) {
1525                 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
1526                 return STATUS_MORE_ENTRIES;
1527         }
1528
1529         return NT_STATUS_OK;
1530 }
1531
1532
1533 /* 
1534   samr_CreateDomAlias 
1535 */
1536 static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1537                        struct samr_CreateDomAlias *r)
1538 {
1539         struct samr_domain_state *d_state;
1540         struct samr_account_state *a_state;
1541         struct dcesrv_handle *h;
1542         const char *alias_name, *name;
1543         struct ldb_message *msg;
1544         struct dom_sid *sid;
1545         struct dcesrv_handle *a_handle;
1546         int ret;
1547
1548         ZERO_STRUCTP(r->out.alias_handle);
1549         *r->out.rid = 0;
1550
1551         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1552
1553         d_state = h->data;
1554
1555         alias_name = r->in.alias_name->string;
1556
1557         if (alias_name == NULL) {
1558                 return NT_STATUS_INVALID_PARAMETER;
1559         }
1560
1561         /* Check if alias already exists */
1562         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1563                                    "sAMAccountName",
1564                                    "(sAMAccountName=%s)(objectclass=group))",
1565                                    ldb_binary_encode_string(mem_ctx, alias_name));
1566
1567         if (name != NULL) {
1568                 return NT_STATUS_ALIAS_EXISTS;
1569         }
1570
1571         msg = ldb_msg_new(mem_ctx);
1572         if (msg == NULL) {
1573                 return NT_STATUS_NO_MEMORY;
1574         }
1575
1576         /* add core elements to the ldb_message for the alias */
1577         msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1578         ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", alias_name);
1579         if (!msg->dn) {
1580                 return NT_STATUS_NO_MEMORY;
1581         }
1582
1583         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", alias_name);
1584         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1585         samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "groupType", GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1586
1587         /* create the alias */
1588         ret = samdb_add(d_state->sam_ctx, mem_ctx, msg);
1589         switch (ret) {
1590         case LDB_SUCCESS:
1591                 break;
1592         case LDB_ERR_ENTRY_ALREADY_EXISTS:
1593                 return NT_STATUS_ALIAS_EXISTS;
1594         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1595                 return NT_STATUS_ACCESS_DENIED;
1596         default:
1597                 DEBUG(0,("Failed to create alias record %s: %s\n",
1598                          ldb_dn_get_linearized(msg->dn),
1599                          ldb_errstring(d_state->sam_ctx)));
1600                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1601         }
1602
1603         a_state = talloc(d_state, struct samr_account_state);
1604         if (!a_state) {
1605                 return NT_STATUS_NO_MEMORY;
1606         }
1607
1608         a_state->sam_ctx = d_state->sam_ctx;
1609         a_state->access_mask = r->in.access_mask;
1610         a_state->domain_state = talloc_reference(a_state, d_state);
1611         a_state->account_dn = talloc_steal(a_state, msg->dn);
1612
1613         /* retrieve the sid for the alias just created */
1614         sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1615                                    msg->dn, "objectSid", NULL);
1616
1617         a_state->account_name = talloc_strdup(a_state, alias_name);
1618         if (!a_state->account_name) {
1619                 return NT_STATUS_NO_MEMORY;
1620         }
1621
1622         /* create the policy handle */
1623         a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1624         if (a_handle == NULL)
1625                 return NT_STATUS_NO_MEMORY;
1626
1627         a_handle->data = talloc_steal(a_handle, a_state);
1628
1629         *r->out.alias_handle = a_handle->wire_handle;
1630
1631         *r->out.rid = sid->sub_auths[sid->num_auths-1];
1632
1633         return NT_STATUS_OK;
1634 }
1635
1636
1637 /* 
1638   samr_EnumDomainAliases 
1639 */
1640 static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1641                        struct samr_EnumDomainAliases *r)
1642 {
1643         struct dcesrv_handle *h;
1644         struct samr_domain_state *d_state;
1645         struct ldb_message **res;
1646         int ldb_cnt, count, i, first;
1647         struct samr_SamEntry *entries;
1648         const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1649
1650         *r->out.resume_handle = 0;
1651         r->out.sam = NULL;
1652         r->out.num_entries = 0;
1653
1654         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1655
1656         d_state = h->data;
1657
1658         /* search for all domain groups in this domain. This could possibly be
1659            cached and resumed based on resume_key */
1660         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1661                                       d_state->domain_dn,
1662                                       &res, attrs, 
1663                                       d_state->domain_sid,
1664                                       "(&(|(grouptype=%d)(grouptype=%d)))"
1665                                       "(objectclass=group))",
1666                                       GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1667                                       GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1668         if (ldb_cnt == -1) {
1669                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1670         }
1671         if (ldb_cnt == 0) {
1672                 return NT_STATUS_OK;
1673         }
1674
1675         /* convert to SamEntry format */
1676         entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1677         if (!entries) {
1678                 return NT_STATUS_NO_MEMORY;
1679         }
1680
1681         count = 0;
1682
1683         for (i=0;i<ldb_cnt;i++) {
1684                 struct dom_sid *alias_sid;
1685
1686                 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1687                                                  "objectSid");
1688
1689                 if (alias_sid == NULL)
1690                         continue;
1691
1692                 entries[count].idx =
1693                         alias_sid->sub_auths[alias_sid->num_auths-1];
1694                 entries[count].name.string =
1695                         samdb_result_string(res[i], "sAMAccountName", "");
1696                 count += 1;
1697         }
1698
1699         /* sort the results by rid */
1700         qsort(entries, count, sizeof(struct samr_SamEntry), 
1701               (comparison_fn_t)compare_SamEntry);
1702
1703         /* find the first entry to return */
1704         for (first=0;
1705              first<count && entries[first].idx <= *r->in.resume_handle;
1706              first++) ;
1707
1708         if (first == count) {
1709                 return NT_STATUS_OK;
1710         }
1711
1712         r->out.num_entries = count - first;
1713         r->out.num_entries = MIN(r->out.num_entries, 1000);
1714
1715         r->out.sam = talloc(mem_ctx, struct samr_SamArray);
1716         if (!r->out.sam) {
1717                 return NT_STATUS_NO_MEMORY;
1718         }
1719
1720         r->out.sam->entries = entries+first;
1721         r->out.sam->count = r->out.num_entries;
1722
1723         if (r->out.num_entries < count - first) {
1724                 *r->out.resume_handle =
1725                         entries[first+r->out.num_entries-1].idx;
1726                 return STATUS_MORE_ENTRIES;
1727         }
1728
1729         return NT_STATUS_OK;
1730 }
1731
1732
1733 /* 
1734   samr_GetAliasMembership 
1735 */
1736 static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1737                        struct samr_GetAliasMembership *r)
1738 {
1739         struct dcesrv_handle *h;
1740         struct samr_domain_state *d_state;
1741         struct ldb_message **res;
1742         int i, count = 0;
1743
1744         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1745
1746         d_state = h->data;
1747
1748         if (r->in.sids->num_sids > 0) {
1749                 const char *filter;
1750                 const char * const attrs[2] = { "objectSid", NULL };
1751
1752                 filter = talloc_asprintf(mem_ctx,
1753                                          "(&(|(grouptype=%d)(grouptype=%d))"
1754                                          "(objectclass=group)(|",
1755                                          GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1756                                          GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1757                 if (filter == NULL)
1758                         return NT_STATUS_NO_MEMORY;
1759
1760                 for (i=0; i<r->in.sids->num_sids; i++) {
1761                         const char *memberdn;
1762
1763                         memberdn = 
1764                                 samdb_search_string(d_state->sam_ctx,
1765                                                     mem_ctx, NULL, "distinguishedName",
1766                                                     "(objectSid=%s)",
1767                                                     ldap_encode_ndr_dom_sid(mem_ctx, 
1768                                                                             r->in.sids->sids[i].sid));
1769
1770                         if (memberdn == NULL)
1771                                 continue;
1772
1773                         filter = talloc_asprintf(mem_ctx, "%s(member=%s)",
1774                                                  filter, memberdn);
1775                         if (filter == NULL)
1776                                 return NT_STATUS_NO_MEMORY;
1777                 }
1778
1779                 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1780                                             d_state->domain_dn, &res, attrs,
1781                                             d_state->domain_sid, "%s))", filter);
1782                 if (count < 0)
1783                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1784         }
1785
1786         r->out.rids->count = 0;
1787         r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1788         if (r->out.rids->ids == NULL)
1789                 return NT_STATUS_NO_MEMORY;
1790
1791         for (i=0; i<count; i++) {
1792                 struct dom_sid *alias_sid;
1793
1794                 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1795
1796                 if (alias_sid == NULL) {
1797                         DEBUG(0, ("Could not find objectSid\n"));
1798                         continue;
1799                 }
1800
1801                 r->out.rids->ids[r->out.rids->count] =
1802                         alias_sid->sub_auths[alias_sid->num_auths-1];
1803                 r->out.rids->count += 1;
1804         }
1805
1806         return NT_STATUS_OK;
1807 }
1808
1809
1810 /* 
1811   samr_LookupNames 
1812 */
1813 static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1814                                  struct samr_LookupNames *r)
1815 {
1816         struct dcesrv_handle *h;
1817         struct samr_domain_state *d_state;
1818         int i, num_mapped;
1819         NTSTATUS status = NT_STATUS_OK;
1820         const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1821         int count;
1822
1823         ZERO_STRUCT(r->out.rids);
1824         ZERO_STRUCT(r->out.types);
1825
1826         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1827
1828         d_state = h->data;
1829
1830         if (r->in.num_names == 0) {
1831                 return NT_STATUS_OK;
1832         }
1833
1834         r->out.rids.ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1835         r->out.types.ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1836         if (!r->out.rids.ids || !r->out.types.ids) {
1837                 return NT_STATUS_NO_MEMORY;
1838         }
1839         r->out.rids.count = r->in.num_names;
1840         r->out.types.count = r->in.num_names;
1841
1842         num_mapped = 0;
1843
1844         for (i=0;i<r->in.num_names;i++) {
1845                 struct ldb_message **res;
1846                 struct dom_sid *sid;
1847                 uint32_t atype, rtype;
1848
1849                 r->out.rids.ids[i] = 0;
1850                 r->out.types.ids[i] = SID_NAME_UNKNOWN;
1851
1852                 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs, 
1853                                      "sAMAccountName=%s", 
1854                                      ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1855                 if (count != 1) {
1856                         status = STATUS_SOME_UNMAPPED;
1857                         continue;
1858                 }
1859
1860                 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1861                 if (sid == NULL) {
1862                         status = STATUS_SOME_UNMAPPED;
1863                         continue;
1864                 }
1865                 
1866                 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1867                 if (atype == 0) {
1868                         status = STATUS_SOME_UNMAPPED;
1869                         continue;
1870                 }
1871
1872                 rtype = samdb_atype_map(atype);
1873                 
1874                 if (rtype == SID_NAME_UNKNOWN) {
1875                         status = STATUS_SOME_UNMAPPED;
1876                         continue;
1877                 }
1878
1879                 r->out.rids.ids[i] = sid->sub_auths[sid->num_auths-1];
1880                 r->out.types.ids[i] = rtype;
1881                 num_mapped++;
1882         }
1883         
1884         if (num_mapped == 0) {
1885                 return NT_STATUS_NONE_MAPPED;
1886         }
1887         return status;
1888 }
1889
1890
1891 /* 
1892   samr_LookupRids 
1893 */
1894 static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1895                        struct samr_LookupRids *r)
1896 {
1897         struct dcesrv_handle *h;
1898         struct samr_domain_state *d_state;
1899         int i, total;
1900         NTSTATUS status = NT_STATUS_OK;
1901         struct lsa_String *names;
1902         uint32_t *ids;
1903
1904         ZERO_STRUCT(r->out.names);
1905         ZERO_STRUCT(r->out.types);
1906
1907         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1908
1909         d_state = h->data;
1910
1911         if (r->in.num_rids == 0)
1912                 return NT_STATUS_OK;
1913
1914         names = talloc_array(mem_ctx, struct lsa_String, r->in.num_rids);
1915         ids = talloc_array(mem_ctx, uint32_t, r->in.num_rids);
1916
1917         if ((names == NULL) || (ids == NULL))
1918                 return NT_STATUS_NO_MEMORY;
1919
1920         total = 0;
1921
1922         for (i=0; i<r->in.num_rids; i++) {
1923                 struct ldb_message **res;
1924                 int count;
1925                 const char * const attrs[] = {  "sAMAccountType",
1926                                                 "sAMAccountName", NULL };
1927                 uint32_t atype;
1928                 struct dom_sid *sid;
1929
1930                 ids[i] = SID_NAME_UNKNOWN;
1931
1932                 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rids[i]);
1933                 if (sid == NULL) {
1934                         names[i].string = NULL;
1935                         status = STATUS_SOME_UNMAPPED;
1936                         continue;
1937                 }
1938                 
1939                 count = gendb_search(d_state->sam_ctx, mem_ctx,
1940                                      d_state->domain_dn, &res, attrs,
1941                                      "(objectSid=%s)", 
1942                                      ldap_encode_ndr_dom_sid(mem_ctx, sid));
1943                 if (count != 1) {
1944                         names[i].string = NULL;
1945                         status = STATUS_SOME_UNMAPPED;
1946                         continue;
1947                 }
1948
1949                 names[i].string = samdb_result_string(res[0], "sAMAccountName",
1950                                                       NULL);
1951
1952                 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1953                 if (atype == 0) {
1954                         status = STATUS_SOME_UNMAPPED;
1955                         continue;
1956                 }
1957
1958                 ids[i] = samdb_atype_map(atype);
1959                 
1960                 if (ids[i] == SID_NAME_UNKNOWN) {
1961                         status = STATUS_SOME_UNMAPPED;
1962                         continue;
1963                 }
1964         }
1965
1966         r->out.names.names = names;
1967         r->out.names.count = r->in.num_rids;
1968
1969         r->out.types.ids = ids;
1970         r->out.types.count = r->in.num_rids;
1971
1972         return status;
1973 }
1974
1975
1976 /* 
1977   samr_OpenGroup 
1978 */
1979 static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1980                        struct samr_OpenGroup *r)
1981 {
1982         struct samr_domain_state *d_state;
1983         struct samr_account_state *a_state;
1984         struct dcesrv_handle *h;
1985         const char *groupname;
1986         struct dom_sid *sid;
1987         struct ldb_message **msgs;
1988         struct dcesrv_handle *g_handle;
1989         const char * const attrs[2] = { "sAMAccountName", NULL };
1990         int ret;
1991
1992         ZERO_STRUCTP(r->out.group_handle);
1993
1994         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1995
1996         d_state = h->data;
1997
1998         /* form the group SID */
1999         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2000         if (!sid) {
2001                 return NT_STATUS_NO_MEMORY;
2002         }
2003
2004         /* search for the group record */
2005         ret = gendb_search(d_state->sam_ctx,
2006                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2007                            "(&(objectSid=%s)(objectclass=group)"
2008                            "(grouptype=%d))",
2009                            ldap_encode_ndr_dom_sid(mem_ctx, sid),
2010                            GTYPE_SECURITY_GLOBAL_GROUP);
2011         if (ret == 0) {
2012                 return NT_STATUS_NO_SUCH_GROUP;
2013         }
2014         if (ret != 1) {
2015                 DEBUG(0,("Found %d records matching sid %s\n", 
2016                          ret, dom_sid_string(mem_ctx, sid)));
2017                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2018         }
2019
2020         groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2021         if (groupname == NULL) {
2022                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2023                          dom_sid_string(mem_ctx, sid)));
2024                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2025         }
2026
2027         a_state = talloc(d_state, struct samr_account_state);
2028         if (!a_state) {
2029                 return NT_STATUS_NO_MEMORY;
2030         }
2031         a_state->sam_ctx = d_state->sam_ctx;
2032         a_state->access_mask = r->in.access_mask;
2033         a_state->domain_state = talloc_reference(a_state, d_state);
2034         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2035         a_state->account_sid = talloc_steal(a_state, sid);
2036         a_state->account_name = talloc_strdup(a_state, groupname);
2037         if (!a_state->account_name) {
2038                 return NT_STATUS_NO_MEMORY;
2039         }
2040
2041         /* create the policy handle */
2042         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
2043         if (!g_handle) {
2044                 return NT_STATUS_NO_MEMORY;
2045         }
2046
2047         g_handle->data = talloc_steal(g_handle, a_state);
2048
2049         *r->out.group_handle = g_handle->wire_handle;
2050
2051         return NT_STATUS_OK;
2052 }
2053
2054 /* 
2055   samr_QueryGroupInfo 
2056 */
2057 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2058                        struct samr_QueryGroupInfo *r)
2059 {
2060         struct dcesrv_handle *h;
2061         struct samr_account_state *a_state;
2062         struct ldb_message *msg, **res;
2063         const char * const attrs[4] = { "sAMAccountName", "description",
2064                                         "numMembers", NULL };
2065         int ret;
2066
2067         r->out.info = NULL;
2068
2069         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2070
2071         a_state = h->data;
2072
2073         /* pull all the group attributes */
2074         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2075                               a_state->account_dn, &res, attrs);
2076         if (ret != 1) {
2077                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2078         }
2079         msg = res[0];
2080
2081         /* allocate the info structure */
2082         r->out.info = talloc(mem_ctx, union samr_GroupInfo);
2083         if (r->out.info == NULL) {
2084                 return NT_STATUS_NO_MEMORY;
2085         }
2086         ZERO_STRUCTP(r->out.info);
2087
2088         /* Fill in the level */
2089         switch (r->in.level) {
2090         case GROUPINFOALL:
2091                 QUERY_STRING(msg, all.name,        "sAMAccountName");
2092                 r->out.info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2093                 QUERY_UINT  (msg, all.num_members,      "numMembers")
2094                 QUERY_STRING(msg, all.description, "description");
2095                 break;
2096         case GROUPINFONAME:
2097                 QUERY_STRING(msg, name,            "sAMAccountName");
2098                 break;
2099         case GROUPINFOATTRIBUTES:
2100                 r->out.info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2101                 break;
2102         case GROUPINFODESCRIPTION:
2103                 QUERY_STRING(msg, description, "description");
2104                 break;
2105         case GROUPINFOALL2:
2106                 QUERY_STRING(msg, all2.name,        "sAMAccountName");
2107                 r->out.info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2108                 QUERY_UINT  (msg, all2.num_members,      "numMembers")
2109                 QUERY_STRING(msg, all2.description, "description");
2110                 break;
2111         default:
2112                 r->out.info = NULL;
2113                 return NT_STATUS_INVALID_INFO_CLASS;
2114         }
2115         
2116         return NT_STATUS_OK;
2117 }
2118
2119
2120 /* 
2121   samr_SetGroupInfo 
2122 */
2123 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2124                                   struct samr_SetGroupInfo *r)
2125 {
2126         struct dcesrv_handle *h;
2127         struct samr_account_state *g_state;
2128         struct ldb_message *msg;
2129         struct ldb_context *sam_ctx;
2130         int ret;
2131
2132         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2133
2134         g_state = h->data;
2135         sam_ctx = g_state->sam_ctx;
2136
2137         msg = ldb_msg_new(mem_ctx);
2138         if (msg == NULL) {
2139                 return NT_STATUS_NO_MEMORY;
2140         }       
2141
2142         msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
2143         if (!msg->dn) {
2144                 return NT_STATUS_NO_MEMORY;
2145         }
2146
2147         switch (r->in.level) {
2148         case GROUPINFODESCRIPTION:
2149                 SET_STRING(msg, description,         "description");
2150                 break;
2151         case GROUPINFONAME:
2152                 /* On W2k3 this does not change the name, it changes the
2153                  * sAMAccountName attribute */
2154                 SET_STRING(msg, name,                "sAMAccountName");
2155                 break;
2156         case GROUPINFOATTRIBUTES:
2157                 /* This does not do anything obviously visible in W2k3 LDAP */
2158                 return NT_STATUS_OK;
2159         default:
2160                 return NT_STATUS_INVALID_INFO_CLASS;
2161         }
2162
2163         /* modify the samdb record */
2164         ret = ldb_modify(g_state->sam_ctx, msg);
2165         if (ret != 0) {
2166                 /* we really need samdb.c to return NTSTATUS */
2167                 return NT_STATUS_UNSUCCESSFUL;
2168         }
2169
2170         return NT_STATUS_OK;
2171 }
2172
2173
2174 /* 
2175   samr_AddGroupMember 
2176 */
2177 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2178                        struct samr_AddGroupMember *r)
2179 {
2180         struct dcesrv_handle *h;
2181         struct samr_account_state *a_state;
2182         struct samr_domain_state *d_state;
2183         struct ldb_message *mod;
2184         struct dom_sid *membersid;
2185         const char *memberdn;
2186         struct ldb_result *res;
2187         const char * const attrs[] = { NULL };
2188         int ret;
2189
2190         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2191
2192         a_state = h->data;
2193         d_state = a_state->domain_state;
2194
2195         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2196         if (membersid == NULL)
2197                 return NT_STATUS_NO_MEMORY;
2198
2199         /* In native mode, AD can also nest domain groups. Not sure yet
2200          * whether this is also available via RPC. */
2201         ret = ldb_search_exp_fmt(d_state->sam_ctx, mem_ctx, &res,
2202                                  d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2203                                  "(&(objectSid=%s)(objectclass=user))",
2204                                  ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2205
2206         if (ret != 0) {
2207                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2208         }
2209
2210         if (res->count == 0) {
2211                 return NT_STATUS_NO_SUCH_USER;
2212         }
2213                 
2214         if (res->count > 1) {
2215                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2216         }
2217
2218         memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2219
2220         if (memberdn == NULL)
2221                 return NT_STATUS_NO_MEMORY;
2222
2223         mod = ldb_msg_new(mem_ctx);
2224         if (mod == NULL) {
2225                 return NT_STATUS_NO_MEMORY;
2226         }
2227
2228         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2229
2230         if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2231                                  memberdn) != 0)
2232                 return NT_STATUS_UNSUCCESSFUL;
2233
2234         ret = ldb_modify(a_state->sam_ctx, mod);
2235         switch (ret) {
2236         case LDB_SUCCESS:
2237                 return NT_STATUS_OK;
2238         case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
2239                 return NT_STATUS_MEMBER_IN_GROUP;
2240         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2241                 return NT_STATUS_ACCESS_DENIED;
2242         default:
2243                 return NT_STATUS_UNSUCCESSFUL;
2244         }
2245
2246 }
2247
2248
2249 /* 
2250   samr_DeleteDomainGroup 
2251 */
2252 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2253                        struct samr_DeleteDomainGroup *r)
2254 {
2255         struct dcesrv_handle *h;
2256         struct samr_account_state *a_state;
2257         int ret;
2258
2259         *r->out.group_handle = *r->in.group_handle;
2260
2261         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2262
2263         a_state = h->data;
2264
2265         ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
2266         if (ret != 0) {
2267                 return NT_STATUS_UNSUCCESSFUL;
2268         }
2269
2270         ZERO_STRUCTP(r->out.group_handle);
2271
2272         return NT_STATUS_OK;
2273 }
2274
2275
2276 /* 
2277   samr_DeleteGroupMember 
2278 */
2279 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2280                        struct samr_DeleteGroupMember *r)
2281 {
2282         struct dcesrv_handle *h;
2283         struct samr_account_state *a_state;
2284         struct samr_domain_state *d_state;
2285         struct ldb_message *mod;
2286         struct dom_sid *membersid;
2287         const char *memberdn;
2288         struct ldb_result *res;
2289         const char * const attrs[] = { NULL };
2290         int ret;
2291
2292         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2293
2294         a_state = h->data;
2295         d_state = a_state->domain_state;
2296
2297         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2298         if (membersid == NULL)
2299                 return NT_STATUS_NO_MEMORY;
2300
2301         /* In native mode, AD can also nest domain groups. Not sure yet
2302          * whether this is also available via RPC. */
2303         ret = ldb_search_exp_fmt(d_state->sam_ctx, mem_ctx, &res,
2304                                  d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2305                                  "(&(objectSid=%s)(objectclass=user))",
2306                                  ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2307
2308         if (ret != 0) {
2309                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2310         }
2311
2312         if (res->count == 0) {
2313                 return NT_STATUS_NO_SUCH_USER;
2314         }
2315                 
2316         if (res->count > 1) {
2317                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2318         }
2319
2320         memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2321
2322         if (memberdn == NULL)
2323                 return NT_STATUS_NO_MEMORY;
2324
2325         mod = ldb_msg_new(mem_ctx);
2326         if (mod == NULL) {
2327                 return NT_STATUS_NO_MEMORY;
2328         }
2329
2330         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2331
2332         if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2333                                  memberdn) != 0) {
2334                 return NT_STATUS_NO_MEMORY;
2335         }
2336
2337         ret = ldb_modify(a_state->sam_ctx, mod);
2338         switch (ret) {
2339         case LDB_SUCCESS:
2340                 return NT_STATUS_OK;
2341         case LDB_ERR_NO_SUCH_ATTRIBUTE:
2342                 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2343         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2344                 return NT_STATUS_ACCESS_DENIED;
2345         default:
2346                 return NT_STATUS_UNSUCCESSFUL;
2347         }
2348
2349 }
2350
2351
2352 /* 
2353   samr_QueryGroupMember 
2354 */
2355 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2356                                       struct samr_QueryGroupMember *r)
2357 {
2358         struct dcesrv_handle *h;
2359         struct samr_account_state *a_state;
2360         struct ldb_message **res;
2361         struct ldb_message_element *el;
2362         struct samr_RidTypeArray *array;
2363         const char * const attrs[2] = { "member", NULL };
2364         int ret;
2365
2366         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2367
2368         a_state = h->data;
2369
2370         /* pull the member attribute */
2371         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2372                               a_state->account_dn, &res, attrs);
2373
2374         if (ret != 1) {
2375                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2376         }
2377
2378         array = talloc(mem_ctx, struct samr_RidTypeArray);
2379
2380         if (array == NULL)
2381                 return NT_STATUS_NO_MEMORY;
2382
2383         ZERO_STRUCTP(array);
2384
2385         el = ldb_msg_find_element(res[0], "member");
2386
2387         if (el != NULL) {
2388                 int i;
2389
2390                 array->count = el->num_values;
2391
2392                 array->rids = talloc_array(mem_ctx, uint32_t,
2393                                              el->num_values);
2394                 if (array->rids == NULL)
2395                         return NT_STATUS_NO_MEMORY;
2396
2397                 array->types = talloc_array(mem_ctx, uint32_t,
2398                                             el->num_values);
2399                 if (array->types == NULL)
2400                         return NT_STATUS_NO_MEMORY;
2401
2402                 for (i=0; i<el->num_values; i++) {
2403                         struct ldb_message **res2;
2404                         const char * const attrs2[2] = { "objectSid", NULL };
2405                         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2406                                            ldb_dn_new(mem_ctx, a_state->sam_ctx, (const char *)el->values[i].data),
2407                                            &res2, attrs2);
2408                         if (ret != 1)
2409                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2410
2411                         array->rids[i] =
2412                                 samdb_result_rid_from_sid(mem_ctx, res2[0],
2413                                                           "objectSid", 0);
2414
2415                         if (array->rids[i] == 0)
2416                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2417
2418                         array->types[i] = 7; /* RID type of some kind, not sure what the value means. */
2419                 }
2420         }
2421
2422         r->out.rids = array;
2423
2424         return NT_STATUS_OK;
2425 }
2426
2427
2428 /* 
2429   samr_SetMemberAttributesOfGroup 
2430 */
2431 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2432                        struct samr_SetMemberAttributesOfGroup *r)
2433 {
2434         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2435 }
2436
2437
2438 /* 
2439   samr_OpenAlias 
2440 */
2441 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2442                        struct samr_OpenAlias *r)
2443 {
2444         struct samr_domain_state *d_state;
2445         struct samr_account_state *a_state;
2446         struct dcesrv_handle *h;
2447         const char *alias_name;
2448         struct dom_sid *sid;
2449         struct ldb_message **msgs;
2450         struct dcesrv_handle *g_handle;
2451         const char * const attrs[2] = { "sAMAccountName", NULL };
2452         int ret;
2453
2454         ZERO_STRUCTP(r->out.alias_handle);
2455
2456         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2457
2458         d_state = h->data;
2459
2460         /* form the alias SID */
2461         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2462         if (sid == NULL)
2463                 return NT_STATUS_NO_MEMORY;
2464
2465         /* search for the group record */
2466         ret = gendb_search(d_state->sam_ctx,
2467                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2468                            "(&(objectSid=%s)(objectclass=group)"
2469                            "(|(grouptype=%d)(grouptype=%d)))",
2470                            ldap_encode_ndr_dom_sid(mem_ctx, sid),
2471                            GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2472                            GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2473         if (ret == 0) {
2474                 return NT_STATUS_NO_SUCH_ALIAS;
2475         }
2476         if (ret != 1) {
2477                 DEBUG(0,("Found %d records matching sid %s\n", 
2478                          ret, dom_sid_string(mem_ctx, sid)));
2479                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2480         }
2481
2482         alias_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2483         if (alias_name == NULL) {
2484                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2485                          dom_sid_string(mem_ctx, sid)));
2486                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2487         }
2488
2489         a_state = talloc(d_state, struct samr_account_state);
2490         if (!a_state) {
2491                 return NT_STATUS_NO_MEMORY;
2492         }
2493         a_state->sam_ctx = d_state->sam_ctx;
2494         a_state->access_mask = r->in.access_mask;
2495         a_state->domain_state = talloc_reference(a_state, d_state);
2496         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2497         a_state->account_sid = talloc_steal(a_state, sid);
2498         a_state->account_name = talloc_strdup(a_state, alias_name);
2499         if (!a_state->account_name) {
2500                 return NT_STATUS_NO_MEMORY;
2501         }
2502
2503         /* create the policy handle */
2504         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2505         if (!g_handle) {
2506                 return NT_STATUS_NO_MEMORY;
2507         }
2508
2509         g_handle->data = talloc_steal(g_handle, a_state);
2510
2511         *r->out.alias_handle = g_handle->wire_handle;
2512
2513         return NT_STATUS_OK;
2514 }
2515
2516
2517 /* 
2518   samr_QueryAliasInfo 
2519 */
2520 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2521                        struct samr_QueryAliasInfo *r)
2522 {
2523         struct dcesrv_handle *h;
2524         struct samr_account_state *a_state;
2525         struct ldb_message *msg, **res;
2526         const char * const attrs[4] = { "sAMAccountName", "description",
2527                                         "numMembers", NULL };
2528         int ret;
2529
2530         r->out.info = NULL;
2531
2532         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2533
2534         a_state = h->data;
2535
2536         /* pull all the alias attributes */
2537         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2538                               a_state->account_dn ,&res, attrs);
2539         if (ret != 1) {
2540                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2541         }
2542         msg = res[0];
2543
2544         /* allocate the info structure */
2545         r->out.info = talloc(mem_ctx, union samr_AliasInfo);
2546         if (r->out.info == NULL) {
2547                 return NT_STATUS_NO_MEMORY;
2548         }
2549         ZERO_STRUCTP(r->out.info);
2550
2551         switch(r->in.level) {
2552         case ALIASINFOALL:
2553                 QUERY_STRING(msg, all.name, "sAMAccountName");
2554                 QUERY_UINT  (msg, all.num_members, "numMembers");
2555                 QUERY_STRING(msg, all.description, "description");
2556                 break;
2557         case ALIASINFONAME:
2558                 QUERY_STRING(msg, name, "sAMAccountName");
2559                 break;
2560         case ALIASINFODESCRIPTION:
2561                 QUERY_STRING(msg, description, "description");
2562                 break;
2563         default:
2564                 r->out.info = NULL;
2565                 return NT_STATUS_INVALID_INFO_CLASS;
2566         }
2567         
2568         return NT_STATUS_OK;
2569 }
2570
2571
2572 /* 
2573   samr_SetAliasInfo 
2574 */
2575 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2576                        struct samr_SetAliasInfo *r)
2577 {
2578         struct dcesrv_handle *h;
2579         struct samr_account_state *a_state;
2580         struct ldb_message *msg;
2581         struct ldb_context *sam_ctx;
2582         int ret;
2583
2584         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2585
2586         a_state = h->data;
2587         sam_ctx = a_state->sam_ctx;
2588
2589         msg = ldb_msg_new(mem_ctx);
2590         if (msg == NULL) {
2591                 return NT_STATUS_NO_MEMORY;
2592         }
2593
2594         msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2595         if (!msg->dn) {
2596                 return NT_STATUS_NO_MEMORY;
2597         }
2598
2599         switch (r->in.level) {
2600         case ALIASINFODESCRIPTION:
2601                 SET_STRING(msg, description,         "description");
2602                 break;
2603         case ALIASINFONAME:
2604                 /* On W2k3 this does not change the name, it changes the
2605                  * sAMAccountName attribute */
2606                 SET_STRING(msg, name,                "sAMAccountName");
2607                 break;
2608         default:
2609                 return NT_STATUS_INVALID_INFO_CLASS;
2610         }
2611
2612         /* modify the samdb record */
2613         ret = ldb_modify(a_state->sam_ctx, msg);
2614         if (ret != 0) {
2615                 /* we really need samdb.c to return NTSTATUS */
2616                 return NT_STATUS_UNSUCCESSFUL;
2617         }
2618
2619         return NT_STATUS_OK;
2620 }
2621
2622
2623 /* 
2624   samr_DeleteDomAlias 
2625 */
2626 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2627                        struct samr_DeleteDomAlias *r)
2628 {
2629         struct dcesrv_handle *h;
2630         struct samr_account_state *a_state;
2631         int ret;
2632
2633         *r->out.alias_handle = *r->in.alias_handle;
2634
2635         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2636
2637         a_state = h->data;
2638
2639         ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
2640         if (ret != 0) {
2641                 return NT_STATUS_UNSUCCESSFUL;
2642         }
2643
2644         ZERO_STRUCTP(r->out.alias_handle);
2645
2646         return NT_STATUS_OK;
2647 }
2648
2649
2650 /* 
2651   samr_AddAliasMember 
2652 */
2653 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2654                        struct samr_AddAliasMember *r)
2655 {
2656         struct dcesrv_handle *h;
2657         struct samr_account_state *a_state;
2658         struct samr_domain_state *d_state;
2659         struct ldb_message *mod;
2660         struct ldb_message **msgs;
2661         const char * const attrs[] = { NULL };
2662         struct ldb_dn *memberdn = NULL;
2663         int ret;
2664         NTSTATUS status;
2665
2666         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2667
2668         a_state = h->data;
2669         d_state = a_state->domain_state;
2670
2671         ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2672                            &msgs, attrs, "(objectsid=%s)", 
2673                            ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2674
2675         if (ret == 1) {
2676                 memberdn = msgs[0]->dn;
2677         } else  if (ret > 1) {
2678                 DEBUG(0,("Found %d records matching sid %s\n", 
2679                          ret, dom_sid_string(mem_ctx, r->in.sid)));
2680                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2681         } else if (ret == 0) {
2682                 status = samdb_create_foreign_security_principal(d_state->sam_ctx, mem_ctx, 
2683                                                                  r->in.sid, &memberdn);
2684                 if (!NT_STATUS_IS_OK(status)) {
2685                         return status;
2686                 }
2687         } else {
2688                 DEBUG(0, ("samdb_search returned %d: %s\n", ret, ldb_errstring(d_state->sam_ctx)));
2689         }
2690
2691         if (memberdn == NULL) {
2692                 DEBUG(0, ("Could not find memberdn\n"));
2693                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2694         }
2695
2696         mod = ldb_msg_new(mem_ctx);
2697         if (mod == NULL) {
2698                 return NT_STATUS_NO_MEMORY;
2699         }
2700
2701         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2702
2703         if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2704                                  ldb_dn_alloc_linearized(mem_ctx, memberdn)) != 0)
2705                 return NT_STATUS_UNSUCCESSFUL;
2706
2707         if (ldb_modify(a_state->sam_ctx, mod) != 0)
2708                 return NT_STATUS_UNSUCCESSFUL;
2709
2710         return NT_STATUS_OK;
2711 }
2712
2713
2714 /* 
2715   samr_DeleteAliasMember 
2716 */
2717 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2718                        struct samr_DeleteAliasMember *r)
2719 {
2720         struct dcesrv_handle *h;
2721         struct samr_account_state *a_state;
2722         struct samr_domain_state *d_state;
2723         struct ldb_message *mod;
2724         const char *memberdn;
2725
2726         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2727
2728         a_state = h->data;
2729         d_state = a_state->domain_state;
2730
2731         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2732                                        "distinguishedName", "(objectSid=%s)", 
2733                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2734
2735         if (memberdn == NULL)
2736                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2737
2738         mod = ldb_msg_new(mem_ctx);
2739         if (mod == NULL) {
2740                 return NT_STATUS_NO_MEMORY;
2741         }
2742
2743         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2744
2745         if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2746                                  memberdn) != 0)
2747                 return NT_STATUS_UNSUCCESSFUL;
2748
2749         if (ldb_modify(a_state->sam_ctx, mod) != 0)
2750                 return NT_STATUS_UNSUCCESSFUL;
2751
2752         return NT_STATUS_OK;
2753 }
2754
2755
2756 /* 
2757   samr_GetMembersInAlias 
2758 */
2759 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2760                        struct samr_GetMembersInAlias *r)
2761 {
2762         struct dcesrv_handle *h;
2763         struct samr_account_state *a_state;
2764         struct samr_domain_state *d_state;
2765         struct ldb_message **msgs;
2766         struct lsa_SidPtr *sids;
2767         struct ldb_message_element *el;
2768         const char * const attrs[2] = { "member", NULL};
2769         int ret;
2770
2771         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2772
2773         a_state = h->data;
2774         d_state = a_state->domain_state;
2775
2776         ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
2777                               a_state->account_dn, &msgs, attrs);
2778
2779         if (ret != 1)
2780                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2781
2782         r->out.sids->num_sids = 0;
2783         r->out.sids->sids = NULL;
2784
2785         el = ldb_msg_find_element(msgs[0], "member");
2786
2787         if (el != NULL) {
2788                 int i;
2789
2790                 sids = talloc_array(mem_ctx, struct lsa_SidPtr,
2791                                       el->num_values);
2792
2793                 if (sids == NULL)
2794                         return NT_STATUS_NO_MEMORY;
2795
2796                 for (i=0; i<el->num_values; i++) {
2797                         struct ldb_message **msgs2;
2798                         const char * const attrs2[2] = { "objectSid", NULL };
2799                         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2800                                            ldb_dn_new(mem_ctx, a_state->sam_ctx, (const char *)el->values[i].data),
2801                                            &msgs2, attrs2);
2802                         if (ret != 1)
2803                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2804
2805                         sids[i].sid = samdb_result_dom_sid(mem_ctx, msgs2[0],
2806                                                            "objectSid");
2807
2808                         if (sids[i].sid == NULL)
2809                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2810                 }
2811                 r->out.sids->num_sids = el->num_values;
2812                 r->out.sids->sids = sids;
2813         }
2814
2815         return NT_STATUS_OK;
2816 }
2817
2818 /* 
2819   samr_OpenUser 
2820 */
2821 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2822                               struct samr_OpenUser *r)
2823 {
2824         struct samr_domain_state *d_state;
2825         struct samr_account_state *a_state;
2826         struct dcesrv_handle *h;
2827         const char *account_name;
2828         struct dom_sid *sid;
2829         struct ldb_message **msgs;
2830         struct dcesrv_handle *u_handle;
2831         const char * const attrs[2] = { "sAMAccountName", NULL };
2832         int ret;
2833
2834         ZERO_STRUCTP(r->out.user_handle);
2835
2836         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2837
2838         d_state = h->data;
2839
2840         /* form the users SID */
2841         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2842         if (!sid) {
2843                 return NT_STATUS_NO_MEMORY;
2844         }
2845
2846         /* search for the user record */
2847         ret = gendb_search(d_state->sam_ctx,
2848                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2849                            "(&(objectSid=%s)(objectclass=user))", 
2850                            ldap_encode_ndr_dom_sid(mem_ctx, sid));
2851         if (ret == 0) {
2852                 return NT_STATUS_NO_SUCH_USER;
2853         }
2854         if (ret != 1) {
2855                 DEBUG(0,("Found %d records matching sid %s\n", ret, 
2856                          dom_sid_string(mem_ctx, sid)));
2857                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2858         }
2859
2860         account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2861         if (account_name == NULL) {
2862                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2863                          dom_sid_string(mem_ctx, sid)));
2864                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2865         }
2866
2867         a_state = talloc(mem_ctx, struct samr_account_state);
2868         if (!a_state) {
2869                 return NT_STATUS_NO_MEMORY;
2870         }
2871         a_state->sam_ctx = d_state->sam_ctx;
2872         a_state->access_mask = r->in.access_mask;
2873         a_state->domain_state = talloc_reference(a_state, d_state);
2874         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2875         a_state->account_sid = talloc_steal(a_state, sid);
2876         a_state->account_name = talloc_strdup(a_state, account_name);
2877         if (!a_state->account_name) {
2878                 return NT_STATUS_NO_MEMORY;
2879         }
2880
2881         /* create the policy handle */
2882         u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2883         if (!u_handle) {
2884                 return NT_STATUS_NO_MEMORY;
2885         }
2886
2887         u_handle->data = talloc_steal(u_handle, a_state);
2888
2889         *r->out.user_handle = u_handle->wire_handle;
2890
2891         return NT_STATUS_OK;
2892
2893 }
2894
2895
2896 /* 
2897   samr_DeleteUser 
2898 */
2899 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2900                                 struct samr_DeleteUser *r)
2901 {
2902         struct dcesrv_handle *h;
2903         struct samr_account_state *a_state;
2904         int ret;
2905
2906         *r->out.user_handle = *r->in.user_handle;
2907
2908         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2909
2910         a_state = h->data;
2911
2912         ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
2913         if (ret != 0) {
2914                 return NT_STATUS_UNSUCCESSFUL;
2915         }
2916
2917         ZERO_STRUCTP(r->out.user_handle);
2918
2919         return NT_STATUS_OK;
2920 }
2921
2922
2923 /* 
2924   samr_QueryUserInfo 
2925 */
2926 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2927                                    struct samr_QueryUserInfo *r)
2928 {
2929         struct dcesrv_handle *h;
2930         struct samr_account_state *a_state;
2931         struct ldb_message *msg, **res;
2932         int ret;
2933         struct ldb_context *sam_ctx;
2934
2935         const char * const *attrs = NULL;
2936
2937         r->out.info = NULL;
2938
2939         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2940
2941         a_state = h->data;
2942         sam_ctx = a_state->sam_ctx;
2943
2944         /* fill in the reply */
2945         switch (r->in.level) {
2946         case 1:
2947         {
2948                 static const char * const attrs2[] = {"sAMAccountName", "displayName",
2949                                                       "primaryGroupID", "description",
2950                                                       "comment", NULL};
2951                 attrs = attrs2;
2952                 break;
2953         }
2954         case 2:
2955         {
2956                 static const char * const attrs2[] = {"comment", "countryCode", "codePage", NULL};
2957                 attrs = attrs2;
2958                 break;
2959         }
2960         case 3:
2961         {
2962                 static const char * const attrs2[] = {"sAMAccountName",
2963                                                       "displayName",
2964                                                       "objectSid",
2965                                                       "primaryGroupID",
2966                                                       "homeDirectory",
2967                                                       "homeDrive",
2968                                                       "scriptPath",
2969                                                       "profilePath",
2970                                                       "userWorkstations",
2971                                                       "lastLogon",
2972                                                       "lastLogoff",
2973                                                       "pwdLastSet",
2974                                                       "logonHours",
2975                                                       "badPwdCount",
2976                                                       "logonCount",
2977                                                       "userAccountControl", NULL};
2978                 attrs = attrs2;
2979                 break;
2980         }
2981         case 4:
2982         {
2983                 static const char * const attrs2[] = {"logonHours", NULL};
2984                 attrs = attrs2;
2985                 break;
2986         }
2987         case 5:
2988         {
2989                 static const char * const attrs2[] = {"sAMAccountName", 
2990                                                       "displayName",
2991                                                       "objectSid",
2992                                                       "primaryGroupID",
2993                                                       "homeDirectory",
2994                                                       "homeDrive",
2995                                                       "scriptPath", 
2996                                                       "profilePath",
2997                                                       "description",
2998                                                       "userWorkstations",
2999                                                       "lastLogon",
3000                                                       "lastLogoff",
3001                                                       "logonHours",
3002                                                       "badPwdCount",
3003                                                       "logonCount",
3004                                                       "pwdLastSet",
3005                                                       "accountExpires",
3006                                                       "userAccountControl",
3007                                                       NULL};
3008                 attrs = attrs2;
3009                 break;
3010         }
3011         case 6:
3012         {
3013                 static const char * const attrs2[] = {"sAMAccountName", "displayName", NULL};
3014                 attrs = attrs2;
3015                 break;
3016         }
3017         case 7:
3018         {
3019                 static const char * const attrs2[] = {"sAMAccountName", NULL};
3020                 attrs = attrs2;
3021                 break;
3022         }
3023         case 8:
3024         {
3025                 static const char * const attrs2[] = {"displayName", NULL};
3026                 attrs = attrs2;
3027                 break;
3028         }
3029         case 9:
3030         {
3031                 static const char * const attrs2[] = {"primaryGroupID", NULL};
3032                 attrs = attrs2;
3033                 break;
3034         }
3035         case 10:
3036         {
3037                 static const char * const attrs2[] = {"homeDirectory", "homeDrive", NULL};
3038                 attrs = attrs2;
3039                 break;
3040         }
3041         case 11:
3042         {
3043                 static const char * const attrs2[] = {"scriptPath", NULL};
3044                 attrs = attrs2;
3045                 break;
3046         }
3047         case 12:
3048         {
3049                 static const char * const attrs2[] = {"profilePath", NULL};
3050                 attrs = attrs2;
3051                 break;
3052         }
3053         case 13:
3054         {
3055                 static const char * const attrs2[] = {"description", NULL};
3056                 attrs = attrs2;
3057                 break;
3058         }
3059         case 14:
3060         {
3061                 static const char * const attrs2[] = {"userWorkstations", NULL};
3062                 attrs = attrs2;
3063                 break;
3064         }
3065         case 16:
3066         {
3067                 static const char * const attrs2[] = {"userAccountControl", NULL};
3068                 attrs = attrs2;
3069                 break;
3070         }
3071         case 17:
3072         {
3073                 static const char * const attrs2[] = {"accountExpires", NULL};
3074                 attrs = attrs2;
3075                 break;
3076         }
3077         case 20:
3078         {
3079                 static const char * const attrs2[] = {"userParameters", NULL};
3080                 attrs = attrs2;
3081                 break;
3082         }
3083         case 21:
3084         {
3085                 static const char * const attrs2[] = {"lastLogon",
3086                                                       "lastLogoff",
3087                                                       "pwdLastSet",
3088                                                       "accountExpires",
3089                                                       "sAMAccountName",
3090                                                       "displayName",
3091                                                       "homeDirectory",
3092                                                       "homeDrive",
3093                                                       "scriptPath",
3094                                                       "profilePath",
3095                                                       "description",
3096                                                       "userWorkstations",
3097                                                       "comment",
3098                                                       "userParameters",
3099                                                       "objectSid",
3100                                                       "primaryGroupID",
3101                                                       "userAccountControl",
3102                                                       "logonHours",
3103                                                       "badPwdCount",
3104                                                       "logonCount",
3105                                                       "countryCode",
3106                                                       "codePage",
3107                                                       NULL};
3108                 attrs = attrs2;
3109                 break;
3110         }
3111         }
3112
3113         /* pull all the user attributes */
3114         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
3115                               a_state->account_dn ,&res, attrs);
3116         if (ret != 1) {
3117                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3118         }
3119         msg = res[0];
3120
3121         /* allocate the info structure */
3122         r->out.info = talloc(mem_ctx, union samr_UserInfo);
3123         if (r->out.info == NULL) {
3124                 return NT_STATUS_NO_MEMORY;
3125         }
3126         ZERO_STRUCTP(r->out.info);
3127
3128         /* fill in the reply */
3129         switch (r->in.level) {
3130         case 1:
3131                 QUERY_STRING(msg, info1.account_name,          "sAMAccountName");
3132                 QUERY_STRING(msg, info1.full_name,             "displayName");
3133                 QUERY_UINT  (msg, info1.primary_gid,           "primaryGroupID");
3134                 QUERY_STRING(msg, info1.description,           "description");
3135                 QUERY_STRING(msg, info1.comment,               "comment");
3136                 break;
3137
3138         case 2:
3139                 QUERY_STRING(msg, info2.comment,               "comment");
3140                 QUERY_UINT  (msg, info2.country_code,          "countryCode");
3141                 QUERY_UINT  (msg, info2.code_page,             "codePage");
3142                 break;
3143
3144         case 3:
3145                 QUERY_STRING(msg, info3.account_name,          "sAMAccountName");
3146                 QUERY_STRING(msg, info3.full_name,             "displayName");
3147                 QUERY_RID   (msg, info3.rid,                   "objectSid");
3148                 QUERY_UINT  (msg, info3.primary_gid,           "primaryGroupID");
3149                 QUERY_STRING(msg, info3.home_directory,        "homeDirectory");
3150                 QUERY_STRING(msg, info3.home_drive,            "homeDrive");
3151                 QUERY_STRING(msg, info3.logon_script,          "scriptPath");
3152                 QUERY_STRING(msg, info3.profile_path,          "profilePath");
3153                 QUERY_STRING(msg, info3.workstations,          "userWorkstations");
3154                 QUERY_UINT64(msg, info3.last_logon,            "lastLogon");
3155                 QUERY_UINT64(msg, info3.last_logoff,           "lastLogoff");
3156                 QUERY_UINT64(msg, info3.last_password_change,  "pwdLastSet");
3157                 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
3158                 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
3159                 QUERY_LHOURS(msg, info3.logon_hours,           "logonHours");
3160                 QUERY_UINT  (msg, info3.bad_password_count,    "badPwdCount");
3161                 QUERY_UINT  (msg, info3.logon_count,           "logonCount");
3162                 QUERY_AFLAGS(msg, info3.acct_flags,            "userAccountControl");
3163                 break;
3164
3165         case 4:
3166                 QUERY_LHOURS(msg, info4.logon_hours,           "logonHours");
3167                 break;
3168
3169         case 5:
3170                 QUERY_STRING(msg, info5.account_name,          "sAMAccountName");
3171                 QUERY_STRING(msg, info5.full_name,             "displayName");
3172                 QUERY_RID   (msg, info5.rid,                   "objectSid");
3173                 QUERY_UINT  (msg, info5.primary_gid,           "primaryGroupID");
3174                 QUERY_STRING(msg, info5.home_directory,        "homeDirectory");
3175                 QUERY_STRING(msg, info5.home_drive,            "homeDrive");
3176                 QUERY_STRING(msg, info5.logon_script,          "scriptPath");
3177                 QUERY_STRING(msg, info5.profile_path,          "profilePath");
3178                 QUERY_STRING(msg, info5.description,           "description");
3179                 QUERY_STRING(msg, info5.workstations,          "userWorkstations");
3180                 QUERY_UINT64(msg, info5.last_logon,            "lastLogon");
3181                 QUERY_UINT64(msg, info5.last_logoff,           "lastLogoff");
3182                 QUERY_LHOURS(msg, info5.logon_hours,           "logonHours");
3183                 QUERY_UINT  (msg, info5.bad_password_count,    "badPwdCount");
3184                 QUERY_UINT  (msg, info5.logon_count,           "logonCount");
3185                 QUERY_UINT64(msg, info5.last_password_change,  "pwdLastSet");
3186                 QUERY_UINT64(msg, info5.acct_expiry,           "accountExpires");
3187                 QUERY_AFLAGS(msg, info5.acct_flags,            "userAccountControl");
3188                 break;
3189
3190         case 6:
3191                 QUERY_STRING(msg, info6.account_name,   "sAMAccountName");
3192                 QUERY_STRING(msg, info6.full_name,      "displayName");
3193                 break;
3194
3195         case 7:
3196                 QUERY_STRING(msg, info7.account_name,   "sAMAccountName");
3197                 break;
3198
3199         case 8:
3200                 QUERY_STRING(msg, info8.full_name,      "displayName");
3201                 break;
3202
3203         case 9:
3204                 QUERY_UINT  (msg, info9.primary_gid,    "primaryGroupID");
3205                 break;
3206
3207         case 10:
3208                 QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3209                 QUERY_STRING(msg, info10.home_drive,    "homeDrive");
3210                 break;
3211
3212         case 11:
3213                 QUERY_STRING(msg, info11.logon_script,  "scriptPath");
3214                 break;
3215
3216         case 12:
3217                 QUERY_STRING(msg, info12.profile_path,  "profilePath");
3218                 break;
3219
3220         case 13:
3221                 QUERY_STRING(msg, info13.description,   "description");
3222                 break;
3223
3224         case 14:
3225                 QUERY_STRING(msg, info14.workstations,  "userWorkstations");
3226                 break;
3227
3228         case 16:
3229                 QUERY_AFLAGS(msg, info16.acct_flags,    "userAccountControl");
3230                 break;
3231
3232         case 17:
3233                 QUERY_UINT64(msg, info17.acct_expiry,   "accountExpires");
3234
3235         case 20:
3236                 QUERY_STRING(msg, info20.parameters,    "userParameters");
3237                 break;
3238
3239         case 21:
3240                 QUERY_UINT64(msg, info21.last_logon,           "lastLogon");
3241                 QUERY_UINT64(msg, info21.last_logoff,          "lastLogoff");
3242                 QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3243                 QUERY_UINT64(msg, info21.acct_expiry,          "accountExpires");
3244                 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3245                 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3246                 QUERY_STRING(msg, info21.account_name,         "sAMAccountName");
3247                 QUERY_STRING(msg, info21.full_name,            "displayName");
3248                 QUERY_STRING(msg, info21.home_directory,       "homeDirectory");
3249                 QUERY_STRING(msg, info21.home_drive,           "homeDrive");
3250                 QUERY_STRING(msg, info21.logon_script,         "scriptPath");
3251                 QUERY_STRING(msg, info21.profile_path,         "profilePath");
3252                 QUERY_STRING(msg, info21.description,          "description");
3253                 QUERY_STRING(msg, info21.workstations,         "userWorkstations");
3254                 QUERY_STRING(msg, info21.comment,              "comment");
3255                 QUERY_STRING(msg, info21.parameters,           "userParameters");
3256                 QUERY_RID   (msg, info21.rid,                  "objectSid");
3257                 QUERY_UINT  (msg, info21.primary_gid,          "primaryGroupID");
3258                 QUERY_AFLAGS(msg, info21.acct_flags,           "userAccountControl");
3259                 r->out.info->info21.fields_present = 0x00FFFFFF;
3260                 QUERY_LHOURS(msg, info21.logon_hours,          "logonHours");
3261                 QUERY_UINT  (msg, info21.bad_password_count,   "badPwdCount");
3262                 QUERY_UINT  (msg, info21.logon_count,          "logonCount");
3263                 QUERY_UINT  (msg, info21.country_code,         "countryCode");
3264                 QUERY_UINT  (msg, info21.code_page,            "codePage");
3265                 break;
3266                 
3267
3268         default:
3269                 r->out.info = NULL;
3270                 return NT_STATUS_INVALID_INFO_CLASS;
3271         }
3272         
3273         return NT_STATUS_OK;
3274 }
3275
3276
3277 /* 
3278   samr_SetUserInfo 
3279 */
3280 static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3281                                  struct samr_SetUserInfo *r)
3282 {
3283         struct dcesrv_handle *h;
3284         struct samr_account_state *a_state;
3285         struct ldb_message *msg;
3286         int ret;
3287         NTSTATUS status = NT_STATUS_OK;
3288         struct ldb_context *sam_ctx;
3289
3290         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3291
3292         a_state = h->data;
3293         sam_ctx = a_state->sam_ctx;
3294
3295         msg = ldb_msg_new(mem_ctx);
3296         if (msg == NULL) {
3297                 return NT_STATUS_NO_MEMORY;
3298         }
3299
3300         msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3301         if (!msg->dn) {
3302                 return NT_STATUS_NO_MEMORY;
3303         }
3304
3305         switch (r->in.level) {
3306         case 2:
3307                 SET_STRING(msg, info2.comment,          "comment");
3308                 SET_UINT  (msg, info2.country_code,     "countryCode");
3309                 SET_UINT  (msg, info2.code_page,        "codePage");
3310                 break;
3311
3312         case 4:
3313                 SET_LHOURS(msg, info4.logon_hours,      "logonHours");
3314                 break;
3315
3316         case 6:
3317                 SET_STRING(msg, info6.full_name,        "displayName");
3318                 break;
3319
3320         case 7:
3321                 SET_STRING(msg, info7.account_name,     "samAccountName");
3322                 break;
3323
3324         case 8:
3325                 SET_STRING(msg, info8.full_name,        "displayName");
3326                 break;
3327
3328         case 9:
3329                 SET_UINT(msg, info9.primary_gid,        "primaryGroupID");
3330                 break;
3331
3332         case 10:
3333                 SET_STRING(msg, info10.home_directory,  "homeDirectory");
3334                 SET_STRING(msg, info10.home_drive,      "homeDrive");
3335                 break;
3336
3337         case 11:
3338                 SET_STRING(msg, info11.logon_script,    "scriptPath");
3339                 break;
3340
3341         case 12:
3342                 SET_STRING(msg, info12.profile_path,    "profilePath");
3343                 break;
3344
3345         case 13:
3346                 SET_STRING(msg, info13.description,     "description");
3347                 break;
3348
3349         case 14:
3350                 SET_STRING(msg, info14.workstations,    "userWorkstations");
3351                 break;
3352
3353         case 16:
3354                 SET_AFLAGS(msg, info16.acct_flags,      "userAccountControl");
3355                 break;
3356
3357         case 17:
3358                 SET_UINT64(msg, info17.acct_expiry,     "accountExpires");
3359                 break;
3360
3361         case 20:
3362                 SET_STRING(msg, info20.parameters,      "userParameters");
3363                 break;
3364
3365         case 21:
3366 #define IFSET(bit) if (bit & r->in.info->info21.fields_present) 
3367                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3368                         SET_UINT64(msg, info21.acct_expiry,    "accountExpires");       
3369                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
3370                         SET_STRING(msg, info21.account_name,   "samAccountName");
3371                 IFSET(SAMR_FIELD_FULL_NAME) 
3372                         SET_STRING(msg, info21.full_name,      "displayName");
3373                 IFSET(SAMR_FIELD_DESCRIPTION)
3374                         SET_STRING(msg, info21.description,    "description");
3375                 IFSET(SAMR_FIELD_COMMENT)
3376                         SET_STRING(msg, info21.comment,        "comment");
3377                 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3378                         SET_STRING(msg, info21.logon_script,   "scriptPath");
3379                 IFSET(SAMR_FIELD_PROFILE_PATH)
3380                         SET_STRING(msg, info21.profile_path,   "profilePath");
3381                 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3382                         SET_STRING(msg, info21.home_directory, "homeDirectory");
3383                 IFSET(SAMR_FIELD_HOME_DRIVE)
3384                         SET_STRING(msg, info21.home_drive,     "homeDrive");
3385                 IFSET(SAMR_FIELD_WORKSTATIONS)
3386                         SET_STRING(msg, info21.workstations,   "userWorkstations");
3387                 IFSET(SAMR_FIELD_LOGON_HOURS)
3388                         SET_LHOURS(msg, info21.logon_hours,    "logonHours");
3389                 IFSET(SAMR_FIELD_ACCT_FLAGS)
3390                         SET_AFLAGS(msg, info21.acct_flags,     "userAccountControl");
3391                 IFSET(SAMR_FIELD_PARAMETERS)   
3392                         SET_STRING(msg, info21.parameters,     "userParameters");
3393                 IFSET(SAMR_FIELD_COUNTRY_CODE)
3394                         SET_UINT  (msg, info21.country_code,   "countryCode");
3395                 IFSET(SAMR_FIELD_CODE_PAGE)
3396                         SET_UINT  (msg, info21.code_page,      "codePage");     
3397 #undef IFSET
3398                 break;
3399
3400         case 23:
3401 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3402                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3403                         SET_UINT64(msg, info23.info.acct_expiry,  "accountExpires");    
3404                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
3405                         SET_STRING(msg, info23.info.account_name, "samAccountName");
3406                 IFSET(SAMR_FIELD_FULL_NAME)         
3407                         SET_STRING(msg, info23.info.full_name,    "displayName");
3408                 IFSET(SAMR_FIELD_DESCRIPTION)  
3409                         SET_STRING(msg, info23.info.description,  "description");
3410                 IFSET(SAMR_FIELD_COMMENT)      
3411                         SET_STRING(msg, info23.info.comment,      "comment");
3412                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
3413                         SET_STRING(msg, info23.info.logon_script, "scriptPath");
3414                 IFSET(SAMR_FIELD_PROFILE_PATH)      
3415                         SET_STRING(msg, info23.info.profile_path, "profilePath");
3416                 IFSET(SAMR_FIELD_WORKSTATIONS)  
3417                         SET_STRING(msg, info23.info.workstations, "userWorkstations");
3418                 IFSET(SAMR_FIELD_LOGON_HOURS)  
3419                         SET_LHOURS(msg, info23.info.logon_hours,  "logonHours");
3420                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
3421                         SET_AFLAGS(msg, info23.info.acct_flags,   "userAccountControl");
3422                 IFSET(SAMR_FIELD_PARAMETERS)     
3423                         SET_STRING(msg, info23.info.parameters,   "userParameters");
3424                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
3425                         SET_UINT  (msg, info23.info.country_code, "countryCode");
3426                 IFSET(SAMR_FIELD_CODE_PAGE)    
3427                         SET_UINT  (msg, info23.info.code_page,    "codePage");
3428                 IFSET(SAMR_FIELD_PASSWORD) {
3429                         status = samr_set_password(dce_call,
3430                                                    a_state->sam_ctx,
3431                                                    a_state->account_dn,
3432                                                    a_state->domain_state->domain_dn,
3433                                                    mem_ctx, msg, 
3434                                                    &r->in.info->info23.password);
3435                 } else IFSET(SAMR_FIELD_PASSWORD2) {
3436                         status = samr_set_password(dce_call,
3437                                                    a_state->sam_ctx,
3438                                                    a_state->account_dn,
3439                                                    a_state->domain_state->domain_dn,
3440                                                    mem_ctx, msg, 
3441                                                    &r->in.info->info23.password);
3442                 }
3443 #undef IFSET
3444                 break;
3445
3446                 /* the set password levels are handled separately */
3447         case 24:
3448                 status = samr_set_password(dce_call,
3449                                            a_state->sam_ctx,
3450                                            a_state->account_dn,
3451                                            a_state->domain_state->domain_dn,
3452                                            mem_ctx, msg, 
3453                                            &r->in.info->info24.password);
3454                 break;
3455
3456         case 25:
3457 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3458                 IFSET(SAMR_FIELD_ACCT_EXPIRY)
3459                         SET_UINT64(msg, info25.info.acct_expiry,  "accountExpires");    
3460                 IFSET(SAMR_FIELD_ACCOUNT_NAME)         
3461                         SET_STRING(msg, info25.info.account_name, "samAccountName");
3462                 IFSET(SAMR_FIELD_FULL_NAME)         
3463                         SET_STRING(msg, info25.info.full_name,    "displayName");
3464                 IFSET(SAMR_FIELD_DESCRIPTION)  
3465                         SET_STRING(msg, info25.info.description,  "description");
3466                 IFSET(SAMR_FIELD_COMMENT)      
3467                         SET_STRING(msg, info25.info.comment,      "comment");
3468                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
3469                         SET_STRING(msg, info25.info.logon_script, "scriptPath");
3470                 IFSET(SAMR_FIELD_PROFILE_PATH)      
3471                         SET_STRING(msg, info25.info.profile_path, "profilePath");
3472                 IFSET(SAMR_FIELD_WORKSTATIONS)  
3473                         SET_STRING(msg, info25.info.workstations, "userWorkstations");
3474                 IFSET(SAMR_FIELD_LOGON_HOURS)  
3475                         SET_LHOURS(msg, info25.info.logon_hours,  "logonHours");
3476                 IFSET(SAMR_FIELD_ACCT_FLAGS)     
3477                         SET_AFLAGS(msg, info25.info.acct_flags,   "userAccountControl");
3478                 IFSET(SAMR_FIELD_PARAMETERS)     
3479                         SET_STRING(msg, info25.info.parameters,   "userParameters");
3480                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
3481                         SET_UINT  (msg, info25.info.country_code, "countryCode");
3482                 IFSET(SAMR_FIELD_CODE_PAGE)    
3483                         SET_UINT  (msg, info25.info.code_page,    "codePage");
3484                 IFSET(SAMR_FIELD_PASSWORD) {
3485                         status = samr_set_password_ex(dce_call,
3486                                                       a_state->sam_ctx,
3487                                                       a_state->account_dn,
3488                                                       a_state->domain_state->domain_dn,
3489                                                       mem_ctx, msg, 
3490                                                       &r->in.info->info25.password);
3491                 } else IFSET(SAMR_FIELD_PASSWORD2) {
3492                         status = samr_set_password_ex(dce_call,
3493                                                       a_state->sam_ctx,
3494                                                       a_state->account_dn,
3495                                                       a_state->domain_state->domain_dn,
3496                                                       mem_ctx, msg, 
3497                                                       &r->in.info->info25.password);
3498                 }
3499 #undef IFSET
3500                 break;
3501
3502                 /* the set password levels are handled separately */
3503         case 26:
3504                 status = samr_set_password_ex(dce_call,
3505                                               a_state->sam_ctx,
3506                                               a_state->account_dn,
3507                                               a_state->domain_state->domain_dn,
3508                                               mem_ctx, msg, 
3509                                               &r->in.info->info26.password);
3510                 break;
3511                 
3512
3513         default:
3514                 /* many info classes are not valid for SetUserInfo */
3515                 return NT_STATUS_INVALID_INFO_CLASS;
3516         }
3517
3518         if (!NT_STATUS_IS_OK(status)) {
3519                 return status;
3520         }
3521
3522         /* modify the samdb record */
3523         ret = ldb_modify(a_state->sam_ctx, msg);
3524         if (ret != 0) {
3525                 DEBUG(1,("Failed to modify record %s: %s\n",
3526                          ldb_dn_get_linearized(a_state->account_dn),
3527                          ldb_errstring(a_state->sam_ctx)));
3528
3529                 /* we really need samdb.c to return NTSTATUS */
3530                 return NT_STATUS_UNSUCCESSFUL;
3531         }
3532
3533         return NT_STATUS_OK;
3534 }
3535
3536
3537 /* 
3538   samr_GetGroupsForUser 
3539 */
3540 static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3541                        struct samr_GetGroupsForUser *r)
3542 {
3543         struct dcesrv_handle *h;
3544         struct samr_account_state *a_state;
3545         struct samr_domain_state *d_state;
3546         struct ldb_message **res;
3547         const char * const attrs[2] = { "objectSid", NULL };
3548         struct samr_RidWithAttributeArray *array;
3549         int count;
3550
3551         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3552
3553         a_state = h->data;
3554         d_state = a_state->domain_state;
3555
3556         count = samdb_search_domain(a_state->sam_ctx, mem_ctx, d_state->domain_dn, &res,
3557                                     attrs, d_state->domain_sid,
3558                                     "(&(member=%s)(grouptype=%d)(objectclass=group))",
3559                                     ldb_dn_get_linearized(a_state->account_dn),
3560                                     GTYPE_SECURITY_GLOBAL_GROUP);
3561         if (count < 0)
3562                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3563
3564         array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3565         if (array == NULL)
3566                 return NT_STATUS_NO_MEMORY;
3567
3568         array->count = 0;
3569         array->rids = NULL;
3570
3571         if (count > 0) {
3572                 int i;
3573                 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3574                                             count);
3575
3576                 if (array->rids == NULL)
3577                         return NT_STATUS_NO_MEMORY;
3578
3579                 for (i=0; i<count; i++) {
3580                         struct dom_sid *group_sid;
3581
3582                         group_sid = samdb_result_dom_sid(mem_ctx, res[i],
3583                                                          "objectSid");
3584                         if (group_sid == NULL) {
3585                                 DEBUG(0, ("Couldn't find objectSid attrib\n"));
3586                                 continue;
3587                         }
3588
3589                         array->rids[array->count].rid =
3590                                 group_sid->sub_auths[group_sid->num_auths-1];
3591                         array->rids[array->count].attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3592                         array->count += 1;
3593                 }
3594         }
3595
3596         r->out.rids = array;
3597
3598         return NT_STATUS_OK;
3599 }
3600
3601
3602 /* 
3603   samr_QueryDisplayInfo 
3604 */
3605 static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3606                        struct samr_QueryDisplayInfo *r)
3607 {
3608         struct dcesrv_handle *h;
3609         struct samr_domain_state *d_state;
3610         struct ldb_message **res;
3611         int ldb_cnt, count, i;
3612         const char * const attrs[] = { "objectSid", "sAMAccountName", "displayName",
3613                                         "description", "userAccountControl", NULL };
3614         struct samr_DispEntryFull *entriesFull = NULL;
3615         struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
3616         struct samr_DispEntryAscii *entriesAscii = NULL;
3617         struct samr_DispEntryGeneral * entriesGeneral = NULL;
3618         const char *filter;
3619
3620         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3621
3622         d_state = h->data;
3623
3624         switch (r->in.level) {
3625         case 1:
3626         case 4:
3627                 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3628                                          "(sAMAccountType=%u))",
3629                                          ATYPE_NORMAL_ACCOUNT);
3630                 break;
3631         case 2:
3632                 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3633                                          "(sAMAccountType=%u))",
3634                                          ATYPE_WORKSTATION_TRUST);
3635                 break;
3636         case 3:
3637         case 5:
3638                 filter = talloc_asprintf(mem_ctx, "(&(grouptype=%d)"
3639                                          "(objectclass=group))",
3640                                          GTYPE_SECURITY_GLOBAL_GROUP);
3641                 break;
3642         default:
3643                 return NT_STATUS_INVALID_INFO_CLASS;
3644         }
3645
3646         /* search for all requested objects in this domain. This could
3647            possibly be cached and resumed based on resume_key */
3648         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3649                                       d_state->domain_dn, &res, attrs,
3650                                       d_state->domain_sid, "%s", filter);
3651         if (ldb_cnt == -1) {
3652                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3653         }
3654         if (ldb_cnt == 0 || r->in.max_entries == 0) {
3655                 return NT_STATUS_OK;
3656         }
3657
3658         switch (r->in.level) {
3659         case 1:
3660                 entriesGeneral = talloc_array(mem_ctx,
3661                                                 struct samr_DispEntryGeneral,
3662                                                 ldb_cnt);
3663                 break;
3664         case 2:
3665                 entriesFull = talloc_array(mem_ctx,
3666                                              struct samr_DispEntryFull,
3667                                              ldb_cnt);
3668                 break;
3669         case 3:
3670                 entriesFullGroup = talloc_array(mem_ctx,
3671                                              struct samr_DispEntryFullGroup,
3672                                              ldb_cnt);
3673                 break;
3674         case 4:
3675         case 5:
3676                 entriesAscii = talloc_array(mem_ctx,
3677                                               struct samr_DispEntryAscii,
3678                                               ldb_cnt);
3679                 break;
3680         }
3681
3682         if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3683             (entriesAscii == NULL) && (entriesFullGroup == NULL))
3684                 return NT_STATUS_NO_MEMORY;
3685
3686         count = 0;
3687
3688         for (i=0; i<ldb_cnt; i++) {
3689                 struct dom_sid *objectsid;
3690
3691                 objectsid = samdb_result_dom_sid(mem_ctx, res[i],
3692                                                  "objectSid");
3693                 if (objectsid == NULL)
3694                         continue;
3695
3696                 switch(r->in.level) {
3697                 case 1:
3698                         entriesGeneral[count].idx = count + 1;
3699                         entriesGeneral[count].rid = 
3700                                 objectsid->sub_auths[objectsid->num_auths-1];
3701                         entriesGeneral[count].acct_flags =
3702                                 samdb_result_acct_flags(res[i], 
3703                                                         "userAccountControl");
3704                         entriesGeneral[count].account_name.string =
3705                                 samdb_result_string(res[i],
3706                                                     "sAMAccountName", "");
3707                         entriesGeneral[count].full_name.string =
3708                                 samdb_result_string(res[i], "displayName", "");
3709                         entriesGeneral[count].description.string =
3710                                 samdb_result_string(res[i], "description", "");
3711                         break;
3712                 case 2:
3713                         entriesFull[count].idx = count + 1;
3714                         entriesFull[count].rid =
3715                                 objectsid->sub_auths[objectsid->num_auths-1];
3716
3717                         /* No idea why we need to or in ACB_NORMAL here, but this is what Win2k3 seems to do... */
3718                         entriesFull[count].acct_flags =
3719                                 samdb_result_acct_flags(res[i], 
3720                                                         "userAccountControl") | ACB_NORMAL;
3721                         entriesFull[count].account_name.string =
3722                                 samdb_result_string(res[i], "sAMAccountName",
3723                                                     "");
3724                         entriesFull[count].description.string =
3725                                 samdb_result_string(res[i], "description", "");
3726                         break;
3727                 case 3:
3728                         entriesFullGroup[count].idx = count + 1;
3729                         entriesFullGroup[count].rid =
3730                                 objectsid->sub_auths[objectsid->num_auths-1];
3731                         entriesFullGroup[count].acct_flags =
3732                                 samdb_result_acct_flags(res[i], 
3733                                                         "userAccountControl");
3734                         /* We get a "7" here for groups */
3735                         entriesFullGroup[count].acct_flags
3736                                 = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3737                         entriesFullGroup[count].account_name.string =
3738                                 samdb_result_string(res[i], "sAMAccountName",
3739                                                     "");
3740                         entriesFullGroup[count].description.string =
3741                                 samdb_result_string(res[i], "description", "");
3742                         break;
3743                 case 4:
3744                 case 5:
3745                         entriesAscii[count].idx = count + 1;
3746                         entriesAscii[count].account_name.string =
3747                                 samdb_result_string(res[i], "sAMAccountName",
3748                                                     "");
3749                         break;
3750                 }
3751
3752                 count += 1;
3753         }
3754
3755         r->out.total_size = count;
3756
3757         if (r->in.start_idx >= count) {
3758                 r->out.returned_size = 0;
3759                 switch(r->in.level) {
3760                 case 1:
3761                         r->out.info.info1.count = r->out.returned_size;
3762                         r->out.info.info1.entries = NULL;
3763                         break;
3764                 case 2:
3765                         r->out.info.info2.count = r->out.returned_size;
3766                         r->out.info.info2.entries = NULL;
3767                         break;
3768                 case 3:
3769                         r->out.info.info3.count = r->out.returned_size;
3770                         r->out.info.info3.entries = NULL;
3771                         break;
3772                 case 4:
3773                         r->out.info.info4.count = r->out.returned_size;
3774                         r->out.info.info4.entries = NULL;
3775                         break;
3776                 case 5:
3777                         r->out.info.info5.count = r->out.returned_size;
3778                         r->out.info.info5.entries = NULL;
3779                         break;
3780                 }
3781         } else {
3782                 r->out.returned_size = MIN(count - r->in.start_idx,
3783                                            r->in.max_entries);
3784                 switch(r->in.level) {
3785                 case 1:
3786                         r->out.info.info1.count = r->out.returned_size;
3787                         r->out.info.info1.entries =
3788                                 &(entriesGeneral[r->in.start_idx]);
3789                         break;
3790                 case 2:
3791                         r->out.info.info2.count = r->out.returned_size;
3792                         r->out.info.info2.entries =
3793                                 &(entriesFull[r->in.start_idx]);
3794                         break;
3795                 case 3:
3796                         r->out.info.info3.count = r->out.returned_size;
3797                         r->out.info.info3.entries =
3798                                 &(entriesFullGroup[r->in.start_idx]);
3799                         break;
3800                 case 4:
3801                         r->out.info.info4.count = r->out.returned_size;
3802                         r->out.info.info4.entries =
3803                                 &(entriesAscii[r->in.start_idx]);
3804                         break;
3805                 case 5:
3806                         r->out.info.info5.count = r->out.returned_size;
3807                         r->out.info.info5.entries =
3808                                 &(entriesAscii[r->in.start_idx]);
3809                         break;
3810                 }
3811         }
3812
3813         return (r->out.returned_size < (count - r->in.start_idx)) ?
3814                 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3815 }
3816
3817
3818 /* 
3819   samr_GetDisplayEnumerationIndex 
3820 */
3821 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3822                        struct samr_GetDisplayEnumerationIndex *r)
3823 {
3824         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3825 }
3826
3827
3828 /* 
3829   samr_TestPrivateFunctionsDomain 
3830 */
3831 static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3832                        struct samr_TestPrivateFunctionsDomain *r)
3833 {
3834         return NT_STATUS_NOT_IMPLEMENTED;
3835 }
3836
3837
3838 /* 
3839   samr_TestPrivateFunctionsUser 
3840 */
3841 static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3842                        struct samr_TestPrivateFunctionsUser *r)
3843 {
3844         return NT_STATUS_NOT_IMPLEMENTED;
3845 }
3846
3847
3848 /* 
3849   samr_GetUserPwInfo 
3850 */
3851 static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3852                                    struct samr_GetUserPwInfo *r)
3853 {
3854         struct dcesrv_handle *h;
3855         struct samr_account_state *a_state;
3856
3857         ZERO_STRUCT(r->out.info);
3858
3859         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3860
3861         a_state = h->data;
3862
3863         r->out.info.min_password_length = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0,
3864                                                             a_state->domain_state->domain_dn, "minPwdLength", 
3865                                                             NULL);
3866         r->out.info.password_properties = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0,
3867                                                             a_state->account_dn, 
3868                                                             "pwdProperties", NULL);
3869         return NT_STATUS_OK;
3870 }
3871
3872
3873 /* 
3874   samr_RemoveMemberFromForeignDomain 
3875 */
3876 static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3877                        struct samr_RemoveMemberFromForeignDomain *r)
3878 {
3879         struct dcesrv_handle *h;
3880         struct samr_domain_state *d_state;
3881         const char *memberdn;
3882         struct ldb_message **res;
3883         const char * const attrs[3] = { "distinguishedName", "objectSid", NULL };
3884         int i, count;
3885
3886         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3887
3888         d_state = h->data;
3889
3890         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3891                                        "distinguishedName", "(objectSid=%s)", 
3892                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3893         /* Nothing to do */
3894         if (memberdn == NULL) {
3895                 return NT_STATUS_OK;
3896         }
3897
3898         /* TODO: Does this call only remove alias members, or does it do this
3899          * for domain groups as well? */
3900
3901         count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3902                                     d_state->domain_dn, &res, attrs,
3903                                     d_state->domain_sid,
3904                                     "(&(member=%s)(objectClass=group)"
3905                                     "(|(groupType=%d)(groupType=%d)))",
3906                                     memberdn,
3907                                     GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
3908                                     GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
3909
3910         if (count < 0)
3911                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3912
3913         for (i=0; i<count; i++) {
3914                 struct ldb_message *mod;
3915
3916                 mod = ldb_msg_new(mem_ctx);
3917                 if (mod == NULL) {
3918                         return NT_STATUS_NO_MEMORY;
3919                 }
3920
3921                 mod->dn = samdb_result_dn(d_state->sam_ctx, mod, res[i], "distinguishedName", NULL);
3922                 if (mod->dn == NULL) {
3923                         talloc_free(mod);
3924                         continue;
3925                 }
3926
3927                 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
3928                                          "member", memberdn) != 0)
3929                         return NT_STATUS_NO_MEMORY;
3930
3931                 if (ldb_modify(d_state->sam_ctx, mod) != 0)
3932                         return NT_STATUS_UNSUCCESSFUL;
3933
3934                 talloc_free(mod);
3935         }
3936
3937         return NT_STATUS_OK;
3938 }
3939
3940
3941 /* 
3942   samr_QueryDomainInfo2 
3943
3944   just an alias for samr_QueryDomainInfo
3945 */
3946 static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3947                        struct samr_QueryDomainInfo2 *r)
3948 {
3949         struct samr_QueryDomainInfo r1;
3950         NTSTATUS status;
3951
3952         ZERO_STRUCT(r1.out);
3953         r1.in.domain_handle = r->in.domain_handle;
3954         r1.in.level  = r->in.level;
3955         
3956         status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
3957         
3958         r->out.info = r1.out.info;
3959
3960         return status;
3961 }
3962
3963
3964 /* 
3965   samr_QueryUserInfo2 
3966
3967   just an alias for samr_QueryUserInfo
3968 */
3969 static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3970                                     struct samr_QueryUserInfo2 *r)
3971 {
3972         struct samr_QueryUserInfo r1;
3973         NTSTATUS status;
3974
3975         ZERO_STRUCT(r1.out);
3976         r1.in.user_handle = r->in.user_handle;
3977         r1.in.level  = r->in.level;
3978         
3979         status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
3980         
3981         r->out.info = r1.out.info;
3982
3983         return status;
3984 }
3985
3986
3987 /* 
3988   samr_QueryDisplayInfo2 
3989 */
3990 static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3991                                        struct samr_QueryDisplayInfo2 *r)
3992 {
3993         struct samr_QueryDisplayInfo q;
3994         NTSTATUS result;
3995
3996         q.in.domain_handle = r->in.domain_handle;
3997         q.in.level = r->in.level;
3998         q.in.start_idx = r->in.start_idx;
3999         q.in.max_entries = r->in.max_entries;
4000         q.in.buf_size = r->in.buf_size;
4001         ZERO_STRUCT(q.out);
4002
4003         result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4004
4005         r->out.total_size = q.out.total_size;
4006         r->out.returned_size = q.out.returned_size;
4007         r->out.info = q.out.info;
4008
4009         return result;
4010 }
4011
4012
4013 /* 
4014   samr_GetDisplayEnumerationIndex2 
4015 */
4016 static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4017                        struct samr_GetDisplayEnumerationIndex2 *r)
4018 {
4019         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4020 }
4021
4022
4023 /* 
4024   samr_QueryDisplayInfo3 
4025 */
4026 static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4027                        struct samr_QueryDisplayInfo3 *r)
4028 {
4029         struct samr_QueryDisplayInfo q;
4030         NTSTATUS result;
4031
4032         q.in.domain_handle = r->in.domain_handle;
4033         q.in.level = r->in.level;
4034         q.in.start_idx = r->in.start_idx;
4035         q.in.max_entries = r->in.max_entries;
4036         q.in.buf_size = r->in.buf_size;
4037         ZERO_STRUCT(q.out);
4038
4039         result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4040
4041         r->out.total_size = q.out.total_size;
4042         r->out.returned_size = q.out.returned_size;
4043         r->out.info = q.out.info;
4044
4045         return result;
4046 }
4047
4048
4049 /* 
4050   samr_AddMultipleMembersToAlias 
4051 */
4052 static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4053                        struct samr_AddMultipleMembersToAlias *r)
4054 {
4055         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4056 }
4057
4058
4059 /* 
4060   samr_RemoveMultipleMembersFromAlias 
4061 */
4062 static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4063                        struct samr_RemoveMultipleMembersFromAlias *r)
4064 {
4065         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4066 }
4067
4068
4069 /* 
4070   samr_GetDomPwInfo 
4071
4072   this fetches the default password properties for a domain
4073
4074   note that w2k3 completely ignores the domain name in this call, and 
4075   always returns the information for the servers primary domain
4076 */
4077 static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4078                                   struct samr_GetDomPwInfo *r)
4079 {
4080         struct ldb_message **msgs;
4081         int ret;
4082         const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
4083         struct ldb_context *sam_ctx;
4084
4085         ZERO_STRUCT(r->out.info);
4086
4087         sam_ctx = samdb_connect(mem_ctx, dce_call->conn->auth_state.session_info); 
4088         if (sam_ctx == NULL) {
4089                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
4090         }
4091
4092         /* The domain name in this call is ignored */
4093         ret = gendb_search_dn(sam_ctx, 
4094                            mem_ctx, NULL, &msgs, attrs);
4095         if (ret <= 0) {
4096                 return NT_STATUS_NO_SUCH_DOMAIN;
4097         }
4098         if (ret > 1) {
4099                 talloc_free(msgs);
4100                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
4101         }
4102
4103         r->out.info.min_password_length = samdb_result_uint(msgs[0], "minPwdLength", 0);
4104         r->out.info.password_properties = samdb_result_uint(msgs[0], "pwdProperties", 1);
4105
4106         talloc_free(msgs);
4107
4108         talloc_free(sam_ctx);
4109         return NT_STATUS_OK;
4110 }
4111
4112
4113 /* 
4114   samr_Connect2 
4115 */
4116 static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4117                               struct samr_Connect2 *r)
4118 {
4119         struct samr_Connect c;
4120
4121         c.in.system_name = NULL;
4122         c.in.access_mask = r->in.access_mask;
4123         c.out.connect_handle = r->out.connect_handle;
4124
4125         return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4126 }
4127
4128
4129 /* 
4130   samr_SetUserInfo2 
4131
4132   just an alias for samr_SetUserInfo
4133 */
4134 static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4135                                   struct samr_SetUserInfo2 *r)
4136 {
4137         struct samr_SetUserInfo r2;
4138
4139         r2.in.user_handle = r->in.user_handle;
4140         r2.in.level = r->in.level;
4141         r2.in.info = r->in.info;
4142
4143         return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
4144 }
4145
4146
4147 /* 
4148   samr_SetBootKeyInformation 
4149 */
4150 static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4151                        struct samr_SetBootKeyInformation *r)
4152 {
4153         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4154 }
4155
4156
4157 /* 
4158   samr_GetBootKeyInformation 
4159 */
4160 static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4161                        struct samr_GetBootKeyInformation *r)
4162 {
4163         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4164 }
4165
4166
4167 /* 
4168   samr_Connect3 
4169 */
4170 static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4171                        struct samr_Connect3 *r)
4172 {
4173         struct samr_Connect c;
4174
4175         c.in.system_name = NULL;
4176         c.in.access_mask = r->in.access_mask;
4177         c.out.connect_handle = r->out.connect_handle;
4178
4179         return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4180 }
4181
4182
4183 /* 
4184   samr_Connect4 
4185 */
4186 static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4187                        struct samr_Connect4 *r)
4188 {
4189         struct samr_Connect c;
4190
4191         c.in.system_name = NULL;
4192         c.in.access_mask = r->in.access_mask;
4193         c.out.connect_handle = r->out.connect_handle;
4194
4195         return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4196 }
4197
4198
4199 /* 
4200   samr_Connect5 
4201 */
4202 static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4203                               struct samr_Connect5 *r)
4204 {
4205         struct samr_Connect c;
4206         NTSTATUS status;
4207
4208         c.in.system_name = NULL;
4209         c.in.access_mask = r->in.access_mask;
4210         c.out.connect_handle = r->out.connect_handle;
4211
4212         status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
4213
4214         r->out.info->info1.unknown1 = 3;
4215         r->out.info->info1.unknown2 = 0;
4216         r->out.level = r->in.level;
4217
4218         return status;
4219 }
4220
4221
4222 /* 
4223   samr_RidToSid 
4224 */
4225 static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4226                               struct samr_RidToSid *r)
4227 {
4228         struct samr_domain_state *d_state;
4229         struct dcesrv_handle *h;
4230
4231         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4232
4233         d_state = h->data;
4234
4235         /* form the users SID */
4236         r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4237         if (!r->out.sid) {
4238                 return NT_STATUS_NO_MEMORY;
4239         }
4240
4241         return NT_STATUS_OK;
4242 }
4243
4244
4245 /* 
4246   samr_SetDsrmPassword 
4247 */
4248 static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4249                        struct samr_SetDsrmPassword *r)
4250 {
4251         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4252 }
4253
4254
4255 /* 
4256   samr_ValidatePassword 
4257 */
4258 static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4259                                       struct samr_ValidatePassword *r)
4260 {
4261         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4262 }
4263
4264
4265 /* include the generated boilerplate */
4266 #include "librpc/gen_ndr/ndr_samr_s.c"