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 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/param.h>
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <sys/fcntl.h>
31 #include <bsm/audit.h>
32 #include <bsm/audit_record.h>
33 #include <bsm/audit_uevents.h>
34 #include <bsm/libbsm.h>
35 #include <bsm/audit_private.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <syslog.h>
39 #include <pwd.h>
40 #include <netinet/in.h>
41 #include <tsol/label.h>
42 #include <locale.h>
43 #include "generic.h"
44 
45 #ifdef C2_DEBUG
46 #define	dprintf(x) { (void) printf x; }
47 #else
48 #define	dprintf(x)
49 #endif
50 
51 #define	UNKNOWN_CMD	"???"
52 
53 static au_event_t	event;
54 static int		audit_rexd_status = 0;
55 
56 static char *
57 build_cmd(char **cmd)
58 {
59 	int i, l;
60 	char *r;
61 
62 	if (cmd == NULL)
63 		return (NULL);
64 	/* count the total length of command line */
65 	for (i = 0, l = 0; cmd[i] != NULL; i++)
66 		l += strlen(cmd[i]) + 1;
67 
68 	if (l == 0)
69 		return (NULL);
70 	r = malloc(l);
71 	if (r != NULL) {
72 		for (i = 0; cmd[i] != NULL; i++) {
73 			(void) strcat(r, cmd[i]);
74 			if (cmd[i + 1] != NULL)
75 				(void) strcat(r, " ");
76 		}
77 	}
78 	return (r);
79 }
80 
81 static int
82 selected(uid, user, event, sf)
83 uid_t uid;
84 char	*user;
85 au_event_t	event;
86 int	sf;
87 {
88 	int	rc, sorf;
89 	char	naflags[512];
90 	struct au_mask mask;
91 
92 	mask.am_success = mask.am_failure = 0;
93 	if (uid > MAXEPHUID) {
94 		rc = getacna(naflags, 256); /* get non-attrib flags */
95 		if (rc == 0)
96 			(void) getauditflagsbin(naflags, &mask);
97 	} else {
98 		rc = au_user_mask(user, &mask);
99 	}
100 
101 	if (sf == 0)
102 		sorf = AU_PRS_SUCCESS;
103 	else if (sf == -1)
104 		sorf = AU_PRS_FAILURE;
105 	else
106 		sorf = AU_PRS_BOTH;
107 	rc = au_preselect(event, &mask, sorf, AU_PRS_REREAD);
108 	return (rc);
109 }
110 
111 void
112 audit_rexd_setup()
113 {
114 	dprintf(("audit_rexd_setup()\n"));
115 
116 	event = AUE_rexd;
117 }
118 
119 /* ARGSUSED */
120 static void
121 audit_rexd_session_setup(char *name, char *mach, uid_t uid)
122 {
123 	int			rc;
124 	au_mask_t		mask;
125 	struct auditinfo_addr	info;
126 
127 	if (getaudit_addr(&info, sizeof (info)) < 0) {
128 		perror("getaudit_addr");
129 		exit(1);
130 	}
131 
132 	info.ai_auid = uid;
133 	info.ai_asid = getpid();
134 
135 	mask.am_success = 0;
136 	mask.am_failure = 0;
137 
138 	(void) au_user_mask(name, &mask);
139 
140 	info.ai_mask.am_success  = mask.am_success;
141 	info.ai_mask.am_failure  = mask.am_failure;
142 
143 	rc = setaudit_addr(&info, sizeof (info));
144 	if (rc < 0) {
145 		perror("setaudit_addr");
146 	}
147 }
148 
149 void
150 audit_rexd_fail(msg, hostname, user, uid, gid, shell, cmd)
151 	char	*msg;		/* message containing failure information */
152 	char	*hostname;	/* hostname of machine requesting service */
153 	char	*user;		/* username of user requesting service */
154 	uid_t 	uid;		/* user id of user requesting service */
155 	gid_t	gid;		/* group of user requesting service */
156 	char	*shell;		/* login shell of user requesting service */
157 	char	**cmd;		/* argv to be executed locally */
158 {
159 	int	rd;		/* audit record descriptor */
160 	char	buf[256];	/* temporary buffer */
161 	char	*tbuf;		/* temporary buffer */
162 	int	tlen;
163 	const char *gtxt;	/* gettext return value */
164 	pid_t	pid;
165 	char	*cmdbuf;
166 	char	*audit_cmd[2] = {NULL, NULL};
167 	int	dont_free = 0;
168 	struct auditinfo_addr info;
169 
170 	dprintf(("audit_rexd_fail()\n"));
171 
172 	/*
173 	 * check if audit_rexd_fail() or audit_rexd_success()
174 	 * have been called already.
175 	 */
176 	if (audit_rexd_status == 1) {
177 		return;
178 	}
179 
180 	if (cannot_audit(0)) {
181 		return;
182 	}
183 
184 	/*
185 	 * set status to prevent multiple calls
186 	 * to audit_rexd_fail() and audit_rexd_success()
187 	 */
188 	audit_rexd_status = 1;
189 
190 	/* determine if we're preselected */
191 	if (!selected(uid, user, event, -1))
192 		return;
193 
194 	pid = getpid();
195 
196 	if (getaudit_addr(&info, sizeof (info)) < 0) {
197 		perror("getaudit_addr");
198 		exit(1);
199 	}
200 
201 	rd = au_open();
202 
203 	/* add subject token */
204 	(void) au_write(rd,
205 		au_to_subject_ex(uid, uid, gid, uid, gid, pid, pid,
206 			&info.ai_termid));
207 	if (is_system_labeled())
208 		(void) au_write(rd, au_to_mylabel());
209 
210 	/* add reason for failure */
211 	(void) au_write(rd, au_to_text(msg));
212 
213 	/* add hostname of machine requesting service */
214 	(void) snprintf(buf, sizeof (buf), dgettext(bsm_dom,
215 		"Remote execution requested by: %s"), hostname);
216 	(void) au_write(rd, au_to_text(buf));
217 
218 	/* add username of user requesting service */
219 	if (user == NULL)
220 		user = "???";
221 	(void) snprintf(buf, sizeof (buf), dgettext(bsm_dom,
222 	    "Username: %s"), user);
223 	(void) au_write(rd, au_to_text(buf));
224 
225 	(void) snprintf(buf, sizeof (buf), dgettext(bsm_dom,
226 	    "User id: %d"), uid);
227 	(void) au_write(rd, au_to_text(buf));
228 
229 	if (cmd == NULL) {
230 		audit_cmd[0] = shell;
231 		cmd = audit_cmd;
232 	}
233 
234 	cmdbuf = build_cmd(cmd);
235 	if (cmdbuf == NULL) {
236 		cmdbuf = UNKNOWN_CMD;
237 		dont_free = 1;
238 	}
239 
240 	gtxt = dgettext(bsm_dom, "Command line: %s");
241 	/* over estimate of size of buffer needed (%s is replaced) */
242 	tlen = strlen(cmdbuf) + strlen(gtxt) + 1;
243 
244 	if ((tbuf = malloc(tlen)) == NULL) {
245 		(void) au_close(rd, 0, 0);
246 		return;
247 	}
248 	(void) snprintf(tbuf, tlen, gtxt, cmdbuf);
249 	(void) au_write(rd, au_to_text(tbuf));
250 	(void) free(tbuf);
251 	if (!dont_free)
252 		(void) free(cmdbuf);
253 
254 	/* add return token */
255 #ifdef _LP64
256 	(void) au_write(rd, au_to_return64(-1, (int64_t)0));
257 #else
258 	(void) au_write(rd, au_to_return32(-1, (int32_t)0));
259 #endif
260 
261 	/* write audit record */
262 	if (au_close(rd, 1, event) < 0) {
263 		(void) au_close(rd, 0, 0);
264 		return;
265 	}
266 }
267 
268 void
269 audit_rexd_success(hostname, user, uid, gid, shell, cmd)
270 char	*hostname;	/* hostname of machine requesting service */
271 char	*user;		/* username of user requesting service, may be NULL */
272 uid_t 	uid;		/* user id of user requesting service */
273 gid_t	gid;		/* group of user requesting service */
274 char	*shell;		/* login shell of user requesting service */
275 char	**cmd;		/* argv to be executed locally, may be NULL */
276 {
277 	int	rd;			/* audit record descriptor */
278 	char	buf[256];	/* temporary buffer */
279 	char	*tbuf;		/* temporary buffer */
280 	int	tlen;
281 	const char *gtxt;
282 	pid_t	pid;
283 	char	*cmdbuf;
284 	char	*audit_cmd[2] = {NULL, NULL};
285 	int	dont_free = 0;
286 	struct auditinfo_addr info;
287 	char	*empty = "";
288 
289 	dprintf(("audit_rexd_success()\n"));
290 
291 	/*
292 	 * check if audit_rexd_fail() or audit_rexd_success()
293 	 * have been called already.
294 	 */
295 	if (audit_rexd_status == 1) {
296 		return;
297 	}
298 
299 	if (cannot_audit(0)) {
300 		return;
301 	}
302 
303 	/* a little bullet proofing... */
304 
305 	if (hostname == NULL)
306 		hostname = empty;
307 	if (shell == NULL)
308 		shell = empty;
309 
310 	/*
311 	 * set status to prevent multiple calls
312 	 * to audit_rexd_fail() and audit_rexd_success()
313 	 */
314 	audit_rexd_status = 1;
315 
316 	/* determine if we're preselected */
317 	if (!selected(uid, user, event, 0))
318 		goto rexd_audit_session;
319 
320 	pid = getpid();
321 
322 	if (getaudit_addr(&info, sizeof (info)) < 0) {
323 		perror("getaudit_addr");
324 		exit(1);
325 	}
326 
327 	rd = au_open();
328 
329 	/* add subject token */
330 	(void) au_write(rd,
331 		au_to_subject_ex(uid, uid, gid, uid, gid, pid, pid,
332 			&info.ai_termid));
333 	if (is_system_labeled())
334 		(void) au_write(rd, au_to_mylabel());
335 
336 	/* add hostname of machine requesting service */
337 
338 	(void) snprintf(buf, sizeof (buf), dgettext(bsm_dom,
339 		"Remote execution requested by: %s"), hostname);
340 	(void) au_write(rd, au_to_text(buf));
341 
342 	/* add username at machine requesting service */
343 	(void) snprintf(buf, sizeof (buf), dgettext(bsm_dom,
344 	    "Username: %s"), user);
345 	(void) au_write(rd, au_to_text(buf));
346 
347 	if (cmd == NULL) {
348 		audit_cmd[0] = shell;
349 		cmd = audit_cmd;
350 	}
351 
352 	cmdbuf = build_cmd(cmd);
353 	if (cmdbuf == NULL) {
354 		cmdbuf = UNKNOWN_CMD;
355 		dont_free = 1;
356 	}
357 
358 	gtxt = dgettext(bsm_dom, "Command line: %s");
359 	tlen = strlen(cmdbuf) + strlen(gtxt) + 1;
360 
361 	if ((tbuf = malloc(tlen)) == NULL) {
362 		(void) au_close(rd, 0, 0);
363 		goto rexd_audit_session;
364 	}
365 
366 	(void) snprintf(tbuf, tlen, gtxt, cmdbuf);
367 	(void) au_write(rd, au_to_text(tbuf));
368 	(void) free(tbuf);
369 	if (!dont_free)
370 		(void) free(cmdbuf);
371 
372 	/* add return token */
373 #ifdef _LP64
374 	(void) au_write(rd, au_to_return64(0, (int64_t)0));
375 #else
376 	(void) au_write(rd, au_to_return32(0, (int32_t)0));
377 #endif
378 
379 	/* write audit record */
380 	if (au_close(rd, 1, event) < 0) {
381 		(void) au_close(rd, 0, 0);
382 	}
383 
384 rexd_audit_session:
385 	audit_rexd_session_setup(user, hostname, uid);
386 }
387