r25026: Move param/param.h out of includes.h
[kai/samba-autobuild/.git] / source4 / rpc_server / samr / dcesrv_samr.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    endpoint server for the samr pipe
5
6    Copyright (C) Andrew Tridgell 2004
7    Copyright (C) Volker Lendecke 2004
8    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "librpc/gen_ndr/ndr_samr.h"
26 #include "rpc_server/dcerpc_server.h"
27 #include "rpc_server/common/common.h"
28 #include "rpc_server/samr/dcesrv_samr.h"
29 #include "system/time.h"
30 #include "lib/ldb/include/ldb.h"
31 #include "lib/ldb/include/ldb_errors.h"
32 #include "dsdb/common/flags.h"
33 #include "dsdb/samdb/samdb.h"
34 #include "libcli/ldap/ldap.h"
35 #include "libcli/security/security.h"
36 #include "rpc_server/samr/proto.h"
37 #include "db_wrap.h"
38 #include "param/param.h"
39
40 /* these query macros make samr_Query[User|Group]Info a bit easier to read */
41
42 #define QUERY_STRING(msg, field, attr) \
43         r->out.info->field.string = samdb_result_string(msg, attr, "");
44 #define QUERY_UINT(msg, field, attr) \
45         r->out.info->field = samdb_result_uint(msg, attr, 0);
46 #define QUERY_RID(msg, field, attr) \
47         r->out.info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
48 #define QUERY_UINT64(msg, field, attr) \
49         r->out.info->field = samdb_result_uint64(msg, attr, 0);
50 #define QUERY_APASSC(msg, field, attr) \
51         r->out.info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
52                                                            a_state->domain_state->domain_dn, msg, attr);
53 #define QUERY_FPASSC(msg, field, attr) \
54         r->out.info->field = samdb_result_force_password_change(sam_ctx, mem_ctx, \
55                                                            a_state->domain_state->domain_dn, msg);
56 #define QUERY_LHOURS(msg, field, attr) \
57         r->out.info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
58 #define QUERY_AFLAGS(msg, field, attr) \
59         r->out.info->field = samdb_result_acct_flags(msg, attr);
60
61
62 /* these are used to make the Set[User|Group]Info code easier to follow */
63
64 #define SET_STRING(msg, field, attr) do {                               \
65         struct ldb_message_element *set_el;                             \
66         if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
67         if (r->in.info->field.string[0] == '\0') {                      \
68                 if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL)) { \
69                         return NT_STATUS_NO_MEMORY;                     \
70                 }                                                       \
71         }                                                               \
72         if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != 0) { \
73                 return NT_STATUS_NO_MEMORY;                             \
74         }                                                               \
75         set_el = ldb_msg_find_element(msg, attr);                       \
76         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
77 } while (0)
78
79 #define SET_UINT(msg, field, attr) do {                                 \
80         struct ldb_message_element *set_el;                             \
81         if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
82                 return NT_STATUS_NO_MEMORY;                             \
83         }                                                               \
84         set_el = ldb_msg_find_element(msg, attr);                       \
85         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
86 } while (0)                                                             
87                                                                         
88 #define SET_INT64(msg, field, attr) do {                                \
89         struct ldb_message_element *set_el;                             \
90         if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
91                 return NT_STATUS_NO_MEMORY;                             \
92         }                                                               \
93         set_el = ldb_msg_find_element(msg, attr);                       \
94         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
95 } while (0)                                                             
96                                                                         
97 #define SET_UINT64(msg, field, attr) do {                               \
98         struct ldb_message_element *set_el;                             \
99         if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
100                 return NT_STATUS_NO_MEMORY;                             \
101         }                                                               \
102         set_el = ldb_msg_find_element(msg, attr);                       \
103         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
104 } while (0)                                                             
105                                                                         
106 #define SET_AFLAGS(msg, field, attr) do {                               \
107         struct ldb_message_element *set_el;                             \
108         if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
109                 return NT_STATUS_NO_MEMORY;                             \
110         }                                                               \
111         set_el = ldb_msg_find_element(msg, attr);                       \
112         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
113 } while (0)                                                             
114                                                                         
115 #define SET_LHOURS(msg, field, attr) do {                               \
116         struct ldb_message_element *set_el;                             \
117         if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
118                 return NT_STATUS_NO_MEMORY;                             \
119         }                                                               \
120         set_el = ldb_msg_find_element(msg, attr);                       \
121         set_el->flags = LDB_FLAG_MOD_REPLACE;                           \
122 } while (0)
123
124
125 /* 
126   samr_Connect 
127
128   create a connection to the SAM database
129 */
130 static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
131                              struct samr_Connect *r)
132 {
133         struct samr_connect_state *c_state;
134         struct dcesrv_handle *handle;
135
136         ZERO_STRUCTP(r->out.connect_handle);
137
138         c_state = talloc(dce_call->conn, struct samr_connect_state);
139         if (!c_state) {
140                 return NT_STATUS_NO_MEMORY;
141         }
142
143         /* make sure the sam database is accessible */
144         c_state->sam_ctx = samdb_connect(c_state, dce_call->conn->auth_state.session_info); 
145         if (c_state->sam_ctx == NULL) {
146                 talloc_free(c_state);
147                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
148         }
149
150
151         handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_CONNECT);
152         if (!handle) {
153                 talloc_free(c_state);
154                 return NT_STATUS_NO_MEMORY;
155         }
156
157         handle->data = talloc_steal(handle, c_state);
158
159         c_state->access_mask = r->in.access_mask;
160         *r->out.connect_handle = handle->wire_handle;
161
162         return NT_STATUS_OK;
163 }
164
165
166 /* 
167   samr_Close 
168 */
169 static NTSTATUS dcesrv_samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
170                            struct samr_Close *r)
171 {
172         struct dcesrv_handle *h;
173
174         *r->out.handle = *r->in.handle;
175
176         DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
177
178         talloc_free(h);
179
180         ZERO_STRUCTP(r->out.handle);
181
182         return NT_STATUS_OK;
183 }
184
185
186 /* 
187   samr_SetSecurity 
188 */
189 static NTSTATUS dcesrv_samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
190                                  struct samr_SetSecurity *r)
191 {
192         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
193 }
194
195
196 /* 
197   samr_QuerySecurity 
198 */
199 static NTSTATUS dcesrv_samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
200                                    struct samr_QuerySecurity *r)
201 {
202         struct dcesrv_handle *h;
203         struct sec_desc_buf *sd;
204
205         r->out.sdbuf = NULL;
206
207         DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
208
209         sd = talloc(mem_ctx, struct sec_desc_buf);
210         if (sd == NULL) {
211                 return NT_STATUS_NO_MEMORY;
212         }
213
214         sd->sd = samdb_default_security_descriptor(mem_ctx);
215
216         r->out.sdbuf = sd;
217
218         return NT_STATUS_OK;
219 }
220
221
222 /* 
223   samr_Shutdown 
224
225   we refuse this operation completely. If a admin wants to shutdown samr
226   in Samba then they should use the samba admin tools to disable the samr pipe
227 */
228 static NTSTATUS dcesrv_samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
229                               struct samr_Shutdown *r)
230 {
231         return NT_STATUS_ACCESS_DENIED;
232 }
233
234
235 /* 
236   samr_LookupDomain 
237
238   this maps from a domain name to a SID
239 */
240 static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
241                                   struct samr_LookupDomain *r)
242 {
243         struct samr_connect_state *c_state;
244         struct dcesrv_handle *h;
245         struct dom_sid *sid;
246         const char * const dom_attrs[] = { "objectSid", NULL};
247         const char * const ref_attrs[] = { "ncName", NULL};
248         struct ldb_message **dom_msgs;
249         struct ldb_message **ref_msgs;
250         int ret;
251         struct ldb_dn *partitions_basedn;
252
253         r->out.sid = NULL;
254
255         DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
256
257         c_state = h->data;
258
259         if (r->in.domain_name->string == NULL) {
260                 return NT_STATUS_INVALID_PARAMETER;
261         }
262
263         partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx);
264
265         if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
266                 ret = gendb_search(c_state->sam_ctx,
267                                    mem_ctx, NULL, &dom_msgs, dom_attrs,
268                                    "(objectClass=builtinDomain)");
269         } else {
270                 ret = gendb_search(c_state->sam_ctx,
271                                    mem_ctx, partitions_basedn, &ref_msgs, ref_attrs,
272                                    "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))", 
273                                    ldb_binary_encode_string(mem_ctx, r->in.domain_name->string));
274                 if (ret != 1) {
275                         return NT_STATUS_NO_SUCH_DOMAIN;
276                 }
277                 
278                 ret = gendb_search_dn(c_state->sam_ctx, mem_ctx, 
279                                       samdb_result_dn(c_state->sam_ctx, mem_ctx,
280                                                       ref_msgs[0], "ncName", NULL), 
281                                       &dom_msgs, dom_attrs);
282         }
283
284         if (ret != 1) {
285                 return NT_STATUS_NO_SUCH_DOMAIN;
286         }
287         
288         sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
289                                    "objectSid");
290                 
291         if (sid == NULL) {
292                 return NT_STATUS_NO_SUCH_DOMAIN;
293         }
294
295         r->out.sid = sid;
296
297         return NT_STATUS_OK;
298 }
299
300
301 /* 
302   samr_EnumDomains 
303
304   list the domains in the SAM
305 */
306 static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
307                                  struct samr_EnumDomains *r)
308 {
309         struct samr_connect_state *c_state;
310         struct dcesrv_handle *h;
311         struct samr_SamArray *array;
312         int count, i, start_i;
313         const char * const dom_attrs[] = { "cn", NULL};
314         const char * const ref_attrs[] = { "nETBIOSName", NULL};
315         struct ldb_message **dom_msgs;
316         struct ldb_message **ref_msgs;
317         struct ldb_dn *partitions_basedn;
318
319         *r->out.resume_handle = 0;
320         r->out.sam = NULL;
321         r->out.num_entries = 0;
322
323         DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
324
325         c_state = h->data;
326
327         partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx);
328
329         count = gendb_search(c_state->sam_ctx,
330                              mem_ctx, NULL, &dom_msgs, dom_attrs,
331                              "(objectClass=domain)");
332         if (count == -1) {
333                 DEBUG(0,("samdb: no domains found in EnumDomains\n"));
334                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
335         }
336
337         *r->out.resume_handle = count;
338
339         start_i = *r->in.resume_handle;
340
341         if (start_i >= count) {
342                 /* search past end of list is not an error for this call */
343                 return NT_STATUS_OK;
344         }
345
346         array = talloc(mem_ctx, struct samr_SamArray);
347         if (array == NULL) {
348                 return NT_STATUS_NO_MEMORY;
349         }
350                 
351         array->count = 0;
352         array->entries = NULL;
353
354         array->entries = talloc_array(mem_ctx, struct samr_SamEntry, count - start_i);
355         if (array->entries == NULL) {
356                 return NT_STATUS_NO_MEMORY;
357         }
358
359         for (i=0;i<count-start_i;i++) {
360                 int ret;
361                 array->entries[i].idx = start_i + i;
362                 /* try and find the domain */
363                 ret = gendb_search(c_state->sam_ctx, mem_ctx, partitions_basedn,
364                                    &ref_msgs, ref_attrs, 
365                                    "(&(objectClass=crossRef)(ncName=%s))", 
366                                    ldb_dn_get_linearized(dom_msgs[i]->dn));
367                 if (ret == 1) {
368                         array->entries[i].name.string = samdb_result_string(ref_msgs[0], "nETBIOSName", NULL);
369                 } else {
370                         array->entries[i].name.string = samdb_result_string(dom_msgs[i], "cn", NULL);
371                 }
372         }
373
374         r->out.sam = array;
375         r->out.num_entries = i;
376         array->count = r->out.num_entries;
377
378         return NT_STATUS_OK;
379 }
380
381
382 /* 
383   samr_OpenDomain 
384 */
385 static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
386                                 struct samr_OpenDomain *r)
387 {
388         struct dcesrv_handle *h_conn, *h_domain;
389         const char *domain_name;
390         struct samr_connect_state *c_state;
391         struct samr_domain_state *d_state;
392         const char * const dom_attrs[] = { "cn", NULL};
393         const char * const ref_attrs[] = { "nETBIOSName", NULL};
394         struct ldb_message **dom_msgs;
395         struct ldb_message **ref_msgs;
396         int ret;
397         struct ldb_dn *partitions_basedn;
398
399         ZERO_STRUCTP(r->out.domain_handle);
400
401         DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
402
403         c_state = h_conn->data;
404
405         if (r->in.sid == NULL) {
406                 return NT_STATUS_INVALID_PARAMETER;
407         }
408
409         partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx);
410
411         ret = gendb_search(c_state->sam_ctx,
412                            mem_ctx, NULL, &dom_msgs, dom_attrs,
413                            "(&(objectSid=%s)(&(|(objectclass=domain)(objectClass=builtinDomain))))",
414                            ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
415         if (ret == 0) {
416                 return NT_STATUS_NO_SUCH_DOMAIN;
417         } else if (ret > 1) {
418                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
419         } else if (ret == -1) {
420                 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx)));
421                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
422         } else {
423                 ret = gendb_search(c_state->sam_ctx,
424                                    mem_ctx, partitions_basedn, &ref_msgs, ref_attrs,
425                                    "(&(&(nETBIOSName=*)(objectclass=crossRef))(ncName=%s))", 
426                                    ldb_dn_get_linearized(dom_msgs[0]->dn));
427                 if (ret == 0) {
428                         domain_name = ldb_msg_find_attr_as_string(dom_msgs[0], "cn", NULL);
429                         if (domain_name == NULL) {
430                                 return NT_STATUS_NO_SUCH_DOMAIN;
431                         }
432                 } else if (ret == 1) {
433                 
434                         domain_name = ldb_msg_find_attr_as_string(ref_msgs[0], "nETBIOSName", NULL);
435                         if (domain_name == NULL) {
436                                 return NT_STATUS_NO_SUCH_DOMAIN;
437                         }
438                 } else {
439                         return NT_STATUS_NO_SUCH_DOMAIN;
440                 }
441         }
442
443         d_state = talloc(c_state, struct samr_domain_state);
444         if (!d_state) {
445                 return NT_STATUS_NO_MEMORY;
446         }
447
448         d_state->connect_state = talloc_reference(d_state, c_state);
449         d_state->sam_ctx = c_state->sam_ctx;
450         d_state->domain_sid = dom_sid_dup(d_state, r->in.sid);
451         d_state->domain_name = talloc_strdup(d_state, domain_name);
452         d_state->domain_dn = ldb_dn_copy(d_state, dom_msgs[0]->dn);
453         if (!d_state->domain_sid || !d_state->domain_name || !d_state->domain_dn) {
454                 talloc_free(d_state);
455                 return NT_STATUS_NO_MEMORY;             
456         }
457         d_state->access_mask = r->in.access_mask;
458
459         h_domain = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_DOMAIN);
460         if (!h_domain) {
461                 talloc_free(d_state);
462                 return NT_STATUS_NO_MEMORY;
463         }
464         
465         h_domain->data = talloc_steal(h_domain, d_state);
466
467         *r->out.domain_handle = h_domain->wire_handle;
468
469         return NT_STATUS_OK;
470 }
471
472 /*
473   return DomInfo1
474 */
475 static NTSTATUS dcesrv_samr_info_DomInfo1(struct samr_domain_state *state,
476                                    TALLOC_CTX *mem_ctx,
477                                     struct ldb_message **dom_msgs,
478                                    struct samr_DomInfo1 *info)
479 {
480         info->min_password_length =
481                 samdb_result_uint(dom_msgs[0], "minPwdLength", 0);
482         info->password_history_length =
483                 samdb_result_uint(dom_msgs[0], "pwdHistoryLength", 0);
484         info->password_properties = 
485                 samdb_result_uint(dom_msgs[0], "pwdProperties", 0);
486         info->max_password_age = 
487                 samdb_result_int64(dom_msgs[0], "maxPwdAge", 0);
488         info->min_password_age = 
489                 samdb_result_int64(dom_msgs[0], "minPwdAge", 0);
490
491         return NT_STATUS_OK;
492 }
493
494 /*
495   return DomInfo2
496 */
497 static NTSTATUS dcesrv_samr_info_DomInfo2(struct samr_domain_state *state, TALLOC_CTX *mem_ctx,
498                                     struct ldb_message **dom_msgs,
499                                    struct samr_DomInfo2 *info)
500 {
501         enum server_role role = lp_server_role();
502
503         /* This pulls the NetBIOS name from the 
504            cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
505            string */
506         info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx, dom_msgs[0], "fSMORoleOwner");
507
508         info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff", 
509                                                             0x8000000000000000LL);
510
511         info->comment.string = samdb_result_string(dom_msgs[0], "comment", NULL);
512         info->domain_name.string  = state->domain_name;
513
514         info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount", 
515                                                  0);
516         switch (role) {
517         case ROLE_DOMAIN_CONTROLLER:
518                 /* This pulls the NetBIOS name from the 
519                    cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
520                    string */
521                 if (samdb_is_pdc(state->sam_ctx)) {
522                         info->role = SAMR_ROLE_DOMAIN_PDC;
523                 } else {
524                         info->role = SAMR_ROLE_DOMAIN_BDC;
525                 }
526                 break;
527         case ROLE_DOMAIN_MEMBER:
528                 info->role = SAMR_ROLE_DOMAIN_MEMBER;
529                 break;
530         case ROLE_STANDALONE:
531                 info->role = SAMR_ROLE_STANDALONE;
532                 break;
533         }
534
535         /* No users in BUILTIN, and the LOCAL group types are only in builtin, and the global group type is never in BUILTIN */
536         info->num_users = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn, 
537                                              "(objectClass=user)");
538         info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
539                                               "(&(objectClass=group)(sAMAccountType=%u))",
540                                               ATYPE_GLOBAL_GROUP);
541         info->num_aliases = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
542                                                "(&(objectClass=group)(sAMAccountType=%u))",
543                                                ATYPE_LOCAL_GROUP);
544
545         return NT_STATUS_OK;
546 }
547
548 /*
549   return DomInfo3
550 */
551 static NTSTATUS dcesrv_samr_info_DomInfo3(struct samr_domain_state *state,
552                                    TALLOC_CTX *mem_ctx,
553                                     struct ldb_message **dom_msgs,
554                                    struct samr_DomInfo3 *info)
555 {
556         info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff", 
557                                                       0x8000000000000000LL);
558
559         return NT_STATUS_OK;
560 }
561
562 /*
563   return DomInfo4
564 */
565 static NTSTATUS dcesrv_samr_info_DomInfo4(struct samr_domain_state *state,
566                                    TALLOC_CTX *mem_ctx,
567                                     struct ldb_message **dom_msgs,
568                                    struct samr_DomInfo4 *info)
569 {
570         info->comment.string = samdb_result_string(dom_msgs[0], "comment", NULL);
571
572         return NT_STATUS_OK;
573 }
574
575 /*
576   return DomInfo5
577 */
578 static NTSTATUS dcesrv_samr_info_DomInfo5(struct samr_domain_state *state,
579                                    TALLOC_CTX *mem_ctx,
580                                     struct ldb_message **dom_msgs,
581                                    struct samr_DomInfo5 *info)
582 {
583         info->domain_name.string  = state->domain_name;
584
585         return NT_STATUS_OK;
586 }
587
588 /*
589   return DomInfo6
590 */
591 static NTSTATUS dcesrv_samr_info_DomInfo6(struct samr_domain_state *state,
592                                    TALLOC_CTX *mem_ctx,
593                                    struct ldb_message **dom_msgs,
594                                    struct samr_DomInfo6 *info)
595 {
596         /* This pulls the NetBIOS name from the 
597            cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
598            string */
599         info->primary.string = samdb_result_fsmo_name(state->sam_ctx, mem_ctx, 
600                                                       dom_msgs[0], "fSMORoleOwner");
601
602         return NT_STATUS_OK;
603 }
604
605 /*
606   return DomInfo7
607 */
608 static NTSTATUS dcesrv_samr_info_DomInfo7(struct samr_domain_state *state,
609                                    TALLOC_CTX *mem_ctx,
610                                     struct ldb_message **dom_msgs,
611                                    struct samr_DomInfo7 *info)
612 {
613
614         enum server_role role = lp_server_role();
615
616         switch (role) {
617         case ROLE_DOMAIN_CONTROLLER:
618                 /* This pulls the NetBIOS name from the 
619                    cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
620                    string */
621                 if (samdb_is_pdc(state->sam_ctx)) {
622                         info->role = SAMR_ROLE_DOMAIN_PDC;
623                 } else {
624                         info->role = SAMR_ROLE_DOMAIN_BDC;
625                 }
626                 break;
627         case ROLE_DOMAIN_MEMBER:
628                 info->role = SAMR_ROLE_DOMAIN_MEMBER;
629                 break;
630         case ROLE_STANDALONE:
631                 info->role = SAMR_ROLE_STANDALONE;
632                 break;
633         }
634
635         return NT_STATUS_OK;
636 }
637
638 /*
639   return DomInfo8
640 */
641 static NTSTATUS dcesrv_samr_info_DomInfo8(struct samr_domain_state *state,
642                                    TALLOC_CTX *mem_ctx,
643                                     struct ldb_message **dom_msgs,
644                                    struct samr_DomInfo8 *info)
645 {
646         info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount", 
647                                                time(NULL));
648
649         info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
650                                                      0x0LL);
651
652         return NT_STATUS_OK;
653 }
654
655 /*
656   return DomInfo9
657 */
658 static NTSTATUS dcesrv_samr_info_DomInfo9(struct samr_domain_state *state,
659                                    TALLOC_CTX *mem_ctx,
660                                     struct ldb_message **dom_msgs,
661                                    struct samr_DomInfo9 *info)
662 {
663         info->unknown = 1;
664
665         return NT_STATUS_OK;
666 }
667
668 /*
669   return DomInfo11
670 */
671 static NTSTATUS dcesrv_samr_info_DomInfo11(struct samr_domain_state *state,
672                                     TALLOC_CTX *mem_ctx,
673                                     struct ldb_message **dom_msgs,
674                                     struct samr_DomInfo11 *info)
675 {
676         NTSTATUS status;
677         status = dcesrv_samr_info_DomInfo2(state, mem_ctx, dom_msgs, &info->info2);
678         if (!NT_STATUS_IS_OK(status)) {
679                 return status;
680         }
681         
682         info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration", 
683                                                     -18000000000LL);
684         info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
685                                                     -18000000000LL);
686         info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
687
688         return NT_STATUS_OK;
689 }
690
691 /*
692   return DomInfo12
693 */
694 static NTSTATUS dcesrv_samr_info_DomInfo12(struct samr_domain_state *state,
695                                    TALLOC_CTX *mem_ctx,
696                                     struct ldb_message **dom_msgs,
697                                    struct samr_DomInfo12 *info)
698 {
699         info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration", 
700                                                     -18000000000LL);
701         info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
702                                                     -18000000000LL);
703         info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
704
705         return NT_STATUS_OK;
706 }
707
708 /*
709   return DomInfo13
710 */
711 static NTSTATUS dcesrv_samr_info_DomInfo13(struct samr_domain_state *state,
712                                     TALLOC_CTX *mem_ctx,
713                                     struct ldb_message **dom_msgs,
714                                     struct samr_DomInfo13 *info)
715 {
716         info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount", 
717                                                time(NULL));
718
719         info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
720                                                      0x0LL);
721
722         info->unknown1 = 0;
723         info->unknown2 = 0;
724
725         return NT_STATUS_OK;
726 }
727
728 /* 
729   samr_QueryDomainInfo 
730 */
731 static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
732                                      struct samr_QueryDomainInfo *r)
733 {
734         struct dcesrv_handle *h;
735         struct samr_domain_state *d_state;
736
737         struct ldb_message **dom_msgs;
738         const char * const *attrs = NULL;
739         
740         r->out.info = NULL;
741
742         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
743
744         d_state = h->data;
745
746         r->out.info = talloc(mem_ctx, union samr_DomainInfo);
747         if (!r->out.info) {
748                 return NT_STATUS_NO_MEMORY;
749         }
750
751         switch (r->in.level) {
752         case 1: 
753         {
754                 static const char * const attrs2[] = { "minPwdLength", "pwdHistoryLength",
755                                                        "pwdProperties", "maxPwdAge",
756                                                        "minPwdAge", NULL };
757                 attrs = attrs2;
758                 break;
759         }
760         case 2:
761         {
762                 static const char * const attrs2[] = {"forceLogoff",
763                                                       "comment", 
764                                                       "modifiedCount", 
765                                                       "fSMORoleOwner",
766                                                       NULL};
767                 attrs = attrs2;
768                 break;
769         }
770         case 3:
771         {
772                 static const char * const attrs2[] = {"forceLogoff", 
773                                                       NULL};
774                 attrs = attrs2;
775                 break;
776         }
777         case 4:
778         {
779                 static const char * const attrs2[] = {"comment", 
780                                                       NULL};
781                 attrs = attrs2;
782                 break;
783         }
784         case 5:
785         {
786                 attrs = NULL;
787                 break;
788         }
789         case 6:
790         {
791                 static const char * const attrs2[] = {"fSMORoleOwner", 
792                                                       NULL};
793                 attrs = attrs2;
794                 break;
795         }
796         case 7:
797         {
798                 attrs = NULL;
799                 break;
800         }
801         case 8:
802         {
803                 static const char * const attrs2[] = { "modifiedCount", 
804                                                        "creationTime", 
805                                                        NULL };
806                 attrs = attrs2;
807                 break;
808         }
809         case 9:
810                 attrs = NULL;
811                 break;          
812         case 11:
813         {
814                 static const char * const attrs2[] = { "comment", "forceLogoff", 
815                                                        "modifiedCount", 
816                                                        "lockoutDuration", 
817                                                        "lockOutObservationWindow", 
818                                                        "lockoutThreshold", 
819                                                        NULL};
820                 attrs = attrs2;
821                 break;
822         }
823         case 12:
824         {
825                 static const char * const attrs2[] = { "lockoutDuration", 
826                                                        "lockOutObservationWindow", 
827                                                        "lockoutThreshold", 
828                                                        NULL};
829                 attrs = attrs2;
830                 break;
831         }
832         case 13:
833         {
834                 static const char * const attrs2[] = { "modifiedCount", 
835                                                        "creationTime", 
836                                                        NULL };
837                 attrs = attrs2;
838                 break;
839         }
840         }
841
842         /* some levels don't need a search */
843         if (attrs) {
844                 int ret;
845                 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
846                                       d_state->domain_dn, &dom_msgs, attrs);
847                 if (ret != 1) {
848                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
849                 }
850         }
851
852         ZERO_STRUCTP(r->out.info);
853
854         switch (r->in.level) {
855         case 1:
856                 return dcesrv_samr_info_DomInfo1(d_state, mem_ctx, dom_msgs, 
857                                           &r->out.info->info1);
858         case 2:
859                 return dcesrv_samr_info_DomInfo2(d_state, mem_ctx, dom_msgs, 
860                                           &r->out.info->info2);
861         case 3:
862                 return dcesrv_samr_info_DomInfo3(d_state, mem_ctx, dom_msgs, 
863                                           &r->out.info->info3);
864         case 4:
865                 return dcesrv_samr_info_DomInfo4(d_state, mem_ctx, dom_msgs, 
866                                           &r->out.info->info4);
867         case 5:
868                 return dcesrv_samr_info_DomInfo5(d_state, mem_ctx, dom_msgs, 
869                                           &r->out.info->info5);
870         case 6:
871                 return dcesrv_samr_info_DomInfo6(d_state, mem_ctx, dom_msgs, 
872                                           &r->out.info->info6);
873         case 7:
874                 return dcesrv_samr_info_DomInfo7(d_state, mem_ctx, dom_msgs, 
875                                           &r->out.info->info7);
876         case 8:
877                 return dcesrv_samr_info_DomInfo8(d_state, mem_ctx, dom_msgs, 
878                                           &r->out.info->info8);
879         case 9:
880                 return dcesrv_samr_info_DomInfo9(d_state, mem_ctx, dom_msgs, 
881                                           &r->out.info->info9);
882         case 11:
883                 return dcesrv_samr_info_DomInfo11(d_state, mem_ctx, dom_msgs, 
884                                           &r->out.info->info11);
885         case 12:
886                 return dcesrv_samr_info_DomInfo12(d_state, mem_ctx, dom_msgs, 
887                                           &r->out.info->info12);
888         case 13:
889                 return dcesrv_samr_info_DomInfo13(d_state, mem_ctx, dom_msgs, 
890                                           &r->out.info->info13);
891         }
892
893         return NT_STATUS_INVALID_INFO_CLASS;
894 }
895
896
897 /* 
898   samr_SetDomainInfo 
899 */
900 static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
901                        struct samr_SetDomainInfo *r)
902 {
903         struct dcesrv_handle *h;
904         struct samr_domain_state *d_state;
905         struct ldb_message *msg;
906         int ret;
907         struct ldb_context *sam_ctx;
908
909         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
910
911         d_state = h->data;
912         sam_ctx = d_state->sam_ctx;
913
914         msg = ldb_msg_new(mem_ctx);
915         if (msg == NULL) {
916                 return NT_STATUS_NO_MEMORY;
917         }
918
919         msg->dn = talloc_reference(mem_ctx, d_state->domain_dn);
920         if (!msg->dn) {
921                 return NT_STATUS_NO_MEMORY;
922         }
923
924         switch (r->in.level) {
925         case 1:
926                 SET_UINT  (msg, info1.min_password_length,     "minPwdLength");
927                 SET_UINT  (msg, info1.password_history_length, "pwdHistoryLength");
928                 SET_UINT  (msg, info1.password_properties,     "pwdProperties");
929                 SET_INT64  (msg, info1.max_password_age,       "maxPwdAge");
930                 SET_INT64  (msg, info1.min_password_age,       "minPwdAge");
931                 break;
932         case 3:
933                 SET_UINT64  (msg, info3.force_logoff_time,      "forceLogoff");
934                 break;
935         case 4:
936                 SET_STRING(msg, info4.comment,          "comment");
937                 break;
938
939         case 6:
940         case 7:
941         case 9:
942                 /* No op, we don't know where to set these */
943                 return NT_STATUS_OK;
944
945         case 12:
946                 
947                 SET_INT64  (msg, info12.lockout_duration,      "lockoutDuration");
948                 SET_INT64  (msg, info12.lockout_window,        "lockOutObservationWindow");
949                 SET_INT64  (msg, info12.lockout_threshold,     "lockoutThreshold");
950                 break;
951
952         default:
953                 /* many info classes are not valid for SetDomainInfo */
954                 return NT_STATUS_INVALID_INFO_CLASS;
955         }
956
957         /* modify the samdb record */
958         ret = ldb_modify(sam_ctx, msg);
959         if (ret != 0) {
960                 DEBUG(1,("Failed to modify record %s: %s\n",
961                          ldb_dn_get_linearized(d_state->domain_dn),
962                          ldb_errstring(sam_ctx)));
963
964                 /* we really need samdb.c to return NTSTATUS */
965                 return NT_STATUS_UNSUCCESSFUL;
966         }
967
968         return NT_STATUS_OK;
969 }
970
971 /* 
972   samr_CreateDomainGroup 
973 */
974 static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
975                                        struct samr_CreateDomainGroup *r)
976 {
977         struct samr_domain_state *d_state;
978         struct samr_account_state *a_state;
979         struct dcesrv_handle *h;
980         const char *name;
981         struct ldb_message *msg;
982         struct dom_sid *sid;
983         const char *groupname;
984         struct dcesrv_handle *g_handle;
985         int ret;
986
987         ZERO_STRUCTP(r->out.group_handle);
988         *r->out.rid = 0;
989
990         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
991
992         d_state = h->data;
993
994         groupname = r->in.name->string;
995
996         if (groupname == NULL) {
997                 return NT_STATUS_INVALID_PARAMETER;
998         }
999
1000         /* check if the group already exists */
1001         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL, 
1002                                    "sAMAccountName",
1003                                    "(&(sAMAccountName=%s)(objectclass=group))",
1004                                    ldb_binary_encode_string(mem_ctx, groupname));
1005         if (name != NULL) {
1006                 return NT_STATUS_GROUP_EXISTS;
1007         }
1008
1009         msg = ldb_msg_new(mem_ctx);
1010         if (msg == NULL) {
1011                 return NT_STATUS_NO_MEMORY;
1012         }
1013
1014         /* add core elements to the ldb_message for the user */
1015         msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1016         ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", groupname);
1017         if (!msg->dn) {
1018                 return NT_STATUS_NO_MEMORY;
1019         }
1020         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", groupname);
1021         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1022                              
1023         /* create the group */
1024         ret = samdb_add(d_state->sam_ctx, mem_ctx, msg);
1025         switch (ret) {
1026         case  LDB_SUCCESS:
1027                 break;
1028         case  LDB_ERR_ENTRY_ALREADY_EXISTS:
1029                 DEBUG(0,("Failed to create group record %s: %s\n",
1030                          ldb_dn_get_linearized(msg->dn),
1031                          ldb_errstring(d_state->sam_ctx)));
1032                 return NT_STATUS_GROUP_EXISTS;
1033         case  LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1034                 DEBUG(0,("Failed to create group record %s: %s\n",
1035                          ldb_dn_get_linearized(msg->dn),
1036                          ldb_errstring(d_state->sam_ctx)));
1037                 return NT_STATUS_ACCESS_DENIED;
1038         default:
1039                 DEBUG(0,("Failed to create group record %s: %s\n",
1040                          ldb_dn_get_linearized(msg->dn),
1041                          ldb_errstring(d_state->sam_ctx)));
1042                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1043         }
1044
1045         a_state = talloc(d_state, struct samr_account_state);
1046         if (!a_state) {
1047                 return NT_STATUS_NO_MEMORY;
1048         }
1049         a_state->sam_ctx = d_state->sam_ctx;
1050         a_state->access_mask = r->in.access_mask;
1051         a_state->domain_state = talloc_reference(a_state, d_state);
1052         a_state->account_dn = talloc_steal(a_state, msg->dn);
1053
1054         /* retrieve the sid for the group just created */
1055         sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1056                                    msg->dn, "objectSid", NULL);
1057         if (sid == NULL) {
1058                 return NT_STATUS_UNSUCCESSFUL;
1059         }
1060
1061         a_state->account_name = talloc_strdup(a_state, groupname);
1062         if (!a_state->account_name) {
1063                 return NT_STATUS_NO_MEMORY;
1064         }
1065
1066         /* create the policy handle */
1067         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1068         if (!g_handle) {
1069                 return NT_STATUS_NO_MEMORY;
1070         }
1071
1072         g_handle->data = talloc_steal(g_handle, a_state);
1073
1074         *r->out.group_handle = g_handle->wire_handle;
1075         *r->out.rid = sid->sub_auths[sid->num_auths-1];
1076
1077         return NT_STATUS_OK;
1078 }
1079
1080
1081 /*
1082   comparison function for sorting SamEntry array
1083 */
1084 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
1085 {
1086         return e1->idx - e2->idx;
1087 }
1088
1089 /* 
1090   samr_EnumDomainGroups 
1091 */
1092 static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1093                                       struct samr_EnumDomainGroups *r)
1094 {
1095         struct dcesrv_handle *h;
1096         struct samr_domain_state *d_state;
1097         struct ldb_message **res;
1098         int ldb_cnt, count, i, first;
1099         struct samr_SamEntry *entries;
1100         const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1101
1102         *r->out.resume_handle = 0;
1103         r->out.sam = NULL;
1104         r->out.num_entries = 0;
1105
1106         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1107
1108         d_state = h->data;
1109
1110         /* search for all domain groups in this domain. This could possibly be
1111            cached and resumed based on resume_key */
1112         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1113                                       d_state->domain_dn, &res, attrs,
1114                                       d_state->domain_sid,
1115                                       "(&(grouptype=%d)(objectclass=group))",
1116                                       GTYPE_SECURITY_GLOBAL_GROUP);
1117         if (ldb_cnt == -1) {
1118                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1119         }
1120         if (ldb_cnt == 0 || r->in.max_size == 0) {
1121                 return NT_STATUS_OK;
1122         }
1123
1124         /* convert to SamEntry format */
1125         entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1126         if (!entries) {
1127                 return NT_STATUS_NO_MEMORY;
1128         }
1129
1130         count = 0;
1131
1132         for (i=0;i<ldb_cnt;i++) {
1133                 struct dom_sid *group_sid;
1134
1135                 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
1136                                                  "objectSid");
1137                 if (group_sid == NULL)
1138                         continue;
1139
1140                 entries[count].idx =
1141                         group_sid->sub_auths[group_sid->num_auths-1];
1142                 entries[count].name.string =
1143                         samdb_result_string(res[i], "sAMAccountName", "");
1144                 count += 1;
1145         }
1146
1147         /* sort the results by rid */
1148         qsort(entries, count, sizeof(struct samr_SamEntry), 
1149               (comparison_fn_t)compare_SamEntry);
1150
1151         /* find the first entry to return */
1152         for (first=0;
1153              first<count && entries[first].idx <= *r->in.resume_handle;
1154              first++) ;
1155
1156         if (first == count) {
1157                 return NT_STATUS_OK;
1158         }
1159
1160         /* return the rest, limit by max_size. Note that we 
1161            use the w2k3 element size value of 54 */
1162         r->out.num_entries = count - first;
1163         r->out.num_entries = MIN(r->out.num_entries, 
1164                                  1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1165
1166         r->out.sam = talloc(mem_ctx, struct samr_SamArray);
1167         if (!r->out.sam) {
1168                 return NT_STATUS_NO_MEMORY;
1169         }
1170
1171         r->out.sam->entries = entries+first;
1172         r->out.sam->count = r->out.num_entries;
1173
1174         if (r->out.num_entries < count - first) {
1175                 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
1176                 return STATUS_MORE_ENTRIES;
1177         }
1178
1179         return NT_STATUS_OK;
1180 }
1181
1182
1183 /* 
1184   samr_CreateUser2 
1185
1186   This call uses transactions to ensure we don't get a new conflicting
1187   user while we are processing this, and to ensure the user either
1188   completly exists, or does not.
1189 */
1190 static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1191                                  struct samr_CreateUser2 *r)
1192 {
1193         struct samr_domain_state *d_state;
1194         struct samr_account_state *a_state;
1195         struct dcesrv_handle *h;
1196         const char *name;
1197         struct ldb_message *msg;
1198         struct dom_sid *sid;
1199         const char *account_name;
1200         struct dcesrv_handle *u_handle;
1201         int ret;
1202         const char *container, *obj_class=NULL;
1203         char *cn_name;
1204         int cn_name_len;
1205
1206         const char *attrs[] = {
1207                 "objectSid", 
1208                 "userAccountControl",
1209                 NULL
1210         };
1211
1212         uint32_t user_account_control;
1213
1214         struct ldb_message **msgs;
1215
1216         ZERO_STRUCTP(r->out.user_handle);
1217         *r->out.access_granted = 0;
1218         *r->out.rid = 0;
1219
1220         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1221
1222         d_state = h->data;
1223
1224         account_name = r->in.account_name->string;
1225
1226         if (account_name == NULL) {
1227                 return NT_STATUS_INVALID_PARAMETER;
1228         }
1229
1230         ret = ldb_transaction_start(d_state->sam_ctx);
1231         if (ret != 0) {
1232                 DEBUG(0,("Failed to start a transaction for user creation: %s\n",
1233                          ldb_errstring(d_state->sam_ctx)));
1234                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1235         }
1236
1237         /* check if the user already exists */
1238         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL, 
1239                                    "sAMAccountName", 
1240                                    "(&(sAMAccountName=%s)(objectclass=user))", 
1241                                    ldb_binary_encode_string(mem_ctx, account_name));
1242         if (name != NULL) {
1243                 ldb_transaction_cancel(d_state->sam_ctx);
1244                 return NT_STATUS_USER_EXISTS;
1245         }
1246
1247         msg = ldb_msg_new(mem_ctx);
1248         if (msg == NULL) {
1249                 ldb_transaction_cancel(d_state->sam_ctx);
1250                 return NT_STATUS_NO_MEMORY;
1251         }
1252
1253         cn_name   = talloc_strdup(mem_ctx, account_name);
1254         if (!cn_name) {
1255                 ldb_transaction_cancel(d_state->sam_ctx);
1256                 return NT_STATUS_NO_MEMORY;
1257         }
1258
1259         cn_name_len = strlen(cn_name);
1260
1261         /* This must be one of these values *only* */
1262         if (r->in.acct_flags == ACB_NORMAL) {
1263                 container = "CN=Users";
1264                 obj_class = "user";
1265
1266         } else if (r->in.acct_flags == ACB_WSTRUST) {
1267                 if (cn_name[cn_name_len - 1] != '$') {
1268                         return NT_STATUS_FOOBAR;
1269                 }
1270                 cn_name[cn_name_len - 1] = '\0';
1271                 container = "CN=Computers";
1272                 obj_class = "computer";
1273                 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "primaryGroupID", DOMAIN_RID_DOMAIN_MEMBERS);
1274
1275         } else if (r->in.acct_flags == ACB_SVRTRUST) {
1276                 if (cn_name[cn_name_len - 1] != '$') {
1277                         return NT_STATUS_FOOBAR;                
1278                 }
1279                 cn_name[cn_name_len - 1] = '\0';
1280                 container = "OU=Domain Controllers";
1281                 obj_class = "computer";
1282                 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "primaryGroupID", DOMAIN_RID_DCS);
1283
1284         } else if (r->in.acct_flags == ACB_DOMTRUST) {
1285                 container = "CN=Users";
1286                 obj_class = "user";
1287
1288         } else {
1289                 ldb_transaction_cancel(d_state->sam_ctx);
1290                 return NT_STATUS_INVALID_PARAMETER;
1291         }
1292
1293         /* add core elements to the ldb_message for the user */
1294         msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1295         if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s,%s", cn_name, container)) {
1296                 ldb_transaction_cancel(d_state->sam_ctx);
1297                 return NT_STATUS_FOOBAR;
1298         }
1299
1300         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", account_name);
1301         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", obj_class);
1302         
1303         /* Start a transaction, so we can query and do a subsequent atomic modify */
1304         
1305         /* create the user */
1306         ret = samdb_add(d_state->sam_ctx, mem_ctx, msg);
1307         switch (ret) {
1308         case  LDB_SUCCESS:
1309                 break;
1310         case  LDB_ERR_ENTRY_ALREADY_EXISTS:
1311                 ldb_transaction_cancel(d_state->sam_ctx);
1312                 DEBUG(0,("Failed to create user record %s: %s\n",
1313                          ldb_dn_get_linearized(msg->dn),
1314                          ldb_errstring(d_state->sam_ctx)));
1315                 return NT_STATUS_USER_EXISTS;
1316         case  LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1317                 ldb_transaction_cancel(d_state->sam_ctx);
1318                 DEBUG(0,("Failed to create user record %s: %s\n",
1319                          ldb_dn_get_linearized(msg->dn),
1320                          ldb_errstring(d_state->sam_ctx)));
1321                 return NT_STATUS_ACCESS_DENIED;
1322         default:
1323                 ldb_transaction_cancel(d_state->sam_ctx);
1324                 DEBUG(0,("Failed to create user record %s: %s\n",
1325                          ldb_dn_get_linearized(msg->dn),
1326                          ldb_errstring(d_state->sam_ctx)));
1327                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1328         }
1329
1330         a_state = talloc(d_state, struct samr_account_state);
1331         if (!a_state) {
1332                 ldb_transaction_cancel(d_state->sam_ctx);
1333                 return NT_STATUS_NO_MEMORY;
1334         }
1335         a_state->sam_ctx = d_state->sam_ctx;
1336         a_state->access_mask = r->in.access_mask;
1337         a_state->domain_state = talloc_reference(a_state, d_state);
1338         a_state->account_dn = talloc_steal(a_state, msg->dn);
1339
1340         /* retrieve the sid and account control bits for the user just created */
1341         ret = gendb_search_dn(d_state->sam_ctx, a_state,
1342                               msg->dn, &msgs, attrs);
1343
1344         if (ret != 1) {
1345                 ldb_transaction_cancel(d_state->sam_ctx);
1346                 DEBUG(0,("Apparently we failed to create an account record, as %s now doesn't exist\n",
1347                          ldb_dn_get_linearized(msg->dn)));
1348                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1349         }
1350         sid = samdb_result_dom_sid(mem_ctx, msgs[0], "objectSid");
1351         if (sid == NULL) {
1352                 ldb_transaction_cancel(d_state->sam_ctx);
1353                 DEBUG(0,("Apparently we failed to get the objectSid of the just created account record %s\n",
1354                          ldb_dn_get_linearized(msg->dn)));
1355                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1356         }
1357
1358         /* Change the account control to be the correct account type.
1359          * The default is for a workstation account */
1360         user_account_control = samdb_result_uint(msgs[0], "userAccountControl", 0);
1361         user_account_control = (user_account_control & 
1362                                 ~(UF_NORMAL_ACCOUNT |
1363                                   UF_INTERDOMAIN_TRUST_ACCOUNT | 
1364                                   UF_WORKSTATION_TRUST_ACCOUNT | 
1365                                   UF_SERVER_TRUST_ACCOUNT));
1366         user_account_control |= samdb_acb2uf(r->in.acct_flags);
1367
1368         talloc_free(msg);
1369         msg = ldb_msg_new(mem_ctx);
1370         if (msg == NULL) {
1371                 ldb_transaction_cancel(d_state->sam_ctx);
1372                 return NT_STATUS_NO_MEMORY;
1373         }
1374
1375         msg->dn = ldb_dn_copy(msg, a_state->account_dn);
1376
1377         if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, msg, 
1378                                "userAccountControl", 
1379                                user_account_control) != 0) { 
1380                 ldb_transaction_cancel(d_state->sam_ctx);
1381                 return NT_STATUS_NO_MEMORY; 
1382         }
1383
1384         /* modify the samdb record */
1385         ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
1386         if (ret != 0) {
1387                 DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n",
1388                          ldb_dn_get_linearized(msg->dn),
1389                          ldb_errstring(d_state->sam_ctx)));
1390                 ldb_transaction_cancel(d_state->sam_ctx);
1391
1392                 /* we really need samdb.c to return NTSTATUS */
1393                 return NT_STATUS_UNSUCCESSFUL;
1394         }
1395
1396         ret = ldb_transaction_commit(d_state->sam_ctx);
1397         if (ret != 0) {
1398                 DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n",
1399                          ldb_dn_get_linearized(msg->dn),
1400                          ldb_errstring(d_state->sam_ctx)));
1401                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1402         }
1403
1404         a_state->account_name = talloc_steal(a_state, account_name);
1405         if (!a_state->account_name) {
1406                 return NT_STATUS_NO_MEMORY;
1407         }
1408
1409         /* create the policy handle */
1410         u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
1411         if (!u_handle) {
1412                 return NT_STATUS_NO_MEMORY;
1413         }
1414
1415         u_handle->data = talloc_steal(u_handle, a_state);
1416
1417         *r->out.user_handle = u_handle->wire_handle;
1418         *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1419
1420         *r->out.rid = sid->sub_auths[sid->num_auths-1];
1421
1422         return NT_STATUS_OK;
1423 }
1424
1425
1426 /* 
1427   samr_CreateUser 
1428 */
1429 static NTSTATUS dcesrv_samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1430                                 struct samr_CreateUser *r)
1431 {
1432         struct samr_CreateUser2 r2;
1433         uint32_t access_granted = 0;
1434
1435
1436         /* a simple wrapper around samr_CreateUser2 works nicely */
1437         r2.in.domain_handle = r->in.domain_handle;
1438         r2.in.account_name = r->in.account_name;
1439         r2.in.acct_flags = ACB_NORMAL;
1440         r2.in.access_mask = r->in.access_mask;
1441         r2.out.user_handle = r->out.user_handle;
1442         r2.out.access_granted = &access_granted;
1443         r2.out.rid = r->out.rid;
1444
1445         return dcesrv_samr_CreateUser2(dce_call, mem_ctx, &r2);
1446 }
1447
1448 /* 
1449   samr_EnumDomainUsers 
1450 */
1451 static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1452                                      struct samr_EnumDomainUsers *r)
1453 {
1454         struct dcesrv_handle *h;
1455         struct samr_domain_state *d_state;
1456         struct ldb_message **res;
1457         int count, num_filtered_entries, i, first;
1458         struct samr_SamEntry *entries;
1459         const char * const attrs[] = { "objectSid", "sAMAccountName", "userAccountControl", NULL };
1460
1461         *r->out.resume_handle = 0;
1462         r->out.sam = NULL;
1463         r->out.num_entries = 0;
1464
1465         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1466
1467         d_state = h->data;
1468         
1469         /* search for all users in this domain. This could possibly be cached and 
1470            resumed based on resume_key */
1471         count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs, 
1472                              "objectclass=user");
1473         if (count == -1) {
1474                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1475         }
1476         if (count == 0 || r->in.max_size == 0) {
1477                 return NT_STATUS_OK;
1478         }
1479
1480         /* convert to SamEntry format */
1481         entries = talloc_array(mem_ctx, struct samr_SamEntry, count);
1482         if (!entries) {
1483                 return NT_STATUS_NO_MEMORY;
1484         }
1485         num_filtered_entries = 0;
1486         for (i=0;i<count;i++) {
1487                 /* Check if a mask has been requested */
1488                 if (r->in.acct_flags
1489                     && ((samdb_result_acct_flags(res[i], 
1490                                                  "userAccountControl") & r->in.acct_flags) == 0)) {
1491                         continue;
1492                 }
1493                 entries[num_filtered_entries].idx = samdb_result_rid_from_sid(mem_ctx, res[i], "objectSid", 0);
1494                 entries[num_filtered_entries].name.string = samdb_result_string(res[i], "sAMAccountName", "");
1495                 num_filtered_entries++;
1496         }
1497
1498         /* sort the results by rid */
1499         qsort(entries, num_filtered_entries, sizeof(struct samr_SamEntry), 
1500               (comparison_fn_t)compare_SamEntry);
1501
1502         /* find the first entry to return */
1503         for (first=0;
1504              first<num_filtered_entries && entries[first].idx <= *r->in.resume_handle;
1505              first++) ;
1506
1507         /* return the rest, limit by max_size. Note that we 
1508            use the w2k3 element size value of 54 */
1509         r->out.num_entries = num_filtered_entries - first;
1510         r->out.num_entries = MIN(r->out.num_entries, 
1511                                  1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1512
1513         r->out.sam = talloc(mem_ctx, struct samr_SamArray);
1514         if (!r->out.sam) {
1515                 return NT_STATUS_NO_MEMORY;
1516         }
1517
1518         r->out.sam->entries = entries+first;
1519         r->out.sam->count = r->out.num_entries;
1520
1521         if (first == num_filtered_entries) {
1522                 return NT_STATUS_OK;
1523         }
1524
1525         if (r->out.num_entries < num_filtered_entries - first) {
1526                 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
1527                 return STATUS_MORE_ENTRIES;
1528         }
1529
1530         return NT_STATUS_OK;
1531 }
1532
1533
1534 /* 
1535   samr_CreateDomAlias 
1536 */
1537 static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1538                        struct samr_CreateDomAlias *r)
1539 {
1540         struct samr_domain_state *d_state;
1541         struct samr_account_state *a_state;
1542         struct dcesrv_handle *h;
1543         const char *alias_name, *name;
1544         struct ldb_message *msg;
1545         struct dom_sid *sid;
1546         struct dcesrv_handle *a_handle;
1547         int ret;
1548
1549         ZERO_STRUCTP(r->out.alias_handle);
1550         *r->out.rid = 0;
1551
1552         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1553
1554         d_state = h->data;
1555
1556         alias_name = r->in.alias_name->string;
1557
1558         if (alias_name == NULL) {
1559                 return NT_STATUS_INVALID_PARAMETER;
1560         }
1561
1562         /* Check if alias already exists */
1563         name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1564                                    "sAMAccountName",
1565                                    "(sAMAccountName=%s)(objectclass=group))",
1566                                    ldb_binary_encode_string(mem_ctx, alias_name));
1567
1568         if (name != NULL) {
1569                 return NT_STATUS_ALIAS_EXISTS;
1570         }
1571
1572         msg = ldb_msg_new(mem_ctx);
1573         if (msg == NULL) {
1574                 return NT_STATUS_NO_MEMORY;
1575         }
1576
1577         /* add core elements to the ldb_message for the alias */
1578         msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1579         ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", alias_name);
1580         if (!msg->dn) {
1581                 return NT_STATUS_NO_MEMORY;
1582         }
1583
1584         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", alias_name);
1585         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1586         samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "groupType", GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1587
1588         /* create the alias */
1589         ret = samdb_add(d_state->sam_ctx, mem_ctx, msg);
1590         switch (ret) {
1591         case LDB_SUCCESS:
1592                 break;
1593         case LDB_ERR_ENTRY_ALREADY_EXISTS:
1594                 return NT_STATUS_ALIAS_EXISTS;
1595         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1596                 return NT_STATUS_ACCESS_DENIED;
1597         default:
1598                 DEBUG(0,("Failed to create alias record %s: %s\n",
1599                          ldb_dn_get_linearized(msg->dn),
1600                          ldb_errstring(d_state->sam_ctx)));
1601                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1602         }
1603
1604         a_state = talloc(d_state, struct samr_account_state);
1605         if (!a_state) {
1606                 return NT_STATUS_NO_MEMORY;
1607         }
1608
1609         a_state->sam_ctx = d_state->sam_ctx;
1610         a_state->access_mask = r->in.access_mask;
1611         a_state->domain_state = talloc_reference(a_state, d_state);
1612         a_state->account_dn = talloc_steal(a_state, msg->dn);
1613
1614         /* retrieve the sid for the alias just created */
1615         sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1616                                    msg->dn, "objectSid", NULL);
1617
1618         a_state->account_name = talloc_strdup(a_state, alias_name);
1619         if (!a_state->account_name) {
1620                 return NT_STATUS_NO_MEMORY;
1621         }
1622
1623         /* create the policy handle */
1624         a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1625         if (a_handle == NULL)
1626                 return NT_STATUS_NO_MEMORY;
1627
1628         a_handle->data = talloc_steal(a_handle, a_state);
1629
1630         *r->out.alias_handle = a_handle->wire_handle;
1631
1632         *r->out.rid = sid->sub_auths[sid->num_auths-1];
1633
1634         return NT_STATUS_OK;
1635 }
1636
1637
1638 /* 
1639   samr_EnumDomainAliases 
1640 */
1641 static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1642                        struct samr_EnumDomainAliases *r)
1643 {
1644         struct dcesrv_handle *h;
1645         struct samr_domain_state *d_state;
1646         struct ldb_message **res;
1647         int ldb_cnt, count, i, first;
1648         struct samr_SamEntry *entries;
1649         const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1650
1651         *r->out.resume_handle = 0;
1652         r->out.sam = NULL;
1653         r->out.num_entries = 0;
1654
1655         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1656
1657         d_state = h->data;
1658
1659         /* search for all domain groups in this domain. This could possibly be
1660            cached and resumed based on resume_key */
1661         ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1662                                       d_state->domain_dn,
1663                                       &res, attrs, 
1664                                       d_state->domain_sid,
1665                                       "(&(|(grouptype=%d)(grouptype=%d)))"
1666                                       "(objectclass=group))",
1667                                       GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1668                                       GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1669         if (ldb_cnt == -1) {
1670                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1671         }
1672         if (ldb_cnt == 0) {
1673                 return NT_STATUS_OK;
1674         }
1675
1676         /* convert to SamEntry format */
1677         entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1678         if (!entries) {
1679                 return NT_STATUS_NO_MEMORY;
1680         }
1681
1682         count = 0;
1683
1684         for (i=0;i<ldb_cnt;i++) {
1685                 struct dom_sid *alias_sid;
1686
1687                 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1688                                                  "objectSid");
1689
1690                 if (alias_sid == NULL)
1691                         continue;
1692
1693                 entries[count].idx =
1694                         alias_sid->sub_auths[alias_sid->num_auths-1];
1695                 entries[count].name.string =
1696                         samdb_result_string(res[i], "sAMAccountName", "");
1697                 count += 1;
1698         }
1699
1700         /* sort the results by rid */
1701         qsort(entries, count, sizeof(struct samr_SamEntry), 
1702               (comparison_fn_t)compare_SamEntry);
1703
1704         /* find the first entry to return */
1705         for (first=0;
1706              first<count && entries[first].idx <= *r->in.resume_handle;
1707              first++) ;
1708
1709         if (first == count) {
1710                 return NT_STATUS_OK;
1711         }
1712
1713         r->out.num_entries = count - first;
1714         r->out.num_entries = MIN(r->out.num_entries, 1000);
1715
1716         r->out.sam = talloc(mem_ctx, struct samr_SamArray);
1717         if (!r->out.sam) {
1718                 return NT_STATUS_NO_MEMORY;
1719         }
1720
1721         r->out.sam->entries = entries+first;
1722         r->out.sam->count = r->out.num_entries;
1723
1724         if (r->out.num_entries < count - first) {
1725                 *r->out.resume_handle =
1726                         entries[first+r->out.num_entries-1].idx;
1727                 return STATUS_MORE_ENTRIES;
1728         }
1729
1730         return NT_STATUS_OK;
1731 }
1732
1733
1734 /* 
1735   samr_GetAliasMembership 
1736 */
1737 static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1738                        struct samr_GetAliasMembership *r)
1739 {
1740         struct dcesrv_handle *h;
1741         struct samr_domain_state *d_state;
1742         struct ldb_message **res;
1743         int i, count = 0;
1744
1745         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1746
1747         d_state = h->data;
1748
1749         if (r->in.sids->num_sids > 0) {
1750                 const char *filter;
1751                 const char * const attrs[2] = { "objectSid", NULL };
1752
1753                 filter = talloc_asprintf(mem_ctx,
1754                                          "(&(|(grouptype=%d)(grouptype=%d))"
1755                                          "(objectclass=group)(|",
1756                                          GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1757                                          GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1758                 if (filter == NULL)
1759                         return NT_STATUS_NO_MEMORY;
1760
1761                 for (i=0; i<r->in.sids->num_sids; i++) {
1762                         const char *memberdn;
1763
1764                         memberdn = 
1765                                 samdb_search_string(d_state->sam_ctx,
1766                                                     mem_ctx, NULL, "distinguishedName",
1767                                                     "(objectSid=%s)",
1768                                                     ldap_encode_ndr_dom_sid(mem_ctx, 
1769                                                                             r->in.sids->sids[i].sid));
1770
1771                         if (memberdn == NULL)
1772                                 continue;
1773
1774                         filter = talloc_asprintf(mem_ctx, "%s(member=%s)",
1775                                                  filter, memberdn);
1776                         if (filter == NULL)
1777                                 return NT_STATUS_NO_MEMORY;
1778                 }
1779
1780                 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1781                                             d_state->domain_dn, &res, attrs,
1782                                             d_state->domain_sid, "%s))", filter);
1783                 if (count < 0)
1784                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1785         }
1786
1787         r->out.rids->count = 0;
1788         r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1789         if (r->out.rids->ids == NULL)
1790                 return NT_STATUS_NO_MEMORY;
1791
1792         for (i=0; i<count; i++) {
1793                 struct dom_sid *alias_sid;
1794
1795                 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1796
1797                 if (alias_sid == NULL) {
1798                         DEBUG(0, ("Could not find objectSid\n"));
1799                         continue;
1800                 }
1801
1802                 r->out.rids->ids[r->out.rids->count] =
1803                         alias_sid->sub_auths[alias_sid->num_auths-1];
1804                 r->out.rids->count += 1;
1805         }
1806
1807         return NT_STATUS_OK;
1808 }
1809
1810
1811 /* 
1812   samr_LookupNames 
1813 */
1814 static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1815                                  struct samr_LookupNames *r)
1816 {
1817         struct dcesrv_handle *h;
1818         struct samr_domain_state *d_state;
1819         int i, num_mapped;
1820         NTSTATUS status = NT_STATUS_OK;
1821         const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1822         int count;
1823
1824         ZERO_STRUCT(r->out.rids);
1825         ZERO_STRUCT(r->out.types);
1826
1827         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1828
1829         d_state = h->data;
1830
1831         if (r->in.num_names == 0) {
1832                 return NT_STATUS_OK;
1833         }
1834
1835         r->out.rids.ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1836         r->out.types.ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1837         if (!r->out.rids.ids || !r->out.types.ids) {
1838                 return NT_STATUS_NO_MEMORY;
1839         }
1840         r->out.rids.count = r->in.num_names;
1841         r->out.types.count = r->in.num_names;
1842
1843         num_mapped = 0;
1844
1845         for (i=0;i<r->in.num_names;i++) {
1846                 struct ldb_message **res;
1847                 struct dom_sid *sid;
1848                 uint32_t atype, rtype;
1849
1850                 r->out.rids.ids[i] = 0;
1851                 r->out.types.ids[i] = SID_NAME_UNKNOWN;
1852
1853                 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs, 
1854                                      "sAMAccountName=%s", 
1855                                      ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1856                 if (count != 1) {
1857                         status = STATUS_SOME_UNMAPPED;
1858                         continue;
1859                 }
1860
1861                 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1862                 if (sid == NULL) {
1863                         status = STATUS_SOME_UNMAPPED;
1864                         continue;
1865                 }
1866                 
1867                 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1868                 if (atype == 0) {
1869                         status = STATUS_SOME_UNMAPPED;
1870                         continue;
1871                 }
1872
1873                 rtype = samdb_atype_map(atype);
1874                 
1875                 if (rtype == SID_NAME_UNKNOWN) {
1876                         status = STATUS_SOME_UNMAPPED;
1877                         continue;
1878                 }
1879
1880                 r->out.rids.ids[i] = sid->sub_auths[sid->num_auths-1];
1881                 r->out.types.ids[i] = rtype;
1882                 num_mapped++;
1883         }
1884         
1885         if (num_mapped == 0) {
1886                 return NT_STATUS_NONE_MAPPED;
1887         }
1888         return status;
1889 }
1890
1891
1892 /* 
1893   samr_LookupRids 
1894 */
1895 static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1896                        struct samr_LookupRids *r)
1897 {
1898         struct dcesrv_handle *h;
1899         struct samr_domain_state *d_state;
1900         int i, total;
1901         NTSTATUS status = NT_STATUS_OK;
1902         struct lsa_String *names;
1903         uint32_t *ids;
1904
1905         ZERO_STRUCT(r->out.names);
1906         ZERO_STRUCT(r->out.types);
1907
1908         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1909
1910         d_state = h->data;
1911
1912         if (r->in.num_rids == 0)
1913                 return NT_STATUS_OK;
1914
1915         names = talloc_array(mem_ctx, struct lsa_String, r->in.num_rids);
1916         ids = talloc_array(mem_ctx, uint32_t, r->in.num_rids);
1917
1918         if ((names == NULL) || (ids == NULL))
1919                 return NT_STATUS_NO_MEMORY;
1920
1921         total = 0;
1922
1923         for (i=0; i<r->in.num_rids; i++) {
1924                 struct ldb_message **res;
1925                 int count;
1926                 const char * const attrs[] = {  "sAMAccountType",
1927                                                 "sAMAccountName", NULL };
1928                 uint32_t atype;
1929                 struct dom_sid *sid;
1930
1931                 ids[i] = SID_NAME_UNKNOWN;
1932
1933                 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rids[i]);
1934                 if (sid == NULL) {
1935                         names[i].string = NULL;
1936                         status = STATUS_SOME_UNMAPPED;
1937                         continue;
1938                 }
1939                 
1940                 count = gendb_search(d_state->sam_ctx, mem_ctx,
1941                                      d_state->domain_dn, &res, attrs,
1942                                      "(objectSid=%s)", 
1943                                      ldap_encode_ndr_dom_sid(mem_ctx, sid));
1944                 if (count != 1) {
1945                         names[i].string = NULL;
1946                         status = STATUS_SOME_UNMAPPED;
1947                         continue;
1948                 }
1949
1950                 names[i].string = samdb_result_string(res[0], "sAMAccountName",
1951                                                       NULL);
1952
1953                 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1954                 if (atype == 0) {
1955                         status = STATUS_SOME_UNMAPPED;
1956                         continue;
1957                 }
1958
1959                 ids[i] = samdb_atype_map(atype);
1960                 
1961                 if (ids[i] == SID_NAME_UNKNOWN) {
1962                         status = STATUS_SOME_UNMAPPED;
1963                         continue;
1964                 }
1965         }
1966
1967         r->out.names.names = names;
1968         r->out.names.count = r->in.num_rids;
1969
1970         r->out.types.ids = ids;
1971         r->out.types.count = r->in.num_rids;
1972
1973         return status;
1974 }
1975
1976
1977 /* 
1978   samr_OpenGroup 
1979 */
1980 static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1981                        struct samr_OpenGroup *r)
1982 {
1983         struct samr_domain_state *d_state;
1984         struct samr_account_state *a_state;
1985         struct dcesrv_handle *h;
1986         const char *groupname;
1987         struct dom_sid *sid;
1988         struct ldb_message **msgs;
1989         struct dcesrv_handle *g_handle;
1990         const char * const attrs[2] = { "sAMAccountName", NULL };
1991         int ret;
1992
1993         ZERO_STRUCTP(r->out.group_handle);
1994
1995         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1996
1997         d_state = h->data;
1998
1999         /* form the group SID */
2000         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2001         if (!sid) {
2002                 return NT_STATUS_NO_MEMORY;
2003         }
2004
2005         /* search for the group record */
2006         ret = gendb_search(d_state->sam_ctx,
2007                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2008                            "(&(objectSid=%s)(objectclass=group)"
2009                            "(grouptype=%d))",
2010                            ldap_encode_ndr_dom_sid(mem_ctx, sid),
2011                            GTYPE_SECURITY_GLOBAL_GROUP);
2012         if (ret == 0) {
2013                 return NT_STATUS_NO_SUCH_GROUP;
2014         }
2015         if (ret != 1) {
2016                 DEBUG(0,("Found %d records matching sid %s\n", 
2017                          ret, dom_sid_string(mem_ctx, sid)));
2018                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2019         }
2020
2021         groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2022         if (groupname == NULL) {
2023                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2024                          dom_sid_string(mem_ctx, sid)));
2025                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2026         }
2027
2028         a_state = talloc(d_state, struct samr_account_state);
2029         if (!a_state) {
2030                 return NT_STATUS_NO_MEMORY;
2031         }
2032         a_state->sam_ctx = d_state->sam_ctx;
2033         a_state->access_mask = r->in.access_mask;
2034         a_state->domain_state = talloc_reference(a_state, d_state);
2035         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2036         a_state->account_sid = talloc_steal(a_state, sid);
2037         a_state->account_name = talloc_strdup(a_state, groupname);
2038         if (!a_state->account_name) {
2039                 return NT_STATUS_NO_MEMORY;
2040         }
2041
2042         /* create the policy handle */
2043         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
2044         if (!g_handle) {
2045                 return NT_STATUS_NO_MEMORY;
2046         }
2047
2048         g_handle->data = talloc_steal(g_handle, a_state);
2049
2050         *r->out.group_handle = g_handle->wire_handle;
2051
2052         return NT_STATUS_OK;
2053 }
2054
2055 /* 
2056   samr_QueryGroupInfo 
2057 */
2058 static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2059                        struct samr_QueryGroupInfo *r)
2060 {
2061         struct dcesrv_handle *h;
2062         struct samr_account_state *a_state;
2063         struct ldb_message *msg, **res;
2064         const char * const attrs[4] = { "sAMAccountName", "description",
2065                                         "numMembers", NULL };
2066         int ret;
2067
2068         r->out.info = NULL;
2069
2070         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2071
2072         a_state = h->data;
2073
2074         /* pull all the group attributes */
2075         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2076                               a_state->account_dn, &res, attrs);
2077         if (ret != 1) {
2078                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2079         }
2080         msg = res[0];
2081
2082         /* allocate the info structure */
2083         r->out.info = talloc(mem_ctx, union samr_GroupInfo);
2084         if (r->out.info == NULL) {
2085                 return NT_STATUS_NO_MEMORY;
2086         }
2087         ZERO_STRUCTP(r->out.info);
2088
2089         /* Fill in the level */
2090         switch (r->in.level) {
2091         case GROUPINFOALL:
2092                 QUERY_STRING(msg, all.name,        "sAMAccountName");
2093                 r->out.info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2094                 QUERY_UINT  (msg, all.num_members,      "numMembers")
2095                 QUERY_STRING(msg, all.description, "description");
2096                 break;
2097         case GROUPINFONAME:
2098                 QUERY_STRING(msg, name,            "sAMAccountName");
2099                 break;
2100         case GROUPINFOATTRIBUTES:
2101                 r->out.info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2102                 break;
2103         case GROUPINFODESCRIPTION:
2104                 QUERY_STRING(msg, description, "description");
2105                 break;
2106         case GROUPINFOALL2:
2107                 QUERY_STRING(msg, all2.name,        "sAMAccountName");
2108                 r->out.info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2109                 QUERY_UINT  (msg, all2.num_members,      "numMembers")
2110                 QUERY_STRING(msg, all2.description, "description");
2111                 break;
2112         default:
2113                 r->out.info = NULL;
2114                 return NT_STATUS_INVALID_INFO_CLASS;
2115         }
2116         
2117         return NT_STATUS_OK;
2118 }
2119
2120
2121 /* 
2122   samr_SetGroupInfo 
2123 */
2124 static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2125                                   struct samr_SetGroupInfo *r)
2126 {
2127         struct dcesrv_handle *h;
2128         struct samr_account_state *g_state;
2129         struct ldb_message *msg;
2130         struct ldb_context *sam_ctx;
2131         int ret;
2132
2133         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2134
2135         g_state = h->data;
2136         sam_ctx = g_state->sam_ctx;
2137
2138         msg = ldb_msg_new(mem_ctx);
2139         if (msg == NULL) {
2140                 return NT_STATUS_NO_MEMORY;
2141         }       
2142
2143         msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
2144         if (!msg->dn) {
2145                 return NT_STATUS_NO_MEMORY;
2146         }
2147
2148         switch (r->in.level) {
2149         case GROUPINFODESCRIPTION:
2150                 SET_STRING(msg, description,         "description");
2151                 break;
2152         case GROUPINFONAME:
2153                 /* On W2k3 this does not change the name, it changes the
2154                  * sAMAccountName attribute */
2155                 SET_STRING(msg, name,                "sAMAccountName");
2156                 break;
2157         case GROUPINFOATTRIBUTES:
2158                 /* This does not do anything obviously visible in W2k3 LDAP */
2159                 return NT_STATUS_OK;
2160         default:
2161                 return NT_STATUS_INVALID_INFO_CLASS;
2162         }
2163
2164         /* modify the samdb record */
2165         ret = ldb_modify(g_state->sam_ctx, msg);
2166         if (ret != 0) {
2167                 /* we really need samdb.c to return NTSTATUS */
2168                 return NT_STATUS_UNSUCCESSFUL;
2169         }
2170
2171         return NT_STATUS_OK;
2172 }
2173
2174
2175 /* 
2176   samr_AddGroupMember 
2177 */
2178 static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2179                        struct samr_AddGroupMember *r)
2180 {
2181         struct dcesrv_handle *h;
2182         struct samr_account_state *a_state;
2183         struct samr_domain_state *d_state;
2184         struct ldb_message *mod;
2185         struct dom_sid *membersid;
2186         const char *memberdn;
2187         struct ldb_result *res;
2188         const char * const attrs[] = { NULL };
2189         int ret;
2190
2191         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2192
2193         a_state = h->data;
2194         d_state = a_state->domain_state;
2195
2196         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2197         if (membersid == NULL)
2198                 return NT_STATUS_NO_MEMORY;
2199
2200         /* In native mode, AD can also nest domain groups. Not sure yet
2201          * whether this is also available via RPC. */
2202         ret = ldb_search_exp_fmt(d_state->sam_ctx, mem_ctx, &res,
2203                                  d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2204                                  "(&(objectSid=%s)(objectclass=user))",
2205                                  ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2206
2207         if (ret != 0) {
2208                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2209         }
2210
2211         if (res->count == 0) {
2212                 return NT_STATUS_NO_SUCH_USER;
2213         }
2214                 
2215         if (res->count > 1) {
2216                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2217         }
2218
2219         memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2220
2221         if (memberdn == NULL)
2222                 return NT_STATUS_NO_MEMORY;
2223
2224         mod = ldb_msg_new(mem_ctx);
2225         if (mod == NULL) {
2226                 return NT_STATUS_NO_MEMORY;
2227         }
2228
2229         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2230
2231         if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2232                                  memberdn) != 0)
2233                 return NT_STATUS_UNSUCCESSFUL;
2234
2235         ret = ldb_modify(a_state->sam_ctx, mod);
2236         switch (ret) {
2237         case LDB_SUCCESS:
2238                 return NT_STATUS_OK;
2239         case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
2240                 return NT_STATUS_MEMBER_IN_GROUP;
2241         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2242                 return NT_STATUS_ACCESS_DENIED;
2243         default:
2244                 return NT_STATUS_UNSUCCESSFUL;
2245         }
2246
2247 }
2248
2249
2250 /* 
2251   samr_DeleteDomainGroup 
2252 */
2253 static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2254                        struct samr_DeleteDomainGroup *r)
2255 {
2256         struct dcesrv_handle *h;
2257         struct samr_account_state *a_state;
2258         int ret;
2259
2260         *r->out.group_handle = *r->in.group_handle;
2261
2262         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2263
2264         a_state = h->data;
2265
2266         ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
2267         if (ret != 0) {
2268                 return NT_STATUS_UNSUCCESSFUL;
2269         }
2270
2271         ZERO_STRUCTP(r->out.group_handle);
2272
2273         return NT_STATUS_OK;
2274 }
2275
2276
2277 /* 
2278   samr_DeleteGroupMember 
2279 */
2280 static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2281                        struct samr_DeleteGroupMember *r)
2282 {
2283         struct dcesrv_handle *h;
2284         struct samr_account_state *a_state;
2285         struct samr_domain_state *d_state;
2286         struct ldb_message *mod;
2287         struct dom_sid *membersid;
2288         const char *memberdn;
2289         struct ldb_result *res;
2290         const char * const attrs[] = { NULL };
2291         int ret;
2292
2293         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2294
2295         a_state = h->data;
2296         d_state = a_state->domain_state;
2297
2298         membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2299         if (membersid == NULL)
2300                 return NT_STATUS_NO_MEMORY;
2301
2302         /* In native mode, AD can also nest domain groups. Not sure yet
2303          * whether this is also available via RPC. */
2304         ret = ldb_search_exp_fmt(d_state->sam_ctx, mem_ctx, &res,
2305                                  d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2306                                  "(&(objectSid=%s)(objectclass=user))",
2307                                  ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2308
2309         if (ret != 0) {
2310                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2311         }
2312
2313         if (res->count == 0) {
2314                 return NT_STATUS_NO_SUCH_USER;
2315         }
2316                 
2317         if (res->count > 1) {
2318                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2319         }
2320
2321         memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2322
2323         if (memberdn == NULL)
2324                 return NT_STATUS_NO_MEMORY;
2325
2326         mod = ldb_msg_new(mem_ctx);
2327         if (mod == NULL) {
2328                 return NT_STATUS_NO_MEMORY;
2329         }
2330
2331         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2332
2333         if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2334                                  memberdn) != 0) {
2335                 return NT_STATUS_NO_MEMORY;
2336         }
2337
2338         ret = ldb_modify(a_state->sam_ctx, mod);
2339         switch (ret) {
2340         case LDB_SUCCESS:
2341                 return NT_STATUS_OK;
2342         case LDB_ERR_NO_SUCH_ATTRIBUTE:
2343                 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2344         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2345                 return NT_STATUS_ACCESS_DENIED;
2346         default:
2347                 return NT_STATUS_UNSUCCESSFUL;
2348         }
2349
2350 }
2351
2352
2353 /* 
2354   samr_QueryGroupMember 
2355 */
2356 static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2357                                       struct samr_QueryGroupMember *r)
2358 {
2359         struct dcesrv_handle *h;
2360         struct samr_account_state *a_state;
2361         struct ldb_message **res;
2362         struct ldb_message_element *el;
2363         struct samr_RidTypeArray *array;
2364         const char * const attrs[2] = { "member", NULL };
2365         int ret;
2366
2367         DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2368
2369         a_state = h->data;
2370
2371         /* pull the member attribute */
2372         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2373                               a_state->account_dn, &res, attrs);
2374
2375         if (ret != 1) {
2376                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2377         }
2378
2379         array = talloc(mem_ctx, struct samr_RidTypeArray);
2380
2381         if (array == NULL)
2382                 return NT_STATUS_NO_MEMORY;
2383
2384         ZERO_STRUCTP(array);
2385
2386         el = ldb_msg_find_element(res[0], "member");
2387
2388         if (el != NULL) {
2389                 int i;
2390
2391                 array->count = el->num_values;
2392
2393                 array->rids = talloc_array(mem_ctx, uint32_t,
2394                                              el->num_values);
2395                 if (array->rids == NULL)
2396                         return NT_STATUS_NO_MEMORY;
2397
2398                 array->types = talloc_array(mem_ctx, uint32_t,
2399                                             el->num_values);
2400                 if (array->types == NULL)
2401                         return NT_STATUS_NO_MEMORY;
2402
2403                 for (i=0; i<el->num_values; i++) {
2404                         struct ldb_message **res2;
2405                         const char * const attrs2[2] = { "objectSid", NULL };
2406                         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2407                                            ldb_dn_new(mem_ctx, a_state->sam_ctx, (const char *)el->values[i].data),
2408                                            &res2, attrs2);
2409                         if (ret != 1)
2410                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2411
2412                         array->rids[i] =
2413                                 samdb_result_rid_from_sid(mem_ctx, res2[0],
2414                                                           "objectSid", 0);
2415
2416                         if (array->rids[i] == 0)
2417                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2418
2419                         array->types[i] = 7; /* RID type of some kind, not sure what the value means. */
2420                 }
2421         }
2422
2423         r->out.rids = array;
2424
2425         return NT_STATUS_OK;
2426 }
2427
2428
2429 /* 
2430   samr_SetMemberAttributesOfGroup 
2431 */
2432 static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2433                        struct samr_SetMemberAttributesOfGroup *r)
2434 {
2435         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2436 }
2437
2438
2439 /* 
2440   samr_OpenAlias 
2441 */
2442 static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2443                        struct samr_OpenAlias *r)
2444 {
2445         struct samr_domain_state *d_state;
2446         struct samr_account_state *a_state;
2447         struct dcesrv_handle *h;
2448         const char *alias_name;
2449         struct dom_sid *sid;
2450         struct ldb_message **msgs;
2451         struct dcesrv_handle *g_handle;
2452         const char * const attrs[2] = { "sAMAccountName", NULL };
2453         int ret;
2454
2455         ZERO_STRUCTP(r->out.alias_handle);
2456
2457         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2458
2459         d_state = h->data;
2460
2461         /* form the alias SID */
2462         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2463         if (sid == NULL)
2464                 return NT_STATUS_NO_MEMORY;
2465
2466         /* search for the group record */
2467         ret = gendb_search(d_state->sam_ctx,
2468                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2469                            "(&(objectSid=%s)(objectclass=group)"
2470                            "(|(grouptype=%d)(grouptype=%d)))",
2471                            ldap_encode_ndr_dom_sid(mem_ctx, sid),
2472                            GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2473                            GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2474         if (ret == 0) {
2475                 return NT_STATUS_NO_SUCH_ALIAS;
2476         }
2477         if (ret != 1) {
2478                 DEBUG(0,("Found %d records matching sid %s\n", 
2479                          ret, dom_sid_string(mem_ctx, sid)));
2480                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2481         }
2482
2483         alias_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2484         if (alias_name == NULL) {
2485                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2486                          dom_sid_string(mem_ctx, sid)));
2487                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2488         }
2489
2490         a_state = talloc(d_state, struct samr_account_state);
2491         if (!a_state) {
2492                 return NT_STATUS_NO_MEMORY;
2493         }
2494         a_state->sam_ctx = d_state->sam_ctx;
2495         a_state->access_mask = r->in.access_mask;
2496         a_state->domain_state = talloc_reference(a_state, d_state);
2497         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2498         a_state->account_sid = talloc_steal(a_state, sid);
2499         a_state->account_name = talloc_strdup(a_state, alias_name);
2500         if (!a_state->account_name) {
2501                 return NT_STATUS_NO_MEMORY;
2502         }
2503
2504         /* create the policy handle */
2505         g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2506         if (!g_handle) {
2507                 return NT_STATUS_NO_MEMORY;
2508         }
2509
2510         g_handle->data = talloc_steal(g_handle, a_state);
2511
2512         *r->out.alias_handle = g_handle->wire_handle;
2513
2514         return NT_STATUS_OK;
2515 }
2516
2517
2518 /* 
2519   samr_QueryAliasInfo 
2520 */
2521 static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2522                        struct samr_QueryAliasInfo *r)
2523 {
2524         struct dcesrv_handle *h;
2525         struct samr_account_state *a_state;
2526         struct ldb_message *msg, **res;
2527         const char * const attrs[4] = { "sAMAccountName", "description",
2528                                         "numMembers", NULL };
2529         int ret;
2530
2531         r->out.info = NULL;
2532
2533         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2534
2535         a_state = h->data;
2536
2537         /* pull all the alias attributes */
2538         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2539                               a_state->account_dn ,&res, attrs);
2540         if (ret != 1) {
2541                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2542         }
2543         msg = res[0];
2544
2545         /* allocate the info structure */
2546         r->out.info = talloc(mem_ctx, union samr_AliasInfo);
2547         if (r->out.info == NULL) {
2548                 return NT_STATUS_NO_MEMORY;
2549         }
2550         ZERO_STRUCTP(r->out.info);
2551
2552         switch(r->in.level) {
2553         case ALIASINFOALL:
2554                 QUERY_STRING(msg, all.name, "sAMAccountName");
2555                 QUERY_UINT  (msg, all.num_members, "numMembers");
2556                 QUERY_STRING(msg, all.description, "description");
2557                 break;
2558         case ALIASINFONAME:
2559                 QUERY_STRING(msg, name, "sAMAccountName");
2560                 break;
2561         case ALIASINFODESCRIPTION:
2562                 QUERY_STRING(msg, description, "description");
2563                 break;
2564         default:
2565                 r->out.info = NULL;
2566                 return NT_STATUS_INVALID_INFO_CLASS;
2567         }
2568         
2569         return NT_STATUS_OK;
2570 }
2571
2572
2573 /* 
2574   samr_SetAliasInfo 
2575 */
2576 static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2577                        struct samr_SetAliasInfo *r)
2578 {
2579         struct dcesrv_handle *h;
2580         struct samr_account_state *a_state;
2581         struct ldb_message *msg;
2582         struct ldb_context *sam_ctx;
2583         int ret;
2584
2585         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2586
2587         a_state = h->data;
2588         sam_ctx = a_state->sam_ctx;
2589
2590         msg = ldb_msg_new(mem_ctx);
2591         if (msg == NULL) {
2592                 return NT_STATUS_NO_MEMORY;
2593         }
2594
2595         msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2596         if (!msg->dn) {
2597                 return NT_STATUS_NO_MEMORY;
2598         }
2599
2600         switch (r->in.level) {
2601         case ALIASINFODESCRIPTION:
2602                 SET_STRING(msg, description,         "description");
2603                 break;
2604         case ALIASINFONAME:
2605                 /* On W2k3 this does not change the name, it changes the
2606                  * sAMAccountName attribute */
2607                 SET_STRING(msg, name,                "sAMAccountName");
2608                 break;
2609         default:
2610                 return NT_STATUS_INVALID_INFO_CLASS;
2611         }
2612
2613         /* modify the samdb record */
2614         ret = ldb_modify(a_state->sam_ctx, msg);
2615         if (ret != 0) {
2616                 /* we really need samdb.c to return NTSTATUS */
2617                 return NT_STATUS_UNSUCCESSFUL;
2618         }
2619
2620         return NT_STATUS_OK;
2621 }
2622
2623
2624 /* 
2625   samr_DeleteDomAlias 
2626 */
2627 static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2628                        struct samr_DeleteDomAlias *r)
2629 {
2630         struct dcesrv_handle *h;
2631         struct samr_account_state *a_state;
2632         int ret;
2633
2634         *r->out.alias_handle = *r->in.alias_handle;
2635
2636         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2637
2638         a_state = h->data;
2639
2640         ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
2641         if (ret != 0) {
2642                 return NT_STATUS_UNSUCCESSFUL;
2643         }
2644
2645         ZERO_STRUCTP(r->out.alias_handle);
2646
2647         return NT_STATUS_OK;
2648 }
2649
2650
2651 /* 
2652   samr_AddAliasMember 
2653 */
2654 static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2655                        struct samr_AddAliasMember *r)
2656 {
2657         struct dcesrv_handle *h;
2658         struct samr_account_state *a_state;
2659         struct samr_domain_state *d_state;
2660         struct ldb_message *mod;
2661         struct ldb_message **msgs;
2662         const char * const attrs[] = { NULL };
2663         struct ldb_dn *memberdn = NULL;
2664         int ret;
2665         NTSTATUS status;
2666
2667         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2668
2669         a_state = h->data;
2670         d_state = a_state->domain_state;
2671
2672         ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2673                            &msgs, attrs, "(objectsid=%s)", 
2674                            ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2675
2676         if (ret == 1) {
2677                 memberdn = msgs[0]->dn;
2678         } else  if (ret > 1) {
2679                 DEBUG(0,("Found %d records matching sid %s\n", 
2680                          ret, dom_sid_string(mem_ctx, r->in.sid)));
2681                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2682         } else if (ret == 0) {
2683                 status = samdb_create_foreign_security_principal(d_state->sam_ctx, mem_ctx, 
2684                                                                  r->in.sid, &memberdn);
2685                 if (!NT_STATUS_IS_OK(status)) {
2686                         return status;
2687                 }
2688         } else {
2689                 DEBUG(0, ("samdb_search returned %d: %s\n", ret, ldb_errstring(d_state->sam_ctx)));
2690         }
2691
2692         if (memberdn == NULL) {
2693                 DEBUG(0, ("Could not find memberdn\n"));
2694                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2695         }
2696
2697         mod = ldb_msg_new(mem_ctx);
2698         if (mod == NULL) {
2699                 return NT_STATUS_NO_MEMORY;
2700         }
2701
2702         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2703
2704         if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2705                                  ldb_dn_alloc_linearized(mem_ctx, memberdn)) != 0)
2706                 return NT_STATUS_UNSUCCESSFUL;
2707
2708         if (ldb_modify(a_state->sam_ctx, mod) != 0)
2709                 return NT_STATUS_UNSUCCESSFUL;
2710
2711         return NT_STATUS_OK;
2712 }
2713
2714
2715 /* 
2716   samr_DeleteAliasMember 
2717 */
2718 static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2719                        struct samr_DeleteAliasMember *r)
2720 {
2721         struct dcesrv_handle *h;
2722         struct samr_account_state *a_state;
2723         struct samr_domain_state *d_state;
2724         struct ldb_message *mod;
2725         const char *memberdn;
2726
2727         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2728
2729         a_state = h->data;
2730         d_state = a_state->domain_state;
2731
2732         memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2733                                        "distinguishedName", "(objectSid=%s)", 
2734                                        ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2735
2736         if (memberdn == NULL)
2737                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2738
2739         mod = ldb_msg_new(mem_ctx);
2740         if (mod == NULL) {
2741                 return NT_STATUS_NO_MEMORY;
2742         }
2743
2744         mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2745
2746         if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2747                                  memberdn) != 0)
2748                 return NT_STATUS_UNSUCCESSFUL;
2749
2750         if (ldb_modify(a_state->sam_ctx, mod) != 0)
2751                 return NT_STATUS_UNSUCCESSFUL;
2752
2753         return NT_STATUS_OK;
2754 }
2755
2756
2757 /* 
2758   samr_GetMembersInAlias 
2759 */
2760 static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2761                        struct samr_GetMembersInAlias *r)
2762 {
2763         struct dcesrv_handle *h;
2764         struct samr_account_state *a_state;
2765         struct samr_domain_state *d_state;
2766         struct ldb_message **msgs;
2767         struct lsa_SidPtr *sids;
2768         struct ldb_message_element *el;
2769         const char * const attrs[2] = { "member", NULL};
2770         int ret;
2771
2772         DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2773
2774         a_state = h->data;
2775         d_state = a_state->domain_state;
2776
2777         ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
2778                               a_state->account_dn, &msgs, attrs);
2779
2780         if (ret != 1)
2781                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2782
2783         r->out.sids->num_sids = 0;
2784         r->out.sids->sids = NULL;
2785
2786         el = ldb_msg_find_element(msgs[0], "member");
2787
2788         if (el != NULL) {
2789                 int i;
2790
2791                 sids = talloc_array(mem_ctx, struct lsa_SidPtr,
2792                                       el->num_values);
2793
2794                 if (sids == NULL)
2795                         return NT_STATUS_NO_MEMORY;
2796
2797                 for (i=0; i<el->num_values; i++) {
2798                         struct ldb_message **msgs2;
2799                         const char * const attrs2[2] = { "objectSid", NULL };
2800                         ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2801                                            ldb_dn_new(mem_ctx, a_state->sam_ctx, (const char *)el->values[i].data),
2802                                            &msgs2, attrs2);
2803                         if (ret != 1)
2804                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2805
2806                         sids[i].sid = samdb_result_dom_sid(mem_ctx, msgs2[0],
2807                                                            "objectSid");
2808
2809                         if (sids[i].sid == NULL)
2810                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2811                 }
2812                 r->out.sids->num_sids = el->num_values;
2813                 r->out.sids->sids = sids;
2814         }
2815
2816         return NT_STATUS_OK;
2817 }
2818
2819 /* 
2820   samr_OpenUser 
2821 */
2822 static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2823                               struct samr_OpenUser *r)
2824 {
2825         struct samr_domain_state *d_state;
2826         struct samr_account_state *a_state;
2827         struct dcesrv_handle *h;
2828         const char *account_name;
2829         struct dom_sid *sid;
2830         struct ldb_message **msgs;
2831         struct dcesrv_handle *u_handle;
2832         const char * const attrs[2] = { "sAMAccountName", NULL };
2833         int ret;
2834
2835         ZERO_STRUCTP(r->out.user_handle);
2836
2837         DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2838
2839         d_state = h->data;
2840
2841         /* form the users SID */
2842         sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2843         if (!sid) {
2844                 return NT_STATUS_NO_MEMORY;
2845         }
2846
2847         /* search for the user record */
2848         ret = gendb_search(d_state->sam_ctx,
2849                            mem_ctx, d_state->domain_dn, &msgs, attrs,
2850                            "(&(objectSid=%s)(objectclass=user))", 
2851                            ldap_encode_ndr_dom_sid(mem_ctx, sid));
2852         if (ret == 0) {
2853                 return NT_STATUS_NO_SUCH_USER;
2854         }
2855         if (ret != 1) {
2856                 DEBUG(0,("Found %d records matching sid %s\n", ret, 
2857                          dom_sid_string(mem_ctx, sid)));
2858                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2859         }
2860
2861         account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2862         if (account_name == NULL) {
2863                 DEBUG(0,("sAMAccountName field missing for sid %s\n", 
2864                          dom_sid_string(mem_ctx, sid)));
2865                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2866         }
2867
2868         a_state = talloc(mem_ctx, struct samr_account_state);
2869         if (!a_state) {
2870                 return NT_STATUS_NO_MEMORY;
2871         }
2872         a_state->sam_ctx = d_state->sam_ctx;
2873         a_state->access_mask = r->in.access_mask;
2874         a_state->domain_state = talloc_reference(a_state, d_state);
2875         a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2876         a_state->account_sid = talloc_steal(a_state, sid);
2877         a_state->account_name = talloc_strdup(a_state, account_name);
2878         if (!a_state->account_name) {
2879                 return NT_STATUS_NO_MEMORY;
2880         }
2881
2882         /* create the policy handle */
2883         u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2884         if (!u_handle) {
2885                 return NT_STATUS_NO_MEMORY;
2886         }
2887
2888         u_handle->data = talloc_steal(u_handle, a_state);
2889
2890         *r->out.user_handle = u_handle->wire_handle;
2891
2892         return NT_STATUS_OK;
2893
2894 }
2895
2896
2897 /* 
2898   samr_DeleteUser 
2899 */
2900 static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2901                                 struct samr_DeleteUser *r)
2902 {
2903         struct dcesrv_handle *h;
2904         struct samr_account_state *a_state;
2905         int ret;
2906
2907         *r->out.user_handle = *r->in.user_handle;
2908
2909         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2910
2911         a_state = h->data;
2912
2913         ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
2914         if (ret != 0) {
2915                 return NT_STATUS_UNSUCCESSFUL;
2916         }
2917
2918         ZERO_STRUCTP(r->out.user_handle);
2919
2920         return NT_STATUS_OK;
2921 }
2922
2923
2924 /* 
2925   samr_QueryUserInfo 
2926 */
2927 static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2928                                    struct samr_QueryUserInfo *r)
2929 {
2930         struct dcesrv_handle *h;
2931         struct samr_account_state *a_state;
2932         struct ldb_message *msg, **res;
2933         int ret;
2934         struct ldb_context *sam_ctx;
2935
2936         const char * const *attrs = NULL;
2937
2938         r->out.info = NULL;
2939
2940         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2941
2942         a_state = h->data;
2943         sam_ctx = a_state->sam_ctx;
2944
2945         /* fill in the reply */
2946         switch (r->in.level) {
2947         case 1:
2948         {
2949                 static const char * const attrs2[] = {"sAMAccountName", "displayName",
2950                                                       "primaryGroupID", "description",
2951                                                       "comment", NULL};
2952                 attrs = attrs2;
2953                 break;
2954         }
2955         case 2:
2956         {
2957                 static const char * const attrs2[] = {"comment", "countryCode", "codePage", NULL};
2958                 attrs = attrs2;
2959                 break;
2960         }
2961         case 3:
2962         {
2963                 static const char * const attrs2[] = {"sAMAccountName",
2964                                                       "displayName",
2965                                                       "objectSid",
2966                                                       "primaryGroupID",
2967                                                       "homeDirectory",
2968                                                       "homeDrive",
2969                                                       "scriptPath",
2970                                                       "profilePath",
2971                                                       "userWorkstations",
2972                                                       "lastLogon",
2973                                                       "lastLogoff",
2974                                                       "pwdLastSet",
2975                                                       "logonHours",
2976                                                       "badPwdCount",
2977                                                       "logonCount",
2978                                                       "userAccountControl", NULL};
2979                 attrs = attrs2;
2980                 break;
2981         }
2982         case 4:
2983         {
2984                 static const char * const attrs2[] = {"logonHours", NULL};
2985                 attrs = attrs2;
2986                 break;
2987         }
2988         case 5:
2989         {
2990                 static const char * const attrs2[] = {"sAMAccountName", 
2991                                                       "displayName",
2992                                                       "objectSid",
2993                                                       "primaryGroupID",
2994