From 3d601f5c0b2ed98326587270c5638a8315a2c25d Mon Sep 17 00:00:00 2001 From: wsalamon Date: Sat, 4 Feb 2006 20:20:02 +0000 Subject: [PATCH] Make login audit-enabled, submitting audit records for the login and logout events. The specifics of submitting the records is contained within login_audit.c. Document the auditing behavior in the man page. Obtained from: TrustedBSD Project, Apple Computer, Inc. Approved by: rwatson (mentor) --- usr.bin/login/Makefile | 4 +- usr.bin/login/login.1 | 11 ++ usr.bin/login/login.c | 16 +++ usr.bin/login/login.h | 6 +- usr.bin/login/login_audit.c | 204 ++++++++++++++++++++++++++++++++++++ 5 files changed, 238 insertions(+), 3 deletions(-) create mode 100644 usr.bin/login/login_audit.c diff --git a/usr.bin/login/Makefile b/usr.bin/login/Makefile index 9ddda3633819..e41541140202 100644 --- a/usr.bin/login/Makefile +++ b/usr.bin/login/Makefile @@ -2,10 +2,10 @@ # $FreeBSD$ PROG= login -SRCS= login.c login_fbtab.c +SRCS= login.c login_audit.c login_fbtab.c CFLAGS+=-DLOGALL DPADD= ${LIBUTIL} ${LIBPAM} -LDADD= -lutil ${MINUSLPAM} +LDADD= -lutil ${MINUSLPAM} -lbsm MAN= login.1 login.access.5 .if !defined(NO_SETUID_LOGIN) BINOWN= root diff --git a/usr.bin/login/login.1 b/usr.bin/login/login.1 index ec924ca31d73..ea3297e8160f 100644 --- a/usr.bin/login/login.1 +++ b/usr.bin/login/login.1 @@ -124,6 +124,13 @@ command which is similar or identical to this utility. Consult the .Xr builtin 1 manual page. +.Pp +The +.Nm +utility will submit an audit record when login succeeds or fails. +Failure to determine the current auditing state will +result in an error exit from +.Nm . .Sh FILES .Bl -tag -width ".Pa /etc/login.access" -compact .It Pa /etc/fbtab @@ -143,6 +150,10 @@ configure authentication services .It Pa /etc/pam.d/login .Xr pam 8 configuration file +.It Pa /etc/security/audit_user +user flags for auditing +.It Pa /etc/security/audit_control +global flags for auditing .El .Sh SEE ALSO .Xr builtin 1 , diff --git a/usr.bin/login/login.c b/usr.bin/login/login.c index 68693f82e21c..f23467de807a 100644 --- a/usr.bin/login/login.c +++ b/usr.bin/login/login.c @@ -173,6 +173,7 @@ main(int argc, char *argv[]) login_cap_t *lc = NULL; login_cap_t *lc_user = NULL; pid_t pid; + char auditsuccess = 1; (void)signal(SIGQUIT, SIG_IGN); (void)signal(SIGINT, SIG_IGN); @@ -291,16 +292,19 @@ main(int argc, char *argv[]) pam_err = pam_start("login", username, &pamc, &pamh); if (pam_err != PAM_SUCCESS) { pam_syslog("pam_start()"); + au_login_fail("PAM Error", 1); bail(NO_SLEEP_EXIT, 1); } pam_err = pam_set_item(pamh, PAM_TTY, tty); if (pam_err != PAM_SUCCESS) { pam_syslog("pam_set_item(PAM_TTY)"); + au_login_fail("PAM Error", 1); bail(NO_SLEEP_EXIT, 1); } pam_err = pam_set_item(pamh, PAM_RHOST, hostname); if (pam_err != PAM_SUCCESS) { pam_syslog("pam_set_item(PAM_RHOST)"); + au_login_fail("PAM Error", 1); bail(NO_SLEEP_EXIT, 1); } @@ -317,6 +321,7 @@ main(int argc, char *argv[]) (uid == (uid_t)0 || uid == (uid_t)pwd->pw_uid)) { /* already authenticated */ rval = 0; + auditsuccess = 0; /* opened a terminal window only */ } else { fflag = 0; (void)setpriority(PRIO_PROCESS, 0, -4); @@ -329,6 +334,12 @@ main(int argc, char *argv[]) pam_cleanup(); + /* + * We are not exiting here, but this corresponds to a failed + * login event, so set exitstatus to 1. + */ + au_login_fail("Login incorrect", 1); + (void)printf("Login incorrect\n"); failures++; @@ -351,6 +362,10 @@ main(int argc, char *argv[]) endpwent(); + /* Audit successful login. */ + if (auditsuccess) + au_login_success(); + /* * Establish the login class. */ @@ -936,6 +951,7 @@ bail(int sec, int eval) { pam_cleanup(); + audit_logout(); (void)sleep(sec); exit(eval); } diff --git a/usr.bin/login/login.h b/usr.bin/login/login.h index 6be2539c7bb6..0b33592155c2 100644 --- a/usr.bin/login/login.h +++ b/usr.bin/login/login.h @@ -27,4 +27,8 @@ void login_fbtab(char *, uid_t, gid_t); -extern char **environ; +void au_login_success(void); +void au_login_fail(char *errmsg, int na); + +extern char **environ; +extern struct passwd *pwd; diff --git a/usr.bin/login/login_audit.c b/usr.bin/login/login_audit.c new file mode 100644 index 000000000000..0e0e09151290 --- /dev/null +++ b/usr.bin/login/login_audit.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2005 Apple Computer, Inc. + * All rights reserved. + * + * @APPLE_BSD_LICENSE_HEADER_START@ + * + * 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. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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. + * + * @APPLE_BSD_LICENSE_HEADER_END@ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include + +#include +#include +#include +#include + +#include "login.h" + +/* + * Audit data + */ +static au_tid_t tid; + +/* + * The following tokens are included in the audit record for a successful + * login: header, subject, return. + */ +void +au_login_success(void) +{ + token_t *tok; + int aufd; + au_mask_t aumask; + auditinfo_t auinfo; + uid_t uid = pwd->pw_uid; + gid_t gid = pwd->pw_gid; + pid_t pid = getpid(); + long au_cond; + + /* If we are not auditing, don't cut an audit record; just return. */ + if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) { + if (errno == ENOSYS) + return; + errx(1, "login: Could not determine audit condition"); + } + if (au_cond == AUC_NOAUDIT) + return; + + /* Compute and set the user's preselection mask. */ + if (au_user_mask(pwd->pw_name, &aumask) == -1) + errx(1, "login: Could not set audit mask\n"); + + /* Set the audit info for the user. */ + auinfo.ai_auid = uid; + auinfo.ai_asid = pid; + bcopy(&tid, &auinfo.ai_termid, sizeof(auinfo.ai_termid)); + bcopy(&aumask, &auinfo.ai_mask, sizeof(auinfo.ai_mask)); + if (setaudit(&auinfo) != 0) + err(1, "login: setaudit failed"); + + if ((aufd = au_open()) == -1) + errx(1,"login: Audit Error: au_open() failed"); + + if ((tok = au_to_subject32(uid, geteuid(), getegid(), uid, gid, pid, + pid, &tid)) == NULL) + errx(1, "login: Audit Error: au_to_subject32() failed"); + au_write(aufd, tok); + + if ((tok = au_to_return32(0, 0)) == NULL) + errx(1, "login: Audit Error: au_to_return32() failed"); + au_write(aufd, tok); + + if (au_close(aufd, 1, AUE_login) == -1) + errx(1, "login: Audit Record was not committed."); +} + +/* + * The following tokens are included in the audit record for failed + * login attempts: header, subject, text, return. + */ +void +au_login_fail(char *errmsg, int na) +{ + token_t *tok; + int aufd; + long au_cond; + uid_t uid; + gid_t gid; + pid_t pid = getpid(); + + /* If we are not auditing, don't cut an audit record; just return. */ + if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) { + if (errno == ENOSYS) + return; + errx(1, "login: Could not determine audit condition"); + } + if (au_cond == AUC_NOAUDIT) + return; + + if ((aufd = au_open()) == -1) + errx(1, "login: Audit Error: au_open() failed"); + + if (na) { + /* + * Non attributable event. Assuming that login is not called + * within a user's session => auid,asid == -1. + */ + if ((tok = au_to_subject32(-1, geteuid(), getegid(), -1, -1, + pid, -1, &tid)) == NULL) + errx(1, "login: Audit Error: au_to_subject32() failed"); + } else { + /* We know the subject -- so use its value instead. */ + uid = pwd->pw_uid; + gid = pwd->pw_gid; + if ((tok = au_to_subject32(uid, geteuid(), getegid(), uid, + gid, pid, pid, &tid)) == NULL) + errx(1, "login: Audit Error: au_to_subject32() failed"); + } + au_write(aufd, tok); + + /* Include the error message. */ + if ((tok = au_to_text(errmsg)) == NULL) + errx(1, "login: Audit Error: au_to_text() failed"); + au_write(aufd, tok); + + if ((tok = au_to_return32(1, errno)) == NULL) + errx(1, "login: Audit Error: au_to_return32() failed"); + au_write(aufd, tok); + + if (au_close(aufd, 1, AUE_login) == -1) + errx(1, "login: Audit Error: au_close() was not committed"); +} + +/* + * The following tokens are included in the audit record for a logout: + * header, subject, return. + */ +void +audit_logout(void) +{ + token_t *tok; + int aufd; + au_mask_t aumask; + auditinfo_t auinfo; + uid_t uid = pwd->pw_uid; + gid_t gid = pwd->pw_gid; + pid_t pid = getpid(); + long au_cond; + + /* If we are not auditing, don't cut an audit record; just return. */ + if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) { + if (errno == ENOSYS) + return; + errx(1, "login: Could not determine audit condition"); + } + if (au_cond == AUC_NOAUDIT) + return; + + if ((aufd = au_open()) == -1) + errx(1, "login: Audit Error: au_open() failed"); + + /* The subject that is created (euid, egid of the current process). */ + if ((tok = au_to_subject32(uid, geteuid(), getegid(), uid, gid, pid, + pid, &tid)) == NULL) + errx(1, "login: Audit Error: au_to_subject32() failed"); + au_write(aufd, tok); + + if ((tok = au_to_return32(0, 0)) == NULL) + errx(1, "login: Audit Error: au_to_return32() failed"); + au_write(aufd, tok); + + if (au_close(aufd, 1, AUE_logout) == -1) + errx(1, "login: Audit Record was not committed."); +}