1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25#include <sys/types.h>
26#include <stdio.h>
27#include <unistd.h>
28#include <sys/fcntl.h>
29#include <bsm/audit.h>
30#include <bsm/audit_record.h>
31#include <bsm/audit_uevents.h>
32#include <bsm/libbsm.h>
33#include <bsm/audit_private.h>
34#include <stdlib.h>
35#include <string.h>
36#include <syslog.h>
37#include <pwd.h>
38#include <netinet/in.h>
39#include <tsol/label.h>
40#include <locale.h>
41#include "generic.h"
42
43#ifdef C2_DEBUG
44#define	dprintf(x) { (void) printf x; }
45#else
46#define	dprintf(x)
47#endif
48
49static au_event_t	event;
50static int		audit_rexecd_status = 0;
51
52static int
53selected(uid, user, event, sf)
54uid_t uid;
55char	*user;
56au_event_t	event;
57int	sf;
58{
59	int		sorf;
60	struct au_mask	mask;
61
62	mask.am_success = mask.am_failure = 0;
63	if (uid > MAXEPHUID) {
64		/* get non-attrib flags */
65		(void) auditon(A_GETKMASK, (caddr_t)&mask, sizeof (mask));
66	} else {
67		(void) au_user_mask(user, &mask);
68	}
69
70	if (sf == 0) {
71		sorf = AU_PRS_SUCCESS;
72	} else if (sf == -1) {
73		sorf = AU_PRS_FAILURE;
74	} else {
75		sorf = AU_PRS_BOTH;
76	}
77
78	return (au_preselect(event, &mask, sorf, AU_PRS_REREAD));
79}
80
81void
82audit_rexecd_setup()
83{
84	dprintf(("audit_rexecd_setup()\n"));
85
86	event = AUE_rexecd;
87}
88
89
90static void
91audit_rexecd_session_setup(char *name, char *mach, uid_t uid)
92{
93	int			rc;
94	au_mask_t		mask;
95	struct auditinfo_addr	info;
96	uint32_t addr[4], type;
97
98	info.ai_auid = uid;
99	info.ai_asid = getpid();
100
101	mask.am_success = 0;
102	mask.am_failure = 0;
103
104	(void) au_user_mask(name, &mask);
105
106	info.ai_mask.am_success  = mask.am_success;
107	info.ai_mask.am_failure  = mask.am_failure;
108
109	rc = aug_get_machine(mach, addr, &type);
110	if (rc < 0) {
111		perror("get address");
112	}
113	info.ai_termid.at_port = aug_get_port();
114	info.ai_termid.at_type    = type;
115	info.ai_termid.at_addr[0] = addr[0];
116	info.ai_termid.at_addr[1] = addr[1];
117	info.ai_termid.at_addr[2] = addr[2];
118	info.ai_termid.at_addr[3] = addr[3];
119
120	rc = setaudit_addr(&info, sizeof (info));
121	if (rc < 0) {
122		perror("setaudit");
123	}
124}
125
126void
127audit_rexecd_fail(msg, hostname, user, cmdbuf)
128char	*msg;		/* message containing failure information */
129char	*hostname;	/* hostname of machine requesting service */
130char	*user;		/* username of user requesting service */
131char	*cmdbuf;	/* command line to be executed locally */
132{
133	int	rd;		/* audit record descriptor */
134	char	buf[256];	/* temporary buffer */
135	char	*tbuf;		/* temporary buffer */
136	int	tlen;
137	const char *gtxt;
138	uid_t 	uid;
139	gid_t	gid;
140	pid_t	pid;
141	au_tid_addr_t	tid;
142	struct passwd	*pwd;
143	uint32_t addr[4], type;
144	int rc;
145
146	dprintf(("audit_rexecd_fail()\n"));
147
148	/*
149	 * check if audit_rexecd_fail() or audit_rexecd_success()
150	 * have been called already.
151	 */
152	if (audit_rexecd_status == 1) {
153		return;
154	}
155
156	if (cannot_audit(0)) {
157		return;
158	}
159
160	/*
161	 * set status to prevent multiple calls
162	 * to audit_rexecd_fail() and audit_rexecd_success()
163	 */
164	audit_rexecd_status = 1;
165
166	pwd = getpwnam(user);
167	if (pwd == NULL) {
168		uid = (uid_t)-1;
169		gid = (gid_t)-1;
170	} else {
171		uid = pwd->pw_uid;
172		gid = pwd->pw_gid;
173	}
174
175	/* determine if we're preselected */
176	if (!selected(uid, user, event, -1))
177		return;
178
179	pid = getpid();
180	rc = aug_get_machine(hostname, addr, &type);
181	if (rc < 0) {
182		perror("get address");
183	}
184
185	tid.at_port    = aug_get_port();
186	tid.at_addr[0] = addr[0];
187	tid.at_addr[1] = addr[1];
188	tid.at_addr[2] = addr[2];
189	tid.at_addr[3] = addr[3];
190	tid.at_type    = type;
191
192	rd = au_open();
193
194	/* add subject token */
195	(void) au_write(rd,
196		au_to_subject_ex(uid, uid, gid, uid, gid, pid, pid, &tid));
197	if (is_system_labeled())
198		(void) au_write(rd, au_to_mylabel());
199
200	/* add reason for failure */
201	(void) au_write(rd, au_to_text(msg));
202
203	/* add hostname of machine requesting service */
204	(void) snprintf(buf, sizeof (buf), dgettext(bsm_dom,
205		"Remote execution requested by: %s"), hostname);
206	(void) au_write(rd, au_to_text(buf));
207
208	/* add username of user requesting service */
209	(void) snprintf(buf, sizeof (buf), dgettext(bsm_dom,
210		"Username: %s"), user);
211	(void) au_write(rd, au_to_text(buf));
212
213	/* add command line to be executed locally */
214	gtxt = dgettext(bsm_dom, "Command line: %s");
215	tlen = strlen(gtxt) + strlen(cmdbuf) + 1;
216	if ((tbuf = malloc(tlen)) == NULL) {
217		(void) au_close(rd, 0, 0);
218		return;
219	}
220	(void) snprintf(tbuf, tlen, gtxt, cmdbuf);
221	(void) au_write(rd, au_to_text(tbuf));
222	(void) free(tbuf);
223
224	/* add return token */
225#ifdef _LP64
226	(void) au_write(rd, au_to_return64(-1, (int64_t)0));
227#else
228	(void) au_write(rd, au_to_return32(-1, (int32_t)0));
229#endif
230
231	/* write audit record */
232	if (au_close(rd, 1, event) < 0) {
233		(void) au_close(rd, 0, 0);
234		return;
235	}
236}
237
238void
239audit_rexecd_success(hostname, user, cmdbuf)
240char	*hostname;	/* hostname of machine requesting service */
241char	*user;		/* username of user requesting service */
242char	*cmdbuf;	/* command line to be executed locally */
243{
244	int	rd;		/* audit record descriptor */
245	char	buf[256];	/* temporary buffer */
246	char	*tbuf;		/* temporary buffer */
247	int	tlen;
248	const char *gtxt;
249	uid_t 	uid;
250	gid_t	gid;
251	pid_t	pid;
252	au_tid_addr_t	tid;
253	struct passwd	*pwd;
254	uint32_t addr[4], type;
255	int rc;
256
257	dprintf(("audit_rexecd_success()\n"));
258
259	/*
260	 * check if audit_rexecd_fail() or audit_rexecd_success()
261	 * have been called already.
262	 */
263	if (audit_rexecd_status == 1) {
264		return;
265	}
266
267	if (cannot_audit(0)) {
268		return;
269	}
270
271	/*
272	 * set status to prevent multiple calls
273	 * to audit_rexecd_fail() and audit_rexecd_success()
274	 */
275	audit_rexecd_status = 1;
276
277	pwd = getpwnam(user);
278	if (pwd == NULL) {
279		uid = (uid_t)-1;
280		gid = (gid_t)-1;
281	} else {
282		uid = pwd->pw_uid;
283		gid = pwd->pw_gid;
284	}
285
286	/* determine if we're preselected */
287	if (!selected(uid, user, event, 0))
288		goto rexecd_audit_session;
289
290	pid = getpid();
291	rc = aug_get_machine(hostname, addr, &type);
292	if (rc < 0) {
293		perror("get address");
294	}
295
296	tid.at_port    = aug_get_port();
297	tid.at_addr[0] = addr[0];
298	tid.at_addr[1] = addr[1];
299	tid.at_addr[2] = addr[2];
300	tid.at_addr[3] = addr[3];
301	tid.at_type    = type;
302
303	rd = au_open();
304
305	/* add subject token */
306	(void) au_write(rd,
307		au_to_subject_ex(uid, uid, gid, uid, gid, pid, pid, &tid));
308	if (is_system_labeled())
309		(void) au_write(rd, au_to_mylabel());
310
311	/* add hostname of machine requesting service */
312	(void) snprintf(buf, sizeof (buf), dgettext(bsm_dom,
313		"Remote execution requested by: %s"), hostname);
314	(void) au_write(rd, au_to_text(buf));
315
316	/* add username at machine requesting service */
317	(void) snprintf(buf, sizeof (buf), dgettext(bsm_dom,
318	    "Username: %s"), user);
319	(void) au_write(rd, au_to_text(buf));
320
321	/* add command line to be executed locally */
322	gtxt = dgettext(bsm_dom, "Command line: %s");
323	tlen = strlen(gtxt) + strlen(cmdbuf) + 1;
324	if ((tbuf = malloc(tlen)) == NULL) {
325		(void) au_close(rd, 0, 0);
326	} else {
327		(void) snprintf(tbuf, tlen, gtxt, cmdbuf);
328		(void) au_write(rd, au_to_text(tbuf));
329		(void) free(tbuf);
330
331		/* add return token */
332#ifdef _LP64
333		(void) au_write(rd, au_to_return64(0, (int64_t)0));
334#else
335		(void) au_write(rd, au_to_return32(0, (int32_t)0));
336#endif
337
338		/* write audit record */
339		if (au_close(rd, 1, event) < 0) {
340			(void) au_close(rd, 0, 0);
341		}
342	}
343
344rexecd_audit_session:
345	audit_rexecd_session_setup(user, hostname, uid);
346}
347