3 * Unix SMB/Netbios implementation.
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.
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.
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.
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.
29 extern int DEBUGLEVEL;
31 extern BOOL sam_logon_in_ssb;
32 extern pstring samlogon_user;
36 /*************************************************************************
38 *************************************************************************/
39 static void make_net_r_req_chal(NET_R_REQ_CHAL *r_c,
40 DOM_CHAL *srv_chal, int status)
42 DEBUG(6,("make_net_r_req_chal: %d\n", __LINE__));
43 memcpy(r_c->srv_chal.data, srv_chal->data, sizeof(srv_chal->data));
47 /*************************************************************************
49 *************************************************************************/
50 static void net_reply_req_chal(NET_Q_REQ_CHAL *q_c, prs_struct *rdata,
51 DOM_CHAL *srv_chal, uint32 srv_time)
55 DEBUG(6,("net_reply_req_chal: %d\n", __LINE__));
57 /* set up the LSA REQUEST CHALLENGE response */
58 make_net_r_req_chal(&r_c, srv_chal, srv_time);
60 /* store the response in the SMB stream */
61 net_io_r_req_chal("", &r_c, rdata, 0);
63 DEBUG(6,("net_reply_req_chal: %d\n", __LINE__));
67 /*************************************************************************
68 net_reply_logon_ctrl2:
69 *************************************************************************/
70 static void net_reply_logon_ctrl2(NET_Q_LOGON_CTRL2 *q_l, prs_struct *rdata,
71 uint32 flags, uint32 pdc_status, uint32 logon_attempts,
72 uint32 tc_status, char *trust_domain_name)
74 NET_R_LOGON_CTRL2 r_l;
76 DEBUG(6,("net_reply_logon_ctrl2: %d\n", __LINE__));
78 /* set up the Logon Control2 response */
79 make_r_logon_ctrl2(&r_l, q_l->query_level,
80 flags, pdc_status, logon_attempts,
81 tc_status, trust_domain_name);
83 /* store the response in the SMB stream */
84 net_io_r_logon_ctrl2("", &r_l, rdata, 0);
86 DEBUG(6,("net_reply_logon_ctrl2: %d\n", __LINE__));
90 /*************************************************************************
91 net_reply_trust_dom_list:
92 *************************************************************************/
93 static void net_reply_trust_dom_list(NET_Q_TRUST_DOM_LIST *q_t, prs_struct *rdata,
94 uint32 num_trust_domains, char *trust_domain_name)
96 NET_R_TRUST_DOM_LIST r_t;
98 DEBUG(6,("net_reply_trust_dom_list: %d\n", __LINE__));
100 /* set up the Trusted Domain List response */
101 make_r_trust_dom(&r_t, num_trust_domains, trust_domain_name);
103 /* store the response in the SMB stream */
104 net_io_r_trust_dom("", &r_t, rdata, 0);
106 DEBUG(6,("net_reply_trust_dom_listlogon_ctrl2: %d\n", __LINE__));
110 /*************************************************************************
112 *************************************************************************/
113 static void make_net_r_auth_2(NET_R_AUTH_2 *r_a,
114 DOM_CHAL *resp_cred, NEG_FLAGS *flgs, int status)
116 memcpy( r_a->srv_chal.data, resp_cred->data, sizeof(resp_cred->data));
117 memcpy(&(r_a->srv_flgs) , flgs , sizeof(r_a->srv_flgs));
118 r_a->status = status;
121 /*************************************************************************
123 *************************************************************************/
124 static void net_reply_auth_2(NET_Q_AUTH_2 *q_a, prs_struct *rdata,
125 DOM_CHAL *resp_cred, int status)
129 /* set up the LSA AUTH 2 response */
131 make_net_r_auth_2(&r_a, resp_cred, &(q_a->clnt_flgs), status);
133 /* store the response in the SMB stream */
134 net_io_r_auth_2("", &r_a, rdata, 0);
138 /***********************************************************************************
139 make_net_r_srv_pwset:
140 ***********************************************************************************/
141 static void make_net_r_srv_pwset(NET_R_SRV_PWSET *r_s,
142 DOM_CRED *srv_cred, int status)
144 DEBUG(5,("make_net_r_srv_pwset: %d\n", __LINE__));
146 memcpy(&(r_s->srv_cred), srv_cred, sizeof(r_s->srv_cred));
147 r_s->status = status;
149 DEBUG(5,("make_net_r_srv_pwset: %d\n", __LINE__));
152 /*************************************************************************
154 *************************************************************************/
155 static void net_reply_srv_pwset(NET_Q_SRV_PWSET *q_s, prs_struct *rdata,
156 DOM_CRED *srv_cred, int status)
160 DEBUG(5,("net_srv_pwset: %d\n", __LINE__));
162 /* set up the LSA Server Password Set response */
163 make_net_r_srv_pwset(&r_s, srv_cred, status);
165 /* store the response in the SMB stream */
166 net_io_r_srv_pwset("", &r_s, rdata, 0);
168 DEBUG(5,("net_srv_pwset: %d\n", __LINE__));
172 /*************************************************************************
174 *************************************************************************/
175 static void net_reply_sam_logon(NET_Q_SAM_LOGON *q_s, prs_struct *rdata,
176 DOM_CRED *srv_cred, NET_USER_INFO_3 *user_info,
181 /* XXXX maybe we want to say 'no', reject the client's credentials */
182 r_s.buffer_creds = 1; /* yes, we have valid server credentials */
183 memcpy(&(r_s.srv_creds), srv_cred, sizeof(r_s.srv_creds));
185 /* store the user information, if there is any. */
186 r_s.user = user_info;
187 if (status == 0x0 && user_info != NULL && user_info->ptr_user_info != 0)
189 r_s.switch_value = 3; /* indicates type of validation user info */
193 r_s.switch_value = 0; /* indicates no info */
197 r_s.auth_resp = 1; /* authoritative response */
199 /* store the response in the SMB stream */
200 net_io_r_sam_logon("", &r_s, rdata, 0);
205 /*************************************************************************
206 net_reply_sam_logoff:
207 *************************************************************************/
208 static void net_reply_sam_logoff(NET_Q_SAM_LOGOFF *q_s, prs_struct *rdata,
212 NET_R_SAM_LOGOFF r_s;
214 /* XXXX maybe we want to say 'no', reject the client's credentials */
215 r_s.buffer_creds = 1; /* yes, we have valid server credentials */
216 memcpy(&(r_s.srv_creds), srv_cred, sizeof(r_s.srv_creds));
220 /* store the response in the SMB stream */
221 net_io_r_sam_logoff("", &r_s, rdata, 0);
225 /******************************************************************
226 gets a machine password entry. checks access rights of the host.
227 ******************************************************************/
228 static BOOL get_md4pw(char *md4pw, char *mach_name, char *mach_acct)
230 struct smb_passwd *smb_pass;
233 if (!allow_access(lp_domain_hostsdeny(), lp_domain_hostsallow(),
234 client_name(Client), client_addr(Client)))
236 DEBUG(0,("get_md4pw: Workstation %s denied access to domain\n", mach_acct));
241 smb_pass = get_smbpwd_entry(mach_acct, 0);
244 if (smb_pass != NULL)
246 memcpy(md4pw, smb_pass->smb_nt_passwd, 16);
247 dump_data(5, md4pw, 16);
251 DEBUG(0,("get_md4pw: Workstation %s: no account in domain\n", mach_acct));
255 /*************************************************************************
257 *************************************************************************/
258 static void api_net_req_chal( int uid,
270 DEBUG(5,("api_net_req_chal(%d): vuid %d\n", __LINE__, uid));
272 if ((vuser = get_valid_user_struct(uid)) == NULL) return;
274 /* grab the challenge... */
275 net_io_q_req_chal("", &q_r, data, 0);
277 fstrcpy(mach_acct, unistrn2(q_r.uni_logon_clnt.buffer,
278 q_r.uni_logon_clnt.uni_str_len));
280 fstrcpy(mach_name, mach_acct);
283 strcat(mach_acct, "$");
285 if (get_md4pw(vuser->dc.md4pw, mach_name, mach_acct))
287 /* copy the client credentials */
288 memcpy(vuser->dc.clnt_chal.data , q_r.clnt_chal.data, sizeof(q_r.clnt_chal.data));
289 memcpy(vuser->dc.clnt_cred.challenge.data, q_r.clnt_chal.data, sizeof(q_r.clnt_chal.data));
291 /* create a server challenge for the client */
292 /* PAXX: set these to random values. */
293 /* lkcl: paul, you mentioned that it doesn't really matter much */
294 SIVAL(vuser->dc.srv_chal.data, 0, 0x11111111);
295 SIVAL(vuser->dc.srv_chal.data, 4, 0x11111111);
296 memcpy(vuser->dc.srv_cred.challenge.data, vuser->dc.srv_chal.data, 8);
298 bzero(vuser->dc.sess_key, sizeof(vuser->dc.sess_key));
300 /* from client / server challenges and md4 password, generate sess key */
301 cred_session_key(&(vuser->dc.clnt_chal), &(vuser->dc.srv_chal),
302 vuser->dc.md4pw, vuser->dc.sess_key);
306 /* lkclXXXX take a guess at a good error message to return :-) */
307 status = 0xC0000000 | NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
310 /* construct reply. */
311 net_reply_req_chal(&q_r, rdata,
312 &(vuser->dc.srv_chal), status);
316 /*************************************************************************
318 *************************************************************************/
319 static void api_net_auth_2( int uid,
331 if ((vuser = get_valid_user_struct(uid)) == NULL) return;
335 /* grab the challenge... */
336 net_io_q_auth_2("", &q_a, data, 0);
338 /* check that the client credentials are valid */
339 if (cred_assert(&(q_a.clnt_chal), vuser->dc.sess_key,
340 &(vuser->dc.clnt_cred.challenge), srv_time))
343 /* create server challenge for inclusion in the reply */
344 cred_create(vuser->dc.sess_key, &(vuser->dc.srv_cred.challenge), srv_time, &srv_cred);
346 /* copy the received client credentials for use next time */
347 memcpy(vuser->dc.clnt_cred.challenge.data, &(q_a.clnt_chal.data), sizeof(q_a.clnt_chal.data));
348 memcpy(vuser->dc.srv_cred.challenge.data, &(q_a.clnt_chal.data), sizeof(q_a.clnt_chal.data));
352 status = NT_STATUS_ACCESS_DENIED | 0xC0000000;
355 /* construct reply. */
356 net_reply_auth_2(&q_a, rdata, &srv_cred, status);
360 /*************************************************************************
362 *************************************************************************/
363 static void api_net_srv_pwset( int uid,
368 uint32 status = NT_STATUS_WRONG_PASSWORD|0xC0000000;
370 #ifdef ALLOW_SRV_PWSET
372 struct smb_passwd *smb_pass;
377 if ((vuser = get_valid_user_struct(uid)) == NULL) return;
379 /* grab the challenge and encrypted password ... */
380 net_io_q_srv_pwset("", &q_a, data, 0);
382 /* checks and updates credentials. creates reply credentials */
383 if (deal_with_creds(vuser->dc.sess_key, &(vuser->dc.clnt_cred),
384 &(q_a.clnt_id.cred), &srv_cred))
386 memcpy(&(vuser->dc.srv_cred), &(vuser->dc.clnt_cred), sizeof(vuser->dc.clnt_cred));
388 DEBUG(5,("api_net_srv_pwset: %d\n", __LINE__));
390 #ifdef ALLOW_SRV_PWSET
392 pstrcpy(mach_acct, unistrn2(q_a.clnt_id.login.uni_acct_name.buffer,
393 q_a.clnt_id.login.uni_acct_name.uni_str_len));
395 DEBUG(3,("Server Password Set Wksta:[%s]\n", mach_acct));
398 smb_pass = get_smbpwd_entry(mach_acct, 0);
401 if (smb_pass != NULL)
403 unsigned char pwd[16];
406 memcpy(pwd, q_a.pwd, 16);
408 if (obfuscate_pwd(pwd, vuser->dc.sess_key, mode))
410 /* lies! nt and lm passwords are _not_ the same: don't care */
411 smb_pass->smb_passwd = pwd;
412 smb_pass->smb_nt_passwd = pwd;
413 smb_pass->acct_ctrl = ACB_WSTRUST;
416 ret = mod_smbpwd_entry(smb_pass);
427 DEBUG(5,("api_net_srv_pwset: %d\n", __LINE__));
429 DEBUG(5,("api_net_srv_pwset: server password set being denied\n"));
435 /* lkclXXXX take a guess at a sensible error code to return... */
436 status = 0xC0000000 | NT_STATUS_NETWORK_CREDENTIAL_CONFLICT;
439 /* construct reply. always indicate failure. nt keeps going... */
440 net_reply_srv_pwset(&q_a, rdata,
445 /*************************************************************************
447 *************************************************************************/
448 static void api_net_sam_logoff( int uid,
452 NET_Q_SAM_LOGOFF q_l;
459 if ((vuser = get_valid_user_struct(uid)) == NULL) return;
461 /* the DOM_ID_INFO_1 structure is a bit big. plus we might want to
462 dynamically allocate it inside net_io_q_sam_logon, at some point */
463 q_l.sam_id.ctr = &ctr;
465 /* grab the challenge... */
466 net_io_q_sam_logoff("", &q_l, data, 0);
468 /* checks and updates credentials. creates reply credentials */
469 deal_with_creds(vuser->dc.sess_key, &(vuser->dc.clnt_cred),
470 &(q_l.sam_id.client.cred), &srv_cred);
471 memcpy(&(vuser->dc.srv_cred), &(vuser->dc.clnt_cred), sizeof(vuser->dc.clnt_cred));
473 /* construct reply. always indicate success */
474 net_reply_sam_logoff(&q_l, rdata,
479 /*************************************************************************
480 net_login_interactive:
481 *************************************************************************/
482 static uint32 net_login_interactive(NET_ID_INFO_1 *id1,
483 struct smb_passwd *smb_pass,
490 unsigned char key[16];
493 memcpy(key, vuser->dc.sess_key, 8);
495 memcpy(lm_pwd, id1->lm_owf.data, 16);
496 memcpy(nt_pwd, id1->nt_owf.data, 16);
498 SamOEMhash(lm_pwd, key, False);
499 SamOEMhash(nt_pwd, key, False);
501 #ifdef DEBUG_PASSWORD
502 DEBUG(100,("decrypt of lm owf password:"));
503 dump_data(100, lm_pwd, 16);
505 DEBUG(100,("decrypt of nt owf password:"));
506 dump_data(100, nt_pwd, 16);
509 if (memcmp(smb_pass->smb_passwd , lm_pwd, 16) != 0 &&
510 memcmp(smb_pass->smb_nt_passwd, nt_pwd, 16) != 0)
512 status = 0xC0000000 | NT_STATUS_WRONG_PASSWORD;
518 /*************************************************************************
520 *************************************************************************/
521 static uint32 net_login_network(NET_ID_INFO_2 *id2,
522 struct smb_passwd *smb_pass,
525 DEBUG(5,("net_login_network: lm_len: %d nt_len: %d\n",
526 id2->lm_chal_resp.str_str_len,
527 id2->nt_chal_resp.str_str_len));
529 /* check the lm password, first. */
530 /* lkclXXXX this is not a good place to put disabling of LM hashes in.
531 if that is to be done, first move this entire function into a
532 library routine that calls the two smb_password_check() functions.
533 if disabling LM hashes (which nt can do for security reasons) then
534 an attempt should be made to disable them everywhere (which nt does
535 not do, for various security-hole reasons).
538 if (id2->lm_chal_resp.str_str_len == 24 &&
539 smb_password_check(id2->lm_chal_resp.buffer,
540 smb_pass->smb_passwd,
546 /* now check the nt password, if it exists */
548 if (id2->nt_chal_resp.str_str_len == 24 &&
549 smb_pass->smb_nt_passwd != NULL &&
550 smb_password_check(id2->nt_chal_resp.buffer,
551 smb_pass->smb_nt_passwd,
557 /* oops! neither password check succeeded */
559 return 0xC0000000 | NT_STATUS_WRONG_PASSWORD;
562 /*************************************************************************
564 *************************************************************************/
565 static void api_net_sam_logon( int uid,
571 NET_USER_INFO_3 usr_info;
574 struct smb_passwd *smb_pass = NULL;
575 UNISTR2 *uni_samlogon_user = NULL;
577 user_struct *vuser = NULL;
579 if ((vuser = get_valid_user_struct(uid)) == NULL) return;
581 q_l.sam_id.ctr = &ctr;
583 net_io_q_sam_logon("", &q_l, data, 0);
585 /* checks and updates credentials. creates reply credentials */
586 if (!deal_with_creds(vuser->dc.sess_key, &(vuser->dc.clnt_cred),
587 &(q_l.sam_id.client.cred), &srv_cred))
589 status = 0xC0000000 | NT_STATUS_INVALID_HANDLE;
593 memcpy(&(vuser->dc.srv_cred), &(vuser->dc.clnt_cred), sizeof(vuser->dc.clnt_cred));
596 /* find the username */
600 switch (q_l.sam_id.logon_level)
604 uni_samlogon_user = &(q_l.sam_id.ctr->auth.id1.uni_user_name);
606 DEBUG(3,("SAM Logon (Interactive). Domain:[%s]. ",
612 uni_samlogon_user = &(q_l.sam_id.ctr->auth.id2.uni_user_name);
614 DEBUG(3,("SAM Logon (Network). Domain:[%s]. ",
620 DEBUG(2,("SAM Logon: unsupported switch value\n"));
621 status = 0xC0000000 | NT_STATUS_INVALID_INFO_CLASS;
627 /* check username exists */
631 pstrcpy(samlogon_user, unistrn2(uni_samlogon_user->buffer,
632 uni_samlogon_user->uni_str_len));
634 DEBUG(3,("User:[%s]\n", samlogon_user));
637 smb_pass = get_smbpwd_entry(samlogon_user, 0);
640 if (smb_pass == NULL)
642 status = 0xC0000000 | NT_STATUS_NO_SUCH_USER;
646 /* validate password. */
650 switch (q_l.sam_id.logon_level)
654 /* interactive login. passwords arcfour'd with session key */
655 status = net_login_interactive(&q_l.sam_id.ctr->auth.id1,
661 /* network login. lm challenge and 24 byte responses */
662 status = net_login_network(&q_l.sam_id.ctr->auth.id2,
669 /* lkclXXXX this is the point at which, if the login was
670 successful, that the SAM Local Security Authority should
671 record that the user is logged in to the domain.
674 /* return the profile plus other bits :-) */
678 DOM_GID gids[LSA_MAX_GROUPS];
681 pstring logon_script;
682 pstring profile_path;
686 pstring my_workgroup;
687 pstring domain_groups;
690 extern pstring myname;
694 /* set up pointer indicating user/password failed to be found */
695 usr_info.ptr_user_info = 0;
697 dummy_time.low = 0xffffffff;
698 dummy_time.high = 0x7fffffff;
700 get_myname(myname, NULL);
702 /* XXXX hack to get standard_sub_basic() to use sam logon username */
703 /* possibly a better way would be to do a become_user() call */
704 sam_logon_in_ssb = True;
706 pstrcpy(logon_script, lp_logon_script ());
707 pstrcpy(profile_path, lp_logon_path ());
708 pstrcpy(dom_sid , lp_domain_sid ());
709 pstrcpy(other_sids , lp_domain_other_sids());
710 pstrcpy(my_workgroup, lp_workgroup ());
712 pstrcpy(home_drive , lp_logon_drive ());
713 pstrcpy(home_dir , lp_logon_home ());
715 pstrcpy(my_name , myname );
718 get_domain_user_groups(domain_groups, samlogon_user);
720 num_gids = make_dom_gids(domain_groups, gids);
722 sam_logon_in_ssb = False;
724 if (name_to_rid(samlogon_user, &r_uid, &r_gid))
726 make_net_user_info3(&usr_info,
728 &dummy_time, /* logon_time */
729 &dummy_time, /* logoff_time */
730 &dummy_time, /* kickoff_time */
731 &dummy_time, /* pass_last_set_time */
732 &dummy_time, /* pass_can_change_time */
733 &dummy_time, /* pass_must_change_time */
735 samlogon_user , /* user_name */
736 vuser->real_name, /* full_name */
737 logon_script , /* logon_script */
738 profile_path , /* profile_path */
739 home_dir , /* home_dir */
740 home_drive , /* dir_drive */
743 0, /* bad_pw_count */
745 r_uid , /* RID user_id */
746 r_gid , /* RID group_id */
747 num_gids, /* uint32 num_groups */
748 gids , /* DOM_GID *gids */
749 0x20 , /* uint32 user_flgs (?) */
751 NULL, /* char sess_key[16] */
753 my_name , /* char *logon_srv */
754 my_workgroup, /* char *logon_dom */
756 dom_sid, /* char *dom_sid */
757 other_sids); /* char *other_sids */
761 status = 0xC0000000 | NT_STATUS_NO_SUCH_USER;
765 net_reply_sam_logon(&q_l, rdata, &srv_cred, &usr_info, status);
769 /*************************************************************************
770 api_net_trust_dom_list:
771 *************************************************************************/
772 static void api_net_trust_dom_list( int uid,
776 NET_Q_TRUST_DOM_LIST q_t;
778 char *trusted_domain = "test_domain";
780 DEBUG(6,("api_net_trust_dom_list: %d\n", __LINE__));
782 /* grab the lsa trusted domain list query... */
783 net_io_q_trust_dom("", &q_t, data, 0);
785 /* construct reply. */
786 net_reply_trust_dom_list(&q_t, rdata,
789 DEBUG(6,("api_net_trust_dom_list: %d\n", __LINE__));
793 /*************************************************************************
794 error messages cropping up when using nltest.exe...
795 *************************************************************************/
796 #define ERROR_NO_SUCH_DOMAIN 0x54b
797 #define ERROR_NO_LOGON_SERVERS 0x51f
799 /*************************************************************************
801 *************************************************************************/
802 static void api_net_logon_ctrl2( int uid,
806 NET_Q_LOGON_CTRL2 q_l;
808 /* lkclXXXX - guess what - absolutely no idea what these are! */
810 uint32 pdc_connection_status = 0x0;
811 uint32 logon_attempts = 0x0;
812 uint32 tc_status = ERROR_NO_LOGON_SERVERS;
813 char *trusted_domain = "test_domain";
815 DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__));
817 /* grab the lsa netlogon ctrl2 query... */
818 net_io_q_logon_ctrl2("", &q_l, data, 0);
820 /* construct reply. */
821 net_reply_logon_ctrl2(&q_l, rdata,
822 flags, pdc_connection_status, logon_attempts,
823 tc_status, trusted_domain);
825 DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__));
828 /*******************************************************************
829 array of \PIPE\NETLOGON operations
830 ********************************************************************/
831 static struct api_struct api_net_cmds [] =
833 { "NET_REQCHAL" , NET_REQCHAL , api_net_req_chal },
834 { "NET_AUTH2" , NET_AUTH2 , api_net_auth_2 },
835 { "NET_SRVPWSET" , NET_SRVPWSET , api_net_srv_pwset },
836 { "NET_SAMLOGON" , NET_SAMLOGON , api_net_sam_logon },
837 { "NET_SAMLOGOFF" , NET_SAMLOGOFF , api_net_sam_logoff },
838 { "NET_LOGON_CTRL2" , NET_LOGON_CTRL2 , api_net_logon_ctrl2 },
839 { "NET_TRUST_DOM_LIST", NET_TRUST_DOM_LIST, api_net_trust_dom_list },
843 /*******************************************************************
844 receives a netlogon pipe and responds.
845 ********************************************************************/
846 BOOL api_netlog_rpc(pipes_struct *p, prs_struct *data)
848 return api_rpcTNP(p, "api_netlog_rpc", api_net_cmds, data);