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 = getsmbpwnam(mach_acct);
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 /* Set these to random values. */
293 generate_random_buffer(vuser->dc.srv_chal.data, 8, False);
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;
370 struct smb_passwd *smb_pass;
374 if ((vuser = get_valid_user_struct(uid)) == NULL) return;
376 /* grab the challenge and encrypted password ... */
377 net_io_q_srv_pwset("", &q_a, data, 0);
379 /* checks and updates credentials. creates reply credentials */
380 if (deal_with_creds(vuser->dc.sess_key, &(vuser->dc.clnt_cred),
381 &(q_a.clnt_id.cred), &srv_cred))
383 memcpy(&(vuser->dc.srv_cred), &(vuser->dc.clnt_cred), sizeof(vuser->dc.clnt_cred));
385 DEBUG(5,("api_net_srv_pwset: %d\n", __LINE__));
387 pstrcpy(mach_acct, unistrn2(q_a.clnt_id.login.uni_acct_name.buffer,
388 q_a.clnt_id.login.uni_acct_name.uni_str_len));
390 DEBUG(3,("Server Password Set Wksta:[%s]\n", mach_acct));
393 smb_pass = getsmbpwnam(mach_acct);
396 if (smb_pass != NULL)
398 unsigned char pwd[16];
401 DEBUG(100,("Server password set : new given value was :\n"));
402 for(i = 0; i < 16; i++)
403 DEBUG(100,("%02X ", q_a.pwd[i]));
406 cred_hash3( pwd, q_a.pwd, vuser->dc.sess_key);
408 /* lies! nt and lm passwords are _not_ the same: don't care */
409 smb_pass->smb_passwd = pwd;
410 smb_pass->smb_nt_passwd = pwd;
411 smb_pass->acct_ctrl = ACB_WSTRUST;
414 ret = mod_smbpwd_entry(smb_pass);
424 DEBUG(5,("api_net_srv_pwset: %d\n", __LINE__));
429 /* lkclXXXX take a guess at a sensible error code to return... */
430 status = 0xC0000000 | NT_STATUS_NETWORK_CREDENTIAL_CONFLICT;
433 /* Construct reply. */
434 net_reply_srv_pwset(&q_a, rdata, &srv_cred, status);
438 /*************************************************************************
440 *************************************************************************/
441 static void api_net_sam_logoff( int uid,
445 NET_Q_SAM_LOGOFF q_l;
452 if ((vuser = get_valid_user_struct(uid)) == NULL) return;
454 /* the DOM_ID_INFO_1 structure is a bit big. plus we might want to
455 dynamically allocate it inside net_io_q_sam_logon, at some point */
456 q_l.sam_id.ctr = &ctr;
458 /* grab the challenge... */
459 net_io_q_sam_logoff("", &q_l, data, 0);
461 /* checks and updates credentials. creates reply credentials */
462 deal_with_creds(vuser->dc.sess_key, &(vuser->dc.clnt_cred),
463 &(q_l.sam_id.client.cred), &srv_cred);
464 memcpy(&(vuser->dc.srv_cred), &(vuser->dc.clnt_cred), sizeof(vuser->dc.clnt_cred));
466 /* construct reply. always indicate success */
467 net_reply_sam_logoff(&q_l, rdata,
472 /*************************************************************************
473 net_login_interactive:
474 *************************************************************************/
475 static uint32 net_login_interactive(NET_ID_INFO_1 *id1,
476 struct smb_passwd *smb_pass,
483 unsigned char key[16];
486 memcpy(key, vuser->dc.sess_key, 8);
488 memcpy(lm_pwd, id1->lm_owf.data, 16);
489 memcpy(nt_pwd, id1->nt_owf.data, 16);
491 SamOEMhash(lm_pwd, key, False);
492 SamOEMhash(nt_pwd, key, False);
494 #ifdef DEBUG_PASSWORD
495 DEBUG(100,("decrypt of lm owf password:"));
496 dump_data(100, lm_pwd, 16);
498 DEBUG(100,("decrypt of nt owf password:"));
499 dump_data(100, nt_pwd, 16);
502 if (memcmp(smb_pass->smb_passwd , lm_pwd, 16) != 0 &&
503 memcmp(smb_pass->smb_nt_passwd, nt_pwd, 16) != 0)
505 status = 0xC0000000 | NT_STATUS_WRONG_PASSWORD;
511 /*************************************************************************
513 *************************************************************************/
514 static uint32 net_login_network(NET_ID_INFO_2 *id2,
515 struct smb_passwd *smb_pass,
518 DEBUG(5,("net_login_network: lm_len: %d nt_len: %d\n",
519 id2->lm_chal_resp.str_str_len,
520 id2->nt_chal_resp.str_str_len));
522 /* JRA. Check the NT password first if it exists - this is a higher quality
523 password, if it exists and it doesn't match - fail. */
525 if (id2->nt_chal_resp.str_str_len == 24 &&
526 smb_pass->smb_nt_passwd != NULL)
528 if(smb_password_check(id2->nt_chal_resp.buffer,
529 smb_pass->smb_nt_passwd,
533 return 0xC0000000 | NT_STATUS_WRONG_PASSWORD;
536 /* lkclXXXX this is not a good place to put disabling of LM hashes in.
537 if that is to be done, first move this entire function into a
538 library routine that calls the two smb_password_check() functions.
539 if disabling LM hashes (which nt can do for security reasons) then
540 an attempt should be made to disable them everywhere (which nt does
541 not do, for various security-hole reasons).
544 if (id2->lm_chal_resp.str_str_len == 24 &&
545 smb_password_check(id2->lm_chal_resp.buffer,
546 smb_pass->smb_passwd,
553 /* oops! neither password check succeeded */
555 return 0xC0000000 | NT_STATUS_WRONG_PASSWORD;
558 /*************************************************************************
560 *************************************************************************/
561 static void api_net_sam_logon( int uid,
567 NET_USER_INFO_3 usr_info;
570 struct smb_passwd *smb_pass = NULL;
571 UNISTR2 *uni_samlogon_user = NULL;
573 user_struct *vuser = NULL;
575 if ((vuser = get_valid_user_struct(uid)) == NULL) return;
577 q_l.sam_id.ctr = &ctr;
579 net_io_q_sam_logon("", &q_l, data, 0);
581 /* checks and updates credentials. creates reply credentials */
582 if (!deal_with_creds(vuser->dc.sess_key, &(vuser->dc.clnt_cred),
583 &(q_l.sam_id.client.cred), &srv_cred))
585 status = 0xC0000000 | NT_STATUS_INVALID_HANDLE;
589 memcpy(&(vuser->dc.srv_cred), &(vuser->dc.clnt_cred), sizeof(vuser->dc.clnt_cred));
592 /* find the username */
596 switch (q_l.sam_id.logon_level)
600 uni_samlogon_user = &(q_l.sam_id.ctr->auth.id1.uni_user_name);
602 DEBUG(3,("SAM Logon (Interactive). Domain:[%s]. ",
608 uni_samlogon_user = &(q_l.sam_id.ctr->auth.id2.uni_user_name);
610 DEBUG(3,("SAM Logon (Network). Domain:[%s]. ",
616 DEBUG(2,("SAM Logon: unsupported switch value\n"));
617 status = 0xC0000000 | NT_STATUS_INVALID_INFO_CLASS;
623 /* check username exists */
627 pstrcpy(samlogon_user, unistrn2(uni_samlogon_user->buffer,
628 uni_samlogon_user->uni_str_len));
630 DEBUG(3,("User:[%s]\n", samlogon_user));
633 smb_pass = getsmbpwnam(samlogon_user);
636 if (smb_pass == NULL)
638 status = 0xC0000000 | NT_STATUS_NO_SUCH_USER;
642 /* validate password. */
646 switch (q_l.sam_id.logon_level)
650 /* interactive login. passwords arcfour'd with session key */
651 status = net_login_interactive(&q_l.sam_id.ctr->auth.id1,
657 /* network login. lm challenge and 24 byte responses */
658 status = net_login_network(&q_l.sam_id.ctr->auth.id2,
665 /* lkclXXXX this is the point at which, if the login was
666 successful, that the SAM Local Security Authority should
667 record that the user is logged in to the domain.
670 /* return the profile plus other bits :-) */
674 DOM_GID gids[LSA_MAX_GROUPS];
677 pstring logon_script;
678 pstring profile_path;
682 pstring my_workgroup;
683 pstring domain_groups;
686 extern pstring myname;
690 /* set up pointer indicating user/password failed to be found */
691 usr_info.ptr_user_info = 0;
693 dummy_time.low = 0xffffffff;
694 dummy_time.high = 0x7fffffff;
696 /* XXXX hack to get standard_sub_basic() to use sam logon username */
697 /* possibly a better way would be to do a become_user() call */
698 sam_logon_in_ssb = True;
700 pstrcpy(logon_script, lp_logon_script ());
701 pstrcpy(profile_path, lp_logon_path ());
702 pstrcpy(dom_sid , lp_domain_sid ());
703 pstrcpy(other_sids , lp_domain_other_sids());
704 pstrcpy(my_workgroup, lp_workgroup ());
706 pstrcpy(home_drive , lp_logon_drive ());
707 pstrcpy(home_dir , lp_logon_home ());
709 pstrcpy(my_name , myname );
712 get_domain_user_groups(domain_groups, samlogon_user);
714 num_gids = make_dom_gids(domain_groups, gids);
716 sam_logon_in_ssb = False;
718 if (name_to_rid(samlogon_user, &r_uid, &r_gid))
720 make_net_user_info3(&usr_info,
722 &dummy_time, /* logon_time */
723 &dummy_time, /* logoff_time */
724 &dummy_time, /* kickoff_time */
725 &dummy_time, /* pass_last_set_time */
726 &dummy_time, /* pass_can_change_time */
727 &dummy_time, /* pass_must_change_time */
729 samlogon_user , /* user_name */
730 vuser->real_name, /* full_name */
731 logon_script , /* logon_script */
732 profile_path , /* profile_path */
733 home_dir , /* home_dir */
734 home_drive , /* dir_drive */
737 0, /* bad_pw_count */
739 r_uid , /* RID user_id */
740 r_gid , /* RID group_id */
741 num_gids, /* uint32 num_groups */
742 gids , /* DOM_GID *gids */
743 0x20 , /* uint32 user_flgs (?) */
745 NULL, /* char sess_key[16] */
747 my_name , /* char *logon_srv */
748 my_workgroup, /* char *logon_dom */
750 dom_sid, /* char *dom_sid */
751 other_sids); /* char *other_sids */
755 status = 0xC0000000 | NT_STATUS_NO_SUCH_USER;
759 net_reply_sam_logon(&q_l, rdata, &srv_cred, &usr_info, status);
763 /*************************************************************************
764 api_net_trust_dom_list:
765 *************************************************************************/
766 static void api_net_trust_dom_list( int uid,
770 NET_Q_TRUST_DOM_LIST q_t;
772 char *trusted_domain = "test_domain";
774 DEBUG(6,("api_net_trust_dom_list: %d\n", __LINE__));
776 /* grab the lsa trusted domain list query... */
777 net_io_q_trust_dom("", &q_t, data, 0);
779 /* construct reply. */
780 net_reply_trust_dom_list(&q_t, rdata,
783 DEBUG(6,("api_net_trust_dom_list: %d\n", __LINE__));
787 /*************************************************************************
788 error messages cropping up when using nltest.exe...
789 *************************************************************************/
790 #define ERROR_NO_SUCH_DOMAIN 0x54b
791 #define ERROR_NO_LOGON_SERVERS 0x51f
793 /*************************************************************************
795 *************************************************************************/
796 static void api_net_logon_ctrl2( int uid,
800 NET_Q_LOGON_CTRL2 q_l;
802 /* lkclXXXX - guess what - absolutely no idea what these are! */
804 uint32 pdc_connection_status = 0x0;
805 uint32 logon_attempts = 0x0;
806 uint32 tc_status = ERROR_NO_LOGON_SERVERS;
807 char *trusted_domain = "test_domain";
809 DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__));
811 /* grab the lsa netlogon ctrl2 query... */
812 net_io_q_logon_ctrl2("", &q_l, data, 0);
814 /* construct reply. */
815 net_reply_logon_ctrl2(&q_l, rdata,
816 flags, pdc_connection_status, logon_attempts,
817 tc_status, trusted_domain);
819 DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__));
822 /*******************************************************************
823 array of \PIPE\NETLOGON operations
824 ********************************************************************/
825 static struct api_struct api_net_cmds [] =
827 { "NET_REQCHAL" , NET_REQCHAL , api_net_req_chal },
828 { "NET_AUTH2" , NET_AUTH2 , api_net_auth_2 },
829 { "NET_SRVPWSET" , NET_SRVPWSET , api_net_srv_pwset },
830 { "NET_SAMLOGON" , NET_SAMLOGON , api_net_sam_logon },
831 { "NET_SAMLOGOFF" , NET_SAMLOGOFF , api_net_sam_logoff },
832 { "NET_LOGON_CTRL2" , NET_LOGON_CTRL2 , api_net_logon_ctrl2 },
833 { "NET_TRUST_DOM_LIST", NET_TRUST_DOM_LIST, api_net_trust_dom_list },
837 /*******************************************************************
838 receives a netlogon pipe and responds.
839 ********************************************************************/
840 BOOL api_netlog_rpc(pipes_struct *p, prs_struct *data)
842 return api_rpcTNP(p, "api_netlog_rpc", api_net_cmds, data);