This looks like a big change but really isn't.
[gd/samba-autobuild/.git] / source3 / rpc_server / srv_samr.c
1
2 /* 
3  *  Unix SMB/Netbios implementation.
4  *  Version 1.9.
5  *  RPC Pipe client / server routines
6  *  Copyright (C) Andrew Tridgell              1992-1997,
7  *  Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
8  *  Copyright (C) Paul Ashton                       1997.
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 2 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, write to the Free Software
22  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24
25
26 #include "includes.h"
27 #include "nterr.h"
28
29 extern int DEBUGLEVEL;
30
31 extern BOOL sam_logon_in_ssb;
32 extern pstring samlogon_user;
33 extern rid_name domain_group_rids[];
34 extern rid_name domain_alias_rids[];
35
36 /*******************************************************************
37   This next function should be replaced with something that
38   dynamically returns the correct user info..... JRA.
39  ********************************************************************/
40
41 static BOOL get_smbpwd_entries(SAM_USER_INFO_21 *pw_buf,
42                                 int *total_entries, int *num_entries,
43                                 int max_num_entries,
44                                 uint16 acb_mask)
45 {
46         void *vp = NULL;
47         struct smb_passwd *pwd = NULL;
48  
49         (*num_entries) = 0;
50         (*total_entries) = 0;
51
52         if (pw_buf == NULL) return False;
53
54         vp = startsmbpwent(False);
55         if (!vp)
56         {
57                 DEBUG(0, ("get_smbpwd_entries: Unable to open SMB password file.\n"));
58                 return False;
59         }
60
61         while (((pwd = getsmbpwent(vp)) != NULL) && (*num_entries) < max_num_entries)
62         {
63                 int user_name_len = strlen(pwd->smb_name);
64                 make_unistr2(&(pw_buf[(*num_entries)].uni_user_name), pwd->smb_name, user_name_len);
65                 make_uni_hdr(&(pw_buf[(*num_entries)].hdr_user_name), user_name_len, 
66                 user_name_len, 1);
67                 pw_buf[(*num_entries)].user_rid    = pwd->smb_userid;
68                 bzero( pw_buf[(*num_entries)].nt_pwd , 16);
69
70                 /* Now check if the NT compatible password is available. */
71                 if (pwd->smb_nt_passwd != NULL)
72                 {
73                   memcpy( pw_buf[(*num_entries)].nt_pwd , pwd->smb_nt_passwd, 16);
74                 }
75
76                 pw_buf[(*num_entries)].acb_info = (uint16)pwd->acct_ctrl;
77
78                 DEBUG(5, ("get_smbpwd_entries: idx: %d user %s, uid %d, acb %x",
79                           (*num_entries), pwd->smb_name, pwd->smb_userid, pwd->acct_ctrl));
80
81                 if (acb_mask == 0 || IS_BITS_SET_SOME(pwd->acct_ctrl, acb_mask))
82                 {
83                         DEBUG(5,(" acb_mask %x accepts\n", acb_mask));
84                         (*num_entries)++;
85                 }
86                 else
87                 {
88                         DEBUG(5,(" acb_mask %x rejects\n", acb_mask));
89                 }
90
91                 (*total_entries)++;
92         }
93
94         endsmbpwent(vp);
95
96         return (*num_entries) > 0;
97 }
98
99 /*******************************************************************
100  samr_reply_unknown_1
101  ********************************************************************/
102 static void samr_reply_close_hnd(SAMR_Q_CLOSE_HND *q_u,
103                                 prs_struct *rdata)
104 {
105         SAMR_R_CLOSE_HND r_u;
106
107         /* set up the SAMR unknown_1 response */
108         bzero(&(r_u.pol.data), POL_HND_SIZE);
109
110         /* close the policy handle */
111         if (close_lsa_policy_hnd(&(q_u->pol)))
112         {
113                 r_u.status = 0;
114         }
115         else
116         {
117                 r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_INVALID;
118         }
119
120         DEBUG(5,("samr_reply_close_hnd: %d\n", __LINE__));
121
122         /* store the response in the SMB stream */
123         samr_io_r_close_hnd("", &r_u, rdata, 0);
124
125         DEBUG(5,("samr_reply_close_hnd: %d\n", __LINE__));
126
127 }
128
129 /*******************************************************************
130  api_samr_close_hnd
131  ********************************************************************/
132 static void api_samr_close_hnd( int uid, prs_struct *data, prs_struct *rdata)
133 {
134         SAMR_Q_CLOSE_HND q_u;
135
136         /* grab the samr unknown 1 */
137         samr_io_q_close_hnd("", &q_u, data, 0);
138
139         /* construct reply.  always indicate success */
140         samr_reply_close_hnd(&q_u, rdata);
141 }
142
143
144 /*******************************************************************
145  samr_reply_open_domain
146  ********************************************************************/
147 static void samr_reply_open_domain(SAMR_Q_OPEN_DOMAIN *q_u,
148                                 prs_struct *rdata)
149 {
150         SAMR_R_OPEN_DOMAIN r_u;
151         BOOL pol_open = False;
152         int pol_idx;
153
154         r_u.status = 0x0;
155
156         /* find the connection policy handle. */
157         if (r_u.status == 0x0 && ((pol_idx = find_lsa_policy_by_hnd(&(q_u->connect_pol))) == -1))
158         {
159                 r_u.status = 0xC0000000 | NT_STATUS_INVALID_HANDLE;
160         }
161
162         /* get a (unique) handle.  open a policy on it. */
163         if (r_u.status == 0x0 && !(pol_open = open_lsa_policy_hnd(&(r_u.domain_pol))))
164         {
165                 r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND;
166         }
167
168         /* associate the domain SID with the (unique) handle. */
169         if (r_u.status == 0x0 && !set_lsa_policy_samr_sid(&(r_u.domain_pol), &(q_u->dom_sid.sid)))
170         {
171                 /* oh, whoops.  don't know what error message to return, here */
172                 r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND;
173         }
174
175         if (r_u.status != 0 && pol_open)
176         {
177                 close_lsa_policy_hnd(&(r_u.domain_pol));
178         }
179
180         DEBUG(5,("samr_open_domain: %d\n", __LINE__));
181
182         /* store the response in the SMB stream */
183         samr_io_r_open_domain("", &r_u, rdata, 0);
184
185         DEBUG(5,("samr_open_domain: %d\n", __LINE__));
186
187 }
188
189 /*******************************************************************
190  api_samr_open_domain
191  ********************************************************************/
192 static void api_samr_open_domain( int uid, prs_struct *data, prs_struct *rdata)
193 {
194         SAMR_Q_OPEN_DOMAIN q_u;
195
196         /* grab the samr open */
197         samr_io_q_open_domain("", &q_u, data, 0);
198
199         /* construct reply.  always indicate success */
200         samr_reply_open_domain(&q_u, rdata);
201 }
202
203
204 /*******************************************************************
205  samr_reply_unknown_3
206  ********************************************************************/
207 static void samr_reply_unknown_3(SAMR_Q_UNKNOWN_3 *q_u,
208                                 prs_struct *rdata)
209 {
210         SAMR_R_UNKNOWN_3 r_u;
211         DOM_SID3 sid[MAX_SAM_SIDS];
212         fstring user_sid;
213         fstring user_rid;
214         int pol_idx;
215         uint32 rid;
216         uint32 status;
217
218         status = 0x0;
219
220         /* find the policy handle.  open a policy on it. */
221         if (status == 0x0 && ((pol_idx = find_lsa_policy_by_hnd(&(q_u->user_pol))) == -1))
222         {
223                 status = 0xC0000000 | NT_STATUS_INVALID_HANDLE;
224         }
225
226         /* find the user's rid */
227         if (status == 0x0 && (rid = get_lsa_policy_samr_rid(&(q_u->user_pol))) == 0xffffffff)
228         {
229                 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
230         }
231
232         if (status == 0x0)
233         {
234                 strcpy(user_sid, lp_domain_sid());
235                 sprintf(user_rid, "-%x", rid);
236                 strcat(user_sid, user_rid);
237
238                 /* maybe need another 1 or 2 (S-1-5-20-0x220 and S-1-5-20-0x224) */
239                 /* these two are DOMAIN_ADMIN and DOMAIN_ACCT_OP group RIDs */
240                 make_dom_sid3(&(sid[0]), 0x035b, 0x0002, "S-1-1");
241                 make_dom_sid3(&(sid[1]), 0x0044, 0x0002, user_sid);
242         }
243
244         make_samr_r_unknown_3(&r_u,
245                                 0x0001, 0x8004,
246                                 0x00000014, 0x0002, 0x0070,
247                                 2, sid, status);
248
249         DEBUG(5,("samr_unknown_3: %d\n", __LINE__));
250
251         /* store the response in the SMB stream */
252         samr_io_r_unknown_3("", &r_u, rdata, 0);
253
254         DEBUG(5,("samr_unknown_3: %d\n", __LINE__));
255
256 }
257
258 /*******************************************************************
259  api_samr_unknown_3
260  ********************************************************************/
261 static void api_samr_unknown_3( int uid, prs_struct *data, prs_struct *rdata)
262 {
263         SAMR_Q_UNKNOWN_3 q_u;
264
265         /* grab the samr open */
266         samr_io_q_unknown_3("", &q_u, data, 0);
267
268         /* construct reply.  always indicate success */
269         samr_reply_unknown_3(&q_u, rdata);
270 }
271
272
273 /*******************************************************************
274  samr_reply_enum_dom_users
275  ********************************************************************/
276 static void samr_reply_enum_dom_users(SAMR_Q_ENUM_DOM_USERS *q_u,
277                                 prs_struct *rdata)
278 {
279         SAMR_R_ENUM_DOM_USERS r_e;
280         SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES];
281         int num_entries;
282         int total_entries;
283         int pol_idx;
284         BOOL got_pwds;
285
286         r_e.status = 0x0;
287         r_e.total_num_entries = 0;
288
289         /* find the policy handle.  open a policy on it. */
290         if (r_e.status == 0x0 && ((pol_idx = find_lsa_policy_by_hnd(&(q_u->pol))) == -1))
291         {
292                 r_e.status = 0xC0000000 | NT_STATUS_INVALID_HANDLE;
293         }
294
295         DEBUG(5,("samr_reply_enum_dom_users: %d\n", __LINE__));
296
297         become_root(True);
298         got_pwds = get_smbpwd_entries(pass, &total_entries, &num_entries, MAX_SAM_ENTRIES, q_u->acb_mask);
299         unbecome_root(True);
300
301         make_samr_r_enum_dom_users(&r_e, total_entries,
302                                    q_u->unknown_0, num_entries,
303                                    pass, r_e.status);
304
305         /* store the response in the SMB stream */
306         samr_io_r_enum_dom_users("", &r_e, rdata, 0);
307
308         DEBUG(5,("samr_enum_dom_users: %d\n", __LINE__));
309
310 }
311
312 /*******************************************************************
313  api_samr_enum_dom_users
314  ********************************************************************/
315 static void api_samr_enum_dom_users( int uid, prs_struct *data, prs_struct *rdata)
316 {
317         SAMR_Q_ENUM_DOM_USERS q_e;
318
319         /* grab the samr open */
320         samr_io_q_enum_dom_users("", &q_e, data, 0);
321
322         /* construct reply. */
323         samr_reply_enum_dom_users(&q_e, rdata);
324 }
325
326
327 /*******************************************************************
328  samr_reply_enum_dom_groups
329  ********************************************************************/
330 static void samr_reply_enum_dom_groups(SAMR_Q_ENUM_DOM_GROUPS *q_u,
331                                 prs_struct *rdata)
332 {
333         SAMR_R_ENUM_DOM_GROUPS r_e;
334         SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES];
335         int num_entries;
336         int pol_idx;
337         BOOL got_grps;
338         char *dummy_group = "Domain Admins";
339
340         r_e.status = 0x0;
341         r_e.num_entries = 0;
342
343         /* find the policy handle.  open a policy on it. */
344         if (r_e.status == 0x0 && ((pol_idx = find_lsa_policy_by_hnd(&(q_u->pol))) == -1))
345         {
346                 r_e.status = 0xC0000000 | NT_STATUS_INVALID_HANDLE;
347         }
348
349         DEBUG(5,("samr_reply_enum_dom_groups: %d\n", __LINE__));
350
351         got_grps = True;
352         num_entries = 1;
353         make_unistr2(&(pass[0].uni_user_name), dummy_group, strlen(dummy_group));
354         pass[0].user_rid = DOMAIN_GROUP_RID_ADMINS;
355
356         if (r_e.status == 0 && got_grps)
357         {
358                 make_samr_r_enum_dom_groups(&r_e, q_u->start_idx, num_entries, pass, r_e.status);
359         }
360
361         /* store the response in the SMB stream */
362         samr_io_r_enum_dom_groups("", &r_e, rdata, 0);
363
364         DEBUG(5,("samr_enum_dom_groups: %d\n", __LINE__));
365
366 }
367
368 /*******************************************************************
369  api_samr_enum_dom_groups
370  ********************************************************************/
371 static void api_samr_enum_dom_groups( int uid, prs_struct *data, prs_struct *rdata)
372 {
373         SAMR_Q_ENUM_DOM_GROUPS q_e;
374
375         /* grab the samr open */
376         samr_io_q_enum_dom_groups("", &q_e, data, 0);
377
378         /* construct reply. */
379         samr_reply_enum_dom_groups(&q_e, rdata);
380 }
381
382
383 /*******************************************************************
384  samr_reply_enum_dom_aliases
385  ********************************************************************/
386 static void samr_reply_enum_dom_aliases(SAMR_Q_ENUM_DOM_ALIASES *q_u,
387                                 prs_struct *rdata)
388 {
389         SAMR_R_ENUM_DOM_ALIASES r_e;
390         SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES];
391         int num_entries;
392         int pol_idx;
393         BOOL got_aliases;
394         char *dummy_alias = "admins";
395
396         r_e.status = 0x0;
397         r_e.num_entries = 0;
398
399         /* find the policy handle.  open a policy on it. */
400         if (r_e.status == 0x0 && ((pol_idx = find_lsa_policy_by_hnd(&(q_u->pol))) == -1))
401         {
402                 r_e.status = 0xC0000000 | NT_STATUS_INVALID_HANDLE;
403         }
404
405         DEBUG(5,("samr_reply_enum_dom_aliases: %d\n", __LINE__));
406
407         got_aliases = True;
408         num_entries = 1;
409         make_unistr2(&(pass[0].uni_user_name), dummy_alias, strlen(dummy_alias));
410         pass[0].user_rid = DOMAIN_ALIAS_RID_ADMINS;
411
412         if (r_e.status == 0 && got_aliases)
413         {
414                 make_samr_r_enum_dom_aliases(&r_e, num_entries, pass, r_e.status);
415         }
416
417         /* store the response in the SMB stream */
418         samr_io_r_enum_dom_aliases("", &r_e, rdata, 0);
419
420         DEBUG(5,("samr_enum_dom_aliases: %d\n", __LINE__));
421
422 }
423
424 /*******************************************************************
425  api_samr_enum_dom_aliases
426  ********************************************************************/
427 static void api_samr_enum_dom_aliases( int uid, prs_struct *data, prs_struct *rdata)
428 {
429         SAMR_Q_ENUM_DOM_ALIASES q_e;
430
431         /* grab the samr open */
432         samr_io_q_enum_dom_aliases("", &q_e, data, 0);
433
434         /* construct reply. */
435         samr_reply_enum_dom_aliases(&q_e, rdata);
436 }
437
438
439 /*******************************************************************
440  samr_reply_query_dispinfo
441  ********************************************************************/
442 static void samr_reply_query_dispinfo(SAMR_Q_QUERY_DISPINFO *q_u,
443                                 prs_struct *rdata)
444 {
445         SAMR_R_QUERY_DISPINFO r_e;
446         SAM_INFO_CTR ctr;
447         SAM_INFO_1 info1;
448         SAM_INFO_2 info2;
449         SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES];
450         int num_entries;
451         int total_entries;
452         int pol_idx;
453         BOOL got_pwds;
454         uint16 switch_level = 0x0;
455
456         r_e.status = 0x0;
457
458         /* find the policy handle.  open a policy on it. */
459         if (r_e.status == 0x0 && ((pol_idx = find_lsa_policy_by_hnd(&(q_u->pol))) == -1))
460         {
461                 r_e.status = 0xC0000000 | NT_STATUS_INVALID_HANDLE;
462         }
463
464         DEBUG(5,("samr_reply_query_dispinfo: %d\n", __LINE__));
465
466         become_root(True);
467
468         got_pwds = get_smbpwd_entries(pass, &total_entries, &num_entries, MAX_SAM_ENTRIES, 0);
469
470         unbecome_root(True);
471
472         switch (q_u->switch_level)
473         {
474                 case 0x1:
475                 {
476                         /* query disp info is for users */
477                         make_sam_info_1(&info1, ACB_NORMAL,
478                                 q_u->start_idx, num_entries, pass);
479
480                         ctr.sam.info1 = &info1;
481                         switch_level = 0x1;
482
483                         break;
484                 }
485                 case 0x2:
486                 {
487                         /* query disp info is for servers */
488                         make_sam_info_2(&info2, ACB_WSTRUST,
489                                 q_u->start_idx, num_entries, pass);
490
491                         ctr.sam.info2 = &info2;
492                         switch_level = 0x2;
493
494                         break;
495                 }
496         }
497
498         if (r_e.status == 0 && got_pwds)
499         {
500                 make_samr_r_query_dispinfo(&r_e, switch_level, &ctr, r_e.status);
501         }
502
503         /* store the response in the SMB stream */
504         samr_io_r_query_dispinfo("", &r_e, rdata, 0);
505
506         DEBUG(5,("samr_query_dispinfo: %d\n", __LINE__));
507
508 }
509
510 /*******************************************************************
511  api_samr_query_dispinfo
512  ********************************************************************/
513 static void api_samr_query_dispinfo( int uid, prs_struct *data, prs_struct *rdata)
514 {
515         SAMR_Q_QUERY_DISPINFO q_e;
516
517         /* grab the samr open */
518         samr_io_q_query_dispinfo("", &q_e, data, 0);
519
520         /* construct reply. */
521         samr_reply_query_dispinfo(&q_e, rdata);
522 }
523
524
525 /*******************************************************************
526  samr_reply_query_aliasinfo
527  ********************************************************************/
528 static void samr_reply_query_aliasinfo(SAMR_Q_QUERY_ALIASINFO *q_u,
529                                 prs_struct *rdata)
530 {
531         SAMR_R_QUERY_ALIASINFO r_e;
532         int pol_idx;
533         BOOL got_alias;
534
535         r_e.status = 0x0;
536         r_e.ptr = 0;
537
538         /* find the policy handle.  open a policy on it. */
539         if (r_e.status == 0x0 && ((pol_idx = find_lsa_policy_by_hnd(&(q_u->pol))) == -1))
540         {
541                 r_e.status = 0xC0000000 | NT_STATUS_INVALID_HANDLE;
542         }
543
544         DEBUG(5,("samr_reply_query_aliasinfo: %d\n", __LINE__));
545
546         if (r_e.status == 0x0)
547         {
548                 if (q_u->switch_level != 3)
549                 {
550                         r_e.status = NT_STATUS_INVALID_INFO_CLASS;
551                 }
552         }
553
554         if (r_e.status == 0x0)
555         {
556                 got_alias = True;
557         }
558
559         make_samr_r_query_aliasinfo(&r_e, q_u->switch_level,
560                             "<account description>",
561                                 r_e.status);
562
563         /* store the response in the SMB stream */
564         samr_io_r_query_aliasinfo("", &r_e, rdata, 0);
565
566         DEBUG(5,("samr_query_aliasinfo: %d\n", __LINE__));
567
568 }
569
570 /*******************************************************************
571  api_samr_query_aliasinfo
572  ********************************************************************/
573 static void api_samr_query_aliasinfo( int uid, prs_struct *data, prs_struct *rdata)
574 {
575         SAMR_Q_QUERY_ALIASINFO q_e;
576
577         /* grab the samr open */
578         samr_io_q_query_aliasinfo("", &q_e, data, 0);
579
580         /* construct reply. */
581         samr_reply_query_aliasinfo(&q_e, rdata);
582 }
583
584
585 /*******************************************************************
586  samr_reply_lookup_ids
587  ********************************************************************/
588 static void samr_reply_lookup_ids(SAMR_Q_LOOKUP_IDS *q_u,
589                                 prs_struct *rdata)
590 {
591         uint32 rid[MAX_SAM_ENTRIES];
592         uint32 status     = 0;
593         int num_rids = q_u->num_sids1;
594
595         SAMR_R_LOOKUP_IDS r_u;
596
597         DEBUG(5,("samr_lookup_ids: %d\n", __LINE__));
598
599         if (num_rids > MAX_SAM_ENTRIES)
600         {
601                 num_rids = MAX_SAM_ENTRIES;
602                 DEBUG(5,("samr_lookup_ids: truncating entries to %d\n", num_rids));
603         }
604
605 #if 0
606         int i;
607         for (i = 0; i < num_rids && status == 0; i++)
608         {
609                 struct smb_passwd *smb_pass;
610                 fstring user_name;
611
612                 fstrcpy(user_name, unistrn2(q_u->uni_user_name[i].buffer,
613                                                                         q_u->uni_user_name[i].uni_str_len));
614
615                 /* find the user account */
616                 become_root(True);
617                 smb_pass = get_smbpwd_entry(user_name, 0);
618                 unbecome_root(True);
619
620                 if (smb_pass == NULL)
621                 {
622                         status = 0xC0000000 | NT_STATUS_NO_SUCH_USER;
623                         rid[i] = 0;
624                 }
625                 else
626                 {
627                         /* lkclXXXX SHOULD use name_to_rid() here! */
628                         rid[i] = smb_pass->smb_userid;
629                 }
630         }
631 #endif
632
633         num_rids = 1;
634         rid[0] = DOMAIN_ALIAS_RID_USERS;
635
636         make_samr_r_lookup_ids(&r_u, num_rids, rid, status);
637
638         /* store the response in the SMB stream */
639         samr_io_r_lookup_ids("", &r_u, rdata, 0);
640
641         DEBUG(5,("samr_lookup_ids: %d\n", __LINE__));
642
643 }
644
645 /*******************************************************************
646  api_samr_lookup_ids
647  ********************************************************************/
648 static void api_samr_lookup_ids( int uid, prs_struct *data, prs_struct *rdata)
649 {
650         SAMR_Q_LOOKUP_IDS q_u;
651
652         /* grab the samr 0x10 */
653         samr_io_q_lookup_ids("", &q_u, data, 0);
654
655         /* construct reply.  always indicate success */
656         samr_reply_lookup_ids(&q_u, rdata);
657 }
658
659 /*******************************************************************
660  samr_reply_lookup_names
661  ********************************************************************/
662 static void samr_reply_lookup_names(SAMR_Q_LOOKUP_NAMES *q_u,
663                                 prs_struct *rdata)
664 {
665         uint32 rid[MAX_SAM_ENTRIES];
666         uint32 status     = 0;
667         int i;
668         int num_rids = q_u->num_rids1;
669
670         SAMR_R_LOOKUP_NAMES r_u;
671
672         DEBUG(5,("samr_lookup_names: %d\n", __LINE__));
673
674         if (num_rids > MAX_SAM_ENTRIES)
675         {
676                 num_rids = MAX_SAM_ENTRIES;
677                 DEBUG(5,("samr_lookup_names: truncating entries to %d\n", num_rids));
678         }
679
680         for (i = 0; i < num_rids && status == 0; i++)
681         {
682                 fstring name;
683
684                 status = 0xC0000000 | NT_STATUS_NONE_MAPPED;
685
686                 fstrcpy(name, unistrn2(q_u->uni_user_name[i].buffer, q_u->uni_user_name[i].uni_str_len));
687
688                 status = (status != 0x0) ? lookup_user_rid (name, &(rid[i])) : status;
689                 status = (status != 0x0) ? lookup_group_rid(name, &(rid[i])) : status;
690                 status = (status != 0x0) ? lookup_alias_rid(name, &(rid[i])) : status;
691         }
692
693         make_samr_r_lookup_names(&r_u, num_rids, rid, status);
694
695         /* store the response in the SMB stream */
696         samr_io_r_lookup_names("", &r_u, rdata, 0);
697
698         DEBUG(5,("samr_lookup_names: %d\n", __LINE__));
699
700 }
701
702 /*******************************************************************
703  api_samr_lookup_names
704  ********************************************************************/
705 static void api_samr_lookup_names( int uid, prs_struct *data, prs_struct *rdata)
706 {
707         SAMR_Q_LOOKUP_NAMES q_u;
708
709         /* grab the samr lookup names */
710         samr_io_q_lookup_names("", &q_u, data, 0);
711
712         /* construct reply.  always indicate success */
713         samr_reply_lookup_names(&q_u, rdata);
714 }
715
716
717 /*******************************************************************
718  samr_reply_unknown_12
719  ********************************************************************/
720 static void samr_reply_unknown_12(SAMR_Q_UNKNOWN_12 *q_u,
721                                 prs_struct *rdata)
722 {
723         fstring group_names[MAX_SAM_ENTRIES];
724         uint32  group_attrs[MAX_SAM_ENTRIES];
725         uint32 status     = 0;
726         int num_gids = q_u->num_gids1;
727         uint32 pol_idx;
728
729         SAMR_R_UNKNOWN_12 r_u;
730
731         DEBUG(5,("samr_unknown_12: %d\n", __LINE__));
732
733         /* find the policy handle.  open a policy on it. */
734         if (status == 0x0 && ((pol_idx = find_lsa_policy_by_hnd(&(q_u->pol))) == -1))
735         {
736                 status = 0xC0000000 | NT_STATUS_INVALID_HANDLE;
737         }
738
739         if (status == 0x0)
740         {
741                 int i;
742                 if (num_gids > MAX_SAM_ENTRIES)
743                 {
744                         num_gids = MAX_SAM_ENTRIES;
745                         DEBUG(5,("samr_unknown_12: truncating entries to %d\n", num_gids));
746                 }
747
748                 for (i = 0; i < num_gids && status == 0; i++)
749                 {
750                         fstrcpy(group_names[i], "dummy group");
751                         group_attrs[i] = 0x2;
752                 }
753         }
754
755         make_samr_r_unknown_12(&r_u, num_gids, group_names, group_attrs, status);
756
757         /* store the response in the SMB stream */
758         samr_io_r_unknown_12("", &r_u, rdata, 0);
759
760         DEBUG(5,("samr_unknown_12: %d\n", __LINE__));
761
762 }
763
764 /*******************************************************************
765  api_samr_unknown_12
766  ********************************************************************/
767 static void api_samr_unknown_12( int uid, prs_struct *data, prs_struct *rdata)
768 {
769         SAMR_Q_UNKNOWN_12 q_u;
770
771         /* grab the samr lookup names */
772         samr_io_q_unknown_12("", &q_u, data, 0);
773
774         /* construct reply.  always indicate success */
775         samr_reply_unknown_12(&q_u, rdata);
776 }
777
778
779 /*******************************************************************
780  samr_reply_open_user
781  ********************************************************************/
782 static void samr_reply_open_user(SAMR_Q_OPEN_USER *q_u,
783                                 prs_struct *rdata,
784                                 int status)
785 {
786         SAMR_R_OPEN_USER r_u;
787         struct smb_passwd *smb_pass;
788         int pol_idx;
789         BOOL pol_open = False;
790
791         /* set up the SAMR open_user response */
792         bzero(&(r_u.user_pol.data), POL_HND_SIZE);
793
794         r_u.status = 0x0;
795
796         /* find the policy handle.  open a policy on it. */
797         if (r_u.status == 0x0 && ((pol_idx = find_lsa_policy_by_hnd(&(q_u->domain_pol))) == -1))
798         {
799                 r_u.status = 0xC0000000 | NT_STATUS_INVALID_HANDLE;
800         }
801
802         /* get a (unique) handle.  open a policy on it. */
803         if (r_u.status == 0x0 && !(pol_open = open_lsa_policy_hnd(&(r_u.user_pol))))
804         {
805                 r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND;
806         }
807
808         become_root(True);
809         smb_pass = getsmbpwuid(q_u->user_rid);
810         unbecome_root(True);
811
812         /* check that the RID exists in our domain. */
813         if (r_u.status == 0x0 && smb_pass == NULL)
814         {
815                 r_u.status = 0xC0000000 | NT_STATUS_NO_SUCH_USER;
816         }
817
818         /* associate the RID with the (unique) handle. */
819         if (r_u.status == 0x0 && !set_lsa_policy_samr_rid(&(r_u.user_pol), q_u->user_rid))
820         {
821                 /* oh, whoops.  don't know what error message to return, here */
822                 r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND;
823         }
824
825         if (r_u.status != 0 && pol_open)
826         {
827                 close_lsa_policy_hnd(&(r_u.user_pol));
828         }
829
830         DEBUG(5,("samr_open_user: %d\n", __LINE__));
831
832         /* store the response in the SMB stream */
833         samr_io_r_open_user("", &r_u, rdata, 0);
834
835         DEBUG(5,("samr_open_user: %d\n", __LINE__));
836
837 }
838
839 /*******************************************************************
840  api_samr_open_user
841  ********************************************************************/
842 static void api_samr_open_user( int uid, prs_struct *data, prs_struct *rdata)
843 {
844         SAMR_Q_OPEN_USER q_u;
845
846         /* grab the samr unknown 22 */
847         samr_io_q_open_user("", &q_u, data, 0);
848
849         /* construct reply.  always indicate success */
850         samr_reply_open_user(&q_u, rdata, 0x0);
851 }
852
853
854 /*************************************************************************
855  get_user_info_21
856  *************************************************************************/
857 static BOOL get_user_info_21(SAM_USER_INFO_21 *id21, uint32 rid)
858 {
859         NTTIME dummy_time;
860
861         pstring logon_script;
862         pstring profile_path;
863         pstring home_drive;
864         pstring home_dir;
865         pstring description;
866         pstring workstations;
867         pstring full_name;
868         pstring munged_dialin;
869         pstring unknown_str;
870
871         uint32 r_uid;
872         uint32 r_gid;
873
874         LOGON_HRS hrs;
875         int i;
876
877         struct smb_passwd *smb_pass;
878
879         become_root(True);
880         smb_pass = getsmbpwuid(rid);
881         unbecome_root(True);
882
883         if (smb_pass == NULL)
884         {
885                 return False;
886         }
887
888         DEBUG(3,("User:[%s]\n", smb_pass->smb_name));
889
890         dummy_time.low  = 0xffffffff;
891         dummy_time.high = 0x7fffffff;
892
893         pstrcpy(samlogon_user, smb_pass->smb_name);
894
895         if (samlogon_user[strlen(samlogon_user)-1] != '$')
896         {
897                 if (!name_to_rid(samlogon_user, &r_uid, &r_gid))
898                 {
899                         return False;
900                 }
901
902                 /* XXXX hack to get standard_sub_basic() to use sam logon username */
903                 /* possibly a better way would be to do a become_user() call */
904                 sam_logon_in_ssb = True;
905
906                 pstrcpy(full_name    , "<Full Name>");
907                 pstrcpy(logon_script , lp_logon_script     ());
908                 pstrcpy(profile_path , lp_logon_path       ());
909                 pstrcpy(home_drive   , lp_logon_drive      ());
910                 pstrcpy(home_dir     , lp_logon_home       ());
911                 pstrcpy(description  , "<Description>");
912                 pstrcpy(workstations , "");
913                 pstrcpy(unknown_str  , "");
914                 pstrcpy(munged_dialin, "");
915
916                 sam_logon_in_ssb = False;
917         }
918         else
919         {
920                 r_uid = smb_pass->smb_userid;
921                 r_gid = DOMAIN_GROUP_RID_USERS;
922
923                 pstrcpy(samlogon_user, smb_pass->smb_name);
924
925                 pstrcpy(full_name    , "");
926                 pstrcpy(logon_script , "");
927                 pstrcpy(profile_path , "");
928                 pstrcpy(home_drive   , "");
929                 pstrcpy(home_dir     , "");
930                 pstrcpy(description  , "");
931                 pstrcpy(workstations , "");
932                 pstrcpy(unknown_str  , "");
933                 pstrcpy(munged_dialin, "");
934         }
935
936         hrs.len = 21;
937         for (i = 0; i < hrs.len; i++)
938         {
939                 hrs.hours[i] = 0xff;
940         }
941         make_sam_user_info21(id21,
942
943                            &dummy_time, /* logon_time */
944                            &dummy_time, /* logoff_time */
945                            &dummy_time, /* kickoff_time */
946                            &dummy_time, /* pass_last_set_time */
947                            &dummy_time, /* pass_can_change_time */
948                            &dummy_time, /* pass_must_change_time */
949
950                            samlogon_user, /* user_name */
951                            full_name, /* full_name */
952                            home_dir, /* home_dir */
953                            home_drive, /* dir_drive */
954                            logon_script, /* logon_script */
955                            profile_path, /* profile_path */
956                            description, /* description */
957                            workstations, /* workstations user can log in from */
958                            unknown_str, /* don't know, yet */
959                            munged_dialin, /* dialin info.  contains dialin path and tel no */
960
961                            r_uid, /* RID user_id */
962                            r_gid, /* RID group_id */
963                        smb_pass->acct_ctrl,
964
965                    0x00ffffff, /* unknown_3 */
966                        168, /* divisions per week */
967                            &hrs, /* logon hours */
968                        0x00020000,
969                        0x000004ec);
970
971         return True;
972 }
973
974 /*******************************************************************
975  samr_reply_query_userinfo
976  ********************************************************************/
977 static void samr_reply_query_userinfo(SAMR_Q_QUERY_USERINFO *q_u,
978                                 prs_struct *rdata)
979 {
980         SAMR_R_QUERY_USERINFO r_u;
981 #if 0
982         SAM_USER_INFO_11 id11;
983 #endif
984         SAM_USER_INFO_21 id21;
985         void *info = NULL;
986
987         uint32 status = 0x0;
988         uint32 rid;
989         int obj_idx;
990
991         DEBUG(5,("samr_reply_query_userinfo: %d\n", __LINE__));
992
993         /* search for the handle */
994         if (status == 0x0 && (obj_idx = find_lsa_policy_by_hnd(&(q_u->pol))) == -1)
995         {
996                 status = NT_STATUS_INVALID_HANDLE;
997         }
998
999         /* find the user's rid */
1000         if (status == 0x0 && (rid = get_lsa_policy_samr_rid(&(q_u->pol))) == 0xffffffff)
1001         {
1002                 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
1003         }
1004
1005         /* ok!  user info levels (there are lots: see MSDEV help), off we go... */
1006         if (status == 0x0)
1007         {
1008                 switch (q_u->switch_value)
1009                 {
1010 #if 0
1011 /* whoops - got this wrong.  i think.  or don't understand what's happening. */
1012                         case 0x11:
1013                         {
1014                                 NTTIME expire;
1015                                 info = (void*)&id11;
1016                                 
1017                                 expire.low  = 0xffffffff;
1018                                 expire.high = 0x7fffffff;
1019
1020                                 make_sam_user_info11(&id11, &expire, "BROOKFIELDS$", 0x03ef, 0x201, 0x0080);
1021
1022                                 break;
1023                         }
1024 #endif
1025                         case 21:
1026                         {
1027                                 info = (void*)&id21;
1028                                 status = get_user_info_21(&id21, rid) ? 0 : NT_STATUS_NO_SUCH_USER;
1029
1030                                 break;
1031                         }
1032
1033                         default:
1034                         {
1035                                 status = NT_STATUS_INVALID_INFO_CLASS;
1036
1037                                 break;
1038                         }
1039                 }
1040         }
1041
1042         make_samr_r_query_userinfo(&r_u, q_u->switch_value, info, status);
1043
1044         /* store the response in the SMB stream */
1045         samr_io_r_query_userinfo("", &r_u, rdata, 0);
1046
1047         DEBUG(5,("samr_reply_query_userinfo: %d\n", __LINE__));
1048
1049 }
1050
1051 /*******************************************************************
1052  api_samr_query_userinfo
1053  ********************************************************************/
1054 static void api_samr_query_userinfo( int uid, prs_struct *data, prs_struct *rdata)
1055 {
1056         SAMR_Q_QUERY_USERINFO q_u;
1057
1058         /* grab the samr unknown 24 */
1059         samr_io_q_query_userinfo("", &q_u, data, 0);
1060
1061         /* construct reply.  always indicate success */
1062         samr_reply_query_userinfo(&q_u, rdata);
1063 }
1064
1065
1066 /*******************************************************************
1067  samr_reply_query_usergroups
1068  ********************************************************************/
1069 static void samr_reply_query_usergroups(SAMR_Q_QUERY_USERGROUPS *q_u,
1070                                 prs_struct *rdata)
1071 {
1072         SAMR_R_QUERY_USERGROUPS r_u;
1073         uint32 status = 0x0;
1074
1075         struct smb_passwd *smb_pass;
1076         DOM_GID gids[LSA_MAX_GROUPS];
1077         int num_groups = 0;
1078         int pol_idx;
1079         uint32 rid;
1080
1081         DEBUG(5,("samr_query_usergroups: %d\n", __LINE__));
1082
1083         /* find the policy handle.  open a policy on it. */
1084         if (status == 0x0 && ((pol_idx = find_lsa_policy_by_hnd(&(q_u->pol))) == -1))
1085         {
1086                 status = 0xC0000000 | NT_STATUS_INVALID_HANDLE;
1087         }
1088
1089         /* find the user's rid */
1090         if (status == 0x0 && (rid = get_lsa_policy_samr_rid(&(q_u->pol))) == 0xffffffff)
1091         {
1092                 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
1093         }
1094
1095         if (status == 0x0)
1096         {
1097                 become_root(True);
1098                 smb_pass = getsmbpwuid(rid);
1099                 unbecome_root(True);
1100
1101                 if (smb_pass == NULL)
1102                 {
1103                         status = 0xC0000000 | NT_STATUS_NO_SUCH_USER;
1104                 }
1105         }
1106
1107         if (status == 0x0)
1108         {
1109                 pstring groups;
1110                 get_domain_user_groups(groups, smb_pass->smb_name);
1111                 num_groups = make_dom_gids(groups, gids);
1112         }
1113
1114         /* construct the response.  lkclXXXX: gids are not copied! */
1115         make_samr_r_query_usergroups(&r_u, num_groups, gids, status);
1116
1117         /* store the response in the SMB stream */
1118         samr_io_r_query_usergroups("", &r_u, rdata, 0);
1119
1120         DEBUG(5,("samr_query_usergroups: %d\n", __LINE__));
1121
1122 }
1123
1124 /*******************************************************************
1125  api_samr_query_usergroups
1126  ********************************************************************/
1127 static void api_samr_query_usergroups( int uid, prs_struct *data, prs_struct *rdata)
1128 {
1129         SAMR_Q_QUERY_USERGROUPS q_u;
1130         /* grab the samr unknown 32 */
1131         samr_io_q_query_usergroups("", &q_u, data, 0);
1132
1133         /* construct reply. */
1134         samr_reply_query_usergroups(&q_u, rdata);
1135 }
1136
1137
1138 /*******************************************************************
1139  samr_reply_unknown_32
1140  ********************************************************************/
1141 static void samr_reply_unknown_32(SAMR_Q_UNKNOWN_32 *q_u,
1142                                 prs_struct *rdata,
1143                                 int status)
1144 {
1145         int i;
1146         SAMR_R_UNKNOWN_32 r_u;
1147
1148         /* set up the SAMR unknown_32 response */
1149         bzero(&(r_u.pol.data), POL_HND_SIZE);
1150         if (status == 0)
1151         {
1152                 for (i = 4; i < POL_HND_SIZE; i++)
1153                 {
1154                         r_u.pol.data[i] = i+1;
1155                 }
1156         }
1157
1158         make_dom_rid4(&(r_u.rid4), 0x0030, 0, 0);
1159         r_u.status    = status;
1160
1161         DEBUG(5,("samr_unknown_32: %d\n", __LINE__));
1162
1163         /* store the response in the SMB stream */
1164         samr_io_r_unknown_32("", &r_u, rdata, 0);
1165
1166         DEBUG(5,("samr_unknown_32: %d\n", __LINE__));
1167
1168 }
1169
1170 /*******************************************************************
1171  api_samr_unknown_32
1172  ********************************************************************/
1173 static void api_samr_unknown_32( int uid, prs_struct *data, prs_struct *rdata)
1174 {
1175         uint32 status = 0;
1176         struct smb_passwd *smb_pass;
1177         fstring mach_acct;
1178
1179         SAMR_Q_UNKNOWN_32 q_u;
1180
1181         /* grab the samr unknown 32 */
1182         samr_io_q_unknown_32("", &q_u, data, 0);
1183
1184         /* find the machine account: tell the caller if it exists.
1185            lkclXXXX i have *no* idea if this is a problem or not
1186            or even if you are supposed to construct a different
1187            reply if the account already exists...
1188          */
1189
1190         fstrcpy(mach_acct, unistrn2(q_u.uni_mach_acct.buffer,
1191                                     q_u.uni_mach_acct.uni_str_len));
1192
1193         become_root(True);
1194         smb_pass = getsmbpwnam(mach_acct);
1195         unbecome_root(True);
1196
1197         if (smb_pass != NULL)
1198         {
1199                 /* machine account exists: say so */
1200                 status = 0xC0000000 | NT_STATUS_USER_EXISTS;
1201         }
1202         else
1203         {
1204                 /* this could cause trouble... */
1205                 status = 0;
1206         }
1207
1208         /* construct reply. */
1209         samr_reply_unknown_32(&q_u, rdata, status);
1210 }
1211
1212
1213 /*******************************************************************
1214  samr_reply_connect
1215  ********************************************************************/
1216 static void samr_reply_connect(SAMR_Q_CONNECT *q_u,
1217                                 prs_struct *rdata)
1218 {
1219         SAMR_R_CONNECT r_u;
1220         BOOL pol_open = False;
1221
1222         /* set up the SAMR connect response */
1223
1224         r_u.status = 0x0;
1225         /* get a (unique) handle.  open a policy on it. */
1226         if (r_u.status == 0x0 && !(pol_open = open_lsa_policy_hnd(&(r_u.connect_pol))))
1227         {
1228                 r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND;
1229         }
1230
1231         /* associate the domain SID with the (unique) handle. */
1232         if (r_u.status == 0x0 && !set_lsa_policy_samr_pol_status(&(r_u.connect_pol), q_u->unknown_0))
1233         {
1234                 /* oh, whoops.  don't know what error message to return, here */
1235                 r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND;
1236         }
1237
1238         if (r_u.status != 0 && pol_open)
1239         {
1240                 close_lsa_policy_hnd(&(r_u.connect_pol));
1241         }
1242
1243         DEBUG(5,("samr_connect: %d\n", __LINE__));
1244
1245         /* store the response in the SMB stream */
1246         samr_io_r_connect("", &r_u, rdata, 0);
1247
1248         DEBUG(5,("samr_connect: %d\n", __LINE__));
1249
1250 }
1251
1252 /*******************************************************************
1253  api_samr_connect
1254  ********************************************************************/
1255 static void api_samr_connect( int uid, prs_struct *data, prs_struct *rdata)
1256 {
1257         SAMR_Q_CONNECT q_u;
1258
1259         /* grab the samr open policy */
1260         samr_io_q_connect("", &q_u, data, 0);
1261
1262         /* construct reply.  always indicate success */
1263         samr_reply_connect(&q_u, rdata);
1264 }
1265
1266 /*******************************************************************
1267  samr_reply_open_alias
1268  ********************************************************************/
1269 static void samr_reply_open_alias(SAMR_Q_OPEN_ALIAS *q_u,
1270                                 prs_struct *rdata)
1271 {
1272         SAMR_R_OPEN_ALIAS r_u;
1273         BOOL pol_open = False;
1274
1275         /* set up the SAMR open_alias response */
1276
1277         r_u.status = 0x0;
1278         /* get a (unique) handle.  open a policy on it. */
1279         if (r_u.status == 0x0 && !(pol_open = open_lsa_policy_hnd(&(r_u.pol))))
1280         {
1281                 r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND;
1282         }
1283
1284         /* associate a RID with the (unique) handle. */
1285         if (r_u.status == 0x0 && !set_lsa_policy_samr_rid(&(r_u.pol), q_u->rid_alias))
1286         {
1287                 /* oh, whoops.  don't know what error message to return, here */
1288                 r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND;
1289         }
1290
1291         if (r_u.status != 0 && pol_open)
1292         {
1293                 close_lsa_policy_hnd(&(r_u.pol));
1294         }
1295
1296         DEBUG(5,("samr_open_alias: %d\n", __LINE__));
1297
1298         /* store the response in the SMB stream */
1299         samr_io_r_open_alias("", &r_u, rdata, 0);
1300
1301         DEBUG(5,("samr_open_alias: %d\n", __LINE__));
1302
1303 }
1304
1305 /*******************************************************************
1306  api_samr_open_alias
1307  ********************************************************************/
1308 static void api_samr_open_alias( int uid, prs_struct *data, prs_struct *rdata)
1309                                 
1310 {
1311         SAMR_Q_OPEN_ALIAS q_u;
1312
1313         /* grab the samr open policy */
1314         samr_io_q_open_alias("", &q_u, data, 0);
1315
1316         /* construct reply.  always indicate success */
1317         samr_reply_open_alias(&q_u, rdata);
1318 }
1319
1320 /*******************************************************************
1321  array of \PIPE\samr operations
1322  ********************************************************************/
1323 static struct api_struct api_samr_cmds [] =
1324 {
1325         { "SAMR_CLOSE_HND"        , SAMR_CLOSE_HND        , api_samr_close_hnd        },
1326         { "SAMR_CONNECT"          , SAMR_CONNECT          , api_samr_connect          },
1327         { "SAMR_ENUM_DOM_USERS"   , SAMR_ENUM_DOM_USERS   , api_samr_enum_dom_users   },
1328         { "SAMR_ENUM_DOM_GROUPS"  , SAMR_ENUM_DOM_GROUPS  , api_samr_enum_dom_groups  },
1329         { "SAMR_ENUM_DOM_ALIASES" , SAMR_ENUM_DOM_ALIASES , api_samr_enum_dom_aliases },
1330         { "SAMR_LOOKUP_IDS"       , SAMR_LOOKUP_IDS       , api_samr_lookup_ids       },
1331         { "SAMR_LOOKUP_NAMES"     , SAMR_LOOKUP_NAMES     , api_samr_lookup_names     },
1332         { "SAMR_OPEN_USER"        , SAMR_OPEN_USER        , api_samr_open_user        },
1333         { "SAMR_QUERY_USERINFO"   , SAMR_QUERY_USERINFO   , api_samr_query_userinfo   },
1334         { "SAMR_QUERY_USERGROUPS" , SAMR_QUERY_USERGROUPS , api_samr_query_usergroups },
1335         { "SAMR_QUERY_DISPINFO"   , SAMR_QUERY_DISPINFO   , api_samr_query_dispinfo   },
1336         { "SAMR_QUERY_ALIASINFO"  , SAMR_QUERY_ALIASINFO  , api_samr_query_aliasinfo  },
1337         { "SAMR_0x32"             , 0x32                  , api_samr_unknown_32       },
1338         { "SAMR_UNKNOWN_12"       , SAMR_UNKNOWN_12       , api_samr_unknown_12       },
1339         { "SAMR_OPEN_ALIAS"       , SAMR_OPEN_ALIAS       , api_samr_open_alias       },
1340         { "SAMR_OPEN_DOMAIN"      , SAMR_OPEN_DOMAIN      , api_samr_open_domain      },
1341         { "SAMR_UNKNOWN_3"        , SAMR_UNKNOWN_3        , api_samr_unknown_3        },
1342     { NULL                    , 0                     , NULL                      }
1343 };
1344
1345 /*******************************************************************
1346  receives a samr pipe and responds.
1347  ********************************************************************/
1348 BOOL api_samr_rpc(pipes_struct *p, prs_struct *data)
1349 {
1350     return api_rpcTNP(p, "api_samr_rpc", api_samr_cmds, data);
1351 }
1352