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