1/*
2 * Copyright (c) 2005 Apple Computer, Inc.
3 * All rights reserved.
4 *
5 * @APPLE_BSD_LICENSE_HEADER_START@
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1.  Redistributions of source code must retain the above copyright
12 *     notice, this list of conditions and the following disclaimer.
13 * 2.  Redistributions in binary form must reproduce the above copyright
14 *     notice, this list of conditions and the following disclaimer in the
15 *     documentation and/or other materials provided with the distribution.
16 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
17 *     its contributors may be used to endorse or promote products derived
18 *     from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
21 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
24 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * @APPLE_BSD_LICENSE_HEADER_END@
32 */
33
34#ifdef USE_BSM_AUDIT
35
36#include <sys/cdefs.h>
37__FBSDID("$FreeBSD: src/usr.bin/login/login_audit.c,v 1.2 2007/05/07 11:01:36 dwmalone Exp $");
38
39#include <sys/types.h>
40
41#include <bsm/libbsm.h>
42#include <bsm/audit_uevents.h>
43#include <bsm/audit_session.h>
44
45#include <err.h>
46#include <errno.h>
47#include <pwd.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <strings.h>
51#include <unistd.h>
52
53#include "login.h"
54
55/*
56 * Audit data
57 */
58au_tid_addr_t tid;
59
60/*
61 * The following tokens are included in the audit record for a successful
62 * login: header, subject, return.
63 */
64void
65au_login_success(int fflag)
66{
67	token_t *tok;
68	int aufd;
69	auditinfo_addr_t auinfo;
70	uid_t uid = pwd->pw_uid;
71	gid_t gid = pwd->pw_gid;
72	pid_t pid = getpid();
73	long au_cond;
74
75	/* Determine whether auditing is enabled. */
76 	if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
77		if (errno == ENOSYS)
78			return;
79		errx(1, "login: Could not determine audit condition");
80	}
81
82	/* Initialize with the current audit info. */
83	if (getaudit_addr(&auinfo, sizeof(auinfo)) < 0) {
84		err(1, "getaudit_addr");
85	}
86	auinfo.ai_auid = pwd->pw_uid;
87	memcpy(&auinfo.ai_termid, &tid, sizeof(auinfo.ai_termid));
88
89	/* Do the SessionCreate() equivalent. */
90	if (!fflag) {
91		auinfo.ai_asid = AU_ASSIGN_ASID;
92		auinfo.ai_flags |= AU_SESSION_FLAG_HAS_TTY;
93		auinfo.ai_flags |= AU_SESSION_FLAG_HAS_AUTHENTICATED;
94	}
95
96	if (au_cond != AUC_NOAUDIT) {
97		/* Compute and set the user's preselection mask. */
98		if (au_user_mask(pwd->pw_name, &auinfo.ai_mask) < 0) {
99			errx(1, "login: Could not set audit mask\n");
100		}
101	}
102
103	if (setaudit_addr(&auinfo, sizeof(auinfo)) < 0)
104		err(1, "login: setaudit_addr failed");
105
106	char *session = NULL;
107	asprintf(&session, "%x", auinfo.ai_asid);
108	if (NULL == session) {
109		errx(1, "asprintf failed");
110	}
111	setenv("SECURITYSESSIONID", session, 1);
112	free(session);
113
114	/* If we are not auditing, don't cut an audit record; just return. */
115	if (au_cond == AUC_NOAUDIT)
116		return;
117
118	if ((aufd = au_open()) == -1)
119		errx(1,"login: Audit Error: au_open() failed");
120
121	if ((tok = au_to_subject32_ex(uid, geteuid(), getegid(), uid, gid, pid,
122	    pid, &tid)) == NULL)
123		errx(1, "login: Audit Error: au_to_subject32() failed");
124	au_write(aufd, tok);
125
126	if ((tok = au_to_return32(0, 0)) == NULL)
127		errx(1, "login: Audit Error: au_to_return32() failed");
128	au_write(aufd, tok);
129
130	if (au_close(aufd, 1, AUE_login) == -1)
131		errx(1, "login: Audit Record was not committed.");
132}
133
134/*
135 * The following tokens are included in the audit record for failed
136 * login attempts: header, subject, text, return.
137 */
138void
139au_login_fail(const char *errmsg, int na)
140{
141	token_t *tok;
142	int aufd;
143	long au_cond;
144	uid_t uid;
145	gid_t gid;
146	pid_t pid = getpid();
147
148	/* If we are not auditing, don't cut an audit record; just return. */
149 	if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
150		if (errno == ENOSYS)
151			return;
152		errx(1, "login: Could not determine audit condition");
153	}
154	if (au_cond == AUC_NOAUDIT)
155		return;
156
157	if ((aufd = au_open()) == -1)
158		errx(1, "login: Audit Error: au_open() failed");
159
160	if (na) {
161		/*
162		 * Non attributable event.  Assuming that login is not called
163		 * within a user's session => auid,asid == -1.
164		 */
165		if ((tok = au_to_subject32_ex(-1, geteuid(), getegid(), -1, -1,
166		    pid, -1, &tid)) == NULL)
167			errx(1, "login: Audit Error: au_to_subject32() failed");
168	} else {
169		/* We know the subject -- so use its value instead. */
170		uid = pwd->pw_uid;
171		gid = pwd->pw_gid;
172		if ((tok = au_to_subject32_ex(uid, geteuid(), getegid(), uid,
173		    gid, pid, pid, &tid)) == NULL)
174			errx(1, "login: Audit Error: au_to_subject32() failed");
175	}
176	au_write(aufd, tok);
177
178	/* Include the error message. */
179	if ((tok = au_to_text(errmsg)) == NULL)
180		errx(1, "login: Audit Error: au_to_text() failed");
181	au_write(aufd, tok);
182
183	if ((tok = au_to_return32(1, errno)) == NULL)
184		errx(1, "login: Audit Error: au_to_return32() failed");
185	au_write(aufd, tok);
186
187	if (au_close(aufd, 1, AUE_login) == -1)
188		errx(1, "login: Audit Error: au_close() was not committed");
189}
190
191/*
192 * The following tokens are included in the audit record for a logout:
193 * header, subject, return.
194 */
195void
196audit_logout(void)
197{
198	token_t *tok;
199	int aufd;
200	uid_t uid = pwd->pw_uid;
201	gid_t gid = pwd->pw_gid;
202	pid_t pid = getpid();
203	long au_cond;
204
205	/* If we are not auditing, don't cut an audit record; just return. */
206 	if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
207		if (errno == ENOSYS)
208			return;
209		errx(1, "login: Could not determine audit condition");
210	}
211	if (au_cond == AUC_NOAUDIT)
212		return;
213
214	if ((aufd = au_open()) == -1)
215		errx(1, "login: Audit Error: au_open() failed");
216
217	/* The subject that is created (euid, egid of the current process). */
218	if ((tok = au_to_subject32_ex(uid, geteuid(), getegid(), uid, gid, pid,
219	    pid, &tid)) == NULL)
220		errx(1, "login: Audit Error: au_to_subject32() failed");
221	au_write(aufd, tok);
222
223	if ((tok = au_to_return32(0, 0)) == NULL)
224		errx(1, "login: Audit Error: au_to_return32() failed");
225	au_write(aufd, tok);
226
227	if (au_close(aufd, 1, AUE_logout) == -1)
228		errx(1, "login: Audit Record was not committed.");
229}
230
231#endif /* USE_BSM_AUDIT */
232