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 /* 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;
371 struct smb_passwd *smb_pass;
375 if ((vuser = get_valid_user_struct(uid)) == NULL) return;
377 /* grab the challenge and encrypted password ... */
378 net_io_q_srv_pwset("", &q_a, data, 0);
380 /* checks and updates credentials. creates reply credentials */
381 if (deal_with_creds(vuser->dc.sess_key, &(vuser->dc.clnt_cred),
382 &(q_a.clnt_id.cred), &srv_cred))
384 memcpy(&(vuser->dc.srv_cred), &(vuser->dc.clnt_cred), sizeof(vuser->dc.clnt_cred));
386 DEBUG(5,("api_net_srv_pwset: %d\n", __LINE__));
388 pstrcpy(mach_acct, unistrn2(q_a.clnt_id.login.uni_acct_name.buffer,
389 q_a.clnt_id.login.uni_acct_name.uni_str_len));
391 DEBUG(3,("Server Password Set Wksta:[%s]\n", mach_acct));
394 smb_pass = getsmbpwnam(mach_acct);
397 if (smb_pass != NULL)
399 unsigned char pwd[16];
402 DEBUG(100,("Server password set : new given value was :\n"));
403 for(i = 0; i < 16; i++)
404 DEBUG(100,("%02X ", q_a.pwd[i]));
407 cred_hash3( pwd, q_a.pwd, vuser->dc.sess_key);
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);
425 DEBUG(5,("api_net_srv_pwset: %d\n", __LINE__));
430 /* lkclXXXX take a guess at a sensible error code to return... */
431 status = 0xC0000000 | NT_STATUS_NETWORK_CREDENTIAL_CONFLICT;
434 /* Construct reply. */
435 net_reply_srv_pwset(&q_a, rdata, &srv_cred, status);
439 /*************************************************************************
441 *************************************************************************/
442 static void api_net_sam_logoff( int uid,
446 NET_Q_SAM_LOGOFF q_l;
453 if ((vuser = get_valid_user_struct(uid)) == NULL) return;
455 /* the DOM_ID_INFO_1 structure is a bit big. plus we might want to
456 dynamically allocate it inside net_io_q_sam_logon, at some point */
457 q_l.sam_id.ctr = &ctr;
459 /* grab the challenge... */
460 net_io_q_sam_logoff("", &q_l, data, 0);
462 /* checks and updates credentials. creates reply credentials */
463 deal_with_creds(vuser->dc.sess_key, &(vuser->dc.clnt_cred),
464 &(q_l.sam_id.client.cred), &srv_cred);
465 memcpy(&(vuser->dc.srv_cred), &(vuser->dc.clnt_cred), sizeof(vuser->dc.clnt_cred));
467 /* construct reply. always indicate success */
468 net_reply_sam_logoff(&q_l, rdata,
473 /*************************************************************************
474 net_login_interactive:
475 *************************************************************************/
476 static uint32 net_login_interactive(NET_ID_INFO_1 *id1,
477 struct smb_passwd *smb_pass,
484 unsigned char key[16];
487 memcpy(key, vuser->dc.sess_key, 8);
489 memcpy(lm_pwd, id1->lm_owf.data, 16);
490 memcpy(nt_pwd, id1->nt_owf.data, 16);
492 SamOEMhash(lm_pwd, key, False);
493 SamOEMhash(nt_pwd, key, False);
495 #ifdef DEBUG_PASSWORD
496 DEBUG(100,("decrypt of lm owf password:"));
497 dump_data(100, lm_pwd, 16);
499 DEBUG(100,("decrypt of nt owf password:"));
500 dump_data(100, nt_pwd, 16);
503 if (memcmp(smb_pass->smb_passwd , lm_pwd, 16) != 0 &&
504 memcmp(smb_pass->smb_nt_passwd, nt_pwd, 16) != 0)
506 status = 0xC0000000 | NT_STATUS_WRONG_PASSWORD;
512 /*************************************************************************
514 *************************************************************************/
515 static uint32 net_login_network(NET_ID_INFO_2 *id2,
516 struct smb_passwd *smb_pass,
519 DEBUG(5,("net_login_network: lm_len: %d nt_len: %d\n",
520 id2->lm_chal_resp.str_str_len,
521 id2->nt_chal_resp.str_str_len));
523 /* JRA. Check the NT password first if it exists - this is a higher quality
524 password, if it exists and it doesn't match - fail. */
526 if (id2->nt_chal_resp.str_str_len == 24 &&
527 smb_pass->smb_nt_passwd != NULL)
529 if(smb_password_check(id2->nt_chal_resp.buffer,
530 smb_pass->smb_nt_passwd,
534 return 0xC0000000 | NT_STATUS_WRONG_PASSWORD;
537 /* lkclXXXX this is not a good place to put disabling of LM hashes in.
538 if that is to be done, first move this entire function into a
539 library routine that calls the two smb_password_check() functions.
540 if disabling LM hashes (which nt can do for security reasons) then
541 an attempt should be made to disable them everywhere (which nt does
542 not do, for various security-hole reasons).
545 if (id2->lm_chal_resp.str_str_len == 24 &&
546 smb_password_check(id2->lm_chal_resp.buffer,
547 smb_pass->smb_passwd,
554 /* oops! neither password check succeeded */
556 return 0xC0000000 | NT_STATUS_WRONG_PASSWORD;
559 /*************************************************************************
561 *************************************************************************/
562 static void api_net_sam_logon( int uid,
568 NET_USER_INFO_3 usr_info;
571 struct smb_passwd *smb_pass = NULL;
572 UNISTR2 *uni_samlogon_user = NULL;
574 user_struct *vuser = NULL;
576 if ((vuser = get_valid_user_struct(uid)) == NULL) return;
578 q_l.sam_id.ctr = &ctr;
580 net_io_q_sam_logon("", &q_l, data, 0);
582 /* checks and updates credentials. creates reply credentials */
583 if (!deal_with_creds(vuser->dc.sess_key, &(vuser->dc.clnt_cred),
584 &(q_l.sam_id.client.cred), &srv_cred))
586 status = 0xC0000000 | NT_STATUS_INVALID_HANDLE;
590 memcpy(&(vuser->dc.srv_cred), &(vuser->dc.clnt_cred), sizeof(vuser->dc.clnt_cred));
593 /* find the username */
597 switch (q_l.sam_id.logon_level)
601 uni_samlogon_user = &(q_l.sam_id.ctr->auth.id1.uni_user_name);
603 DEBUG(3,("SAM Logon (Interactive). Domain:[%s]. ",
609 uni_samlogon_user = &(q_l.sam_id.ctr->auth.id2.uni_user_name);
611 DEBUG(3,("SAM Logon (Network). Domain:[%s]. ",
617 DEBUG(2,("SAM Logon: unsupported switch value\n"));
618 status = 0xC0000000 | NT_STATUS_INVALID_INFO_CLASS;
624 /* check username exists */
628 pstrcpy(samlogon_user, unistrn2(uni_samlogon_user->buffer,
629 uni_samlogon_user->uni_str_len));
631 DEBUG(3,("User:[%s]\n", samlogon_user));
634 smb_pass = getsmbpwnam(samlogon_user);
637 if (smb_pass == NULL)
639 status = 0xC0000000 | NT_STATUS_NO_SUCH_USER;
643 /* validate password. */
647 switch (q_l.sam_id.logon_level)
651 /* interactive login. passwords arcfour'd with session key */
652 status = net_login_interactive(&q_l.sam_id.ctr->auth.id1,
658 /* network login. lm challenge and 24 byte responses */
659 status = net_login_network(&q_l.sam_id.ctr->auth.id2,
666 /* lkclXXXX this is the point at which, if the login was
667 successful, that the SAM Local Security Authority should
668 record that the user is logged in to the domain.
671 /* return the profile plus other bits :-) */
675 DOM_GID gids[LSA_MAX_GROUPS];
678 pstring logon_script;
679 pstring profile_path;
683 pstring my_workgroup;
684 pstring domain_groups;
687 extern pstring myname;
691 /* set up pointer indicating user/password failed to be found */
692 usr_info.ptr_user_info = 0;
694 dummy_time.low = 0xffffffff;
695 dummy_time.high = 0x7fffffff;
697 get_myname(myname, NULL);
699 /* XXXX hack to get standard_sub_basic() to use sam logon username */
700 /* possibly a better way would be to do a become_user() call */
701 sam_logon_in_ssb = True;
703 pstrcpy(logon_script, lp_logon_script ());
704 pstrcpy(profile_path, lp_logon_path ());
705 pstrcpy(dom_sid , lp_domain_sid ());
706 pstrcpy(other_sids , lp_domain_other_sids());
707 pstrcpy(my_workgroup, lp_workgroup ());
709 pstrcpy(home_drive , lp_logon_drive ());
710 pstrcpy(home_dir , lp_logon_home ());
712 pstrcpy(my_name , myname );
715 get_domain_user_groups(domain_groups, samlogon_user);
717 num_gids = make_dom_gids(domain_groups, gids);
719 sam_logon_in_ssb = False;
721 if (name_to_rid(samlogon_user, &r_uid, &r_gid))
723 make_net_user_info3(&usr_info,
725 &dummy_time, /* logon_time */
726 &dummy_time, /* logoff_time */
727 &dummy_time, /* kickoff_time */
728 &dummy_time, /* pass_last_set_time */
729 &dummy_time, /* pass_can_change_time */
730 &dummy_time, /* pass_must_change_time */
732 samlogon_user , /* user_name */
733 vuser->real_name, /* full_name */
734 logon_script , /* logon_script */
735 profile_path , /* profile_path */
736 home_dir , /* home_dir */
737 home_drive , /* dir_drive */
740 0, /* bad_pw_count */
742 r_uid , /* RID user_id */
743 r_gid , /* RID group_id */
744 num_gids, /* uint32 num_groups */
745 gids , /* DOM_GID *gids */
746 0x20 , /* uint32 user_flgs (?) */
748 NULL, /* char sess_key[16] */
750 my_name , /* char *logon_srv */
751 my_workgroup, /* char *logon_dom */
753 dom_sid, /* char *dom_sid */
754 other_sids); /* char *other_sids */
758 status = 0xC0000000 | NT_STATUS_NO_SUCH_USER;
762 net_reply_sam_logon(&q_l, rdata, &srv_cred, &usr_info, status);
766 /*************************************************************************
767 api_net_trust_dom_list:
768 *************************************************************************/
769 static void api_net_trust_dom_list( int uid,
773 NET_Q_TRUST_DOM_LIST q_t;
775 char *trusted_domain = "test_domain";
777 DEBUG(6,("api_net_trust_dom_list: %d\n", __LINE__));
779 /* grab the lsa trusted domain list query... */
780 net_io_q_trust_dom("", &q_t, data, 0);
782 /* construct reply. */
783 net_reply_trust_dom_list(&q_t, rdata,
786 DEBUG(6,("api_net_trust_dom_list: %d\n", __LINE__));
790 /*************************************************************************
791 error messages cropping up when using nltest.exe...
792 *************************************************************************/
793 #define ERROR_NO_SUCH_DOMAIN 0x54b
794 #define ERROR_NO_LOGON_SERVERS 0x51f
796 /*************************************************************************
798 *************************************************************************/
799 static void api_net_logon_ctrl2( int uid,
803 NET_Q_LOGON_CTRL2 q_l;
805 /* lkclXXXX - guess what - absolutely no idea what these are! */
807 uint32 pdc_connection_status = 0x0;
808 uint32 logon_attempts = 0x0;
809 uint32 tc_status = ERROR_NO_LOGON_SERVERS;
810 char *trusted_domain = "test_domain";
812 DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__));
814 /* grab the lsa netlogon ctrl2 query... */
815 net_io_q_logon_ctrl2("", &q_l, data, 0);
817 /* construct reply. */
818 net_reply_logon_ctrl2(&q_l, rdata,
819 flags, pdc_connection_status, logon_attempts,
820 tc_status, trusted_domain);
822 DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__));
825 /*******************************************************************
826 array of \PIPE\NETLOGON operations
827 ********************************************************************/
828 static struct api_struct api_net_cmds [] =
830 { "NET_REQCHAL" , NET_REQCHAL , api_net_req_chal },
831 { "NET_AUTH2" , NET_AUTH2 , api_net_auth_2 },
832 { "NET_SRVPWSET" , NET_SRVPWSET , api_net_srv_pwset },
833 { "NET_SAMLOGON" , NET_SAMLOGON , api_net_sam_logon },
834 { "NET_SAMLOGOFF" , NET_SAMLOGOFF , api_net_sam_logoff },
835 { "NET_LOGON_CTRL2" , NET_LOGON_CTRL2 , api_net_logon_ctrl2 },
836 { "NET_TRUST_DOM_LIST", NET_TRUST_DOM_LIST, api_net_trust_dom_list },
840 /*******************************************************************
841 receives a netlogon pipe and responds.
842 ********************************************************************/
843 BOOL api_netlog_rpc(pipes_struct *p, prs_struct *data)
845 return api_rpcTNP(p, "api_netlog_rpc", api_net_cmds, data);