xref: /dflybsd-src/crypto/openssh/sshlogin.c (revision 95577b5e0147377b730485d25b052a4472277761)
150a69bb5SSascha Wildner /* $OpenBSD: sshlogin.c,v 1.35 2020/10/18 11:32:02 djm Exp $ */
218de8d7fSPeter Avalos /*
318de8d7fSPeter Avalos  * Author: Tatu Ylonen <ylo@cs.hut.fi>
418de8d7fSPeter Avalos  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
518de8d7fSPeter Avalos  *                    All rights reserved
618de8d7fSPeter Avalos  * This file performs some of the things login(1) normally does.  We cannot
718de8d7fSPeter Avalos  * easily use something like login -p -h host -f user, because there are
818de8d7fSPeter Avalos  * several different logins around, and it is hard to determined what kind of
918de8d7fSPeter Avalos  * login the current system has.  Also, we want to be able to execute commands
1018de8d7fSPeter Avalos  * on a tty.
1118de8d7fSPeter Avalos  *
1218de8d7fSPeter Avalos  * As far as I am concerned, the code I have written for this software
1318de8d7fSPeter Avalos  * can be used freely for any purpose.  Any derived versions of this
1418de8d7fSPeter Avalos  * software must be clearly marked as such, and if the derived work is
1518de8d7fSPeter Avalos  * incompatible with the protocol description in the RFC file, it must be
1618de8d7fSPeter Avalos  * called by a name other than "ssh" or "Secure Shell".
1718de8d7fSPeter Avalos  *
1818de8d7fSPeter Avalos  * Copyright (c) 1999 Theo de Raadt.  All rights reserved.
1918de8d7fSPeter Avalos  * Copyright (c) 1999 Markus Friedl.  All rights reserved.
2018de8d7fSPeter Avalos  *
2118de8d7fSPeter Avalos  * Redistribution and use in source and binary forms, with or without
2218de8d7fSPeter Avalos  * modification, are permitted provided that the following conditions
2318de8d7fSPeter Avalos  * are met:
2418de8d7fSPeter Avalos  * 1. Redistributions of source code must retain the above copyright
2518de8d7fSPeter Avalos  *    notice, this list of conditions and the following disclaimer.
2618de8d7fSPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
2718de8d7fSPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
2818de8d7fSPeter Avalos  *    documentation and/or other materials provided with the distribution.
2918de8d7fSPeter Avalos  *
3018de8d7fSPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
3118de8d7fSPeter Avalos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
3218de8d7fSPeter Avalos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
3318de8d7fSPeter Avalos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
3418de8d7fSPeter Avalos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
3518de8d7fSPeter Avalos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3618de8d7fSPeter Avalos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3718de8d7fSPeter Avalos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3818de8d7fSPeter Avalos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3918de8d7fSPeter Avalos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4018de8d7fSPeter Avalos  */
4118de8d7fSPeter Avalos 
4218de8d7fSPeter Avalos #include "includes.h"
4318de8d7fSPeter Avalos 
4418de8d7fSPeter Avalos #include <sys/types.h>
4518de8d7fSPeter Avalos #include <sys/socket.h>
4618de8d7fSPeter Avalos 
4718de8d7fSPeter Avalos #include <netinet/in.h>
4818de8d7fSPeter Avalos 
4918de8d7fSPeter Avalos #include <errno.h>
5018de8d7fSPeter Avalos #include <fcntl.h>
5118de8d7fSPeter Avalos #include <stdarg.h>
5218de8d7fSPeter Avalos #include <stdio.h>
53*ee116499SAntonio Huete Jimenez #include <stdlib.h>
5418de8d7fSPeter Avalos #include <string.h>
5518de8d7fSPeter Avalos #include <time.h>
5618de8d7fSPeter Avalos #include <unistd.h>
57e9778795SPeter Avalos #include <limits.h>
5818de8d7fSPeter Avalos 
59664f4763Szrj #include "sshlogin.h"
60664f4763Szrj #include "ssherr.h"
6118de8d7fSPeter Avalos #include "loginrec.h"
6218de8d7fSPeter Avalos #include "log.h"
63664f4763Szrj #include "sshbuf.h"
6436e94dc5SPeter Avalos #include "misc.h"
6518de8d7fSPeter Avalos #include "servconf.h"
6618de8d7fSPeter Avalos 
67664f4763Szrj extern struct sshbuf *loginmsg;
6818de8d7fSPeter Avalos extern ServerOptions options;
6918de8d7fSPeter Avalos 
7018de8d7fSPeter Avalos /*
7118de8d7fSPeter Avalos  * Returns the time when the user last logged in.  Returns 0 if the
7218de8d7fSPeter Avalos  * information is not available.  This must be called before record_login.
7318de8d7fSPeter Avalos  * The host the user logged in from will be returned in buf.
7418de8d7fSPeter Avalos  */
7518de8d7fSPeter Avalos time_t
get_last_login_time(uid_t uid,const char * logname,char * buf,size_t bufsize)7618de8d7fSPeter Avalos get_last_login_time(uid_t uid, const char *logname,
7718de8d7fSPeter Avalos     char *buf, size_t bufsize)
7818de8d7fSPeter Avalos {
7918de8d7fSPeter Avalos 	struct logininfo li;
8018de8d7fSPeter Avalos 
8118de8d7fSPeter Avalos 	login_get_lastlog(&li, uid);
8218de8d7fSPeter Avalos 	strlcpy(buf, li.hostname, bufsize);
8318de8d7fSPeter Avalos 	return (time_t)li.tv_sec;
8418de8d7fSPeter Avalos }
8518de8d7fSPeter Avalos 
8618de8d7fSPeter Avalos /*
8718de8d7fSPeter Avalos  * Generate and store last login message.  This must be done before
8818de8d7fSPeter Avalos  * login_login() is called and lastlog is updated.
8918de8d7fSPeter Avalos  */
9018de8d7fSPeter Avalos static void
store_lastlog_message(const char * user,uid_t uid)9118de8d7fSPeter Avalos store_lastlog_message(const char *user, uid_t uid)
9218de8d7fSPeter Avalos {
9340c002afSPeter Avalos #ifndef NO_SSH_LASTLOG
940cbfa66cSDaniel Fojt # ifndef CUSTOM_SYS_AUTH_GET_LASTLOGIN_MSG
950cbfa66cSDaniel Fojt 	char hostname[HOST_NAME_MAX+1] = "";
9618de8d7fSPeter Avalos 	time_t last_login_time;
970cbfa66cSDaniel Fojt # endif
980cbfa66cSDaniel Fojt 	char *time_string;
99664f4763Szrj 	int r;
10018de8d7fSPeter Avalos 
10118de8d7fSPeter Avalos 	if (!options.print_lastlog)
10218de8d7fSPeter Avalos 		return;
10318de8d7fSPeter Avalos 
10440c002afSPeter Avalos # ifdef CUSTOM_SYS_AUTH_GET_LASTLOGIN_MSG
10540c002afSPeter Avalos 	time_string = sys_auth_get_lastlogin_msg(user, uid);
10640c002afSPeter Avalos 	if (time_string != NULL) {
107664f4763Szrj 		if ((r = sshbuf_put(loginmsg,
108664f4763Szrj 		    time_string, strlen(time_string))) != 0)
109664f4763Szrj 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
11036e94dc5SPeter Avalos 		free(time_string);
11140c002afSPeter Avalos 	}
11240c002afSPeter Avalos # else
11318de8d7fSPeter Avalos 	last_login_time = get_last_login_time(uid, user, hostname,
11418de8d7fSPeter Avalos 	    sizeof(hostname));
11518de8d7fSPeter Avalos 
11618de8d7fSPeter Avalos 	if (last_login_time != 0) {
11718de8d7fSPeter Avalos 		time_string = ctime(&last_login_time);
11818de8d7fSPeter Avalos 		time_string[strcspn(time_string, "\n")] = '\0';
11918de8d7fSPeter Avalos 		if (strcmp(hostname, "") == 0)
120664f4763Szrj 			r = sshbuf_putf(loginmsg, "Last login: %s\r\n",
12118de8d7fSPeter Avalos 			    time_string);
12218de8d7fSPeter Avalos 		else
123664f4763Szrj 			r = sshbuf_putf(loginmsg, "Last login: %s from %s\r\n",
12418de8d7fSPeter Avalos 			    time_string, hostname);
125664f4763Szrj 		if (r != 0)
12650a69bb5SSascha Wildner 			fatal_fr(r, "sshbuf_putf");
12718de8d7fSPeter Avalos 	}
12840c002afSPeter Avalos # endif /* CUSTOM_SYS_AUTH_GET_LASTLOGIN_MSG */
12918de8d7fSPeter Avalos #endif /* NO_SSH_LASTLOG */
13018de8d7fSPeter Avalos }
13118de8d7fSPeter Avalos 
13218de8d7fSPeter Avalos /*
13318de8d7fSPeter Avalos  * Records that the user has logged in.  I wish these parts of operating
13418de8d7fSPeter Avalos  * systems were more standardized.
13518de8d7fSPeter Avalos  */
13618de8d7fSPeter Avalos void
record_login(pid_t pid,const char * tty,const char * user,uid_t uid,const char * host,struct sockaddr * addr,socklen_t addrlen)13718de8d7fSPeter Avalos record_login(pid_t pid, const char *tty, const char *user, uid_t uid,
13818de8d7fSPeter Avalos     const char *host, struct sockaddr *addr, socklen_t addrlen)
13918de8d7fSPeter Avalos {
14018de8d7fSPeter Avalos 	struct logininfo *li;
14118de8d7fSPeter Avalos 
14218de8d7fSPeter Avalos 	/* save previous login details before writing new */
14318de8d7fSPeter Avalos 	store_lastlog_message(user, uid);
14418de8d7fSPeter Avalos 
14518de8d7fSPeter Avalos 	li = login_alloc_entry(pid, user, host, tty);
14618de8d7fSPeter Avalos 	login_set_addr(li, addr, addrlen);
14718de8d7fSPeter Avalos 	login_login(li);
14818de8d7fSPeter Avalos 	login_free_entry(li);
14918de8d7fSPeter Avalos }
15018de8d7fSPeter Avalos 
15118de8d7fSPeter Avalos #ifdef LOGIN_NEEDS_UTMPX
15218de8d7fSPeter Avalos void
record_utmp_only(pid_t pid,const char * ttyname,const char * user,const char * host,struct sockaddr * addr,socklen_t addrlen)15318de8d7fSPeter Avalos record_utmp_only(pid_t pid, const char *ttyname, const char *user,
15418de8d7fSPeter Avalos 		 const char *host, struct sockaddr *addr, socklen_t addrlen)
15518de8d7fSPeter Avalos {
15618de8d7fSPeter Avalos 	struct logininfo *li;
15718de8d7fSPeter Avalos 
15818de8d7fSPeter Avalos 	li = login_alloc_entry(pid, user, host, ttyname);
15918de8d7fSPeter Avalos 	login_set_addr(li, addr, addrlen);
16018de8d7fSPeter Avalos 	login_utmp_only(li);
16118de8d7fSPeter Avalos 	login_free_entry(li);
16218de8d7fSPeter Avalos }
16318de8d7fSPeter Avalos #endif
16418de8d7fSPeter Avalos 
16518de8d7fSPeter Avalos /* Records that the user has logged out. */
16618de8d7fSPeter Avalos void
record_logout(pid_t pid,const char * tty,const char * user)16718de8d7fSPeter Avalos record_logout(pid_t pid, const char *tty, const char *user)
16818de8d7fSPeter Avalos {
16918de8d7fSPeter Avalos 	struct logininfo *li;
17018de8d7fSPeter Avalos 
17118de8d7fSPeter Avalos 	li = login_alloc_entry(pid, user, NULL, tty);
17218de8d7fSPeter Avalos 	login_logout(li);
17318de8d7fSPeter Avalos 	login_free_entry(li);
17418de8d7fSPeter Avalos }
175