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