17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5c13de8f6Sab196087 * Common Development and Distribution License (the "License").
6c13de8f6Sab196087 * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22*57ef7aa9SRod Evans * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <stdio.h>
287c478bd9Sstevel@tonic-gate #include <errno.h>
297c478bd9Sstevel@tonic-gate #include <unistd.h>
307c478bd9Sstevel@tonic-gate #include <string.h>
317c478bd9Sstevel@tonic-gate #include <wait.h>
327c478bd9Sstevel@tonic-gate #include <limits.h>
337c478bd9Sstevel@tonic-gate #include <gelf.h>
347c478bd9Sstevel@tonic-gate #include "machdep.h"
357c478bd9Sstevel@tonic-gate #include "sgs.h"
367c478bd9Sstevel@tonic-gate #include "conv.h"
377c478bd9Sstevel@tonic-gate #include "_crle.h"
387c478bd9Sstevel@tonic-gate #include "msg.h"
397c478bd9Sstevel@tonic-gate
407c478bd9Sstevel@tonic-gate /*
417c478bd9Sstevel@tonic-gate * Establish an association between a filter and filtee. Both the filter and
427c478bd9Sstevel@tonic-gate * filtee already exist in the internal hash table, since auditing registers
437c478bd9Sstevel@tonic-gate * objects (la_objopen()) before it registers filters (la_objfilter()).
447c478bd9Sstevel@tonic-gate */
457c478bd9Sstevel@tonic-gate static int
filter(Crle_desc * crle,const char * filter,const char * str,const char * filtee)467c478bd9Sstevel@tonic-gate filter(Crle_desc *crle, const char *filter, const char *str, const char *filtee)
477c478bd9Sstevel@tonic-gate {
487c478bd9Sstevel@tonic-gate Hash_ent *fltrent, *flteent;
497c478bd9Sstevel@tonic-gate Flt_desc *flt;
50*57ef7aa9SRod Evans Aliste idx;
517c478bd9Sstevel@tonic-gate
527c478bd9Sstevel@tonic-gate /*
537c478bd9Sstevel@tonic-gate * Locate the filter. Mark the underlying object as the filter to
547c478bd9Sstevel@tonic-gate * reflect that no matter how it is referenced, it's a filter.
557c478bd9Sstevel@tonic-gate */
567c478bd9Sstevel@tonic-gate if ((fltrent = get_hash(crle->c_strtbl, (Addr)filter, 0,
57*57ef7aa9SRod Evans HASH_FND_ENT)) == NULL)
587c478bd9Sstevel@tonic-gate return (1);
597c478bd9Sstevel@tonic-gate if ((fltrent = get_hash(crle->c_strtbl, (Addr)fltrent->e_obj->o_path, 0,
60*57ef7aa9SRod Evans HASH_FND_ENT)) == NULL)
617c478bd9Sstevel@tonic-gate return (1);
627c478bd9Sstevel@tonic-gate fltrent->e_obj->o_flags |= RTC_OBJ_FILTER;
637c478bd9Sstevel@tonic-gate
647c478bd9Sstevel@tonic-gate /*
657c478bd9Sstevel@tonic-gate * Locate the filtee. Mark the referencing object as the filtee, as
667c478bd9Sstevel@tonic-gate * this is the object referenced by the filter.
677c478bd9Sstevel@tonic-gate */
687c478bd9Sstevel@tonic-gate if ((flteent = get_hash(crle->c_strtbl, (Addr)filtee, 0,
69*57ef7aa9SRod Evans HASH_FND_ENT)) == NULL)
707c478bd9Sstevel@tonic-gate return (1);
717c478bd9Sstevel@tonic-gate flteent->e_flags |= RTC_OBJ_FILTEE;
727c478bd9Sstevel@tonic-gate
737c478bd9Sstevel@tonic-gate /*
747c478bd9Sstevel@tonic-gate * Traverse the filter list using the filters real name. If ld.so.1
757c478bd9Sstevel@tonic-gate * inspects the resulting configuration file for filters, it's the
767c478bd9Sstevel@tonic-gate * objects real name that will be used (PATHNAME()).
777c478bd9Sstevel@tonic-gate */
78*57ef7aa9SRod Evans for (APLIST_TRAVERSE(crle->c_flt, idx, flt)) {
797c478bd9Sstevel@tonic-gate /*
807c478bd9Sstevel@tonic-gate * Determine whether this filter and filtee string pair already
817c478bd9Sstevel@tonic-gate * exist.
827c478bd9Sstevel@tonic-gate */
837c478bd9Sstevel@tonic-gate if ((strcmp(flt->f_fent->e_obj->o_path,
847c478bd9Sstevel@tonic-gate fltrent->e_obj->o_path) != 0) &&
857c478bd9Sstevel@tonic-gate (strcmp(flt->f_str, str) != 0))
867c478bd9Sstevel@tonic-gate continue;
877c478bd9Sstevel@tonic-gate
887c478bd9Sstevel@tonic-gate /*
897c478bd9Sstevel@tonic-gate * Add this filtee additional association.
907c478bd9Sstevel@tonic-gate */
91*57ef7aa9SRod Evans if (aplist_append(&(flt->f_filtee), flteent,
92*57ef7aa9SRod Evans AL_CNT_CRLE) == NULL)
937c478bd9Sstevel@tonic-gate return (1);
947c478bd9Sstevel@tonic-gate
957c478bd9Sstevel@tonic-gate crle->c_fltenum++;
967c478bd9Sstevel@tonic-gate return (0);
977c478bd9Sstevel@tonic-gate }
987c478bd9Sstevel@tonic-gate
997c478bd9Sstevel@tonic-gate /*
1007c478bd9Sstevel@tonic-gate * This is a new filter descriptor. Add this new filtee association.
1017c478bd9Sstevel@tonic-gate */
102*57ef7aa9SRod Evans if (((flt = malloc(sizeof (Flt_desc))) == NULL) ||
1037c478bd9Sstevel@tonic-gate ((flt->f_strsz = strlen(str) + 1) == 0) ||
104*57ef7aa9SRod Evans ((flt->f_str = malloc(flt->f_strsz)) == NULL)) {
1057c478bd9Sstevel@tonic-gate int err = errno;
1067c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC),
1077c478bd9Sstevel@tonic-gate crle->c_name, strerror(err));
1087c478bd9Sstevel@tonic-gate return (1);
1097c478bd9Sstevel@tonic-gate }
110*57ef7aa9SRod Evans if ((aplist_append(&(crle->c_flt), flt, AL_CNT_CRLE) == NULL) ||
111*57ef7aa9SRod Evans (aplist_append(&(flt->f_filtee), flteent, AL_CNT_CRLE) == NULL))
1127c478bd9Sstevel@tonic-gate return (1);
1137c478bd9Sstevel@tonic-gate
1147c478bd9Sstevel@tonic-gate flt->f_fent = fltrent;
1157c478bd9Sstevel@tonic-gate (void) memcpy((void *)flt->f_str, (void *)str, flt->f_strsz);
1167c478bd9Sstevel@tonic-gate crle->c_strsize += flt->f_strsz;
1177c478bd9Sstevel@tonic-gate crle->c_fltrnum += 1;
1187c478bd9Sstevel@tonic-gate crle->c_fltenum += 2; /* Account for null filtee desc. */
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate return (0);
1217c478bd9Sstevel@tonic-gate }
1227c478bd9Sstevel@tonic-gate
1237c478bd9Sstevel@tonic-gate /*
1247c478bd9Sstevel@tonic-gate * Establish the dependencies of an ELF object and add them to the internal
1257c478bd9Sstevel@tonic-gate * configuration information. This information is gathered by using libcrle.so.1
1267c478bd9Sstevel@tonic-gate * as an audit library - this is akin to using ldd(1) only simpler.
1277c478bd9Sstevel@tonic-gate */
1287c478bd9Sstevel@tonic-gate int
depend(Crle_desc * crle,const char * name,Half flags,GElf_Ehdr * ehdr)1297c478bd9Sstevel@tonic-gate depend(Crle_desc *crle, const char *name, Half flags, GElf_Ehdr *ehdr)
1307c478bd9Sstevel@tonic-gate {
1317c478bd9Sstevel@tonic-gate const char *exename;
1327c478bd9Sstevel@tonic-gate const char *preload;
1337c478bd9Sstevel@tonic-gate int fildes[2], pid;
1347c478bd9Sstevel@tonic-gate
1357c478bd9Sstevel@tonic-gate /*
1367c478bd9Sstevel@tonic-gate * If we're dealing with a dynamic executable we'll execute it,
1377c478bd9Sstevel@tonic-gate * otherwise we'll preload the shared object with one of the lddstub's.
1387c478bd9Sstevel@tonic-gate */
1397c478bd9Sstevel@tonic-gate if (ehdr->e_type == ET_EXEC) {
1407c478bd9Sstevel@tonic-gate exename = name;
141*57ef7aa9SRod Evans preload = NULL;
1427c478bd9Sstevel@tonic-gate } else {
143c13de8f6Sab196087 exename = conv_lddstub(M_CLASS);
1447c478bd9Sstevel@tonic-gate preload = name;
1457c478bd9Sstevel@tonic-gate }
1467c478bd9Sstevel@tonic-gate
1477c478bd9Sstevel@tonic-gate /*
1487c478bd9Sstevel@tonic-gate * Set up a pipe through which the audit library will write the
1497c478bd9Sstevel@tonic-gate * dependencies.
1507c478bd9Sstevel@tonic-gate */
1517c478bd9Sstevel@tonic-gate if (pipe(fildes) == -1) {
1527c478bd9Sstevel@tonic-gate int err = errno;
1537c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_SYS_PIPE),
1547c478bd9Sstevel@tonic-gate crle->c_name, strerror(err));
1557c478bd9Sstevel@tonic-gate return (1);
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate
1587c478bd9Sstevel@tonic-gate /*
1597c478bd9Sstevel@tonic-gate * Fork ourselves to run our executable and collect its dependencies.
1607c478bd9Sstevel@tonic-gate */
1617c478bd9Sstevel@tonic-gate if ((pid = fork()) == -1) {
1627c478bd9Sstevel@tonic-gate int err = errno;
1637c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_SYS_FORK),
1647c478bd9Sstevel@tonic-gate crle->c_name, strerror(err));
1657c478bd9Sstevel@tonic-gate return (1);
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate
1687c478bd9Sstevel@tonic-gate if (pid) {
1697c478bd9Sstevel@tonic-gate /*
1707c478bd9Sstevel@tonic-gate * Parent. Read each dependency from the audit library. The read
1717c478bd9Sstevel@tonic-gate * side of the pipe is attached to stdio to make obtaining the
1727c478bd9Sstevel@tonic-gate * individual dependencies easier.
1737c478bd9Sstevel@tonic-gate */
1747c478bd9Sstevel@tonic-gate int error = 0, status;
1757c478bd9Sstevel@tonic-gate FILE *fd;
1767c478bd9Sstevel@tonic-gate char buffer[PATH_MAX];
1777c478bd9Sstevel@tonic-gate
1787c478bd9Sstevel@tonic-gate (void) close(fildes[1]);
1797c478bd9Sstevel@tonic-gate if ((fd = fdopen(fildes[0], MSG_ORIG(MSG_STR_READ))) != NULL) {
1807c478bd9Sstevel@tonic-gate char *str;
1817c478bd9Sstevel@tonic-gate
1827c478bd9Sstevel@tonic-gate while (fgets(buffer, PATH_MAX, fd) != NULL) {
1837c478bd9Sstevel@tonic-gate /*
1847c478bd9Sstevel@tonic-gate * Make sure we recognize the message, remove
1857c478bd9Sstevel@tonic-gate * the newline (which allowed fgets() use) and
1867c478bd9Sstevel@tonic-gate * register the name;
1877c478bd9Sstevel@tonic-gate */
1887c478bd9Sstevel@tonic-gate if (strncmp(MSG_ORIG(MSG_AUD_PRF), buffer,
1897c478bd9Sstevel@tonic-gate MSG_AUD_PRF_SIZE))
1907c478bd9Sstevel@tonic-gate continue;
1917c478bd9Sstevel@tonic-gate
1927c478bd9Sstevel@tonic-gate str = strrchr(buffer, '\n');
1937c478bd9Sstevel@tonic-gate *str = '\0';
1947c478bd9Sstevel@tonic-gate str = buffer + MSG_AUD_PRF_SIZE;
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gate if (strncmp(MSG_ORIG(MSG_AUD_DEPEND),
1977c478bd9Sstevel@tonic-gate str, MSG_AUD_DEPEND_SIZE) == 0) {
1987c478bd9Sstevel@tonic-gate /*
1997c478bd9Sstevel@tonic-gate * Process any dependencies.
2007c478bd9Sstevel@tonic-gate */
2017c478bd9Sstevel@tonic-gate str += MSG_AUD_DEPEND_SIZE;
2027c478bd9Sstevel@tonic-gate
2037c478bd9Sstevel@tonic-gate if ((error = inspect(crle, str,
2047c478bd9Sstevel@tonic-gate (flags & ~RTC_OBJ_GROUP))) != 0)
2057c478bd9Sstevel@tonic-gate break;
2067c478bd9Sstevel@tonic-gate
2077c478bd9Sstevel@tonic-gate } else if (strncmp(MSG_ORIG(MSG_AUD_FILTER),
2087c478bd9Sstevel@tonic-gate str, MSG_AUD_FILTER_SIZE) == 0) {
2097c478bd9Sstevel@tonic-gate char *_flt, *_str;
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate /*
2127c478bd9Sstevel@tonic-gate * Process any filters.
2137c478bd9Sstevel@tonic-gate */
2147c478bd9Sstevel@tonic-gate _flt = str += MSG_AUD_FILTER_SIZE;
2157c478bd9Sstevel@tonic-gate _str = strchr(str, ':');
2167c478bd9Sstevel@tonic-gate *_str++ = '\0'; str = _str++;
2177c478bd9Sstevel@tonic-gate str = strrchr(str, ')');
2187c478bd9Sstevel@tonic-gate *str++ = '\0'; str++;
2197c478bd9Sstevel@tonic-gate if ((error = filter(crle, _flt, _str,
2207c478bd9Sstevel@tonic-gate str)) != 0)
2217c478bd9Sstevel@tonic-gate break;
2227c478bd9Sstevel@tonic-gate }
2237c478bd9Sstevel@tonic-gate }
2247c478bd9Sstevel@tonic-gate } else
2257c478bd9Sstevel@tonic-gate error = errno;
2267c478bd9Sstevel@tonic-gate
2277c478bd9Sstevel@tonic-gate while (wait(&status) != pid)
2287c478bd9Sstevel@tonic-gate ;
2297c478bd9Sstevel@tonic-gate if (status) {
2307c478bd9Sstevel@tonic-gate if (WIFSIGNALED(status)) {
2317c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
2327c478bd9Sstevel@tonic-gate MSG_INTL(MSG_SYS_EXEC), crle->c_name,
2337c478bd9Sstevel@tonic-gate exename, (WSIGMASK & status),
2347c478bd9Sstevel@tonic-gate ((status & WCOREFLG) ?
2357c478bd9Sstevel@tonic-gate MSG_INTL(MSG_SYS_CORE) :
2367c478bd9Sstevel@tonic-gate MSG_ORIG(MSG_STR_EMPTY)));
2377c478bd9Sstevel@tonic-gate }
2387c478bd9Sstevel@tonic-gate error = status;
2397c478bd9Sstevel@tonic-gate }
2407c478bd9Sstevel@tonic-gate (void) fclose(fd);
2417c478bd9Sstevel@tonic-gate
2427c478bd9Sstevel@tonic-gate return (error);
2437c478bd9Sstevel@tonic-gate } else {
2447c478bd9Sstevel@tonic-gate char efds[MSG_ENV_AUD_FD_SIZE + 10];
2457c478bd9Sstevel@tonic-gate char epld[PATH_MAX];
2467c478bd9Sstevel@tonic-gate char eldf[PATH_MAX];
2477c478bd9Sstevel@tonic-gate
2487c478bd9Sstevel@tonic-gate (void) close(fildes[0]);
2497c478bd9Sstevel@tonic-gate
2507c478bd9Sstevel@tonic-gate /*
2517c478bd9Sstevel@tonic-gate * Child. Set up environment variables to enable and identify
2527c478bd9Sstevel@tonic-gate * auditing. Initialize CRLE_FD and LD_FLAGS strings.
2537c478bd9Sstevel@tonic-gate */
2547c478bd9Sstevel@tonic-gate (void) snprintf(efds, (MSG_ENV_AUD_FD_SIZE + 10),
2557c478bd9Sstevel@tonic-gate MSG_ORIG(MSG_ENV_AUD_FD), fildes[1]);
2567c478bd9Sstevel@tonic-gate (void) snprintf(eldf, PATH_MAX, MSG_ORIG(MSG_ENV_LD_FLAGS));
2577c478bd9Sstevel@tonic-gate
2587c478bd9Sstevel@tonic-gate /*
2597c478bd9Sstevel@tonic-gate * If asked to dump a group of dependencies make sure any
2607c478bd9Sstevel@tonic-gate * lazily-loaded objects get processed - (append loadavail to
2617c478bd9Sstevel@tonic-gate * LD_FLAGS=confgen).
2627c478bd9Sstevel@tonic-gate */
2637c478bd9Sstevel@tonic-gate if (flags & RTC_OBJ_GROUP)
2647c478bd9Sstevel@tonic-gate (void) strcat(eldf, MSG_ORIG(MSG_LDFLG_LOADAVAIL));
2657c478bd9Sstevel@tonic-gate
2667c478bd9Sstevel@tonic-gate /*
2677c478bd9Sstevel@tonic-gate * Put LD_PRELOAD= in the environment if necessary.
2687c478bd9Sstevel@tonic-gate */
2697c478bd9Sstevel@tonic-gate if (preload) {
2707c478bd9Sstevel@tonic-gate (void) snprintf(epld, PATH_MAX,
2717c478bd9Sstevel@tonic-gate MSG_ORIG(MSG_ENV_LD_PRELOAD), preload);
2727c478bd9Sstevel@tonic-gate }
2737c478bd9Sstevel@tonic-gate
2747c478bd9Sstevel@tonic-gate /*
2757c478bd9Sstevel@tonic-gate * Put strings in the environment for exec().
2767c478bd9Sstevel@tonic-gate * NOTE, use of automatic variables for construction of the
2777c478bd9Sstevel@tonic-gate * environment variables is legitimate here, as they are local
2787c478bd9Sstevel@tonic-gate * to the child process and are established solely for exec().
2797c478bd9Sstevel@tonic-gate */
2807c478bd9Sstevel@tonic-gate if ((putenv(efds) != 0) || (putenv(crle->c_audit) != 0) ||
2817c478bd9Sstevel@tonic-gate (putenv(eldf) != 0) || (preload && (putenv(epld) != 0))) {
2827c478bd9Sstevel@tonic-gate int err = errno;
2837c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_SYS_PUTENV),
2847c478bd9Sstevel@tonic-gate crle->c_name, strerror(err));
2857c478bd9Sstevel@tonic-gate return (1);
2867c478bd9Sstevel@tonic-gate }
2877c478bd9Sstevel@tonic-gate
2887c478bd9Sstevel@tonic-gate if (execlp(exename, exename, 0) == -1) {
2897c478bd9Sstevel@tonic-gate _exit(errno);
2907c478bd9Sstevel@tonic-gate /* NOTREACHED */
2917c478bd9Sstevel@tonic-gate }
2927c478bd9Sstevel@tonic-gate }
293b3fbe5e6Sseizo return (0);
2947c478bd9Sstevel@tonic-gate }
295