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