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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
41 * Establish an association between a filter and filtee. Both the filter and
42 * filtee already exist in the internal hash table, since auditing registers
43 * objects (la_objopen()) before it registers filters (la_objfilter()).
46 filter(Crle_desc
*crle
, const char *filter
, const char *str
, const char *filtee
)
48 Hash_ent
*fltrent
, *flteent
;
53 * Locate the filter. Mark the underlying object as the filter to
54 * reflect that no matter how it is referenced, it's a filter.
56 if ((fltrent
= get_hash(crle
->c_strtbl
, (Addr
)filter
, 0,
57 HASH_FND_ENT
)) == NULL
)
59 if ((fltrent
= get_hash(crle
->c_strtbl
, (Addr
)fltrent
->e_obj
->o_path
, 0,
60 HASH_FND_ENT
)) == NULL
)
62 fltrent
->e_obj
->o_flags
|= RTC_OBJ_FILTER
;
65 * Locate the filtee. Mark the referencing object as the filtee, as
66 * this is the object referenced by the filter.
68 if ((flteent
= get_hash(crle
->c_strtbl
, (Addr
)filtee
, 0,
69 HASH_FND_ENT
)) == NULL
)
71 flteent
->e_flags
|= RTC_OBJ_FILTEE
;
74 * Traverse the filter list using the filters real name. If ld.so.1
75 * inspects the resulting configuration file for filters, it's the
76 * objects real name that will be used (PATHNAME()).
78 for (APLIST_TRAVERSE(crle
->c_flt
, idx
, flt
)) {
80 * Determine whether this filter and filtee string pair already
83 if ((strcmp(flt
->f_fent
->e_obj
->o_path
,
84 fltrent
->e_obj
->o_path
) != 0) &&
85 (strcmp(flt
->f_str
, str
) != 0))
89 * Add this filtee additional association.
91 if (aplist_append(&(flt
->f_filtee
), flteent
,
100 * This is a new filter descriptor. Add this new filtee association.
102 if (((flt
= malloc(sizeof (Flt_desc
))) == NULL
) ||
103 ((flt
->f_strsz
= strlen(str
) + 1) == 0) ||
104 ((flt
->f_str
= malloc(flt
->f_strsz
)) == NULL
)) {
106 (void) fprintf(stderr
, MSG_INTL(MSG_SYS_MALLOC
),
107 crle
->c_name
, strerror(err
));
110 if ((aplist_append(&(crle
->c_flt
), flt
, AL_CNT_CRLE
) == NULL
) ||
111 (aplist_append(&(flt
->f_filtee
), flteent
, AL_CNT_CRLE
) == NULL
))
114 flt
->f_fent
= fltrent
;
115 (void) memcpy((void *)flt
->f_str
, (void *)str
, flt
->f_strsz
);
116 crle
->c_strsize
+= flt
->f_strsz
;
117 crle
->c_fltrnum
+= 1;
118 crle
->c_fltenum
+= 2; /* Account for null filtee desc. */
124 * Establish the dependencies of an ELF object and add them to the internal
125 * configuration information. This information is gathered by using libcrle.so.1
126 * as an audit library - this is akin to using ldd(1) only simpler.
129 depend(Crle_desc
*crle
, const char *name
, Half flags
, GElf_Ehdr
*ehdr
)
136 * If we're dealing with a dynamic executable we'll execute it,
137 * otherwise we'll preload the shared object with one of the lddstub's.
139 if (ehdr
->e_type
== ET_EXEC
) {
143 exename
= conv_lddstub(M_CLASS
);
148 * Set up a pipe through which the audit library will write the
151 if (pipe(fildes
) == -1) {
153 (void) fprintf(stderr
, MSG_INTL(MSG_SYS_PIPE
),
154 crle
->c_name
, strerror(err
));
159 * Fork ourselves to run our executable and collect its dependencies.
161 if ((pid
= fork()) == -1) {
163 (void) fprintf(stderr
, MSG_INTL(MSG_SYS_FORK
),
164 crle
->c_name
, strerror(err
));
170 * Parent. Read each dependency from the audit library. The read
171 * side of the pipe is attached to stdio to make obtaining the
172 * individual dependencies easier.
174 int error
= 0, status
;
176 char buffer
[PATH_MAX
];
178 (void) close(fildes
[1]);
179 if ((fd
= fdopen(fildes
[0], MSG_ORIG(MSG_STR_READ
))) != NULL
) {
182 while (fgets(buffer
, PATH_MAX
, fd
) != NULL
) {
184 * Make sure we recognize the message, remove
185 * the newline (which allowed fgets() use) and
188 if (strncmp(MSG_ORIG(MSG_AUD_PRF
), buffer
,
192 str
= strrchr(buffer
, '\n');
194 str
= buffer
+ MSG_AUD_PRF_SIZE
;
196 if (strncmp(MSG_ORIG(MSG_AUD_DEPEND
),
197 str
, MSG_AUD_DEPEND_SIZE
) == 0) {
199 * Process any dependencies.
201 str
+= MSG_AUD_DEPEND_SIZE
;
203 if ((error
= inspect(crle
, str
,
204 (flags
& ~RTC_OBJ_GROUP
))) != 0)
207 } else if (strncmp(MSG_ORIG(MSG_AUD_FILTER
),
208 str
, MSG_AUD_FILTER_SIZE
) == 0) {
212 * Process any filters.
214 _flt
= str
+= MSG_AUD_FILTER_SIZE
;
215 _str
= strchr(str
, ':');
216 *_str
++ = '\0'; str
= _str
++;
217 str
= strrchr(str
, ')');
218 *str
++ = '\0'; str
++;
219 if ((error
= filter(crle
, _flt
, _str
,
227 while (wait(&status
) != pid
)
230 if (WIFSIGNALED(status
)) {
231 (void) fprintf(stderr
,
232 MSG_INTL(MSG_SYS_EXEC
), crle
->c_name
,
233 exename
, (WSIGMASK
& status
),
234 ((status
& WCOREFLG
) ?
235 MSG_INTL(MSG_SYS_CORE
) :
236 MSG_ORIG(MSG_STR_EMPTY
)));
244 char efds
[MSG_ENV_AUD_FD_SIZE
+ 10];
248 (void) close(fildes
[0]);
251 * Child. Set up environment variables to enable and identify
252 * auditing. Initialize CRLE_FD and LD_FLAGS strings.
254 (void) snprintf(efds
, (MSG_ENV_AUD_FD_SIZE
+ 10),
255 MSG_ORIG(MSG_ENV_AUD_FD
), fildes
[1]);
256 (void) snprintf(eldf
, PATH_MAX
, MSG_ORIG(MSG_ENV_LD_FLAGS
));
259 * If asked to dump a group of dependencies make sure any
260 * lazily-loaded objects get processed - (append loadavail to
263 if (flags
& RTC_OBJ_GROUP
)
264 (void) strcat(eldf
, MSG_ORIG(MSG_LDFLG_LOADAVAIL
));
267 * Put LD_PRELOAD= in the environment if necessary.
270 (void) snprintf(epld
, PATH_MAX
,
271 MSG_ORIG(MSG_ENV_LD_PRELOAD
), preload
);
275 * Put strings in the environment for exec().
276 * NOTE, use of automatic variables for construction of the
277 * environment variables is legitimate here, as they are local
278 * to the child process and are established solely for exec().
280 if ((putenv(efds
) != 0) || (putenv(crle
->c_audit
) != 0) ||
281 (putenv(eldf
) != 0) || (preload
&& (putenv(epld
) != 0))) {
283 (void) fprintf(stderr
, MSG_INTL(MSG_SYS_PUTENV
),
284 crle
->c_name
, strerror(err
));
288 if (execlp(exename
, exename
, 0) == -1) {