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;
232 if (!allow_access(lp_domain_hostsdeny(), lp_domain_hostsallow(),
233 client_name(), client_addr()))
235 DEBUG(0,("get_md4pw: Workstation %s denied access to domain\n", mach_acct));
240 smb_pass = get_smbpwd_entry(mach_acct, 0);
243 if (smb_pass != NULL)
245 memcpy(md4pw, smb_pass->smb_nt_passwd, 16);
246 dump_data(5, md4pw, 16);
250 DEBUG(0,("get_md4pw: Workstation %s: no account in domain\n", mach_acct));
254 /*************************************************************************
256 *************************************************************************/
257 static void api_net_req_chal( int uid,
269 DEBUG(5,("api_net_req_chal(%d): vuid %d\n", __LINE__, uid));
271 if ((vuser = get_valid_user_struct(uid)) == NULL) return;
273 /* grab the challenge... */
274 net_io_q_req_chal("", &q_r, data, 0);
276 fstrcpy(mach_acct, unistrn2(q_r.uni_logon_clnt.buffer,
277 q_r.uni_logon_clnt.uni_str_len));
279 fstrcpy(mach_name, mach_acct);
282 strcat(mach_acct, "$");
284 if (get_md4pw(vuser->dc.md4pw, mach_name, mach_acct))
286 /* copy the client credentials */
287 memcpy(vuser->dc.clnt_chal.data , q_r.clnt_chal.data, sizeof(q_r.clnt_chal.data));
288 memcpy(vuser->dc.clnt_cred.challenge.data, q_r.clnt_chal.data, sizeof(q_r.clnt_chal.data));
290 /* create a server challenge for the client */
291 /* PAXX: set these to random values. */
292 /* lkcl: paul, you mentioned that it doesn't really matter much */
293 SIVAL(vuser->dc.srv_chal.data, 0, 0x11111111);
294 SIVAL(vuser->dc.srv_chal.data, 4, 0x11111111);
295 memcpy(vuser->dc.srv_cred.challenge.data, vuser->dc.srv_chal.data, 8);
297 bzero(vuser->dc.sess_key, sizeof(vuser->dc.sess_key));
299 /* from client / server challenges and md4 password, generate sess key */
300 cred_session_key(&(vuser->dc.clnt_chal), &(vuser->dc.srv_chal),
301 vuser->dc.md4pw, vuser->dc.sess_key);
305 /* lkclXXXX take a guess at a good error message to return :-) */
306 status = 0xC0000000 | NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
309 /* construct reply. */
310 net_reply_req_chal(&q_r, rdata,
311 &(vuser->dc.srv_chal), status);
315 /*************************************************************************
317 *************************************************************************/
318 static void api_net_auth_2( int uid,
330 if ((vuser = get_valid_user_struct(uid)) == NULL) return;
334 /* grab the challenge... */
335 net_io_q_auth_2("", &q_a, data, 0);
337 /* check that the client credentials are valid */
338 if (cred_assert(&(q_a.clnt_chal), vuser->dc.sess_key,
339 &(vuser->dc.clnt_cred.challenge), srv_time))
342 /* create server challenge for inclusion in the reply */
343 cred_create(vuser->dc.sess_key, &(vuser->dc.srv_cred.challenge), srv_time, &srv_cred);
345 /* copy the received client credentials for use next time */
346 memcpy(vuser->dc.clnt_cred.challenge.data, &(q_a.clnt_chal.data), sizeof(q_a.clnt_chal.data));
347 memcpy(vuser->dc.srv_cred.challenge.data, &(q_a.clnt_chal.data), sizeof(q_a.clnt_chal.data));
351 status = NT_STATUS_ACCESS_DENIED | 0xC0000000;
354 /* construct reply. */
355 net_reply_auth_2(&q_a, rdata, &srv_cred, status);
359 /*************************************************************************
361 *************************************************************************/
362 static void api_net_srv_pwset( int uid,
367 uint32 status = NT_STATUS_WRONG_PASSWORD|0xC0000000;
369 #ifdef ALLOW_SRV_PWSET
371 struct smb_passwd *smb_pass;
376 if ((vuser = get_valid_user_struct(uid)) == NULL) return;
378 /* grab the challenge and encrypted password ... */
379 net_io_q_srv_pwset("", &q_a, data, 0);
381 /* checks and updates credentials. creates reply credentials */
382 if (deal_with_creds(vuser->dc.sess_key, &(vuser->dc.clnt_cred),
383 &(q_a.clnt_id.cred), &srv_cred))
385 memcpy(&(vuser->dc.srv_cred), &(vuser->dc.clnt_cred), sizeof(vuser->dc.clnt_cred));
387 DEBUG(5,("api_net_srv_pwset: %d\n", __LINE__));
389 #ifdef ALLOW_SRV_PWSET
391 pstrcpy(mach_acct, unistrn2(q_a.clnt_id.login.uni_acct_name.buffer,
392 q_a.clnt_id.login.uni_acct_name.uni_str_len));
394 DEBUG(3,("Server Password Set Wksta:[%s]\n", mach_acct));
397 smb_pass = get_smbpwd_entry(mach_acct, 0);
400 if (smb_pass != NULL)
402 unsigned char pwd[16];
405 memcpy(pwd, q_a.pwd, 16);
407 if (obfuscate_pwd(pwd, vuser->dc.sess_key, mode))
409 /* lies! nt and lm passwords are _not_ the same: don't care */
410 smb_pass->smb_passwd = pwd;
411 smb_pass->smb_nt_passwd = pwd;
412 smb_pass->acct_ctrl = ACB_WSTRUST;
415 ret = mod_smbpwd_entry(smb_pass);
426 DEBUG(5,("api_net_srv_pwset: %d\n", __LINE__));
428 DEBUG(5,("api_net_srv_pwset: server password set being denied\n"));
434 /* lkclXXXX take a guess at a sensible error code to return... */
435 status = 0xC0000000 | NT_STATUS_NETWORK_CREDENTIAL_CONFLICT;
438 /* construct reply. always indicate failure. nt keeps going... */
439 net_reply_srv_pwset(&q_a, rdata,
444 /*************************************************************************
446 *************************************************************************/
447 static void api_net_sam_logoff( int uid,
451 NET_Q_SAM_LOGOFF q_l;
458 if ((vuser = get_valid_user_struct(uid)) == NULL) return;
460 /* the DOM_ID_INFO_1 structure is a bit big. plus we might want to
461 dynamically allocate it inside net_io_q_sam_logon, at some point */
462 q_l.sam_id.ctr = &ctr;
464 /* grab the challenge... */
465 net_io_q_sam_logoff("", &q_l, data, 0);
467 /* checks and updates credentials. creates reply credentials */
468 deal_with_creds(vuser->dc.sess_key, &(vuser->dc.clnt_cred),
469 &(q_l.sam_id.client.cred), &srv_cred);
470 memcpy(&(vuser->dc.srv_cred), &(vuser->dc.clnt_cred), sizeof(vuser->dc.clnt_cred));
472 /* construct reply. always indicate success */
473 net_reply_sam_logoff(&q_l, rdata,
478 /*************************************************************************
479 net_login_interactive:
480 *************************************************************************/
481 static uint32 net_login_interactive(NET_ID_INFO_1 *id1,
482 struct smb_passwd *smb_pass,
488 extern void arcfour(uint8 key[16], uint8 out[16], uint8 in[16]);
491 unsigned char arc4_key[16];
492 memset(arc4_key, 0, 16);
493 memcpy(arc4_key, vuser->dc.sess_key, 8);
495 arcfour(arc4_key, lm_pwd, id1->arc4_lm_owf.data);
496 arcfour(arc4_key, nt_pwd, id1->arc4_nt_owf.data);
498 #ifdef DEBUG_PASSWORD
499 DEBUG(100,("arcfour decrypt of lm owf password:"));
500 dump_data(100, lm_pwd, 16);
502 DEBUG(100,("arcfour decrypt of nt owf password:"));
503 dump_data(100, nt_pwd, 16);
506 if (memcmp(smb_pass->smb_passwd , lm_pwd, 16) != 0 &&
507 memcmp(smb_pass->smb_nt_passwd, nt_pwd, 16) != 0)
509 status = 0xC0000000 | NT_STATUS_WRONG_PASSWORD;
512 /* sorry. have to assume that the password is always ok.
513 this _is_ ok, because the LSA SAM Logon is nothing to do
514 with SMB connections to shares.
516 DEBUG(3,("SAM Logon. Password not being checked\n"));
522 /*************************************************************************
524 *************************************************************************/
525 static uint32 net_login_network(NET_ID_INFO_2 *id2,
526 struct smb_passwd *smb_pass,
529 if ((id2->lm_chal_resp.str_str_len == 24 ||
530 id2->lm_chal_resp.str_str_len == 0) &&
531 id2->nt_chal_resp.str_str_len == 24 &&
532 (((smb_pass->smb_nt_passwd != NULL) &&
533 smb_password_check(id2->nt_chal_resp.buffer, smb_pass->smb_nt_passwd,
535 smb_password_check(id2->lm_chal_resp.buffer, smb_pass->smb_passwd,
540 return 0xC0000000 | NT_STATUS_WRONG_PASSWORD;
543 /*************************************************************************
545 *************************************************************************/
546 static void api_net_sam_logon( int uid,
552 NET_USER_INFO_3 usr_info;
555 struct smb_passwd *smb_pass = NULL;
556 UNISTR2 *uni_samlogon_user = NULL;
558 user_struct *vuser = NULL;
560 if ((vuser = get_valid_user_struct(uid)) == NULL) return;
562 q_l.sam_id.ctr = &ctr;
564 net_io_q_sam_logon("", &q_l, data, 0);
566 /* checks and updates credentials. creates reply credentials */
567 if (!deal_with_creds(vuser->dc.sess_key, &(vuser->dc.clnt_cred),
568 &(q_l.sam_id.client.cred), &srv_cred))
570 status = 0xC0000000 | NT_STATUS_INVALID_HANDLE;
574 memcpy(&(vuser->dc.srv_cred), &(vuser->dc.clnt_cred), sizeof(vuser->dc.clnt_cred));
577 /* find the username */
581 switch (q_l.sam_id.logon_level)
585 uni_samlogon_user = &(q_l.sam_id.ctr->auth.id1.uni_user_name);
586 pstrcpy(samlogon_user, unistrn2(uni_samlogon_user->buffer,
587 uni_samlogon_user->uni_str_len));
589 DEBUG(3,("SAM Logon (Interactive). Domain:[%s]. User:[%s]\n",
590 lp_workgroup(), samlogon_user));
595 uni_samlogon_user = &(q_l.sam_id.ctr->auth.id2.uni_user_name);
596 pstrcpy(samlogon_user, unistrn2(uni_samlogon_user->buffer,
597 uni_samlogon_user->uni_str_len));
599 DEBUG(3,("SAM Logon (Network). Domain:[%s]. User:[%s]\n",
600 lp_workgroup(), samlogon_user));
605 DEBUG(2,("SAM Logon: unsupported switch value\n"));
606 status = 0xC0000000 | NT_STATUS_INVALID_INFO_CLASS;
612 /* check username exists */
616 pstrcpy(samlogon_user, unistrn2(uni_samlogon_user->buffer,
617 uni_samlogon_user->uni_str_len));
620 smb_pass = get_smbpwd_entry(samlogon_user, 0);
623 if (smb_pass == NULL)
625 status = 0xC0000000 | NT_STATUS_NO_SUCH_USER;
629 /* validate password. */
633 switch (q_l.sam_id.logon_level)
637 /* interactive login. passwords arcfour'd with session key */
638 status = net_login_interactive(&q_l.sam_id.ctr->auth.id1,
644 /* network login. lm challenge and 24 byte responses */
645 status = net_login_network(&q_l.sam_id.ctr->auth.id2,
652 /* lkclXXXX this is the point at which, if the login was
653 successful, that the SAM Local Security Authority should
654 record that the user is logged in to the domain.
657 /* return the profile plus other bits :-) */
661 DOM_GID gids[LSA_MAX_GROUPS];
664 pstring logon_script;
665 pstring profile_path;
669 pstring my_workgroup;
670 pstring domain_groups;
673 extern pstring myname;
677 /* set up pointer indicating user/password failed to be found */
678 usr_info.ptr_user_info = 0;
680 dummy_time.low = 0xffffffff;
681 dummy_time.high = 0x7fffffff;
683 get_myname(myname, NULL);
685 /* XXXX hack to get standard_sub_basic() to use sam logon username */
686 /* possibly a better way would be to do a become_user() call */
687 sam_logon_in_ssb = True;
689 pstrcpy(logon_script, lp_logon_script ());
690 pstrcpy(profile_path, lp_logon_path ());
691 pstrcpy(dom_sid , lp_domain_sid ());
692 pstrcpy(other_sids , lp_domain_other_sids());
693 pstrcpy(my_workgroup, lp_workgroup ());
695 pstrcpy(home_drive , lp_logon_drive ());
696 pstrcpy(home_dir , lp_logon_home ());
698 pstrcpy(my_name , myname );
701 get_domain_user_groups(domain_groups, samlogon_user);
703 num_gids = make_dom_gids(domain_groups, gids);
705 sam_logon_in_ssb = False;
707 if (name_to_rid(samlogon_user, &r_uid, &r_gid))
709 make_net_user_info3(&usr_info,
711 &dummy_time, /* logon_time */
712 &dummy_time, /* logoff_time */
713 &dummy_time, /* kickoff_time */
714 &dummy_time, /* pass_last_set_time */
715 &dummy_time, /* pass_can_change_time */
716 &dummy_time, /* pass_must_change_time */
718 samlogon_user , /* user_name */
719 vuser->real_name, /* full_name */
720 logon_script , /* logon_script */
721 profile_path , /* profile_path */
722 home_dir , /* home_dir */
723 home_drive , /* dir_drive */
726 0, /* bad_pw_count */
728 r_uid , /* RID user_id */
729 r_gid , /* RID group_id */
730 num_gids, /* uint32 num_groups */
731 gids , /* DOM_GID *gids */
732 0x20 , /* uint32 user_flgs (?) */
734 NULL, /* char sess_key[16] */
736 my_name , /* char *logon_srv */
737 my_workgroup, /* char *logon_dom */
739 dom_sid, /* char *dom_sid */
740 other_sids); /* char *other_sids */
744 status = 0xC0000000 | NT_STATUS_NO_SUCH_USER;
748 net_reply_sam_logon(&q_l, rdata, &srv_cred, &usr_info, status);
752 /*************************************************************************
753 api_net_trust_dom_list:
754 *************************************************************************/
755 static void api_net_trust_dom_list( int uid,
759 NET_Q_TRUST_DOM_LIST q_t;
761 char *trusted_domain = "test_domain";
763 DEBUG(6,("api_net_trust_dom_list: %d\n", __LINE__));
765 /* grab the lsa trusted domain list query... */
766 net_io_q_trust_dom("", &q_t, data, 0);
768 /* construct reply. */
769 net_reply_trust_dom_list(&q_t, rdata,
772 DEBUG(6,("api_net_trust_dom_list: %d\n", __LINE__));
776 /*************************************************************************
777 error messages cropping up when using nltest.exe...
778 *************************************************************************/
779 #define ERROR_NO_SUCH_DOMAIN 0x54b
780 #define ERROR_NO_LOGON_SERVERS 0x51f
782 /*************************************************************************
784 *************************************************************************/
785 static void api_net_logon_ctrl2( int uid,
789 NET_Q_LOGON_CTRL2 q_l;
791 /* lkclXXXX - guess what - absolutely no idea what these are! */
793 uint32 pdc_connection_status = 0x0;
794 uint32 logon_attempts = 0x0;
795 uint32 tc_status = ERROR_NO_LOGON_SERVERS;
796 char *trusted_domain = "test_domain";
798 DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__));
800 /* grab the lsa netlogon ctrl2 query... */
801 net_io_q_logon_ctrl2("", &q_l, data, 0);
803 /* construct reply. */
804 net_reply_logon_ctrl2(&q_l, rdata,
805 flags, pdc_connection_status, logon_attempts,
806 tc_status, trusted_domain);
808 DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__));
811 /*******************************************************************
812 array of \PIPE\NETLOGON operations
813 ********************************************************************/
814 static struct api_struct api_net_cmds [] =
816 { "NET_REQCHAL" , NET_REQCHAL , api_net_req_chal },
817 { "NET_AUTH2" , NET_AUTH2 , api_net_auth_2 },
818 { "NET_SRVPWSET" , NET_SRVPWSET , api_net_srv_pwset },
819 { "NET_SAMLOGON" , NET_SAMLOGON , api_net_sam_logon },
820 { "NET_SAMLOGOFF" , NET_SAMLOGOFF , api_net_sam_logoff },
821 { "NET_LOGON_CTRL2" , NET_LOGON_CTRL2 , api_net_logon_ctrl2 },
822 { "NET_TRUST_DOM_LIST", NET_TRUST_DOM_LIST, api_net_trust_dom_list },
826 /*******************************************************************
827 receives a netlogon pipe and responds.
828 ********************************************************************/
829 BOOL api_netlog_rpc(pipes_struct *p, prs_struct *data)
831 return api_rpcTNP(p, "api_netlog_rpc", api_net_cmds, data);