/*- * Copyright (c) 2002 Brian Fundakowski Feldman * Copyright (c) 2002 Networks Associates Technologies, Inc. * All rights reserved. * * This software was developed by Robert Watson and Ilmar Habibulin for the * TrustedBSD Project. * * This software was developed for the FreeBSD Project in part by NAI Labs, * the Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The names of the authors may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: pam_alreadyloggedin.c,v 1.2 2002/03/07 16:54:40 green Exp $ */ /* * Implement a PAM module which will, given restrictions upon whether the * user to be authenticated is root or logging in on a given terminal, * will allow the user to be authenticated successfully if the user * is currently already logged in on another terminal. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define PAM_OPT_NO_ROOT "no_root" #define PAM_OPT_RESTRICT_TTY "restrict_tty" #define PAM_OPT_RESTRICT_LOGGEDIN_TTY "restrict_loggedin_tty" int getutmp(int *fd, struct utmp *utmp); int inutmp(struct utmp *utmp, const char *lineglob, const char *username, uid_t uid); #ifdef PAM_MAX_OPTIONS /* The old PAM requires this structure. */ static struct options options; #endif PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags __unused, int argc, const char **argv) { struct utmp utmp; struct passwd *pw; const char *logname; const char *lineglob, *loggedinlineglob = NULL; unsigned int matched = 0; int retval, fd = -1; retval = pam_get_user(pamh, &logname, NULL); if (retval != PAM_SUCCESS) PAM_RETURN(retval); lineglob = openpam_get_option(pamh, PAM_OPT_RESTRICT_TTY); if (lineglob != NULL) { const char *pam_tty; retval = pam_get_item(pamh, PAM_TTY, (const void **)&pam_tty); if (retval != PAM_SUCCESS) PAM_RETURN(retval); if (fnmatch(lineglob, pam_tty, 0) != 0) PAM_RETURN(PAM_AUTH_ERR); } loggedinlineglob = openpam_get_option(pamh, PAM_OPT_RESTRICT_LOGGEDIN_TTY); pw = getpwnam(logname); if (pw == NULL) PAM_RETURN(PAM_AUTH_ERR); if (pw->pw_uid == 0 && openpam_get_option(pamh, PAM_OPT_NO_ROOT) != NULL) PAM_RETURN(PAM_AUTH_ERR); while (getutmp(&fd, &utmp) == 1) { if (inutmp(&utmp, loggedinlineglob, logname, pw->pw_uid) == 1) matched++; } if (matched) PAM_RETURN(PAM_SUCCESS); PAM_RETURN(PAM_AUTH_ERR); } PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv) { PAM_RETURN(PAM_SUCCESS); } PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv) { PAM_RETURN(PAM_IGNORE); } PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv) { PAM_RETURN(PAM_IGNORE); } PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv) { PAM_RETURN(PAM_IGNORE); } PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv) { PAM_RETURN(PAM_IGNORE); } PAM_MODULE_ENTRY("pam_alreadyloggedin"); int getutmp(int *fd, struct utmp *utmp) { if (*fd == -1) { *fd = open(_PATH_UTMP, O_RDONLY); if (*fd == -1) { warn("Failure opening %s", _PATH_UTMP); return (-1); } } if (read(*fd, utmp, sizeof(*utmp)) == sizeof(*utmp)) return (1); (void)close(*fd); return (0); } int inutmp(struct utmp *utmp, const char *lineglob, const char *username, uid_t uid) { char ttypath[MAXPATHLEN]; struct stat sb; if (utmp->ut_name[0] == '\0' || utmp->ut_line[0] == '\0') return (0); utmp->ut_line[sizeof(utmp->ut_line) - 1] = '\0'; utmp->ut_name[sizeof(utmp->ut_name) - 1] = '\0'; if (utmp->ut_line[strcspn(utmp->ut_line, "./")] != '\0') { warnx("Evil utmp line: `%s'", utmp->ut_line); return (-1); } if (lineglob != NULL && fnmatch(lineglob, utmp->ut_line, 0) != 0) return (0); if (*username != '\0' && strcmp(username, utmp->ut_name) != 0) return (0); /* can't fail */ (void)snprintf(ttypath, sizeof(ttypath), "/dev/%s", utmp->ut_line); if (stat(ttypath, &sb) == -1) { warn("Can't stat line `%s'", ttypath); return (-1); } if (sb.st_uid != uid) { warnx("Line's uid %d does not match %d", sb.st_uid, uid); return (-1); } return (1); }