r625: - handle passwords longer than length 14 (thanks to abartlet for pointing...
[samba.git] / source / 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    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "rpc_server/common/common.h"
25
26 /*
27   this type allows us to distinguish handle types
28 */
29 enum samr_handle {
30         SAMR_HANDLE_CONNECT,
31         SAMR_HANDLE_DOMAIN,
32         SAMR_HANDLE_USER,
33         SAMR_HANDLE_GROUP,
34         SAMR_HANDLE_ALIAS
35 };
36
37
38 /*
39   state asscoiated with a samr_Connect*() operation
40 */
41 struct samr_connect_state {
42         int reference_count;
43         void *sam_ctx;
44         TALLOC_CTX *mem_ctx;
45         uint32 access_mask;
46 };
47
48 /*
49   state associated with a samr_OpenDomain() operation
50 */
51 struct samr_domain_state {
52         struct samr_connect_state *connect_state;
53         int reference_count;
54         void *sam_ctx;
55         TALLOC_CTX *mem_ctx;
56         uint32 access_mask;
57         const char *domain_sid;
58         const char *domain_name;
59         const char *basedn;
60 };
61
62 /*
63   state associated with a open account handle
64 */
65 struct samr_account_state {
66         struct samr_domain_state *domain_state;
67         void *sam_ctx;
68         TALLOC_CTX *mem_ctx;
69         uint32 access_mask;
70         const char *account_sid;
71         const char *account_name;
72         const char *basedn;
73 };
74
75
76 /*
77   destroy connection state
78 */
79 static void samr_Connect_close(struct samr_connect_state *state)
80 {
81         state->reference_count--;
82         if (state->reference_count == 0) {
83                 samdb_close(state->sam_ctx);
84                 talloc_destroy(state->mem_ctx);
85         }
86 }
87
88 /*
89   destroy an open connection. This closes the database connection
90 */
91 static void samr_Connect_destroy(struct dcesrv_connection *conn, struct dcesrv_handle *h)
92 {
93         struct samr_connect_state *state = h->data;
94         samr_Connect_close(state);
95 }
96
97 /* 
98   samr_Connect 
99
100   create a connection to the SAM database
101 */
102 static NTSTATUS samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
103                              struct samr_Connect *r)
104 {
105         struct samr_connect_state *state;
106         struct dcesrv_handle *handle;
107         TALLOC_CTX *connect_mem_ctx;
108
109         ZERO_STRUCTP(r->out.handle);
110
111         connect_mem_ctx = talloc_init("samr_Connect");
112         if (!connect_mem_ctx) {
113                 return NT_STATUS_NO_MEMORY;
114         }
115
116         state = talloc_p(connect_mem_ctx, struct samr_connect_state);
117         if (!state) {
118                 return NT_STATUS_NO_MEMORY;
119         }
120         state->mem_ctx = connect_mem_ctx;
121
122         /* make sure the sam database is accessible */
123         state->sam_ctx = samdb_connect();
124         if (state->sam_ctx == NULL) {
125                 talloc_destroy(state->mem_ctx);
126                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
127         }
128
129         handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_CONNECT);
130         if (!handle) {
131                 talloc_destroy(state->mem_ctx);
132                 return NT_STATUS_NO_MEMORY;
133         }
134
135         handle->data = state;
136         handle->destroy = samr_Connect_destroy;
137
138         state->reference_count = 1;
139         state->access_mask = r->in.access_mask;
140         *r->out.handle = handle->wire_handle;
141
142         return NT_STATUS_OK;
143 }
144
145
146 /* 
147   samr_Close 
148 */
149 static NTSTATUS samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
150                            struct samr_Close *r)
151 {
152         struct dcesrv_handle *h;
153
154         *r->out.handle = *r->in.handle;
155
156         DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
157
158         /* this causes the callback samr_XXX_destroy() to be called by
159            the handle destroy code which destroys the state associated
160            with the handle */
161         dcesrv_handle_destroy(dce_call->conn, h);
162
163         ZERO_STRUCTP(r->out.handle);
164
165         return NT_STATUS_OK;
166 }
167
168
169 /* 
170   samr_SetSecurity 
171 */
172 static NTSTATUS samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
173                                  struct samr_SetSecurity *r)
174 {
175         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
176 }
177
178
179 /* 
180   samr_QuerySecurity 
181 */
182 static NTSTATUS samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
183                                    struct samr_QuerySecurity *r)
184 {
185         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
186 }
187
188
189 /* 
190   samr_Shutdown 
191
192   we refuse this operation completely. If a admin wants to shutdown samr
193   in Samba then they should use the samba admin tools to disable the samr pipe
194 */
195 static NTSTATUS samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
196                               struct samr_Shutdown *r)
197 {
198         return NT_STATUS_ACCESS_DENIED;
199 }
200
201
202 /* 
203   samr_LookupDomain 
204
205   this maps from a domain name to a SID
206 */
207 static NTSTATUS samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
208                                   struct samr_LookupDomain *r)
209 {
210         struct samr_connect_state *state;
211         struct dcesrv_handle *h;
212         struct dom_sid2 *sid;
213         const char *sidstr;
214                 
215         r->out.sid = NULL;
216
217         DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_CONNECT);
218
219         state = h->data;
220
221         if (r->in.domain->name == NULL) {
222                 return NT_STATUS_INVALID_PARAMETER;
223         }
224
225         sidstr = samdb_search_string(state->sam_ctx,
226                                      mem_ctx, NULL, "objectSid",
227                                      "(&(name=%s)(objectclass=domain))",
228                                      r->in.domain->name);
229         if (sidstr == NULL) {
230                 return NT_STATUS_NO_SUCH_DOMAIN;
231         }
232
233         sid = dom_sid_parse_talloc(mem_ctx, sidstr);
234         if (sid == NULL) {
235                 DEBUG(1,("samdb: Invalid sid '%s' for domain %s\n",
236                          sidstr, r->in.domain->name));
237                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
238         }
239
240         r->out.sid = sid;
241
242         return NT_STATUS_OK;
243 }
244
245
246 /* 
247   samr_EnumDomains 
248
249   list the domains in the SAM
250 */
251 static NTSTATUS samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
252                                  struct samr_EnumDomains *r)
253 {
254         struct samr_connect_state *state;
255         struct dcesrv_handle *h;
256         struct samr_SamArray *array;
257         const char **domains;
258         int count, i, start_i;
259
260         *r->out.resume_handle = 0;
261         r->out.sam = NULL;
262         r->out.num_entries = 0;
263
264         DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_CONNECT);
265
266         state = h->data;
267
268         count = samdb_search_string_multiple(state->sam_ctx,
269                                              mem_ctx, NULL, &domains, 
270                                              "name", "(objectclass=domain)");
271         if (count == -1) {
272                 DEBUG(1,("samdb: no domains found in EnumDomains\n"));
273                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
274         }
275
276         *r->out.resume_handle = count;
277
278         start_i = *r->in.resume_handle;
279
280         if (start_i >= count) {
281                 /* search past end of list is not an error for this call */
282                 return NT_STATUS_OK;
283         }
284
285         array = talloc_p(mem_ctx, struct samr_SamArray);
286         if (array == NULL) {
287                 return NT_STATUS_NO_MEMORY;
288         }
289                 
290         array->count = 0;
291         array->entries = NULL;
292
293         array->entries = talloc_array_p(mem_ctx, struct samr_SamEntry, count - start_i);
294         if (array->entries == NULL) {
295                 return NT_STATUS_NO_MEMORY;
296         }
297
298         for (i=0;i<count-start_i;i++) {
299                 array->entries[i].idx = start_i + i;
300                 array->entries[i].name.name = domains[start_i+i];
301         }
302
303         r->out.sam = array;
304         r->out.num_entries = i - start_i;
305         array->count = r->out.num_entries;
306
307         return NT_STATUS_OK;
308 }
309
310
311 /*
312   close an open domain context
313 */
314 static void samr_Domain_close(struct dcesrv_connection *conn, 
315                               struct samr_domain_state *state)
316 {
317         state->reference_count--;
318         if (state->reference_count == 0) {
319                 samr_Connect_close(state->connect_state);
320                 talloc_destroy(state->mem_ctx);
321         }
322 }
323
324 /*
325   destroy an open domain context
326 */
327 static void samr_Domain_destroy(struct dcesrv_connection *conn, struct dcesrv_handle *h)
328 {
329         struct samr_domain_state *state = h->data;
330         samr_Domain_close(conn, state);
331 }
332
333 /* 
334   samr_OpenDomain 
335 */
336 static NTSTATUS samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
337                                 struct samr_OpenDomain *r)
338 {
339         struct dcesrv_handle *h_conn, *h_domain;
340         const char *sidstr, *domain_name;
341         struct samr_connect_state *c_state;
342         struct samr_domain_state *state;
343         TALLOC_CTX *mem_ctx2;
344         const char * const attrs[2] = { "name", NULL};
345         struct ldb_message **msgs;
346         int ret;
347
348         ZERO_STRUCTP(r->out.domain_handle);
349
350         DCESRV_PULL_HANDLE(h_conn, r->in.handle, SAMR_HANDLE_CONNECT);
351
352         c_state = h_conn->data;
353
354         if (r->in.sid == NULL) {
355                 return NT_STATUS_INVALID_PARAMETER;
356         }
357
358         sidstr = dom_sid_string(mem_ctx, r->in.sid);
359         if (sidstr == NULL) {
360                 return NT_STATUS_INVALID_PARAMETER;
361         }
362
363         ret = samdb_search(c_state->sam_ctx,
364                            mem_ctx, NULL, &msgs, attrs,
365                            "(&(objectSid=%s)(objectclass=domain))", 
366                            sidstr);
367         if (ret != 1) {
368                 return NT_STATUS_NO_SUCH_DOMAIN;
369         }
370
371         domain_name = ldb_msg_find_string(msgs[0], "name", NULL);
372         if (domain_name == NULL) {
373                 return NT_STATUS_NO_SUCH_DOMAIN;
374         }
375
376         mem_ctx2 = talloc_init("OpenDomain(%s)\n", domain_name);
377         if (!mem_ctx2) {
378                 return NT_STATUS_NO_MEMORY;
379         }
380
381         state = talloc_p(mem_ctx2, struct samr_domain_state);
382         if (!state) {
383                 talloc_destroy(mem_ctx2);
384                 return NT_STATUS_NO_MEMORY;
385         }
386
387         state->reference_count = 1;
388         state->connect_state = c_state;
389         state->sam_ctx = c_state->sam_ctx;
390         state->mem_ctx = mem_ctx2;
391         state->domain_sid = talloc_strdup(mem_ctx2, sidstr);
392         state->domain_name = talloc_strdup(mem_ctx2, domain_name);
393         state->basedn = talloc_strdup(mem_ctx2, msgs[0]->dn);
394         if (!state->domain_sid || !state->domain_name || !state->basedn) {
395                 talloc_destroy(mem_ctx2);
396                 return NT_STATUS_NO_MEMORY;             
397         }
398         state->access_mask = r->in.access_mask;
399
400         h_domain = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_DOMAIN);
401         if (!h_domain) {
402                 talloc_destroy(mem_ctx2);
403                 return NT_STATUS_NO_MEMORY;
404         }
405
406         c_state->reference_count++;
407         h_domain->data = state;
408         h_domain->destroy = samr_Domain_destroy;
409         *r->out.domain_handle = h_domain->wire_handle;
410
411         return NT_STATUS_OK;
412 }
413
414
415 /* 
416   samr_QueryDomainInfo 
417 */
418 static NTSTATUS samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
419                        struct samr_QueryDomainInfo *r)
420 {
421         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
422 }
423
424
425 /* 
426   samr_SetDomainInfo 
427 */
428 static NTSTATUS samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
429                        struct samr_SetDomainInfo *r)
430 {
431         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
432 }
433
434 /*
435   destroy an open account context
436 */
437 static void samr_Account_destroy(struct dcesrv_connection *conn, struct dcesrv_handle *h)
438 {
439         struct samr_account_state *state = h->data;
440         samr_Domain_close(conn, state->domain_state);
441         talloc_destroy(state->mem_ctx);
442 }
443
444 /* 
445   samr_CreateDomainGroup 
446 */
447 static NTSTATUS samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
448                                        struct samr_CreateDomainGroup *r)
449 {
450         struct samr_domain_state *d_state;
451         struct samr_account_state *state;
452         struct dcesrv_handle *h;
453         const char *name;
454         struct ldb_message msg;
455         uint32 rid;
456         const char *groupname, *sidstr;
457         time_t now = time(NULL);
458         TALLOC_CTX *mem_ctx2;
459         struct dcesrv_handle *g_handle;
460         int ret;
461         NTSTATUS status;
462
463         ZERO_STRUCTP(r->out.group_handle);
464         *r->out.rid = 0;
465
466         DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
467
468         d_state = h->data;
469
470         groupname = r->in.name->name;
471
472         if (groupname == NULL) {
473                 return NT_STATUS_INVALID_PARAMETER;
474         }
475
476         /* check if the group already exists */
477         name = samdb_search_string(d_state->sam_ctx, mem_ctx, d_state->basedn, 
478                                    "sAMAccountName",
479                                    "(&(sAMAccountName=%s)(objectclass=group))",
480                                    groupname);
481         if (name != NULL) {
482                 return NT_STATUS_GROUP_EXISTS;
483         }
484
485         ZERO_STRUCT(msg);
486
487         /* pull in all the template attributes */
488         ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg, 
489                                   "(&(name=TemplateGroup)(objectclass=groupTemplate))");
490         if (ret != 0) {
491                 DEBUG(1,("Failed to load TemplateGroup from samdb\n"));
492                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
493         }
494
495         /* allocate a rid */
496         status = samdb_allocate_next_id(d_state->sam_ctx, mem_ctx, 
497                                         d_state->basedn, "nextRid", &rid);
498         if (!NT_STATUS_IS_OK(status)) {
499                 return status;
500         }
501
502         /* and the group SID */
503         sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, rid);
504         if (!sidstr) {
505                 return NT_STATUS_NO_MEMORY;
506         }
507
508         /* add core elements to the ldb_message for the user */
509         msg.dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Users,%s", groupname,
510                                  d_state->basedn);
511         if (!msg.dn) {
512                 return NT_STATUS_NO_MEMORY;
513         }
514         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
515                              "name", groupname);
516         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
517                              "cn", groupname);
518         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
519                              "sAMAccountName", groupname);
520         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
521                              "objectClass", "group");
522         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg,
523                              "objectSid", sidstr);
524         samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg,
525                                "whenCreated", now);
526         samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg,
527                                "whenChanged", now);
528                              
529         /* create the group */
530         ret = samdb_add(d_state->sam_ctx, mem_ctx, &msg);
531         if (ret != 0) {
532                 DEBUG(1,("Failed to create group record %s\n", msg.dn));
533                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
534         }
535
536         /* create group state and new policy handle */
537         mem_ctx2 = talloc_init("CreateDomainGroup(%s)", groupname);
538         if (!mem_ctx2) {
539                 return NT_STATUS_NO_MEMORY;
540         }
541
542         state = talloc_p(mem_ctx2, struct samr_account_state);
543         if (!state) {
544                 return NT_STATUS_NO_MEMORY;
545         }
546         state->mem_ctx = mem_ctx2;
547         state->sam_ctx = d_state->sam_ctx;
548         state->access_mask = r->in.access_mask;
549         state->domain_state = d_state;
550         state->basedn = talloc_steal(mem_ctx, mem_ctx2, msg.dn);
551         state->account_sid = talloc_strdup(mem_ctx2, sidstr);
552         state->account_name = talloc_strdup(mem_ctx2, groupname);
553         if (!state->account_name || !state->account_sid) {
554                 return NT_STATUS_NO_MEMORY;
555         }
556
557         /* create the policy handle */
558         g_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_GROUP);
559         if (!g_handle) {
560                 return NT_STATUS_NO_MEMORY;
561         }
562
563         g_handle->data = state;
564         g_handle->destroy = samr_Account_destroy;
565
566         /* the domain state is in use one more time */
567         d_state->reference_count++;
568
569         *r->out.group_handle = g_handle->wire_handle;
570         *r->out.rid = rid;      
571
572         return NT_STATUS_OK;
573 }
574
575
576 /* 
577   samr_EnumDomainGroups 
578 */
579 static NTSTATUS samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
580                                       struct samr_EnumDomainGroups *r)
581 {
582         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
583 }
584
585
586 /* 
587   samr_CreateUser2 
588
589   TODO: This should do some form of locking, especially around the rid allocation
590 */
591 static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
592                                  struct samr_CreateUser2 *r)
593 {
594         struct samr_domain_state *d_state;
595         struct samr_account_state *state;
596         struct dcesrv_handle *h;
597         const char *name;
598         struct ldb_message msg;
599         uint32 rid;
600         const char *username, *sidstr;
601         time_t now = time(NULL);
602         TALLOC_CTX *mem_ctx2;
603         struct dcesrv_handle *u_handle;
604         int ret;
605         NTSTATUS status;
606
607         ZERO_STRUCTP(r->out.acct_handle);
608         *r->out.access_granted = 0;
609         *r->out.rid = 0;
610
611         DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
612
613         d_state = h->data;
614
615         username = r->in.username->name;
616
617         if (username == NULL) {
618                 return NT_STATUS_INVALID_PARAMETER;
619         }
620
621         /* check if the user already exists */
622         name = samdb_search_string(d_state->sam_ctx, mem_ctx, d_state->basedn, 
623                                    "sAMAccountName", 
624                                    "(&(sAMAccountName=%s)(objectclass=user))", username);
625         if (name != NULL) {
626                 return NT_STATUS_USER_EXISTS;
627         }
628
629         ZERO_STRUCT(msg);
630
631         /* pull in all the template attributes */
632         ret = samdb_copy_template(d_state->sam_ctx, mem_ctx, &msg, 
633                                   "(&(name=TemplateUser)(objectclass=userTemplate))");
634         if (ret != 0) {
635                 DEBUG(1,("Failed to load TemplateUser from samdb\n"));
636                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
637         }
638         
639         /* allocate a rid */
640         status = samdb_allocate_next_id(d_state->sam_ctx, mem_ctx, 
641                                         d_state->basedn, "nextRid", &rid);
642         if (!NT_STATUS_IS_OK(status)) {
643                 return status;
644         }
645
646         /* and the users SID */
647         sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, rid);
648         if (!sidstr) {
649                 return NT_STATUS_NO_MEMORY;
650         }
651
652         /* add core elements to the ldb_message for the user */
653         msg.dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Users,%s", username, d_state->basedn);
654         if (!msg.dn) {
655                 return NT_STATUS_NO_MEMORY;             
656         }
657         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "name", username);
658         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "cn", username);
659         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "sAMAccountName", username);
660         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectClass", "user");
661         samdb_msg_add_string(d_state->sam_ctx, mem_ctx, &msg, "objectSid", sidstr);
662         samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenCreated", now);
663         samdb_msg_set_ldaptime(d_state->sam_ctx, mem_ctx, &msg, "whenChanged", now);
664
665         /* create the user */
666         ret = samdb_add(d_state->sam_ctx, mem_ctx, &msg);
667         if (ret != 0) {
668                 DEBUG(1,("Failed to create user record %s\n", msg.dn));
669                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
670         }
671
672         /* create user state and new policy handle */
673         mem_ctx2 = talloc_init("CreateUser(%s)", username);
674         if (!mem_ctx2) {
675                 return NT_STATUS_NO_MEMORY;
676         }
677
678         state = talloc_p(mem_ctx2, struct samr_account_state);
679         if (!state) {
680                 return NT_STATUS_NO_MEMORY;
681         }
682         state->mem_ctx = mem_ctx2;
683         state->sam_ctx = d_state->sam_ctx;
684         state->access_mask = r->in.access_mask;
685         state->domain_state = d_state;
686         state->basedn = talloc_steal(mem_ctx, mem_ctx2, msg.dn);
687         state->account_sid = talloc_strdup(mem_ctx2, sidstr);
688         state->account_name = talloc_strdup(mem_ctx2, username);
689         if (!state->account_name || !state->account_sid) {
690                 return NT_STATUS_NO_MEMORY;
691         }
692
693         /* create the policy handle */
694         u_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_USER);
695         if (!u_handle) {
696                 return NT_STATUS_NO_MEMORY;
697         }
698
699         u_handle->data = state;
700         u_handle->destroy = samr_Account_destroy;
701
702         /* the domain state is in use one more time */
703         d_state->reference_count++;
704
705         *r->out.acct_handle = u_handle->wire_handle;
706         *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
707         *r->out.rid = rid;      
708
709         return NT_STATUS_OK;
710 }
711
712
713 /* 
714   samr_CreateUser 
715 */
716 static NTSTATUS samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
717                                 struct samr_CreateUser *r)
718 {
719         struct samr_CreateUser2 r2;
720         uint32 access_granted;
721
722
723         /* a simple wrapper around samr_CreateUser2 works nicely */
724         r2.in.handle = r->in.handle;
725         r2.in.username = r->in.username;
726         r2.in.acct_flags = 1234;
727         r2.in.access_mask = r->in.access_mask;
728         r2.out.acct_handle = r->out.acct_handle;
729         r2.out.access_granted = &access_granted;
730         r2.out.rid = r->out.rid;
731
732         return samr_CreateUser2(dce_call, mem_ctx, &r2);
733 }
734
735 /*
736   comparison function for sorting SamEntry array
737 */
738 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
739 {
740         return e1->idx - e2->idx;
741 }
742
743 /* 
744   samr_EnumDomainUsers 
745 */
746 static NTSTATUS samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
747                                      struct samr_EnumDomainUsers *r)
748 {
749         struct dcesrv_handle *h;
750         struct samr_domain_state *state;
751         struct ldb_message **res;
752         int count, i, first;
753         struct samr_SamEntry *entries;
754         const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
755
756         *r->out.resume_handle = 0;
757         r->out.sam = NULL;
758         r->out.num_entries = 0;
759
760         DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
761
762         state = h->data;
763         
764         /* search for all users in this domain. This could possibly be cached and 
765            resumed based on resume_key */
766         count = samdb_search(state->sam_ctx, mem_ctx, state->basedn, &res, attrs, 
767                              "objectclass=user");
768         if (count == -1) {
769                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
770         }
771         if (count == 0 || r->in.max_size == 0) {
772                 return NT_STATUS_OK;
773         }
774
775         /* convert to SamEntry format */
776         entries = talloc_array_p(mem_ctx, struct samr_SamEntry, count);
777         if (!entries) {
778                 return NT_STATUS_NO_MEMORY;
779         }
780         for (i=0;i<count;i++) {
781                 entries[i].idx = samdb_result_rid_from_sid(mem_ctx, res[i], "objectSid", 0);
782                 entries[i].name.name = samdb_result_string(res[i], "sAMAccountName", "");
783         }
784
785         /* sort the results by rid */
786         qsort(entries, count, sizeof(struct samr_SamEntry), 
787               (comparison_fn_t)compare_SamEntry);
788
789         /* find the first entry to return */
790         for (first=0;
791              first<count && entries[first].idx <= *r->in.resume_handle;
792              first++) ;
793
794         if (first == count) {
795                 return NT_STATUS_OK;
796         }
797
798         /* return the rest, limit by max_size. Note that we 
799            use the w2k3 element size value of 54 */
800         r->out.num_entries = count - first;
801         r->out.num_entries = MIN(r->out.num_entries, 
802                                  1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
803
804         r->out.sam = talloc_p(mem_ctx, struct samr_SamArray);
805         if (!r->out.sam) {
806                 return NT_STATUS_NO_MEMORY;
807         }
808
809         r->out.sam->entries = entries+first;
810         r->out.sam->count = r->out.num_entries;
811
812         if (r->out.num_entries < count - first) {
813                 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
814                 return STATUS_MORE_ENTRIES;
815         }
816
817         return NT_STATUS_OK;
818 }
819
820
821 /* 
822   samr_CreateDomAlias 
823 */
824 static NTSTATUS samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
825                        struct samr_CreateDomAlias *r)
826 {
827         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
828 }
829
830
831 /* 
832   samr_EnumDomainAliases 
833 */
834 static NTSTATUS samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
835                        struct samr_EnumDomainAliases *r)
836 {
837         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
838 }
839
840
841 /* 
842   samr_GetAliasMembership 
843 */
844 static NTSTATUS samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
845                        struct samr_GetAliasMembership *r)
846 {
847         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
848 }
849
850
851 /* 
852   samr_LookupNames 
853 */
854 static NTSTATUS samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
855                                  struct samr_LookupNames *r)
856 {
857         struct dcesrv_handle *h;
858         struct samr_domain_state *state;
859         int i;
860         NTSTATUS status = NT_STATUS_OK;
861         const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
862         int count;
863
864         ZERO_STRUCT(r->out.rids);
865         ZERO_STRUCT(r->out.types);
866
867         DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
868
869         state = h->data;
870
871         if (r->in.num_names == 0) {
872                 return NT_STATUS_OK;
873         }
874
875         r->out.rids.ids = talloc_array_p(mem_ctx, uint32, r->in.num_names);
876         r->out.types.ids = talloc_array_p(mem_ctx, uint32, r->in.num_names);
877         if (!r->out.rids.ids || !r->out.types.ids) {
878                 return NT_STATUS_NO_MEMORY;
879         }
880         r->out.rids.count = r->in.num_names;
881         r->out.types.count = r->in.num_names;
882
883         for (i=0;i<r->in.num_names;i++) {
884                 struct ldb_message **res;
885                 struct dom_sid2 *sid;
886                 const char *sidstr;
887                 uint32 atype, rtype;
888
889                 r->out.rids.ids[i] = 0;
890                 r->out.types.ids[i] = SID_NAME_UNKNOWN;
891
892                 count = samdb_search(state->sam_ctx, mem_ctx, state->basedn, &res, attrs, 
893                                      "sAMAccountName=%s", r->in.names[i].name);
894                 if (count != 1) {
895                         status = STATUS_SOME_UNMAPPED;
896                         continue;
897                 }
898
899                 sidstr = samdb_result_string(res[0], "objectSid", NULL);
900                 if (sidstr == NULL) {
901                         status = STATUS_SOME_UNMAPPED;
902                         continue;
903                 }
904                 
905                 sid = dom_sid_parse_talloc(mem_ctx, sidstr);
906                 if (sid == NULL) {
907                         status = STATUS_SOME_UNMAPPED;
908                         continue;
909                 }
910
911                 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
912                 if (atype == 0) {
913                         status = STATUS_SOME_UNMAPPED;
914                         continue;
915                 }
916
917                 switch (atype & 0xF0000000) {
918                 case ATYPE_ACCOUNT:
919                         rtype = SID_NAME_USER;
920                         break;
921                 case ATYPE_GLOBAL_GROUP:
922                         rtype = SID_NAME_DOM_GRP;
923                         break;
924                 case ATYPE_LOCAL_GROUP:
925                         rtype = SID_NAME_ALIAS;
926                         break;
927                 default:
928                         DEBUG(1,("Unknown sAMAccountType 0x%08x\n", atype));
929                         status = STATUS_SOME_UNMAPPED;
930                         continue;
931                 }
932
933                 r->out.rids.ids[i] = sid->sub_auths[sid->num_auths-1];
934                 r->out.types.ids[i] = rtype;
935         }
936         
937
938         return status;
939 }
940
941
942 /* 
943   samr_LookupRids 
944 */
945 static NTSTATUS samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
946                        struct samr_LookupRids *r)
947 {
948         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
949 }
950
951
952 /* 
953   samr_OpenGroup 
954 */
955 static NTSTATUS samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
956                        struct samr_OpenGroup *r)
957 {
958         struct samr_domain_state *d_state;
959         struct samr_account_state *state;
960         struct dcesrv_handle *h;
961         const char *groupname, *sidstr;
962         TALLOC_CTX *mem_ctx2;
963         struct ldb_message **msgs;
964         struct dcesrv_handle *g_handle;
965         const char * const attrs[2] = { "sAMAccountName", NULL };
966         int ret;
967
968         ZERO_STRUCTP(r->out.acct_handle);
969
970         DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
971
972         d_state = h->data;
973
974         /* form the group SID */
975         sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, r->in.rid);
976         if (!sidstr) {
977                 return NT_STATUS_NO_MEMORY;
978         }
979
980         /* search for the group record */
981         ret = samdb_search(d_state->sam_ctx,
982                            mem_ctx, d_state->basedn, &msgs, attrs,
983                            "(&(objectSid=%s)(objectclass=group))", 
984                            sidstr);
985         if (ret == 0) {
986                 return NT_STATUS_NO_SUCH_GROUP;
987         }
988         if (ret != 1) {
989                 DEBUG(1,("Found %d records matching sid %s\n", ret, sidstr));
990                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
991         }
992
993         groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
994         if (groupname == NULL) {
995                 DEBUG(1,("sAMAccountName field missing for sid %s\n", sidstr));
996                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
997         }
998
999         /* create group state and new policy handle */
1000         mem_ctx2 = talloc_init("OpenGroup(%u)", r->in.rid);
1001         if (!mem_ctx2) {
1002                 return NT_STATUS_NO_MEMORY;
1003         }
1004
1005         state = talloc_p(mem_ctx2, struct samr_account_state);
1006         if (!state) {
1007                 return NT_STATUS_NO_MEMORY;
1008         }
1009         state->mem_ctx = mem_ctx2;
1010         state->sam_ctx = d_state->sam_ctx;
1011         state->access_mask = r->in.access_mask;
1012         state->domain_state = d_state;
1013         state->basedn = talloc_steal(mem_ctx, mem_ctx2, msgs[0]->dn);
1014         state->account_sid = talloc_strdup(mem_ctx2, sidstr);
1015         state->account_name = talloc_strdup(mem_ctx2, groupname);
1016         if (!state->account_name || !state->account_sid) {
1017                 return NT_STATUS_NO_MEMORY;
1018         }
1019
1020         /* create the policy handle */
1021         g_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_GROUP);
1022         if (!g_handle) {
1023                 return NT_STATUS_NO_MEMORY;
1024         }
1025
1026         g_handle->data = state;
1027         g_handle->destroy = samr_Account_destroy;
1028
1029         /* the domain state is in use one more time */
1030         d_state->reference_count++;
1031
1032         *r->out.acct_handle = g_handle->wire_handle;
1033
1034         return NT_STATUS_OK;
1035 }
1036
1037 /* these query macros make samr_Query[User|Group]Info a bit easier to read */
1038
1039 #define QUERY_STRING(msg, field, attr) \
1040         r->out.info->field = samdb_result_string(msg, attr, "");
1041 #define QUERY_UINT(msg, field, attr) \
1042         r->out.info->field = samdb_result_uint(msg, attr, 0);
1043 #define QUERY_RID(msg, field, attr) \
1044         r->out.info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
1045 #define QUERY_NTTIME(msg, field, attr) \
1046         r->out.info->field = samdb_result_nttime(msg, attr, 0);
1047 #define QUERY_APASSC(msg, field, attr) \
1048         r->out.info->field = samdb_result_allow_pwd_change(state->sam_ctx, mem_ctx, \
1049                                                            state->domain_state->basedn, msg, attr);
1050 #define QUERY_FPASSC(msg, field, attr) \
1051         r->out.info->field = samdb_result_force_pwd_change(state->sam_ctx, mem_ctx, \
1052                                                            state->domain_state->basedn, msg, attr);
1053 #define QUERY_LHOURS(msg, field, attr) \
1054         r->out.info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
1055 #define QUERY_AFLAGS(msg, field, attr) \
1056         r->out.info->field = samdb_result_acct_flags(msg, attr);
1057
1058
1059 /* these are used to make the Set[User|Group]Info code easier to follow */
1060
1061 #define SET_STRING(mod, field, attr) do { \
1062         if (r->in.info->field == NULL) return NT_STATUS_INVALID_PARAMETER; \
1063         if (samdb_msg_add_string(state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
1064                 return NT_STATUS_NO_MEMORY; \
1065         } \
1066 } while (0)
1067
1068 #define SET_UINT(mod, field, attr) do { \
1069         if (samdb_msg_add_uint(state->sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
1070                 return NT_STATUS_NO_MEMORY; \
1071         } \
1072 } while (0)
1073
1074 #define SET_AFLAGS(msg, field, attr) do { \
1075         if (samdb_msg_add_acct_flags(state->sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
1076                 return NT_STATUS_NO_MEMORY; \
1077         } \
1078 } while (0)
1079
1080 #define SET_LHOURS(msg, field, attr) do { \
1081         if (samdb_msg_add_logon_hours(state->sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
1082                 return NT_STATUS_NO_MEMORY; \
1083         } \
1084 } while (0)
1085
1086 /* 
1087   samr_QueryGroupInfo 
1088 */
1089 static NTSTATUS samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1090                        struct samr_QueryGroupInfo *r)
1091 {
1092         struct dcesrv_handle *h;
1093         struct samr_account_state *state;
1094         struct ldb_message *msg, **res;
1095         const char * const attrs[4] = { "sAMAccountName", "description",
1096                                         "numMembers", NULL };
1097         int ret;
1098
1099         r->out.info = NULL;
1100
1101         DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_GROUP);
1102
1103         state = h->data;
1104
1105         /* pull all the group attributes */
1106         ret = samdb_search(state->sam_ctx, mem_ctx, NULL, &res, attrs,
1107                            "dn=%s", state->basedn);
1108         if (ret != 1) {
1109                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1110         }
1111         msg = res[0];
1112
1113         /* allocate the info structure */
1114         r->out.info = talloc_p(mem_ctx, union samr_GroupInfo);
1115         if (r->out.info == NULL) {
1116                 return NT_STATUS_NO_MEMORY;
1117         }
1118         ZERO_STRUCTP(r->out.info);
1119
1120         /* Fill in the level */
1121         switch (r->in.level) {
1122         case GroupInfoAll:
1123                 QUERY_STRING(msg, all.name.name,        "sAMAccountName");
1124                 r->out.info->all.unknown = 7; /* Do like w2k3 */
1125                 QUERY_UINT  (msg, all.num_members,      "numMembers")
1126                 QUERY_STRING(msg, all.description.name, "description");
1127                 break;
1128         case GroupInfoName:
1129                 QUERY_STRING(msg, name.name,            "sAMAccountName");
1130                 break;
1131         case GroupInfoX:
1132                 r->out.info->unknown.unknown = 7;
1133                 break;
1134         case GroupInfoDescription:
1135                 QUERY_STRING(msg, description.name, "description");
1136                 break;
1137         default:
1138                 r->out.info = NULL;
1139                 return NT_STATUS_INVALID_INFO_CLASS;
1140         }
1141         
1142         return NT_STATUS_OK;
1143 }
1144
1145
1146 /* 
1147   samr_SetGroupInfo 
1148 */
1149 static NTSTATUS samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1150                        struct samr_SetGroupInfo *r)
1151 {
1152         struct dcesrv_handle *h;
1153         struct samr_account_state *state;
1154         struct ldb_message mod, *msg = &mod;
1155         int i, ret;
1156
1157         DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_GROUP);
1158
1159         state = h->data;
1160
1161         ZERO_STRUCT(mod);
1162         mod.dn = talloc_strdup(mem_ctx, state->basedn);
1163         if (!mod.dn) {
1164                 return NT_STATUS_NO_MEMORY;
1165         }
1166
1167         switch (r->in.level) {
1168         case GroupInfoDescription:
1169                 SET_STRING(msg, description.name,         "description");
1170                 break;
1171         case GroupInfoName:
1172                 /* On W2k3 this does not change the name, it changes the
1173                  * sAMAccountName attribute */
1174                 SET_STRING(msg, name.name,                "sAMAccountName");
1175                 break;
1176         case GroupInfoX:
1177                 /* This does not do anything obviously visible in W2k3 LDAP */
1178                 break;
1179         default:
1180                 return NT_STATUS_INVALID_INFO_CLASS;
1181         }
1182
1183         /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
1184         for (i=0;i<mod.num_elements;i++) {
1185                 mod.elements[i].flags = LDB_FLAG_MOD_REPLACE;
1186         }
1187
1188         /* modify the samdb record */
1189         ret = samdb_modify(state->sam_ctx, mem_ctx, &mod);
1190         if (ret != 0) {
1191                 /* we really need samdb.c to return NTSTATUS */
1192                 return NT_STATUS_UNSUCCESSFUL;
1193         }
1194
1195         return NT_STATUS_OK;
1196 }
1197
1198
1199 /* 
1200   samr_AddGroupMember 
1201 */
1202 static NTSTATUS samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1203                        struct samr_AddGroupMember *r)
1204 {
1205         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1206 }
1207
1208
1209 /* 
1210   samr_DeleteDomainGroup 
1211 */
1212 static NTSTATUS samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1213                        struct samr_DeleteDomainGroup *r)
1214 {
1215         struct dcesrv_handle *h;
1216         struct samr_account_state *state;
1217         int ret;
1218
1219         *r->out.handle = *r->in.handle;
1220
1221         DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_GROUP);
1222
1223         state = h->data;
1224
1225         ret = samdb_delete(state->sam_ctx, mem_ctx, state->basedn);
1226         if (ret != 0) {
1227                 return NT_STATUS_UNSUCCESSFUL;
1228         }
1229
1230         ZERO_STRUCTP(r->out.handle);
1231
1232         return NT_STATUS_OK;
1233 }
1234
1235
1236 /* 
1237   samr_DeleteGroupMember 
1238 */
1239 static NTSTATUS samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1240                        struct samr_DeleteGroupMember *r)
1241 {
1242         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1243 }
1244
1245
1246 /* 
1247   samr_QueryGroupMember 
1248 */
1249 static NTSTATUS samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1250                        struct samr_QueryGroupMember *r)
1251 {
1252         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1253 }
1254
1255
1256 /* 
1257   samr_SetMemberAttributesOfGroup 
1258 */
1259 static NTSTATUS samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1260                        struct samr_SetMemberAttributesOfGroup *r)
1261 {
1262         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1263 }
1264
1265
1266 /* 
1267   samr_OpenAlias 
1268 */
1269 static NTSTATUS samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1270                        struct samr_OpenAlias *r)
1271 {
1272         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1273 }
1274
1275
1276 /* 
1277   samr_QueryAliasInfo 
1278 */
1279 static NTSTATUS samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1280                        struct samr_QueryAliasInfo *r)
1281 {
1282         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1283 }
1284
1285
1286 /* 
1287   samr_SetAliasInfo 
1288 */
1289 static NTSTATUS samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1290                        struct samr_SetAliasInfo *r)
1291 {
1292         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1293 }
1294
1295
1296 /* 
1297   samr_DeleteDomAlias 
1298 */
1299 static NTSTATUS samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1300                        struct samr_DeleteDomAlias *r)
1301 {
1302         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1303 }
1304
1305
1306 /* 
1307   samr_AddAliasMember 
1308 */
1309 static NTSTATUS samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1310                        struct samr_AddAliasMember *r)
1311 {
1312         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1313 }
1314
1315
1316 /* 
1317   samr_DeleteAliasMember 
1318 */
1319 static NTSTATUS samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1320                        struct samr_DeleteAliasMember *r)
1321 {
1322         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1323 }
1324
1325
1326 /* 
1327   samr_GetMembersInAlias 
1328 */
1329 static NTSTATUS samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1330                        struct samr_GetMembersInAlias *r)
1331 {
1332         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1333 }
1334
1335
1336 /* 
1337   samr_OpenUser 
1338 */
1339 static NTSTATUS samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1340                               struct samr_OpenUser *r)
1341 {
1342         struct samr_domain_state *d_state;
1343         struct samr_account_state *state;
1344         struct dcesrv_handle *h;
1345         const char *username, *sidstr;
1346         TALLOC_CTX *mem_ctx2;
1347         struct ldb_message **msgs;
1348         struct dcesrv_handle *u_handle;
1349         const char * const attrs[2] = { "sAMAccountName", NULL };
1350         int ret;
1351
1352         ZERO_STRUCTP(r->out.acct_handle);
1353
1354         DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_DOMAIN);
1355
1356         d_state = h->data;
1357
1358         /* form the users SID */
1359         sidstr = talloc_asprintf(mem_ctx, "%s-%u", d_state->domain_sid, r->in.rid);
1360         if (!sidstr) {
1361                 return NT_STATUS_NO_MEMORY;
1362         }
1363
1364         /* search for the user record */
1365         ret = samdb_search(d_state->sam_ctx,
1366                            mem_ctx, d_state->basedn, &msgs, attrs,
1367                            "(&(objectSid=%s)(objectclass=user))", 
1368                            sidstr);
1369         if (ret == 0) {
1370                 return NT_STATUS_NO_SUCH_USER;
1371         }
1372         if (ret != 1) {
1373                 DEBUG(1,("Found %d records matching sid %s\n", ret, sidstr));
1374                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1375         }
1376
1377         username = samdb_result_string(msgs[0], "sAMAccountName", NULL);
1378         if (username == NULL) {
1379                 DEBUG(1,("sAMAccountName field missing for sid %s\n", sidstr));
1380                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1381         }
1382
1383         /* create user state and new policy handle */
1384         mem_ctx2 = talloc_init("OpenUser(%u)", r->in.rid);
1385         if (!mem_ctx2) {
1386                 return NT_STATUS_NO_MEMORY;
1387         }
1388
1389         state = talloc_p(mem_ctx2, struct samr_account_state);
1390         if (!state) {
1391                 return NT_STATUS_NO_MEMORY;
1392         }
1393         state->mem_ctx = mem_ctx2;
1394         state->sam_ctx = d_state->sam_ctx;
1395         state->access_mask = r->in.access_mask;
1396         state->domain_state = d_state;
1397         state->basedn = talloc_steal(mem_ctx, mem_ctx2, msgs[0]->dn);
1398         state->account_sid = talloc_strdup(mem_ctx2, sidstr);
1399         state->account_name = talloc_strdup(mem_ctx2, username);
1400         if (!state->account_name || !state->account_sid) {
1401                 return NT_STATUS_NO_MEMORY;
1402         }
1403
1404         /* create the policy handle */
1405         u_handle = dcesrv_handle_new(dce_call->conn, SAMR_HANDLE_USER);
1406         if (!u_handle) {
1407                 return NT_STATUS_NO_MEMORY;
1408         }
1409
1410         u_handle->data = state;
1411         u_handle->destroy = samr_Account_destroy;
1412
1413         /* the domain state is in use one more time */
1414         d_state->reference_count++;
1415
1416         *r->out.acct_handle = u_handle->wire_handle;
1417
1418         return NT_STATUS_OK;
1419
1420 }
1421
1422
1423 /* 
1424   samr_DeleteUser 
1425 */
1426 static NTSTATUS samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1427                                 struct samr_DeleteUser *r)
1428 {
1429         struct dcesrv_handle *h;
1430         struct samr_account_state *state;
1431         int ret;
1432
1433         *r->out.handle = *r->in.handle;
1434
1435         DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
1436
1437         state = h->data;
1438
1439         ret = samdb_delete(state->sam_ctx, mem_ctx, state->basedn);
1440         if (ret != 0) {
1441                 return NT_STATUS_UNSUCCESSFUL;
1442         }
1443
1444         ZERO_STRUCTP(r->out.handle);
1445
1446         return NT_STATUS_OK;
1447 }
1448
1449
1450 /* 
1451   samr_QueryUserInfo 
1452 */
1453 static NTSTATUS samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1454                                    struct samr_QueryUserInfo *r)
1455 {
1456         struct dcesrv_handle *h;
1457         struct samr_account_state *state;
1458         struct ldb_message *msg, **res;
1459         int ret;
1460
1461         r->out.info = NULL;
1462
1463         DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
1464
1465         state = h->data;
1466
1467         /* pull all the user attributes */
1468         ret = samdb_search(state->sam_ctx, mem_ctx, NULL, &res, NULL,
1469                            "dn=%s", state->basedn);
1470         if (ret != 1) {
1471                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1472         }
1473         msg = res[0];
1474
1475         /* allocate the info structure */
1476         r->out.info = talloc_p(mem_ctx, union samr_UserInfo);
1477         if (r->out.info == NULL) {
1478                 return NT_STATUS_NO_MEMORY;
1479         }
1480         ZERO_STRUCTP(r->out.info);
1481
1482         /* fill in the reply */
1483         switch (r->in.level) {
1484         case 1:
1485                 QUERY_STRING(msg, info1.username.name,    "sAMAccountName");
1486                 QUERY_STRING(msg, info1.full_name.name,   "displayName");
1487                 QUERY_UINT  (msg, info1.primary_gid,      "primaryGroupID");
1488                 QUERY_STRING(msg, info1.description.name, "description");
1489                 QUERY_STRING(msg, info1.comment.name,     "comment");
1490                 break;
1491
1492         case 2:
1493                 QUERY_STRING(msg, info2.comment.name,     "comment");
1494                 QUERY_UINT  (msg, info2.country_code,     "countryCode");
1495                 QUERY_UINT  (msg, info2.code_page,        "codePage");
1496                 break;
1497
1498         case 3:
1499                 QUERY_STRING(msg, info3.username.name,       "sAMAccountName");
1500                 QUERY_STRING(msg, info3.full_name.name,      "displayName");
1501                 QUERY_RID   (msg, info3.rid,                 "objectSid");
1502                 QUERY_UINT  (msg, info3.primary_gid,         "primaryGroupID");
1503                 QUERY_STRING(msg, info3.home_directory.name, "homeDirectory");
1504                 QUERY_STRING(msg, info3.home_drive.name,     "homeDrive");
1505                 QUERY_STRING(msg, info3.logon_script.name,   "scriptPath");
1506                 QUERY_STRING(msg, info3.profile.name,        "profilePath");
1507                 QUERY_STRING(msg, info3.workstations.name,   "userWorkstations");
1508                 QUERY_NTTIME(msg, info3.last_logon,          "lastLogon");
1509                 QUERY_NTTIME(msg, info3.last_logoff,         "lastLogoff");
1510                 QUERY_NTTIME(msg, info3.last_pwd_change,     "pwdLastSet");
1511                 QUERY_APASSC(msg, info3.allow_pwd_change,    "pwdLastSet");
1512                 QUERY_FPASSC(msg, info3.force_pwd_change,    "pwdLastSet");
1513                 QUERY_LHOURS(msg, info3.logon_hours,         "logonHours");
1514                 QUERY_UINT  (msg, info3.bad_pwd_count,       "badPwdCount");
1515                 QUERY_UINT  (msg, info3.num_logons,          "logonCount");
1516                 QUERY_AFLAGS(msg, info3.acct_flags,          "userAccountControl");
1517                 break;
1518
1519         case 4:
1520                 QUERY_LHOURS(msg, info4.logon_hours,         "logonHours");
1521                 break;
1522
1523         case 5:
1524                 QUERY_STRING(msg, info5.username.name,       "sAMAccountName");
1525                 QUERY_STRING(msg, info5.full_name.name,      "displayName");
1526                 QUERY_RID   (msg, info5.rid,                 "objectSid");
1527                 QUERY_UINT  (msg, info5.primary_gid,         "primaryGroupID");
1528                 QUERY_STRING(msg, info5.home_directory.name, "homeDirectory");
1529                 QUERY_STRING(msg, info5.home_drive.name,     "homeDrive");
1530                 QUERY_STRING(msg, info5.logon_script.name,   "scriptPath");
1531                 QUERY_STRING(msg, info5.profile.name,        "profilePath");
1532                 QUERY_STRING(msg, info5.description.name,    "description");
1533                 QUERY_STRING(msg, info5.workstations.name,   "userWorkstations");
1534                 QUERY_NTTIME(msg, info5.last_logon,          "lastLogon");
1535                 QUERY_NTTIME(msg, info5.last_logoff,         "lastLogoff");
1536                 QUERY_LHOURS(msg, info5.logon_hours,         "logonHours");
1537                 QUERY_UINT  (msg, info5.bad_pwd_count,       "badPwdCount");
1538                 QUERY_UINT  (msg, info5.num_logons,          "logonCount");
1539                 QUERY_NTTIME(msg, info5.last_pwd_change,     "pwdLastSet");
1540                 QUERY_NTTIME(msg, info5.acct_expiry,         "accountExpires");
1541                 QUERY_AFLAGS(msg, info5.acct_flags,          "userAccountControl");
1542                 break;
1543
1544         case 6:
1545                 QUERY_STRING(msg, info6.username.name,       "sAMAccountName");
1546                 QUERY_STRING(msg, info6.full_name.name,      "displayName");
1547                 break;
1548
1549         case 7:
1550                 QUERY_STRING(msg, info7.username.name,       "sAMAccountName");
1551                 break;
1552
1553         case 8:
1554                 QUERY_STRING(msg, info8.full_name.name,      "displayName");
1555                 break;
1556
1557         case 9:
1558                 QUERY_UINT  (msg, info9.primary_gid,         "primaryGroupID");
1559                 break;
1560
1561         case 10:
1562                 QUERY_STRING(msg, info10.home_directory.name, "homeDirectory");
1563                 QUERY_STRING(msg, info10.home_drive.name,     "homeDrive");
1564                 break;
1565
1566         case 11:
1567                 QUERY_STRING(msg, info11.logon_script.name,   "scriptPath");
1568                 break;
1569
1570         case 12:
1571                 QUERY_STRING(msg, info12.profile.name,        "profilePath");
1572                 break;
1573
1574         case 13:
1575                 QUERY_STRING(msg, info13.description.name,    "description");
1576                 break;
1577
1578         case 14:
1579                 QUERY_STRING(msg, info14.workstations.name,   "userWorkstations");
1580                 break;
1581
1582         case 16:
1583                 QUERY_AFLAGS(msg, info16.acct_flags,          "userAccountControl");
1584                 break;
1585
1586         case 17:
1587                 QUERY_NTTIME(msg, info17.acct_expiry,         "accountExpires");
1588
1589         case 20:
1590                 QUERY_STRING(msg, info20.callback.name,       "userParameters");
1591                 break;
1592
1593         case 21:
1594                 QUERY_NTTIME(msg, info21.last_logon,          "lastLogon");
1595                 QUERY_NTTIME(msg, info21.last_logoff,         "lastLogoff");
1596                 QUERY_NTTIME(msg, info21.last_pwd_change,     "pwdLastSet");
1597                 QUERY_NTTIME(msg, info21.acct_expiry,         "accountExpires");
1598                 QUERY_APASSC(msg, info21.allow_pwd_change,    "pwdLastSet");
1599                 QUERY_FPASSC(msg, info21.force_pwd_change,    "pwdLastSet");
1600                 QUERY_STRING(msg, info21.username.name,       "sAMAccountName");
1601                 QUERY_STRING(msg, info21.full_name.name,      "displayName");
1602                 QUERY_STRING(msg, info21.home_directory.name, "homeDirectory");
1603                 QUERY_STRING(msg, info21.home_drive.name,     "homeDrive");
1604                 QUERY_STRING(msg, info21.logon_script.name,   "scriptPath");
1605                 QUERY_STRING(msg, info21.profile.name,        "profilePath");
1606                 QUERY_STRING(msg, info21.description.name,    "description");
1607                 QUERY_STRING(msg, info21.workstations.name,   "userWorkstations");
1608                 QUERY_STRING(msg, info21.comment.name,        "comment");
1609                 QUERY_STRING(msg, info21.callback.name,       "userParameters");
1610                 QUERY_RID   (msg, info21.rid,                 "objectSid");
1611                 QUERY_UINT  (msg, info21.primary_gid,         "primaryGroupID");
1612                 QUERY_AFLAGS(msg, info21.acct_flags,          "userAccountControl");
1613                 r->out.info->info21.fields_present = 0x00FFFFFF;
1614                 QUERY_LHOURS(msg, info21.logon_hours,         "logonHours");
1615                 QUERY_UINT  (msg, info21.bad_pwd_count,       "badPwdCount");
1616                 QUERY_UINT  (msg, info21.num_logons,          "logonCount");
1617                 QUERY_UINT  (msg, info21.country_code,        "countryCode");
1618                 QUERY_UINT  (msg, info21.code_page,           "codePage");
1619                 break;
1620                 
1621
1622         default:
1623                 r->out.info = NULL;
1624                 return NT_STATUS_INVALID_INFO_CLASS;
1625         }
1626         
1627         return NT_STATUS_OK;
1628 }
1629
1630
1631 /*
1632   set password via a samr_CryptPassword buffer
1633   this will in the 'msg' with modify operations that will update the user
1634   password when applied
1635 */
1636 static NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
1637                                   struct samr_account_state *state, TALLOC_CTX *mem_ctx,
1638                                   struct ldb_message *msg, 
1639                                   struct samr_CryptPassword *pwbuf)
1640 {
1641         char new_pass[512];
1642         uint32 new_pass_len;
1643         DATA_BLOB session_key = dce_call->conn->session_key;
1644
1645         SamOEMhashBlob(pwbuf->data, 516, &session_key);
1646
1647         if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
1648                               &new_pass_len, STR_UNICODE)) {
1649                 DEBUG(3,("samr: failed to decode password buffer\n"));
1650                 return NT_STATUS_WRONG_PASSWORD;
1651         }
1652
1653         /* set the password - samdb needs to know both the domain and user DNs,
1654            so the domain password policy can be used */
1655         return samdb_set_password(state->sam_ctx, mem_ctx,
1656                                   state->basedn, state->domain_state->basedn, 
1657                                   msg, new_pass);
1658 }
1659
1660 /* 
1661   samr_SetUserInfo 
1662 */
1663 static NTSTATUS samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1664                                  struct samr_SetUserInfo *r)
1665 {
1666         struct dcesrv_handle *h;
1667         struct samr_account_state *state;
1668         struct ldb_message mod, *msg = &mod;
1669         int i, ret;
1670         NTSTATUS status = NT_STATUS_OK;
1671
1672         DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
1673
1674         state = h->data;
1675
1676         ZERO_STRUCT(mod);
1677         mod.dn = talloc_strdup(mem_ctx, state->basedn);
1678         if (!mod.dn) {
1679                 return NT_STATUS_NO_MEMORY;
1680         }
1681
1682         switch (r->in.level) {
1683         case 2:
1684                 SET_STRING(msg, info2.comment.name,         "comment");
1685                 SET_UINT  (msg, info2.country_code,         "countryCode");
1686                 SET_UINT  (msg, info2.code_page,            "codePage");
1687                 break;
1688
1689         case 4:
1690                 SET_LHOURS(msg, info4.logon_hours,          "logonHours");
1691                 break;
1692
1693         case 6:
1694                 SET_STRING(msg, info6.full_name.name,       "displayName");
1695                 break;
1696
1697         case 8:
1698                 SET_STRING(msg, info8.full_name.name,       "displayName");
1699                 break;
1700
1701         case 9:
1702                 SET_UINT(msg, info9.primary_gid,            "primaryGroupID");
1703                 break;
1704
1705         case 10:
1706                 SET_STRING(msg, info10.home_directory.name, "homeDirectory");
1707                 SET_STRING(msg, info10.home_drive.name,     "homeDrive");
1708                 break;
1709
1710         case 11:
1711                 SET_STRING(msg, info11.logon_script.name,   "scriptPath");
1712                 break;
1713
1714         case 12:
1715                 SET_STRING(msg, info12.profile.name,        "profilePath");
1716                 break;
1717
1718         case 13:
1719                 SET_STRING(msg, info13.description.name,    "description");
1720                 break;
1721
1722         case 14:
1723                 SET_STRING(msg, info14.workstations.name,   "userWorkstations");
1724                 break;
1725
1726         case 16:
1727                 SET_AFLAGS(msg, info16.acct_flags,          "userAccountControl");
1728                 break;
1729
1730         case 20:
1731                 SET_STRING(msg, info20.callback.name,       "userParameters");
1732                 break;
1733
1734         case 21:
1735 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
1736                 IFSET(SAMR_FIELD_NAME)         
1737                         SET_STRING(msg, info21.full_name.name,    "displayName");
1738                 IFSET(SAMR_FIELD_DESCRIPTION)  
1739                         SET_STRING(msg, info21.description.name,  "description");
1740                 IFSET(SAMR_FIELD_COMMENT)      
1741                         SET_STRING(msg, info21.comment.name,      "comment");
1742                 IFSET(SAMR_FIELD_LOGON_SCRIPT) 
1743                         SET_STRING(msg, info21.logon_script.name, "scriptPath");
1744                 IFSET(SAMR_FIELD_PROFILE)      
1745                         SET_STRING(msg, info21.profile.name,      "profilePath");
1746                 IFSET(SAMR_FIELD_WORKSTATION)  
1747                         SET_STRING(msg, info21.workstations.name, "userWorkstations");
1748                 IFSET(SAMR_FIELD_LOGON_HOURS)  
1749                         SET_LHOURS(msg, info21.logon_hours,       "logonHours");
1750                 IFSET(SAMR_FIELD_CALLBACK)     
1751                         SET_STRING(msg, info21.callback.name,     "userParameters");
1752                 IFSET(SAMR_FIELD_COUNTRY_CODE) 
1753                         SET_UINT  (msg, info21.country_code,      "countryCode");
1754                 IFSET(SAMR_FIELD_CODE_PAGE)    
1755                         SET_UINT  (msg, info21.code_page,         "codePage");
1756                 break;
1757
1758                 /* the set password levels are handled separately */
1759         case 24:
1760                 status = samr_set_password(dce_call, state, mem_ctx, msg, 
1761                                            &r->in.info->info24.password);
1762                 break;
1763                 
1764
1765         default:
1766                 /* many info classes are not valid for SetUserInfo */
1767                 return NT_STATUS_INVALID_INFO_CLASS;
1768         }
1769
1770         if (!NT_STATUS_IS_OK(status)) {
1771                 return status;
1772         }
1773
1774         /* mark all the message elements as LDB_FLAG_MOD_REPLACE, 
1775            unless they are already marked with some other flag */
1776         for (i=0;i<mod.num_elements;i++) {
1777                 if (mod.elements[i].flags == 0) {
1778                         mod.elements[i].flags = LDB_FLAG_MOD_REPLACE;
1779                 }
1780         }
1781
1782         /* modify the samdb record */
1783         ret = samdb_modify(state->sam_ctx, mem_ctx, msg);
1784         if (ret != 0) {
1785                 /* we really need samdb.c to return NTSTATUS */
1786                 return NT_STATUS_UNSUCCESSFUL;
1787         }
1788
1789         return NT_STATUS_OK;
1790 }
1791
1792
1793 /* 
1794   samr_ChangePasswordUser 
1795 */
1796 static NTSTATUS samr_ChangePasswordUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1797                        struct samr_ChangePasswordUser *r)
1798 {
1799         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1800 }
1801
1802
1803 /* 
1804   samr_GetGroupsForUser 
1805 */
1806 static NTSTATUS samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1807                        struct samr_GetGroupsForUser *r)
1808 {
1809         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1810 }
1811
1812
1813 /* 
1814   samr_QueryDisplayInfo 
1815 */
1816 static NTSTATUS samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1817                        struct samr_QueryDisplayInfo *r)
1818 {
1819         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1820 }
1821
1822
1823 /* 
1824   samr_GetDisplayEnumerationIndex 
1825 */
1826 static NTSTATUS samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1827                        struct samr_GetDisplayEnumerationIndex *r)
1828 {
1829         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1830 }
1831
1832
1833 /* 
1834   samr_TestPrivateFunctionsDomain 
1835 */
1836 static NTSTATUS samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1837                        struct samr_TestPrivateFunctionsDomain *r)
1838 {
1839         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1840 }
1841
1842
1843 /* 
1844   samr_TestPrivateFunctionsUser 
1845 */
1846 static NTSTATUS samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1847                        struct samr_TestPrivateFunctionsUser *r)
1848 {
1849         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1850 }
1851
1852
1853 /* 
1854   samr_GetUserPwInfo 
1855 */
1856 static NTSTATUS samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1857                                    struct samr_GetUserPwInfo *r)
1858 {
1859         struct dcesrv_handle *h;
1860         struct samr_account_state *state;
1861
1862         ZERO_STRUCT(r->out.info);
1863
1864         DCESRV_PULL_HANDLE(h, r->in.handle, SAMR_HANDLE_USER);
1865
1866         state = h->data;
1867
1868         r->out.info.min_pwd_len = samdb_search_uint(state->sam_ctx, mem_ctx, 0, NULL, "minPwdLength", 
1869                                                     "dn=%s", state->domain_state->basedn);
1870         r->out.info.password_properties = samdb_search_uint(state->sam_ctx, mem_ctx, 0, NULL, "pwdProperties", 
1871                                                             "dn=%s", state->basedn);
1872         return NT_STATUS_OK;
1873 }
1874
1875
1876 /* 
1877   samr_RemoveMemberFromForeignDomain 
1878 */
1879 static NTSTATUS samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1880                        struct samr_RemoveMemberFromForeignDomain *r)
1881 {
1882         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1883 }
1884
1885
1886 /* 
1887   samr_QueryDomainInfo2 
1888 */
1889 static NTSTATUS samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1890                        struct samr_QueryDomainInfo2 *r)
1891 {
1892         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1893 }
1894
1895
1896 /* 
1897   samr_QueryUserInfo2 
1898
1899   just an alias for samr_QueryUserInfo
1900 */
1901 static NTSTATUS samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1902                                     struct samr_QueryUserInfo2 *r)
1903 {
1904         struct samr_QueryUserInfo r1;
1905         NTSTATUS status;
1906
1907         r1.in.handle = r->in.handle;
1908         r1.in.level  = r->in.level;
1909         
1910         status = samr_QueryUserInfo(dce_call, mem_ctx, &r1);
1911         
1912         r->out.info = r1.out.info;
1913
1914         return status;
1915 }
1916
1917
1918 /* 
1919   samr_QueryDisplayInfo2 
1920 */
1921 static NTSTATUS samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1922                        struct samr_QueryDisplayInfo2 *r)
1923 {
1924         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1925 }
1926
1927
1928 /* 
1929   samr_GetDisplayEnumerationIndex2 
1930 */
1931 static NTSTATUS samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1932                        struct samr_GetDisplayEnumerationIndex2 *r)
1933 {
1934         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1935 }
1936
1937
1938 /* 
1939   samr_QueryDisplayInfo3 
1940 */
1941 static NTSTATUS samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1942                        struct samr_QueryDisplayInfo3 *r)
1943 {
1944         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1945 }
1946
1947
1948 /* 
1949   samr_AddMultipleMembersToAlias 
1950 */
1951 static NTSTATUS samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1952                        struct samr_AddMultipleMembersToAlias *r)
1953 {
1954         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1955 }
1956
1957
1958 /* 
1959   samr_RemoveMultipleMembersFromAlias 
1960 */
1961 static NTSTATUS samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1962                        struct samr_RemoveMultipleMembersFromAlias *r)
1963 {
1964         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1965 }
1966
1967
1968 /* 
1969   samr_OemChangePasswordUser2 
1970 */
1971 static NTSTATUS samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1972                        struct samr_OemChangePasswordUser2 *r)
1973 {
1974         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1975 }
1976
1977
1978 /* 
1979   samr_ChangePasswordUser2 
1980 */
1981 static NTSTATUS samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1982                        struct samr_ChangePasswordUser2 *r)
1983 {
1984         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
1985 }
1986
1987
1988 /* 
1989   samr_GetDomPwInfo 
1990
1991   this fetches the default password properties for a domain
1992 */
1993 static NTSTATUS samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1994                                   struct samr_GetDomPwInfo *r)
1995 {
1996         struct ldb_message **msgs;
1997         int ret;
1998         const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
1999         void *sam_ctx;
2000
2001         if (r->in.name == NULL || r->in.name->name == NULL) {
2002                 return NT_STATUS_NO_SUCH_DOMAIN;
2003         }
2004
2005         sam_ctx = samdb_connect();
2006         if (sam_ctx == NULL) {
2007                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
2008         }
2009
2010         ret = samdb_search(sam_ctx, 
2011                            mem_ctx, NULL, &msgs, attrs, 
2012                            "(&(name=%s)(objectclass=domain))",
2013                            r->in.name->name);
2014         if (ret <= 0) {
2015                 samdb_close(sam_ctx);
2016                 return NT_STATUS_NO_SUCH_DOMAIN;
2017         }
2018         if (ret > 1) {
2019                 samdb_search_free(sam_ctx, mem_ctx, msgs);
2020                 samdb_close(sam_ctx);
2021                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2022         }
2023
2024         r->out.info.min_pwd_len         = samdb_result_uint(msgs[0], "minPwdLength", 0);
2025         r->out.info.password_properties = samdb_result_uint(msgs[0], "pwdProperties", 1);
2026
2027         samdb_search_free(sam_ctx, mem_ctx, msgs);
2028
2029         samdb_close(sam_ctx);
2030         return NT_STATUS_OK;
2031 }
2032
2033
2034 /* 
2035   samr_Connect2 
2036 */
2037 static NTSTATUS samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2038                               struct samr_Connect2 *r)
2039 {
2040         struct samr_Connect c;
2041
2042         c.in.system_name = NULL;
2043         c.in.access_mask = r->in.access_mask;
2044         c.out.handle = r->out.handle;
2045
2046         return samr_Connect(dce_call, mem_ctx, &c);
2047 }
2048
2049
2050 /* 
2051   samr_SetUserInfo2 
2052
2053   just an alias for samr_SetUserInfo
2054 */
2055 static NTSTATUS samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2056                                   struct samr_SetUserInfo2 *r)
2057 {
2058         struct samr_SetUserInfo r2;
2059
2060         r2.in.handle = r->in.handle;
2061         r2.in.level = r->in.level;
2062         r2.in.info = r->in.info;
2063
2064         return samr_SetUserInfo(dce_call, mem_ctx, &r2);
2065 }
2066
2067
2068 /* 
2069   samr_SetBootKeyInformation 
2070 */
2071 static NTSTATUS samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2072                        struct samr_SetBootKeyInformation *r)
2073 {
2074         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2075 }
2076
2077
2078 /* 
2079   samr_GetBootKeyInformation 
2080 */
2081 static NTSTATUS samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2082                        struct samr_GetBootKeyInformation *r)
2083 {
2084         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2085 }
2086
2087
2088 /* 
2089   samr_Connect3 
2090 */
2091 static NTSTATUS samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2092                        struct samr_Connect3 *r)
2093 {
2094         struct samr_Connect c;
2095
2096         c.in.system_name = NULL;
2097         c.in.access_mask = r->in.access_mask;
2098         c.out.handle = r->out.handle;
2099
2100         return samr_Connect(dce_call, mem_ctx, &c);
2101 }
2102
2103
2104 /* 
2105   samr_Connect4 
2106 */
2107 static NTSTATUS samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2108                        struct samr_Connect4 *r)
2109 {
2110         struct samr_Connect c;
2111
2112         c.in.system_name = NULL;
2113         c.in.access_mask = r->in.access_mask;
2114         c.out.handle = r->out.handle;
2115
2116         return samr_Connect(dce_call, mem_ctx, &c);
2117 }
2118
2119
2120 /* 
2121   samr_ChangePasswordUser3 
2122 */
2123 static NTSTATUS samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2124                        struct samr_ChangePasswordUser3 *r)
2125 {
2126         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2127 }
2128
2129
2130 /* 
2131   samr_Connect5 
2132 */
2133 static NTSTATUS samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2134                               struct samr_Connect5 *r)
2135 {
2136         struct samr_Connect c;
2137         NTSTATUS status;
2138
2139         c.in.system_name = NULL;
2140         c.in.access_mask = r->in.access_mask;
2141         c.out.handle = r->out.handle;
2142
2143         status = samr_Connect(dce_call, mem_ctx, &c);
2144
2145         r->out.info->info1.unknown1 = 3;
2146         r->out.info->info1.unknown2 = 0;
2147         r->out.level = r->in.level;
2148
2149         return status;
2150 }
2151
2152
2153 /* 
2154   samr_RidToSid 
2155 */
2156 static NTSTATUS samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2157                        struct samr_RidToSid *r)
2158 {
2159         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2160 }
2161
2162
2163 /* 
2164   samr_SetDsrmPassword 
2165 */
2166 static NTSTATUS samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2167                        struct samr_SetDsrmPassword *r)
2168 {
2169         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2170 }
2171
2172
2173 /* 
2174   samr_ValidatePassword 
2175 */
2176 static NTSTATUS samr_ValidatePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2177                        struct samr_ValidatePassword *r)
2178 {
2179         DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2180 }
2181
2182
2183 /* include the generated boilerplate */
2184 #include "librpc/gen_ndr/ndr_samr_s.c"