1114522Sdougb/*
2114522Sdougb * Copyright (c) 2005 Apple Computer, Inc.
3114522Sdougb * All rights reserved.
4114522Sdougb *
5114522Sdougb * @APPLE_BSD_LICENSE_HEADER_START@
6114522Sdougb *
7114522Sdougb * Redistribution and use in source and binary forms, with or without
8114522Sdougb * modification, are permitted provided that the following conditions
9114522Sdougb * are met:
10114522Sdougb *
11114522Sdougb * 1.  Redistributions of source code must retain the above copyright
12114522Sdougb *     notice, this list of conditions and the following disclaimer.
13114522Sdougb * 2.  Redistributions in binary form must reproduce the above copyright
14114522Sdougb *     notice, this list of conditions and the following disclaimer in the
15114522Sdougb *     documentation and/or other materials provided with the distribution.
16114522Sdougb * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
17114522Sdougb *     its contributors may be used to endorse or promote products derived
18114522Sdougb *     from this software without specific prior written permission.
19114522Sdougb *
20114522Sdougb * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
21114522Sdougb * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22114522Sdougb * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23114522Sdougb * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
24114522Sdougb * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25114522Sdougb * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26114522Sdougb * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27114522Sdougb * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28114522Sdougb * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29114522Sdougb * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30114522Sdougb *
31114522Sdougb * @APPLE_BSD_LICENSE_HEADER_END@
32114522Sdougb */
33114522Sdougb
34114522Sdougb#include <sys/cdefs.h>
35114522Sdougb__FBSDID("$FreeBSD$");
36114522Sdougb
37114522Sdougb#include <sys/types.h>
38114522Sdougb
39114522Sdougb#include <bsm/libbsm.h>
40114522Sdougb#include <bsm/audit_uevents.h>
41114522Sdougb
42114522Sdougb#include <err.h>
43114522Sdougb#include <errno.h>
44114522Sdougb#include <pwd.h>
45114522Sdougb#include <stdio.h>
46114522Sdougb#include <strings.h>
47114522Sdougb#include <unistd.h>
48114522Sdougb
49114522Sdougb#include "login.h"
50114522Sdougb
51114522Sdougb/*
52114522Sdougb * Audit data
53114522Sdougb */
54114522Sdougbstatic au_tid_t tid;
55114522Sdougb
56114522Sdougb/*
57114522Sdougb * The following tokens are included in the audit record for a successful
58114522Sdougb * login: header, subject, return.
59114522Sdougb */
60114522Sdougbvoid
61114522Sdougbau_login_success(void)
62114522Sdougb{
63114522Sdougb	token_t *tok;
64114522Sdougb	int aufd;
65114522Sdougb	au_mask_t aumask;
66114522Sdougb	auditinfo_t auinfo;
67114522Sdougb	uid_t uid = pwd->pw_uid;
68114522Sdougb	gid_t gid = pwd->pw_gid;
69114522Sdougb	pid_t pid = getpid();
70114522Sdougb	int au_cond;
71114522Sdougb
72114522Sdougb	/* If we are not auditing, don't cut an audit record; just return. */
73114522Sdougb 	if (auditon(A_GETCOND, &au_cond, sizeof(au_cond)) < 0) {
74114522Sdougb		if (errno == ENOSYS)
75114522Sdougb			return;
76114522Sdougb		errx(1, "login: Could not determine audit condition");
77114522Sdougb	}
78114522Sdougb	if (au_cond == AUC_NOAUDIT)
79114522Sdougb		return;
80114522Sdougb
81114522Sdougb	/* Compute and set the user's preselection mask. */
82114522Sdougb	if (au_user_mask(pwd->pw_name, &aumask) == -1)
83114522Sdougb		errx(1, "login: Could not set audit mask\n");
84114522Sdougb
85114522Sdougb	/* Set the audit info for the user. */
86114522Sdougb	auinfo.ai_auid = uid;
87114522Sdougb	auinfo.ai_asid = pid;
88114522Sdougb	bcopy(&tid, &auinfo.ai_termid, sizeof(auinfo.ai_termid));
89114522Sdougb	bcopy(&aumask, &auinfo.ai_mask, sizeof(auinfo.ai_mask));
90114522Sdougb	if (setaudit(&auinfo) != 0)
91114522Sdougb		err(1, "login: setaudit failed");
92114522Sdougb
93114522Sdougb	if ((aufd = au_open()) == -1)
94114522Sdougb		errx(1,"login: Audit Error: au_open() failed");
95114522Sdougb
96114522Sdougb	if ((tok = au_to_subject32(uid, geteuid(), getegid(), uid, gid, pid,
97114522Sdougb	    pid, &tid)) == NULL)
98114522Sdougb		errx(1, "login: Audit Error: au_to_subject32() failed");
99114522Sdougb	au_write(aufd, tok);
100114522Sdougb
101114522Sdougb	if ((tok = au_to_return32(0, 0)) == NULL)
102114522Sdougb		errx(1, "login: Audit Error: au_to_return32() failed");
103114522Sdougb	au_write(aufd, tok);
104114522Sdougb
105114522Sdougb	if (au_close(aufd, 1, AUE_login) == -1)
106114522Sdougb		errx(1, "login: Audit Record was not committed.");
107114522Sdougb}
108114522Sdougb
109114522Sdougb/*
110114522Sdougb * The following tokens are included in the audit record for failed
111114522Sdougb * login attempts: header, subject, text, return.
112114522Sdougb */
113114522Sdougbvoid
114114522Sdougbau_login_fail(const char *errmsg, int na)
115114522Sdougb{
116114522Sdougb	token_t *tok;
117114522Sdougb	int aufd;
118114522Sdougb	int au_cond;
119114522Sdougb	uid_t uid;
120114522Sdougb	gid_t gid;
121114522Sdougb	pid_t pid = getpid();
122114522Sdougb
123114522Sdougb	/* If we are not auditing, don't cut an audit record; just return. */
124114522Sdougb 	if (auditon(A_GETCOND, &au_cond, sizeof(au_cond)) < 0) {
125114522Sdougb		if (errno == ENOSYS)
126114522Sdougb			return;
127114522Sdougb		errx(1, "login: Could not determine audit condition");
128114522Sdougb	}
129114522Sdougb	if (au_cond == AUC_NOAUDIT)
130114522Sdougb		return;
131114522Sdougb
132114522Sdougb	if ((aufd = au_open()) == -1)
133114522Sdougb		errx(1, "login: Audit Error: au_open() failed");
134114522Sdougb
135114522Sdougb	if (na) {
136114522Sdougb		/*
137114522Sdougb		 * Non attributable event.  Assuming that login is not called
138114522Sdougb		 * within a user's session => auid,asid == -1.
139114522Sdougb		 */
140114522Sdougb		if ((tok = au_to_subject32(-1, geteuid(), getegid(), -1, -1,
141114522Sdougb		    pid, -1, &tid)) == NULL)
142114522Sdougb			errx(1, "login: Audit Error: au_to_subject32() failed");
143114522Sdougb	} else {
144114522Sdougb		/* We know the subject -- so use its value instead. */
145114522Sdougb		uid = pwd->pw_uid;
146114522Sdougb		gid = pwd->pw_gid;
147114522Sdougb		if ((tok = au_to_subject32(uid, geteuid(), getegid(), uid,
148114522Sdougb		    gid, pid, pid, &tid)) == NULL)
149114522Sdougb			errx(1, "login: Audit Error: au_to_subject32() failed");
150114522Sdougb	}
151114522Sdougb	au_write(aufd, tok);
152114522Sdougb
153114522Sdougb	/* Include the error message. */
154114522Sdougb	if ((tok = au_to_text(errmsg)) == NULL)
155114522Sdougb		errx(1, "login: Audit Error: au_to_text() failed");
156114522Sdougb	au_write(aufd, tok);
157114522Sdougb
158114522Sdougb	if ((tok = au_to_return32(1, errno)) == NULL)
159114522Sdougb		errx(1, "login: Audit Error: au_to_return32() failed");
160114522Sdougb	au_write(aufd, tok);
161114522Sdougb
162114522Sdougb	if (au_close(aufd, 1, AUE_login) == -1)
163114522Sdougb		errx(1, "login: Audit Error: au_close() was not committed");
164114522Sdougb}
165114522Sdougb
166114522Sdougb/*
167114522Sdougb * The following tokens are included in the audit record for a logout:
168114522Sdougb * header, subject, return.
169114522Sdougb */
170114522Sdougbvoid
171114522Sdougbaudit_logout(void)
172114522Sdougb{
173114522Sdougb	token_t *tok;
174114522Sdougb	int aufd;
175114522Sdougb	uid_t uid = pwd->pw_uid;
176114522Sdougb	gid_t gid = pwd->pw_gid;
177114522Sdougb	pid_t pid = getpid();
178114522Sdougb	int au_cond;
179114522Sdougb
180114522Sdougb	/* If we are not auditing, don't cut an audit record; just return. */
181114522Sdougb 	if (auditon(A_GETCOND, &au_cond, sizeof(int)) < 0) {
182114522Sdougb		if (errno == ENOSYS)
183114522Sdougb			return;
184114522Sdougb		errx(1, "login: Could not determine audit condition");
185114522Sdougb	}
186114522Sdougb	if (au_cond == AUC_NOAUDIT)
187114522Sdougb		return;
188114522Sdougb
189114522Sdougb	if ((aufd = au_open()) == -1)
190114522Sdougb		errx(1, "login: Audit Error: au_open() failed");
191114522Sdougb
192114522Sdougb	/* The subject that is created (euid, egid of the current process). */
193114522Sdougb	if ((tok = au_to_subject32(uid, geteuid(), getegid(), uid, gid, pid,
194114522Sdougb	    pid, &tid)) == NULL)
195		errx(1, "login: Audit Error: au_to_subject32() failed");
196	au_write(aufd, tok);
197
198	if ((tok = au_to_return32(0, 0)) == NULL)
199		errx(1, "login: Audit Error: au_to_return32() failed");
200	au_write(aufd, tok);
201
202	if (au_close(aufd, 1, AUE_logout) == -1)
203		errx(1, "login: Audit Record was not committed.");
204}
205