760d774f2ea6ebc46a8bcebaf199bb077f8e894f
[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                 DEBUG(1, ("Failed to delete user: %s: %s\n", 
2914                           ldb_dn_get_linearized(a_state->account_dn), 
2915                           ldb_errstring(a_state->sam_ctx)));
2916                 return NT_STATUS_UNSUCCESSFUL;
2917         }
2918
2919         ZERO_STRUCTP(r->out.user_handle);
2920
2921         return NT_STATUS_OK;
2922 }
2923
2924
2925 /* 
2926   samr_QueryUserInfo 
2927 */
2928 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2929                                    struct samr_QueryUserInfo *r)
2930 {
2931         struct dcesrv_handle *h;
2932         struct samr_account_state *a_state;
2933         struct ldb_message *msg, **res;
2934         int ret;
2935         struct ldb_context *sam_ctx;
2936
2937         const char * const *attrs = NULL;
2938
2939         r->out.info = NULL;
2940
2941         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2942
2943         a_state = h->data;
2944         sam_ctx = a_state->sam_ctx;
2945
2946         /* fill in the reply */
2947         switch (r->in.level) {
2948         case 1:
2949         {
2950                 static const char * const attrs2[] = {"sAMAccountName", "displayName",
2951                                                       "primaryGroupID", "description",
2952                                                       "comment", NULL};
2953                 attrs = attrs2;
2954                 break;
2955         }
2956         case 2:
2957         {
2958                 static const char * const attrs2[] = {"comment", "countryCode", "codePage", NULL};
2959                 attrs = attrs2;
2960                 break;
2961         }
2962         case 3:
2963         {
2964                 static const char * const attrs2[] = {"sAMAccountName",
2965                                                       "displayName",
2966                                                       "objectSid",
2967                                                       "primaryGroupID",
2968                                                       "homeDirectory",
2969                                                       "homeDrive",
2970                                                       "scriptPath",
2971                                                       "profilePath",
2972                                                       "userWorkstations",
2973                                                       "lastLogon",
2974                                                       "lastLogoff",
2975                                                       "pwdLastSet",
2976                                                       "logonHours",
2977                                                       "badPwdCount",
2978                                                       "logonCount",
2979                                                       "userAccountControl", NULL};
2980                 attrs = attrs2;
2981                 break;
2982         }
2983         case 4:
2984         {
2985                 static const char * const attrs2[] = {"logonHours", NULL};
2986                 attrs = attrs2;
2987                 break;
2988         }
2989         case 5:
2990         {
2991                 static const char * const attrs2[] = {"sAMAccountName", 
2992                                                       "displayName",
2993                                                       "objectSid",
2994                                                       "primaryGroupID",
2995                                                       "homeDirectory",
2996                                                       "homeDrive",
2997                                                       "scriptPath", 
2998                                                       "profilePath",
2999                                                       "description",
3000                                                       "userWorkstations",
3001                                                       "lastLogon",
3002                                                       "lastLogoff",
3003                                                       "logonHours",
3004                                                       "badPwdCount",
3005                                                       "logonCount",
3006                                                       "pwdLastSet",
3007                                                       "accountExpires",
3008                                                       "userAccountControl",
3009                                                       NULL};
3010                 attrs = attrs2;
3011                 break;
3012         }
3013         case 6:
3014         {
3015                 static const char * const attrs2[] = {"sAMAccountName", "displayName", NULL};
3016                 attrs = attrs2;
3017                 break;
3018         }
3019         case 7:
3020         {
3021                 static const char * const attrs2[] = {"sAMAccountName", NULL};
3022                 attrs = attrs2;
3023                 break;
3024         }
3025         case 8:
3026         {
3027                 static const char * const attrs2[] = {"displayName", NULL};
3028                 attrs = attrs2;
3029                 break;
3030         }
3031         case 9:
3032         {
3033                 static const char * const attrs2[] = {"primaryGroupID", NULL};
3034                 attrs = attrs2;
3035                 break;
3036         }
3037         case 10:
3038         {
3039                 static const char * const attrs2[] = {"homeDirectory", "homeDrive", NULL};
3040                 attrs = attrs2;
3041                 break;
3042         }
3043         case 11:
3044         {
3045                 static const char * const attrs2[] = {"scriptPath", NULL};
3046                 attrs = attrs2;
3047                 break;
3048         }
3049         case 12:
3050         {
3051                 static const char * const attrs2[] = {"profilePath", NULL};
3052                 attrs = attrs2;
3053                 break;
3054         }
3055         case 13:
3056         {
3057                 static const char * const attrs2[] = {"description", NULL};
3058                 attrs = attrs2;
3059                 break;
3060         }
3061         case 14:
3062         {
3063                 static const char * const attrs2[] = {"userWorkstations", NULL};
3064                 attrs = attrs2;
3065                 break;
3066         }
3067         case 16:
3068         {
3069                 static const char * const attrs2[] = {"userAccountControl", NULL};
3070                 attrs = attrs2;
3071                 break;
3072         }
3073         case 17:
3074         {
3075                 static const char * const attrs2[] = {"accountExpires", NULL};
3076                 attrs = attrs2;
3077                 break;
3078         }
3079         case 20:
3080         {
3081                 static const char * const attrs2[] = {"userParameters", NULL};
3082                 attrs = attrs2;
3083                 break;
3084         }
3085         case 21:
3086         {
3087                 static const char * const attrs2[] = {"lastLogon",
3088                                                       "lastLogoff",
3089                                                       "pwdLastSet",
3090                                                       "accountExpires",
3091                                                       "sAMAccountName",
3092                                                       "displayName",
3093                                                       "homeDirectory",
3094                                                       "homeDrive",
3095                                                       "scriptPath",
3096                                                       "profilePath",
3097                                                       "description",
3098                                                       "userWorkstations",
3099                                                       "comment",
3100                                                       "userParameters",
3101                                                       "objectSid",
3102                                                       "primaryGroupID",
3103                                                       "userAccountControl",
3104                                                       "logonHours",
3105                                                       "badPwdCount",
3106                                                       "logonCount",
3107                                                       "countryCode",
3108                                                       "codePage",
3109                                                       NULL};
3110                 attrs = attrs2;
3111                 break;
3112         }
3113         }
3114
3115         /* pull all the user attributes */
3116         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
3117                               a_state->account_dn ,&res, attrs);
3118         if (ret != 1) {
3119                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3120         }
3121         msg = res[0];
3122
3123         /* allocate the info structure */
3124         r->out.info = talloc(mem_ctx, union samr_UserInfo);
3125         if (r->out.info == NULL) {
3126                 return NT_STATUS_NO_MEMORY;
3127         }
3128         ZERO_STRUCTP(r->out.info);
3129
3130         /* fill in the reply */
3131         switch (r->in.level) {
3132         case 1:
3133                 QUERY_STRING(msg, info1.account_name,          "sAMAccountName");
3134                 QUERY_STRING(msg, info1.full_name,             "displayName");
3135                 QUERY_UINT  (msg, info1.primary_gid,           "primaryGroupID");
3136                 QUERY_STRING(msg, info1.description,           "description");
3137                 QUERY_STRING(msg, info1.comment,               "comment");
3138                 break;
3139
3140         case 2:
3141                 QUERY_STRING(msg, info2.comment,               "comment");
3142                 QUERY_UINT  (msg, info2.country_code,          "countryCode");
3143                 QUERY_UINT  (msg, info2.code_page,             "codePage");
3144                 break;
3145
3146         case 3:
3147                 QUERY_STRING(msg, info3.account_name,          "sAMAccountName");
3148                 QUERY_STRING(msg, info3.full_name,             "displayName");
3149                 QUERY_RID   (msg, info3.rid,                   "objectSid");
3150                 QUERY_UINT  (msg, info3.primary_gid,           "primaryGroupID");
3151                 QUERY_STRING(msg, info3.home_directory,        "homeDirectory");
3152                 QUERY_STRING(msg, info3.home_drive,            "homeDrive");
3153                 QUERY_STRING(msg, info3.logon_script,          "scriptPath");
3154                 QUERY_STRING(msg, info3.profile_path,          "profilePath");
3155                 QUERY_STRING(msg, info3.workstations,          "userWorkstations");
3156                 QUERY_UINT64(msg, info3.last_logon,            "lastLogon");
3157                 QUERY_UINT64(msg, info3.last_logoff,           "lastLogoff");
3158                 QUERY_UINT64(msg, info3.last_password_change,  "pwdLastSet");
3159                 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
3160                 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
3161                 QUERY_LHOURS(msg, info3.logon_hours,           "logonHours");
3162                 QUERY_UINT  (msg, info3.bad_password_count,    "badPwdCount");
3163                 QUERY_UINT  (msg, info3.logon_count,           "logonCount");
3164                 QUERY_AFLAGS(msg, info3.acct_flags,            "userAccountControl");
3165                 break;
3166
3167         case 4:
3168                 QUERY_LHOURS(msg, info4.logon_hours,           "logonHours");
3169                 break;
3170
3171         case 5:
3172                 QUERY_STRING(msg, info5.account_name,          "sAMAccountName");
3173                 QUERY_STRING(msg, info5.full_name,             "displayName");
3174                 QUERY_RID   (msg, info5.rid,                   "objectSid");
3175                 QUERY_UINT  (msg, info5.primary_gid,           "primaryGroupID");
3176                 QUERY_STRING(msg, info5.home_directory,        "homeDirectory");
3177                 QUERY_STRING(msg, info5.home_drive,            "homeDrive");
3178                 QUERY_STRING(msg, info5.logon_script,          "scriptPath");
3179                 QUERY_STRING(msg, info5.profile_path,          "profilePath");
3180                 QUERY_STRING(msg, info5.description,           "description");
3181                 QUERY_STRING(msg, info5.workstations,          "userWorkstations");
3182                 QUERY_UINT64(msg, info5.last_logon,            "lastLogon");
3183                 QUERY_UINT64(msg, info5.last_logoff,           "lastLogoff");
3184                 QUERY_LHOURS(msg, info5.logon_hours,           "logonHours");
3185                 QUERY_UINT  (msg, info5.bad_password_count,    "badPwdCount");
3186                 QUERY_UINT  (msg, info5.logon_count,           "logonCount");
3187                 QUERY_UINT64(msg, info5.last_password_change,  "pwdLastSet");