xref: /titanic_44/usr/src/cmd/sgs/rtld/common/paths.c (revision b533f56bf95137d3de6666bd923e15ec373ea611)
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
55aefb655Srie  * Common Development and Distribution License (the "License").
65aefb655Srie  * 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  */
21c174926fSrie 
227c478bd9Sstevel@tonic-gate /*
232020b2b6SRod Evans  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257257d1b4Sraf 
267257d1b4Sraf /*
277257d1b4Sraf  *	Copyright (c) 1988 AT&T
287257d1b4Sraf  *	  All Rights Reserved
297257d1b4Sraf  */
30*b533f56bSRobert Mustacchi /*
31*b533f56bSRobert Mustacchi  * Copyright (c) 2012, Joyent, Inc.  All rights reserved.
32*b533f56bSRobert Mustacchi  */
337257d1b4Sraf 
347c478bd9Sstevel@tonic-gate /*
357c478bd9Sstevel@tonic-gate  * PATH setup and search directory functions.
367c478bd9Sstevel@tonic-gate  */
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include	<stdio.h>
3956deab07SRod Evans #include	<unistd.h>
407c478bd9Sstevel@tonic-gate #include	<limits.h>
417c478bd9Sstevel@tonic-gate #include	<fcntl.h>
427c478bd9Sstevel@tonic-gate #include	<string.h>
435aefb655Srie #include	<debug.h>
445aefb655Srie #include	<conv.h>
457c478bd9Sstevel@tonic-gate #include	"_rtld.h"
467c478bd9Sstevel@tonic-gate #include	"msg.h"
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate /*
4956deab07SRod Evans  * Default and secure dependency search path initialization.
5056deab07SRod Evans  */
5156deab07SRod Evans void
set_dirs(Alist ** alpp,Spath_defn * sdp,uint_t flags)5256deab07SRod Evans set_dirs(Alist **alpp, Spath_defn *sdp, uint_t flags)
5356deab07SRod Evans {
5456deab07SRod Evans 	while (sdp->sd_name) {
5556deab07SRod Evans 		Pdesc	*pdp;
5656deab07SRod Evans 
57dde769a2SRod Evans 		if ((pdp = alist_append(alpp, NULL, sizeof (Pdesc),
5856deab07SRod Evans 		    AL_CNT_SPATH)) == NULL)
5956deab07SRod Evans 			return;
6056deab07SRod Evans 
6156deab07SRod Evans 		pdp->pd_pname = (char *)sdp->sd_name;
6256deab07SRod Evans 		pdp->pd_plen = sdp->sd_len;
6356deab07SRod Evans 		pdp->pd_flags = flags;
6456deab07SRod Evans 		sdp++;
6556deab07SRod Evans 	}
6656deab07SRod Evans }
6756deab07SRod Evans 
6856deab07SRod Evans static void
print_default_dirs(Lm_list * lml,Alist * alp,int search)6956deab07SRod Evans print_default_dirs(Lm_list *lml, Alist *alp, int search)
7056deab07SRod Evans {
7156deab07SRod Evans 	uint_t	flags = 0;
7256deab07SRod Evans 	int	num = 0;
7356deab07SRod Evans 	Aliste	idx;
7456deab07SRod Evans 	Pdesc	*pdp;
7556deab07SRod Evans 
7656deab07SRod Evans 	if (search)
7756deab07SRod Evans 		(void) printf(MSG_INTL(MSG_LDD_PTH_BGNDFL));
7856deab07SRod Evans 
7956deab07SRod Evans 	for (ALIST_TRAVERSE(alp, idx, pdp)) {
8056deab07SRod Evans 		flags = pdp->pd_flags;
8156deab07SRod Evans 
8256deab07SRod Evans 		if (search) {
8356deab07SRod Evans 			const char	*fmt;
8456deab07SRod Evans 
8556deab07SRod Evans 			if (num++)
8656deab07SRod Evans 				fmt = MSG_ORIG(MSG_LDD_FMT_PATHN);
8756deab07SRod Evans 			else
8856deab07SRod Evans 				fmt = MSG_ORIG(MSG_LDD_FMT_PATH1);
8956deab07SRod Evans 
9056deab07SRod Evans 			(void) printf(fmt, pdp->pd_pname);
9156deab07SRod Evans 		} else
9256deab07SRod Evans 			DBG_CALL(Dbg_libs_path(lml, pdp->pd_pname,
9356deab07SRod Evans 			    pdp->pd_flags, config->c_name));
9456deab07SRod Evans 	}
9556deab07SRod Evans 
9656deab07SRod Evans 	if (search) {
9756deab07SRod Evans 		if (flags & LA_SER_CONFIG)
9856deab07SRod Evans 			(void) printf(MSG_INTL(MSG_LDD_PTH_ENDDFLC),
9956deab07SRod Evans 			    config->c_name);
10056deab07SRod Evans 		else
10156deab07SRod Evans 			(void) printf(MSG_INTL(MSG_LDD_PTH_ENDDFL));
10256deab07SRod Evans 	}
10356deab07SRod Evans }
10456deab07SRod Evans 
10556deab07SRod Evans /*
1067c478bd9Sstevel@tonic-gate  * Given a search rule type, return a list of directories to search according
1077c478bd9Sstevel@tonic-gate  * to the specified rule.
1087c478bd9Sstevel@tonic-gate  */
10956deab07SRod Evans static Alist **
get_dir_list(uchar_t rules,Rt_map * lmp,uint_t flags)1109aa23310Srie get_dir_list(uchar_t rules, Rt_map *lmp, uint_t flags)
1117c478bd9Sstevel@tonic-gate {
11256deab07SRod Evans 	Alist	**dalpp = NULL;
1137c478bd9Sstevel@tonic-gate 	Lm_list *lml = LIST(lmp);
1147c478bd9Sstevel@tonic-gate 	int	search;
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	/*
1177c478bd9Sstevel@tonic-gate 	 * Determine whether ldd -s is in effect - ignore when we're searching
1187c478bd9Sstevel@tonic-gate 	 * for audit libraries as these will be added to their own link-map.
1197c478bd9Sstevel@tonic-gate 	 */
1207c478bd9Sstevel@tonic-gate 	if ((lml->lm_flags & LML_FLG_TRC_SEARCH) &&
1217c478bd9Sstevel@tonic-gate 	    ((FLAGS1(lmp) & FL1_RT_LDDSTUB) == 0) &&
1227c478bd9Sstevel@tonic-gate 	    ((flags & FLG_RT_AUDIT) == 0))
1237c478bd9Sstevel@tonic-gate 		search = 1;
1247c478bd9Sstevel@tonic-gate 	else
1257c478bd9Sstevel@tonic-gate 		search = 0;
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	switch (rules) {
1287c478bd9Sstevel@tonic-gate 	case RPLENV:
1297c478bd9Sstevel@tonic-gate 		/*
1307c478bd9Sstevel@tonic-gate 		 * Initialize the replaceable environment variable
1317c478bd9Sstevel@tonic-gate 		 * (LD_LIBRARY_PATH) search path list.  Note, we always call
1327c478bd9Sstevel@tonic-gate 		 * Dbg_libs_path() so that every library lookup diagnostic can
1337c478bd9Sstevel@tonic-gate 		 * be preceded with the appropriate search path information.
1347c478bd9Sstevel@tonic-gate 		 */
1357c478bd9Sstevel@tonic-gate 		if (rpl_libpath) {
13656deab07SRod Evans 			uint_t	mode = (LA_SER_LIBPATH | PD_FLG_UNIQUE);
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 			/*
1397c478bd9Sstevel@tonic-gate 			 * Note, this path may have originated from the users
1407c478bd9Sstevel@tonic-gate 			 * environment or from a configuration file.
1417c478bd9Sstevel@tonic-gate 			 */
1427c478bd9Sstevel@tonic-gate 			if (env_info & ENV_INF_PATHCFG)
1437c478bd9Sstevel@tonic-gate 				mode |= LA_SER_CONFIG;
1447c478bd9Sstevel@tonic-gate 
1455aefb655Srie 			DBG_CALL(Dbg_libs_path(lml, rpl_libpath, mode,
146c174926fSrie 			    config->c_name));
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 			/*
1497c478bd9Sstevel@tonic-gate 			 * For ldd(1) -s, indicate the search paths that'll
150247b82a1SRod Evans 			 * be used.  If this is a secure application then some
1517c478bd9Sstevel@tonic-gate 			 * search paths may be ignored, therefore reset the
1527c478bd9Sstevel@tonic-gate 			 * rpl_libdirs pointer each time so that the
1537c478bd9Sstevel@tonic-gate 			 * diagnostics related to these unsecure directories
1547c478bd9Sstevel@tonic-gate 			 * will be output for each image loaded.
1557c478bd9Sstevel@tonic-gate 			 */
1567c478bd9Sstevel@tonic-gate 			if (search) {
1577c478bd9Sstevel@tonic-gate 				const char	*fmt;
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 				if (env_info & ENV_INF_PATHCFG)
1607c478bd9Sstevel@tonic-gate 					fmt = MSG_INTL(MSG_LDD_PTH_LIBPATHC);
1617c478bd9Sstevel@tonic-gate 				else
1627c478bd9Sstevel@tonic-gate 					fmt = MSG_INTL(MSG_LDD_PTH_LIBPATH);
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 				(void) printf(fmt, rpl_libpath, config->c_name);
1657c478bd9Sstevel@tonic-gate 			}
1667c478bd9Sstevel@tonic-gate 			if (rpl_libdirs && (rtld_flags & RT_FL_SECURE) &&
16756deab07SRod Evans 			    (search || DBG_ENABLED))
1682020b2b6SRod Evans 				remove_alist(&rpl_libdirs, 1);
16956deab07SRod Evans 
17056deab07SRod Evans 			if (rpl_libdirs == NULL) {
1717c478bd9Sstevel@tonic-gate 				/*
1727c478bd9Sstevel@tonic-gate 				 * If this is a secure application we need to
1737c478bd9Sstevel@tonic-gate 				 * be selective over what directories we use.
1747c478bd9Sstevel@tonic-gate 				 */
17556deab07SRod Evans 				(void) expand_paths(lmp, rpl_libpath,
17656deab07SRod Evans 				    &rpl_libdirs, AL_CNT_SEARCH, mode,
17708278a5eSRod Evans 				    PD_TKN_CAP);
1787c478bd9Sstevel@tonic-gate 			}
17956deab07SRod Evans 			dalpp = &rpl_libdirs;
1807c478bd9Sstevel@tonic-gate 		}
1817c478bd9Sstevel@tonic-gate 		break;
1827c478bd9Sstevel@tonic-gate 	case PRMENV:
1837c478bd9Sstevel@tonic-gate 		/*
1847c478bd9Sstevel@tonic-gate 		 * Initialize the permanent (LD_LIBRARY_PATH) search path list.
1857c478bd9Sstevel@tonic-gate 		 * This can only originate from a configuration file.  To be
1867c478bd9Sstevel@tonic-gate 		 * consistent with the debugging display of DEFENV (above),
1877c478bd9Sstevel@tonic-gate 		 * always call Dbg_libs_path().
1887c478bd9Sstevel@tonic-gate 		 */
1897c478bd9Sstevel@tonic-gate 		if (prm_libpath) {
1909aa23310Srie 			uint_t	mode =
19156deab07SRod Evans 			    (LA_SER_LIBPATH | LA_SER_CONFIG | PD_FLG_UNIQUE);
1929aa23310Srie 
1939aa23310Srie 			DBG_CALL(Dbg_libs_path(lml, prm_libpath, mode,
1949aa23310Srie 			    config->c_name));
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 			/*
1977c478bd9Sstevel@tonic-gate 			 * For ldd(1) -s, indicate the search paths that'll
198247b82a1SRod Evans 			 * be used.  If this is a secure application then some
1997c478bd9Sstevel@tonic-gate 			 * search paths may be ignored, therefore reset the
2007c478bd9Sstevel@tonic-gate 			 * prm_libdirs pointer each time so that the
2017c478bd9Sstevel@tonic-gate 			 * diagnostics related to these unsecure directories
2027c478bd9Sstevel@tonic-gate 			 * will be output for each image loaded.
2037c478bd9Sstevel@tonic-gate 			 */
2047c478bd9Sstevel@tonic-gate 			if (search)
2057c478bd9Sstevel@tonic-gate 				(void) printf(MSG_INTL(MSG_LDD_PTH_LIBPATHC),
2067c478bd9Sstevel@tonic-gate 				    prm_libpath, config->c_name);
2077c478bd9Sstevel@tonic-gate 			if (prm_libdirs && (rtld_flags & RT_FL_SECURE) &&
20856deab07SRod Evans 			    (search || DBG_ENABLED))
2092020b2b6SRod Evans 				remove_alist(&prm_libdirs, 1);
21056deab07SRod Evans 
21156deab07SRod Evans 			if (prm_libdirs == NULL) {
2127c478bd9Sstevel@tonic-gate 				/*
2137c478bd9Sstevel@tonic-gate 				 * If this is a secure application we need to
2147c478bd9Sstevel@tonic-gate 				 * be selective over what directories we use.
2157c478bd9Sstevel@tonic-gate 				 */
21656deab07SRod Evans 				(void) expand_paths(lmp, prm_libpath,
21756deab07SRod Evans 				    &prm_libdirs, AL_CNT_SEARCH, mode,
21808278a5eSRod Evans 				    PD_TKN_CAP);
2197c478bd9Sstevel@tonic-gate 			}
22056deab07SRod Evans 			dalpp = &prm_libdirs;
2217c478bd9Sstevel@tonic-gate 		}
2227c478bd9Sstevel@tonic-gate 		break;
2237c478bd9Sstevel@tonic-gate 	case RUNPATH:
2247c478bd9Sstevel@tonic-gate 		/*
2257c478bd9Sstevel@tonic-gate 		 * Initialize the runpath search path list.  To be consistent
2267c478bd9Sstevel@tonic-gate 		 * with the debugging display of DEFENV (above), always call
2277c478bd9Sstevel@tonic-gate 		 * Dbg_libs_path().
2287c478bd9Sstevel@tonic-gate 		 */
2297c478bd9Sstevel@tonic-gate 		if (RPATH(lmp)) {
2305aefb655Srie 			DBG_CALL(Dbg_libs_path(lml, RPATH(lmp), LA_SER_RUNPATH,
2317c478bd9Sstevel@tonic-gate 			    NAME(lmp)));
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 			/*
2347c478bd9Sstevel@tonic-gate 			 * For ldd(1) -s, indicate the search paths that'll
235247b82a1SRod Evans 			 * be used.  If this is a secure application then some
2367c478bd9Sstevel@tonic-gate 			 * search paths may be ignored, therefore reset the
2377c478bd9Sstevel@tonic-gate 			 * runlist pointer each time so that the diagnostics
2387c478bd9Sstevel@tonic-gate 			 * related to these unsecure directories will be
2397c478bd9Sstevel@tonic-gate 			 * output for each image loaded.
2407c478bd9Sstevel@tonic-gate 			 */
2417c478bd9Sstevel@tonic-gate 			if (search)
2421d1fba8aSrie 				(void) printf(MSG_INTL(MSG_LDD_PTH_RUNPATH),
2437c478bd9Sstevel@tonic-gate 				    RPATH(lmp), NAME(lmp));
2447c478bd9Sstevel@tonic-gate 			if (RLIST(lmp) && (rtld_flags & RT_FL_SECURE) &&
24556deab07SRod Evans 			    (search || DBG_ENABLED))
2462020b2b6SRod Evans 				remove_alist(&RLIST(lmp), 1);
24756deab07SRod Evans 
24856deab07SRod Evans 			if (RLIST(lmp) == NULL) {
2497c478bd9Sstevel@tonic-gate 				/*
2507c478bd9Sstevel@tonic-gate 				 * If this is a secure application we need to
2517c478bd9Sstevel@tonic-gate 				 * be selective over what directories we use.
2527c478bd9Sstevel@tonic-gate 				 */
25356deab07SRod Evans 				(void) expand_paths(lmp, RPATH(lmp),
25456deab07SRod Evans 				    &RLIST(lmp), AL_CNT_SEARCH, LA_SER_RUNPATH,
25508278a5eSRod Evans 				    PD_TKN_CAP);
25656deab07SRod Evans 			}
25756deab07SRod Evans 			dalpp = &RLIST(lmp);
2587c478bd9Sstevel@tonic-gate 		}
2597c478bd9Sstevel@tonic-gate 		break;
2607c478bd9Sstevel@tonic-gate 	case DEFAULT:
261*b533f56bSRobert Mustacchi 		/*
262*b533f56bSRobert Mustacchi 		 * If we have been requested to load an audit library through a
263*b533f56bSRobert Mustacchi 		 * DT_DEPAUDIT entry, then we treat this the same way that we
264*b533f56bSRobert Mustacchi 		 * handle a library that has been specified via a DT_NEEDED
265*b533f56bSRobert Mustacchi 		 * entry -- we check the default directories and not the
266*b533f56bSRobert Mustacchi 		 * secure directories.
267*b533f56bSRobert Mustacchi 		 */
2687c478bd9Sstevel@tonic-gate 		if ((FLAGS1(lmp) & FL1_RT_NODEFLIB) == 0) {
2697c478bd9Sstevel@tonic-gate 			if ((rtld_flags & RT_FL_SECURE) &&
270*b533f56bSRobert Mustacchi 			    ((flags & FLG_RT_PRELOAD) ||
271*b533f56bSRobert Mustacchi 			    ((flags & FLG_RT_AUDIT) && !(FLAGS1(lmp) &
272*b533f56bSRobert Mustacchi 			    FL1_RT_DEPAUD))))
27356deab07SRod Evans 				dalpp = LM_SECURE_DIRS(lmp)();
2747c478bd9Sstevel@tonic-gate 			else
27556deab07SRod Evans 				dalpp = LM_DEFAULT_DIRS(lmp)();
2767c478bd9Sstevel@tonic-gate 		}
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 		/*
2797c478bd9Sstevel@tonic-gate 		 * For ldd(1) -s, indicate the default paths that'll be used.
2807c478bd9Sstevel@tonic-gate 		 */
28156deab07SRod Evans 		if (dalpp && (search || DBG_ENABLED))
28256deab07SRod Evans 			print_default_dirs(lml, *dalpp, search);
2837c478bd9Sstevel@tonic-gate 		break;
2847c478bd9Sstevel@tonic-gate 	default:
2857c478bd9Sstevel@tonic-gate 		break;
2867c478bd9Sstevel@tonic-gate 	}
28756deab07SRod Evans 	return (dalpp);
2887c478bd9Sstevel@tonic-gate }
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate /*
29108278a5eSRod Evans  * Get the next directory in the search rules path.  The search path "cookie"
29256deab07SRod Evans  * provided by the caller (sdp) maintains the state of a search in progress.
29356deab07SRod Evans  *
29456deab07SRod Evans  * Typically, a search consists of a series of rules that govern the order of
29556deab07SRod Evans  * a search (ie. LD_LIBRARY_PATH, followed by RPATHS, followed by defaults).
29656deab07SRod Evans  * Each rule can establish a corresponding series of path names, which are
29756deab07SRod Evans  * maintained as an Alist.  The index within this Alist determines the present
29856deab07SRod Evans  * search directory.
2997c478bd9Sstevel@tonic-gate  */
30056deab07SRod Evans Pdesc *
get_next_dir(Spath_desc * sdp,Rt_map * lmp,uint_t flags)30156deab07SRod Evans get_next_dir(Spath_desc *sdp, Rt_map *lmp, uint_t flags)
3027c478bd9Sstevel@tonic-gate {
3037c478bd9Sstevel@tonic-gate 	/*
30456deab07SRod Evans 	 * Make sure there are still rules to process.
3057c478bd9Sstevel@tonic-gate 	 */
30656deab07SRod Evans 	while (*sdp->sp_rule) {
30756deab07SRod Evans 		Alist	*alp;
3087c478bd9Sstevel@tonic-gate 
30956deab07SRod Evans 		/*
31056deab07SRod Evans 		 * If an Alist for this rule already exists, use if, otherwise
31156deab07SRod Evans 		 * obtain an Alist for this rule.  Providing the Alist has
31256deab07SRod Evans 		 * content, and the present Alist index is less than the number
31356deab07SRod Evans 		 * of Alist members, return the associated path name descriptor.
31456deab07SRod Evans 		 */
31556deab07SRod Evans 		if ((sdp->sp_dalpp || ((sdp->sp_dalpp =
31656deab07SRod Evans 		    get_dir_list(*sdp->sp_rule, lmp, flags)) != NULL)) &&
31756deab07SRod Evans 		    ((alp = *sdp->sp_dalpp) != NULL) &&
31856deab07SRod Evans 		    (alist_nitems(alp) > sdp->sp_idx)) {
31956deab07SRod Evans 			return (alist_item(alp, sdp->sp_idx++));
3207c478bd9Sstevel@tonic-gate 		}
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 		/*
32356deab07SRod Evans 		 * If no Alist for this rule exists, or if this is the last
32456deab07SRod Evans 		 * element of this Alist, reset the Alist pointer and index,
32556deab07SRod Evans 		 * and prepare for the next rule.
32656deab07SRod Evans 		 */
32756deab07SRod Evans 		sdp->sp_rule++;
32856deab07SRod Evans 		sdp->sp_dalpp = NULL;
32956deab07SRod Evans 		sdp->sp_idx = 0;
33056deab07SRod Evans 	}
33156deab07SRod Evans 
33256deab07SRod Evans 	/*
33356deab07SRod Evans 	 * All rules and search paths have been exhausted.
3347c478bd9Sstevel@tonic-gate 	 */
335045cda30Srie 	return (NULL);
3367c478bd9Sstevel@tonic-gate }
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate /*
3397c478bd9Sstevel@tonic-gate  * Process a directory (runpath) or filename (needed or filter) string looking
3407c478bd9Sstevel@tonic-gate  * for tokens to expand.  Allocate a new buffer for the string.
3417c478bd9Sstevel@tonic-gate  */
3427c478bd9Sstevel@tonic-gate uint_t
expand(char ** name,size_t * len,char ** list,uint_t orig,uint_t omit,Rt_map * lmp)3437c478bd9Sstevel@tonic-gate expand(char **name, size_t *len, char **list, uint_t orig, uint_t omit,
3447c478bd9Sstevel@tonic-gate     Rt_map *lmp)
3457c478bd9Sstevel@tonic-gate {
3467c478bd9Sstevel@tonic-gate 	char	_name[PATH_MAX];
34756deab07SRod Evans 	char	*token = NULL, *oname, *ename, *optr, *_optr, *nptr, *_list;
3487c478bd9Sstevel@tonic-gate 	size_t	olen = 0, nlen = 0, _len;
3497c478bd9Sstevel@tonic-gate 	int	isaflag = 0;
3507c478bd9Sstevel@tonic-gate 	uint_t	flags = 0;
3515aefb655Srie 	Lm_list	*lml = LIST(lmp);
3527c478bd9Sstevel@tonic-gate 
35356deab07SRod Evans 	optr = _optr = oname = ename = *name;
35456deab07SRod Evans 	ename += *len;
3557c478bd9Sstevel@tonic-gate 	nptr = _name;
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	while ((olen < *len) && (nlen < PATH_MAX)) {
3587c478bd9Sstevel@tonic-gate 		uint_t	_flags;
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 		if ((*optr != '$') || ((olen - *len) == 1)) {
3617c478bd9Sstevel@tonic-gate 			/*
3627c478bd9Sstevel@tonic-gate 			 * When expanding paths while a configuration file
3637c478bd9Sstevel@tonic-gate 			 * exists that contains directory information, determine
3647c478bd9Sstevel@tonic-gate 			 * whether the path contains "./".  If so, we'll resolve
3657c478bd9Sstevel@tonic-gate 			 * the path later to remove these relative entries.
3667c478bd9Sstevel@tonic-gate 			 */
3677c478bd9Sstevel@tonic-gate 			if ((rtld_flags & RT_FL_DIRCFG) &&
3687c478bd9Sstevel@tonic-gate 			    (orig & LA_SER_MASK) && (*optr == '/') &&
3697c478bd9Sstevel@tonic-gate 			    (optr != oname) && (*(optr - 1) == '.'))
3707c478bd9Sstevel@tonic-gate 				flags |= TKN_DOTSLASH;
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 			olen++, optr++;
3737c478bd9Sstevel@tonic-gate 			continue;
3747c478bd9Sstevel@tonic-gate 		}
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 		/*
3777c478bd9Sstevel@tonic-gate 		 * Copy any string we've presently passed over to the new
3787c478bd9Sstevel@tonic-gate 		 * buffer.
3797c478bd9Sstevel@tonic-gate 		 */
3807c478bd9Sstevel@tonic-gate 		if ((_len = (optr - _optr)) != 0) {
3817c478bd9Sstevel@tonic-gate 			if ((nlen += _len) < PATH_MAX) {
3827c478bd9Sstevel@tonic-gate 				(void) strncpy(nptr, _optr, _len);
3837c478bd9Sstevel@tonic-gate 				nptr = nptr + _len;
3847c478bd9Sstevel@tonic-gate 			} else {
3855aefb655Srie 				eprintf(lml, ERR_FATAL,
3865aefb655Srie 				    MSG_INTL(MSG_ERR_EXPAND1), NAME(lmp),
3875aefb655Srie 				    oname);
3887c478bd9Sstevel@tonic-gate 				return (0);
3897c478bd9Sstevel@tonic-gate 			}
3907c478bd9Sstevel@tonic-gate 		}
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 		/*
3937c478bd9Sstevel@tonic-gate 		 * Skip the token delimiter and determine if a reserved token
3947c478bd9Sstevel@tonic-gate 		 * match is found.
3957c478bd9Sstevel@tonic-gate 		 */
3967c478bd9Sstevel@tonic-gate 		olen++, optr++;
3977c478bd9Sstevel@tonic-gate 		_flags = 0;
3987c478bd9Sstevel@tonic-gate 		token = 0;
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 		if (strncmp(optr, MSG_ORIG(MSG_TKN_ORIGIN),
4017c478bd9Sstevel@tonic-gate 		    MSG_TKN_ORIGIN_SIZE) == 0) {
4027c478bd9Sstevel@tonic-gate 			token = (char *)MSG_ORIG(MSG_TKN_ORIGIN);
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 			/*
4057c478bd9Sstevel@tonic-gate 			 * $ORIGIN expansion is required.  Determine this
4067c478bd9Sstevel@tonic-gate 			 * objects basename.  Expansion of $ORIGIN is allowed
4077c478bd9Sstevel@tonic-gate 			 * for secure applications but must be checked by the
4087c478bd9Sstevel@tonic-gate 			 * caller to insure the expanded path matches a
4097c478bd9Sstevel@tonic-gate 			 * registered secure name.
4107c478bd9Sstevel@tonic-gate 			 */
41156deab07SRod Evans 			if (((omit & PD_TKN_ORIGIN) == 0) &&
4127c478bd9Sstevel@tonic-gate 			    (((_len = DIRSZ(lmp)) != 0) ||
4137c478bd9Sstevel@tonic-gate 			    ((_len = fullpath(lmp, 0)) != 0))) {
4147c478bd9Sstevel@tonic-gate 				if ((nlen += _len) < PATH_MAX) {
4157c478bd9Sstevel@tonic-gate 					(void) strncpy(nptr,
4167c478bd9Sstevel@tonic-gate 					    ORIGNAME(lmp), _len);
4177c478bd9Sstevel@tonic-gate 					nptr = nptr +_len;
4187c478bd9Sstevel@tonic-gate 					olen += MSG_TKN_ORIGIN_SIZE;
4197c478bd9Sstevel@tonic-gate 					optr += MSG_TKN_ORIGIN_SIZE;
42056deab07SRod Evans 					_flags |= PD_TKN_ORIGIN;
4217c478bd9Sstevel@tonic-gate 				} else {
4225aefb655Srie 					eprintf(lml, ERR_FATAL,
4237c478bd9Sstevel@tonic-gate 					    MSG_INTL(MSG_ERR_EXPAND1),
4247c478bd9Sstevel@tonic-gate 					    NAME(lmp), oname);
4257c478bd9Sstevel@tonic-gate 					return (0);
4267c478bd9Sstevel@tonic-gate 				}
4277c478bd9Sstevel@tonic-gate 			}
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 		} else if (strncmp(optr, MSG_ORIG(MSG_TKN_PLATFORM),
4307c478bd9Sstevel@tonic-gate 		    MSG_TKN_PLATFORM_SIZE) == 0) {
43108278a5eSRod Evans 			Syscapset	*scapset;
43208278a5eSRod Evans 
43308278a5eSRod Evans 			if (FLAGS1(lmp) & FL1_RT_ALTCAP)
43408278a5eSRod Evans 				scapset = alt_scapset;
43508278a5eSRod Evans 			else
43608278a5eSRod Evans 				scapset = org_scapset;
43708278a5eSRod Evans 
4387c478bd9Sstevel@tonic-gate 			token = (char *)MSG_ORIG(MSG_TKN_PLATFORM);
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 			/*
44108278a5eSRod Evans 			 * $PLATFORM expansion required.
4427c478bd9Sstevel@tonic-gate 			 */
44356deab07SRod Evans 			if (((omit & PD_TKN_PLATFORM) == 0) &&
44408278a5eSRod Evans 			    ((scapset->sc_plat == NULL) &&
44508278a5eSRod Evans 			    (scapset->sc_platsz == 0)))
44608278a5eSRod Evans 				platform_name(scapset);
4477c478bd9Sstevel@tonic-gate 
44856deab07SRod Evans 			if (((omit & PD_TKN_PLATFORM) == 0) &&
44908278a5eSRod Evans 			    scapset->sc_plat) {
45008278a5eSRod Evans 				nlen += scapset->sc_platsz;
45108278a5eSRod Evans 				if (nlen < PATH_MAX) {
45208278a5eSRod Evans 					(void) strncpy(nptr, scapset->sc_plat,
45308278a5eSRod Evans 					    scapset->sc_platsz);
45408278a5eSRod Evans 					nptr = nptr + scapset->sc_platsz;
4557c478bd9Sstevel@tonic-gate 					olen += MSG_TKN_PLATFORM_SIZE;
4567c478bd9Sstevel@tonic-gate 					optr += MSG_TKN_PLATFORM_SIZE;
45756deab07SRod Evans 					_flags |= PD_TKN_PLATFORM;
4587c478bd9Sstevel@tonic-gate 				} else {
4595aefb655Srie 					eprintf(lml, ERR_FATAL,
4607c478bd9Sstevel@tonic-gate 					    MSG_INTL(MSG_ERR_EXPAND1),
4617c478bd9Sstevel@tonic-gate 					    NAME(lmp), oname);
4627c478bd9Sstevel@tonic-gate 					return (0);
4637c478bd9Sstevel@tonic-gate 				}
4647c478bd9Sstevel@tonic-gate 			}
4657c478bd9Sstevel@tonic-gate 
46608278a5eSRod Evans 		} else if (strncmp(optr, MSG_ORIG(MSG_TKN_MACHINE),
46708278a5eSRod Evans 		    MSG_TKN_MACHINE_SIZE) == 0) {
46808278a5eSRod Evans 			Syscapset	*scapset;
46908278a5eSRod Evans 
47008278a5eSRod Evans 			if (FLAGS1(lmp) & FL1_RT_ALTCAP)
47108278a5eSRod Evans 				scapset = alt_scapset;
47208278a5eSRod Evans 			else
47308278a5eSRod Evans 				scapset = org_scapset;
47408278a5eSRod Evans 
47508278a5eSRod Evans 			token = (char *)MSG_ORIG(MSG_TKN_MACHINE);
47608278a5eSRod Evans 
47708278a5eSRod Evans 			/*
47808278a5eSRod Evans 			 * $MACHINE expansion required.
47908278a5eSRod Evans 			 */
48008278a5eSRod Evans 			if (((omit & PD_TKN_MACHINE) == 0) &&
48108278a5eSRod Evans 			    ((scapset->sc_mach == NULL) &&
48208278a5eSRod Evans 			    (scapset->sc_machsz == 0)))
48308278a5eSRod Evans 				machine_name(scapset);
48408278a5eSRod Evans 
48508278a5eSRod Evans 			if (((omit & PD_TKN_MACHINE) == 0) &&
48608278a5eSRod Evans 			    scapset->sc_mach) {
48708278a5eSRod Evans 				nlen += scapset->sc_machsz;
48808278a5eSRod Evans 				if (nlen < PATH_MAX) {
48908278a5eSRod Evans 					(void) strncpy(nptr, scapset->sc_mach,
49008278a5eSRod Evans 					    scapset->sc_machsz);
49108278a5eSRod Evans 					nptr = nptr + scapset->sc_machsz;
49208278a5eSRod Evans 					olen += MSG_TKN_MACHINE_SIZE;
49308278a5eSRod Evans 					optr += MSG_TKN_MACHINE_SIZE;
49408278a5eSRod Evans 					_flags |= PD_TKN_MACHINE;
49508278a5eSRod Evans 				} else {
49608278a5eSRod Evans 					eprintf(lml, ERR_FATAL,
49708278a5eSRod Evans 					    MSG_INTL(MSG_ERR_EXPAND1),
49808278a5eSRod Evans 					    NAME(lmp), oname);
49908278a5eSRod Evans 					return (0);
50008278a5eSRod Evans 				}
50108278a5eSRod Evans 			}
50208278a5eSRod Evans 
5037c478bd9Sstevel@tonic-gate 		} else if (strncmp(optr, MSG_ORIG(MSG_TKN_OSNAME),
5047c478bd9Sstevel@tonic-gate 		    MSG_TKN_OSNAME_SIZE) == 0) {
5057c478bd9Sstevel@tonic-gate 			token = (char *)MSG_ORIG(MSG_TKN_OSNAME);
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 			/*
5087c478bd9Sstevel@tonic-gate 			 * $OSNAME expansion required.  This is established
5097c478bd9Sstevel@tonic-gate 			 * from the sysname[] returned by uname(2).
5107c478bd9Sstevel@tonic-gate 			 */
51156deab07SRod Evans 			if (((omit & PD_TKN_OSNAME) == 0) && (uts == NULL))
5127c478bd9Sstevel@tonic-gate 				uts = conv_uts();
5137c478bd9Sstevel@tonic-gate 
51456deab07SRod Evans 			if (((omit & PD_TKN_OSNAME) == 0) &&
5157c478bd9Sstevel@tonic-gate 			    (uts && uts->uts_osnamesz)) {
5167c478bd9Sstevel@tonic-gate 				if ((nlen += uts->uts_osnamesz) < PATH_MAX) {
5177c478bd9Sstevel@tonic-gate 					(void) strncpy(nptr, uts->uts_osname,
5187c478bd9Sstevel@tonic-gate 					    uts->uts_osnamesz);
5197c478bd9Sstevel@tonic-gate 					nptr = nptr + uts->uts_osnamesz;
5207c478bd9Sstevel@tonic-gate 					olen += MSG_TKN_OSNAME_SIZE;
5217c478bd9Sstevel@tonic-gate 					optr += MSG_TKN_OSNAME_SIZE;
52256deab07SRod Evans 					_flags |= PD_TKN_OSNAME;
5237c478bd9Sstevel@tonic-gate 				} else {
5245aefb655Srie 					eprintf(lml, ERR_FATAL,
5257c478bd9Sstevel@tonic-gate 					    MSG_INTL(MSG_ERR_EXPAND1),
5267c478bd9Sstevel@tonic-gate 					    NAME(lmp), oname);
5277c478bd9Sstevel@tonic-gate 					return (0);
5287c478bd9Sstevel@tonic-gate 				}
5297c478bd9Sstevel@tonic-gate 			}
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 		} else if (strncmp(optr, MSG_ORIG(MSG_TKN_OSREL),
5327c478bd9Sstevel@tonic-gate 		    MSG_TKN_OSREL_SIZE) == 0) {
5337c478bd9Sstevel@tonic-gate 			token = (char *)MSG_ORIG(MSG_TKN_OSREL);
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 			/*
5367c478bd9Sstevel@tonic-gate 			 * $OSREL expansion required.  This is established
5377c478bd9Sstevel@tonic-gate 			 * from the release[] returned by uname(2).
5387c478bd9Sstevel@tonic-gate 			 */
53956deab07SRod Evans 			if (((omit & PD_TKN_OSREL) == 0) && (uts == 0))
5407c478bd9Sstevel@tonic-gate 				uts = conv_uts();
5417c478bd9Sstevel@tonic-gate 
54256deab07SRod Evans 			if (((omit & PD_TKN_OSREL) == 0) &&
5437c478bd9Sstevel@tonic-gate 			    (uts && uts->uts_osrelsz)) {
5447c478bd9Sstevel@tonic-gate 				if ((nlen += uts->uts_osrelsz) < PATH_MAX) {
5457c478bd9Sstevel@tonic-gate 					(void) strncpy(nptr, uts->uts_osrel,
5467c478bd9Sstevel@tonic-gate 					    uts->uts_osrelsz);
5477c478bd9Sstevel@tonic-gate 					nptr = nptr + uts->uts_osrelsz;
5487c478bd9Sstevel@tonic-gate 					olen += MSG_TKN_OSREL_SIZE;
5497c478bd9Sstevel@tonic-gate 					optr += MSG_TKN_OSREL_SIZE;
55056deab07SRod Evans 					_flags |= PD_TKN_OSREL;
5517c478bd9Sstevel@tonic-gate 				} else {
5525aefb655Srie 					eprintf(lml, ERR_FATAL,
5537c478bd9Sstevel@tonic-gate 					    MSG_INTL(MSG_ERR_EXPAND1),
5547c478bd9Sstevel@tonic-gate 					    NAME(lmp), oname);
5557c478bd9Sstevel@tonic-gate 					return (0);
5567c478bd9Sstevel@tonic-gate 				}
5577c478bd9Sstevel@tonic-gate 			}
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 		} else if ((strncmp(optr, MSG_ORIG(MSG_TKN_ISALIST),
5607c478bd9Sstevel@tonic-gate 		    MSG_TKN_ISALIST_SIZE) == 0)) {
5617c478bd9Sstevel@tonic-gate 			int	ok;
5627c478bd9Sstevel@tonic-gate 			token = (char *)MSG_ORIG(MSG_TKN_ISALIST);
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 			/*
5657c478bd9Sstevel@tonic-gate 			 * $ISALIST expansion required.  When accompanied with
5667c478bd9Sstevel@tonic-gate 			 * a list pointer, this routine updates that pointer
5677c478bd9Sstevel@tonic-gate 			 * with the new list of potential candidates.  Without
5687c478bd9Sstevel@tonic-gate 			 * this list pointer, only the first expansion is
5697c478bd9Sstevel@tonic-gate 			 * provided.  NOTE, that two $ISLIST expansions within
5707c478bd9Sstevel@tonic-gate 			 * the same path aren't supported.
5717c478bd9Sstevel@tonic-gate 			 */
57256deab07SRod Evans 			if ((omit & PD_TKN_ISALIST) || isaflag++)
5737c478bd9Sstevel@tonic-gate 				ok = 0;
5747c478bd9Sstevel@tonic-gate 			else
5757c478bd9Sstevel@tonic-gate 				ok = 1;
5767c478bd9Sstevel@tonic-gate 
57756deab07SRod Evans 			if (ok && (isa == NULL))
5787c478bd9Sstevel@tonic-gate 				isa = conv_isalist();
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 			if (ok && isa && isa->isa_listsz) {
5817c478bd9Sstevel@tonic-gate 				size_t	no, mlen, tlen, hlen = olen - 1;
5827c478bd9Sstevel@tonic-gate 				char	*lptr;
5837c478bd9Sstevel@tonic-gate 				Isa_opt *opt = isa->isa_opt;
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 				if ((nlen += opt->isa_namesz) < PATH_MAX) {
5867c478bd9Sstevel@tonic-gate 					(void) strncpy(nptr,  opt->isa_name,
5877c478bd9Sstevel@tonic-gate 					    opt->isa_namesz);
5887c478bd9Sstevel@tonic-gate 					nptr = nptr + opt->isa_namesz;
5897c478bd9Sstevel@tonic-gate 					olen += MSG_TKN_ISALIST_SIZE;
5907c478bd9Sstevel@tonic-gate 					optr += MSG_TKN_ISALIST_SIZE;
59156deab07SRod Evans 					_flags |= PD_TKN_ISALIST;
5927c478bd9Sstevel@tonic-gate 				} else {
5935aefb655Srie 					eprintf(lml, ERR_FATAL,
5947c478bd9Sstevel@tonic-gate 					    MSG_INTL(MSG_ERR_EXPAND1),
5957c478bd9Sstevel@tonic-gate 					    NAME(lmp), oname);
5967c478bd9Sstevel@tonic-gate 					return (0);
5977c478bd9Sstevel@tonic-gate 				}
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 				if (list) {
6007c478bd9Sstevel@tonic-gate 					tlen = *len - olen;
6017c478bd9Sstevel@tonic-gate 					mlen = ((hlen + tlen) *
6027c478bd9Sstevel@tonic-gate 					    (isa->isa_optno - 1)) +
6037c478bd9Sstevel@tonic-gate 					    isa->isa_listsz - opt->isa_namesz +
6047c478bd9Sstevel@tonic-gate 					    strlen(*list);
60556deab07SRod Evans 					if ((_list = lptr =
60656deab07SRod Evans 					    malloc(mlen)) == NULL)
6077c478bd9Sstevel@tonic-gate 						return (0);
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 					for (no = 1, opt++; no < isa->isa_optno;
6107c478bd9Sstevel@tonic-gate 					    no++, opt++) {
6117c478bd9Sstevel@tonic-gate 						(void) strncpy(lptr, *name,
6127c478bd9Sstevel@tonic-gate 						    hlen);
6137c478bd9Sstevel@tonic-gate 						lptr = lptr + hlen;
6147c478bd9Sstevel@tonic-gate 						(void) strncpy(lptr,
6157c478bd9Sstevel@tonic-gate 						    opt->isa_name,
6167c478bd9Sstevel@tonic-gate 						    opt->isa_namesz);
6177c478bd9Sstevel@tonic-gate 						lptr = lptr + opt->isa_namesz;
6187c478bd9Sstevel@tonic-gate 						(void) strncpy(lptr, optr,
6197c478bd9Sstevel@tonic-gate 						    tlen);
6207c478bd9Sstevel@tonic-gate 						lptr = lptr + tlen;
6217c478bd9Sstevel@tonic-gate 						*lptr++ = ':';
6227c478bd9Sstevel@tonic-gate 					}
6237c478bd9Sstevel@tonic-gate 					if (**list)
6247c478bd9Sstevel@tonic-gate 						(void) strcpy(lptr, *list);
6257c478bd9Sstevel@tonic-gate 					else
6267c478bd9Sstevel@tonic-gate 						*--lptr = '\0';
6277c478bd9Sstevel@tonic-gate 				}
6287c478bd9Sstevel@tonic-gate 			}
6297c478bd9Sstevel@tonic-gate 
63008278a5eSRod Evans 		} else if (strncmp(optr, MSG_ORIG(MSG_TKN_CAPABILITY),
63108278a5eSRod Evans 		    MSG_TKN_CAPABILITY_SIZE) == 0) {
63208278a5eSRod Evans 			char	*bptr = nptr - 1;
63308278a5eSRod Evans 			char	*eptr = optr + MSG_TKN_CAPABILITY_SIZE;
63408278a5eSRod Evans 			token = (char *)MSG_ORIG(MSG_TKN_CAPABILITY);
63508278a5eSRod Evans 
63608278a5eSRod Evans 			/*
63708278a5eSRod Evans 			 * $CAPABILITY expansion required.  Expansion is only
63808278a5eSRod Evans 			 * allowed for non-simple path names (must contain a
63908278a5eSRod Evans 			 * '/'), with the token itself being the last element
64008278a5eSRod Evans 			 * of the path.  Therefore, all we need do is test the
64108278a5eSRod Evans 			 * existence of the string "/$CAPABILITY\0".
64208278a5eSRod Evans 			 */
64308278a5eSRod Evans 			if (((omit & PD_TKN_CAP) == 0) &&
64408278a5eSRod Evans 			    ((bptr > _name) && (*bptr == '/') &&
64508278a5eSRod Evans 			    ((*eptr == '\0') || (*eptr == ':')))) {
64608278a5eSRod Evans 				/*
64708278a5eSRod Evans 				 * Decrement the present pointer so that the
64808278a5eSRod Evans 				 * directories trailing "/" gets nuked later.
64908278a5eSRod Evans 				 */
65008278a5eSRod Evans 				nptr--, nlen--;
65108278a5eSRod Evans 				olen += MSG_TKN_CAPABILITY_SIZE;
65208278a5eSRod Evans 				optr += MSG_TKN_CAPABILITY_SIZE;
65308278a5eSRod Evans 				_flags |= PD_TKN_CAP;
65408278a5eSRod Evans 			}
65508278a5eSRod Evans 
6567c478bd9Sstevel@tonic-gate 		} else if (strncmp(optr, MSG_ORIG(MSG_TKN_HWCAP),
6577c478bd9Sstevel@tonic-gate 		    MSG_TKN_HWCAP_SIZE) == 0) {
6587c478bd9Sstevel@tonic-gate 			char	*bptr = nptr - 1;
6597c478bd9Sstevel@tonic-gate 			char	*eptr = optr + MSG_TKN_HWCAP_SIZE;
6607c478bd9Sstevel@tonic-gate 			token = (char *)MSG_ORIG(MSG_TKN_HWCAP);
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 			/*
66308278a5eSRod Evans 			 * $HWCAP expansion required.  This token has been
66408278a5eSRod Evans 			 * superseeded by $CAPABILITY.  For compatibility with
6657c478bd9Sstevel@tonic-gate 			 * older environments, only expand this token when hard-
6667c478bd9Sstevel@tonic-gate 			 * ware capability information is available.   This
6677c478bd9Sstevel@tonic-gate 			 * expansion is only allowed for non-simple path names
6687c478bd9Sstevel@tonic-gate 			 * (must contain a '/'), with the token itself being the
6697c478bd9Sstevel@tonic-gate 			 * last element of the path.  Therefore, all we need do
6707c478bd9Sstevel@tonic-gate 			 * is test the existence of the string "/$HWCAP\0".
6717c478bd9Sstevel@tonic-gate 			 */
67208278a5eSRod Evans 			if (((omit & PD_TKN_CAP) == 0) &&
6737c478bd9Sstevel@tonic-gate 			    (rtld_flags2 & RT_FL2_HWCAP) &&
6747c478bd9Sstevel@tonic-gate 			    ((bptr > _name) && (*bptr == '/') &&
6757c478bd9Sstevel@tonic-gate 			    ((*eptr == '\0') || (*eptr == ':')))) {
6767c478bd9Sstevel@tonic-gate 				/*
6777c478bd9Sstevel@tonic-gate 				 * Decrement the present pointer so that the
6787c478bd9Sstevel@tonic-gate 				 * directories trailing "/" gets nuked later.
6797c478bd9Sstevel@tonic-gate 				 */
6807c478bd9Sstevel@tonic-gate 				nptr--, nlen--;
6817c478bd9Sstevel@tonic-gate 				olen += MSG_TKN_HWCAP_SIZE;
6827c478bd9Sstevel@tonic-gate 				optr += MSG_TKN_HWCAP_SIZE;
68308278a5eSRod Evans 				_flags |= PD_TKN_CAP;
6847c478bd9Sstevel@tonic-gate 			}
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 		} else {
6877c478bd9Sstevel@tonic-gate 			/*
6887c478bd9Sstevel@tonic-gate 			 * If reserved token was not found, copy the
6897c478bd9Sstevel@tonic-gate 			 * character.
6907c478bd9Sstevel@tonic-gate 			 */
6917c478bd9Sstevel@tonic-gate 			*nptr++ = '$';
6927c478bd9Sstevel@tonic-gate 			nlen++;
6937c478bd9Sstevel@tonic-gate 		}
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 		/*
69656deab07SRod Evans 		 * If a reserved token was found, and could not be expanded,
6977b2cbac6Srie 		 * diagnose the error condition.
6987c478bd9Sstevel@tonic-gate 		 */
6997c478bd9Sstevel@tonic-gate 		if (token) {
7007c478bd9Sstevel@tonic-gate 			if (_flags)
7017c478bd9Sstevel@tonic-gate 				flags |= _flags;
7027c478bd9Sstevel@tonic-gate 			else {
7037b2cbac6Srie 				char	buf[PATH_MAX], *str;
7047b2cbac6Srie 
7057b2cbac6Srie 				/*
7067b2cbac6Srie 				 * Note, the original string we're expanding
7077b2cbac6Srie 				 * might contain a number of ':' separated
7087b2cbac6Srie 				 * paths.  Isolate the path we're processing to
7097b2cbac6Srie 				 * provide a more precise error diagnostic.
7107b2cbac6Srie 				 */
7117b2cbac6Srie 				if (str = strchr(oname, ':')) {
7127b2cbac6Srie 					size_t	slen = str - oname;
7137b2cbac6Srie 
7147b2cbac6Srie 					(void) strncpy(buf, oname, slen);
7157b2cbac6Srie 					buf[slen] = '\0';
7167b2cbac6Srie 					str = buf;
7177b2cbac6Srie 				} else
7187b2cbac6Srie 					str = oname;
7197b2cbac6Srie 
7205aefb655Srie 				eprintf(lml, ERR_FATAL,
7215aefb655Srie 				    MSG_INTL(MSG_ERR_EXPAND2), NAME(lmp),
7227b2cbac6Srie 				    str, token);
7237c478bd9Sstevel@tonic-gate 				return (0);
7247c478bd9Sstevel@tonic-gate 			}
7257c478bd9Sstevel@tonic-gate 		}
7267c478bd9Sstevel@tonic-gate 		_optr = optr;
7277c478bd9Sstevel@tonic-gate 	}
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	/*
7307c478bd9Sstevel@tonic-gate 	 * First make sure the current length is shorter than PATH_MAX.  We may
7317c478bd9Sstevel@tonic-gate 	 * arrive here if the given path contains '$' characters which are not
7327c478bd9Sstevel@tonic-gate 	 * the lead of a reserved token.
7337c478bd9Sstevel@tonic-gate 	 */
7347c478bd9Sstevel@tonic-gate 	if (nlen >= PATH_MAX) {
7355aefb655Srie 		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ERR_EXPAND1), NAME(lmp),
7365aefb655Srie 		    oname);
7377c478bd9Sstevel@tonic-gate 		return (0);
7387c478bd9Sstevel@tonic-gate 	}
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 	/*
7417c478bd9Sstevel@tonic-gate 	 * If any ISALIST processing has occurred not only do we return the
7427c478bd9Sstevel@tonic-gate 	 * expanded node we're presently working on, but we can also update the
7437c478bd9Sstevel@tonic-gate 	 * remaining list so that it is effectively prepended with this node
7447c478bd9Sstevel@tonic-gate 	 * expanded to all remaining ISALIST options.  Note that we can only
7457c478bd9Sstevel@tonic-gate 	 * handle one ISALIST per node.  For more than one ISALIST to be
7467c478bd9Sstevel@tonic-gate 	 * processed we'd need a better algorithm than above to replace the
7477c478bd9Sstevel@tonic-gate 	 * newly generated list.  Whether we want to encourage the number of
748247b82a1SRod Evans 	 * path name permutations this would provide is another question.  So,
749247b82a1SRod Evans 	 * for now if more than one ISALIST is encountered we return the
750247b82a1SRod Evans 	 * original node untouched.
7517c478bd9Sstevel@tonic-gate 	 */
7527b2cbac6Srie 	if (isa && isaflag) {
7537c478bd9Sstevel@tonic-gate 		if (isaflag == 1) {
7547c478bd9Sstevel@tonic-gate 			if (list)
7557c478bd9Sstevel@tonic-gate 				*list = _list;
7567c478bd9Sstevel@tonic-gate 		} else {
75756deab07SRod Evans 			flags &= ~PD_TKN_ISALIST;
75856deab07SRod Evans 			if ((nptr = (char *)stravl_insert(*name, 0,
75956deab07SRod Evans 			    (*len + 1), 1)) == NULL)
7607c478bd9Sstevel@tonic-gate 				return (0);
7617c478bd9Sstevel@tonic-gate 			*name = nptr;
7627c478bd9Sstevel@tonic-gate 			return (TKN_NONE);
7637c478bd9Sstevel@tonic-gate 		}
7647c478bd9Sstevel@tonic-gate 	}
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	/*
7677c478bd9Sstevel@tonic-gate 	 * Copy any remaining string. Terminate the new string with a null as
7687c478bd9Sstevel@tonic-gate 	 * this string can be displayed via debugging diagnostics.
7697c478bd9Sstevel@tonic-gate 	 */
7707c478bd9Sstevel@tonic-gate 	if ((_len = (optr - _optr)) != 0) {
7717c478bd9Sstevel@tonic-gate 		if ((nlen += _len) < PATH_MAX) {
7727c478bd9Sstevel@tonic-gate 			(void) strncpy(nptr, _optr, _len);
7737c478bd9Sstevel@tonic-gate 			nptr = nptr + _len;
7747c478bd9Sstevel@tonic-gate 		} else {
7755aefb655Srie 			eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ERR_EXPAND1),
7767c478bd9Sstevel@tonic-gate 			    NAME(lmp), oname);
7777c478bd9Sstevel@tonic-gate 			return (0);
7787c478bd9Sstevel@tonic-gate 		}
7797c478bd9Sstevel@tonic-gate 	}
7807c478bd9Sstevel@tonic-gate 	*nptr = '\0';
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 	/*
783247b82a1SRod Evans 	 * A path that has been expanded is typically used to create full
7847c478bd9Sstevel@tonic-gate 	 * path names for objects that will be opened.  The final path name is
7857c478bd9Sstevel@tonic-gate 	 * resolved to simplify it, and set the stage for possible $ORIGIN
7869aa23310Srie 	 * processing.  Therefore, it's usually unnecessary to resolve the path
7877c478bd9Sstevel@tonic-gate 	 * at this point.  However, if a configuration file, containing
7887c478bd9Sstevel@tonic-gate 	 * directory information is in use, then we might need to lookup this
7897c478bd9Sstevel@tonic-gate 	 * path in the configuration file.  To keep the number of path name
7907c478bd9Sstevel@tonic-gate 	 * resolutions to a minimum, only resolve paths that contain "./".  The
7917c478bd9Sstevel@tonic-gate 	 * use of "$ORIGIN/../lib" will probably only match a configuration file
7927c478bd9Sstevel@tonic-gate 	 * entry after resolution.
7937c478bd9Sstevel@tonic-gate 	 */
79456deab07SRod Evans 	if (list && (rtld_flags & RT_FL_DIRCFG) && (flags & TKN_DOTSLASH)) {
7957c478bd9Sstevel@tonic-gate 		int	len;
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 		if ((len = resolvepath(_name, _name, (PATH_MAX - 1))) >= 0) {
7987c478bd9Sstevel@tonic-gate 			nlen = (size_t)len;
7997c478bd9Sstevel@tonic-gate 			_name[nlen] = '\0';
80056deab07SRod Evans 			flags |= PD_TKN_RESOLVED;
8017c478bd9Sstevel@tonic-gate 		}
8027c478bd9Sstevel@tonic-gate 	}
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 	/*
80556deab07SRod Evans 	 * Allocate a new string if necessary.
80656deab07SRod Evans 	 *
80756deab07SRod Evans 	 * If any form of token expansion, or string resolution has occurred,
80856deab07SRod Evans 	 * the storage must be allocated for the new string.
80956deab07SRod Evans 	 *
81056deab07SRod Evans 	 * If we're processing a substring, for example, any string besides the
81156deab07SRod Evans 	 * last string within a search path "A:B:C", then this substring needs
81256deab07SRod Evans 	 * to be isolated with a null terminator.  However, if this search path
81356deab07SRod Evans 	 * was created from a previous ISALIST expansion, then all strings must
81456deab07SRod Evans 	 * be allocated, as the isalist expansion will be freed after expansion
81556deab07SRod Evans 	 * processing.
8167c478bd9Sstevel@tonic-gate 	 */
81756deab07SRod Evans 	if ((nptr = (char *)stravl_insert(_name, 0, (nlen + 1), 1)) == NULL)
8187c478bd9Sstevel@tonic-gate 		return (0);
8197c478bd9Sstevel@tonic-gate 	*name = nptr;
8207c478bd9Sstevel@tonic-gate 	*len = nlen;
8217c478bd9Sstevel@tonic-gate 	return (flags ? flags : TKN_NONE);
8227c478bd9Sstevel@tonic-gate }
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate /*
8257c478bd9Sstevel@tonic-gate  * Determine whether a path name is secure.
8267c478bd9Sstevel@tonic-gate  */
827247b82a1SRod Evans int
is_path_secure(char * opath,Rt_map * clmp,uint_t info,uint_t flags)8289aa23310Srie is_path_secure(char *opath, Rt_map *clmp, uint_t info, uint_t flags)
8297c478bd9Sstevel@tonic-gate {
83056deab07SRod Evans 	Alist		**salpp;
83156deab07SRod Evans 	Aliste		idx;
832247b82a1SRod Evans 	char		buffer[PATH_MAX], *npath = NULL;
8333dbfc803SRod Evans 	Lm_list		*lml = LIST(clmp);
83456deab07SRod Evans 	Pdesc		*pdp;
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 	/*
8377c478bd9Sstevel@tonic-gate 	 * If a path name originates from a configuration file, use it.  The use
8387c478bd9Sstevel@tonic-gate 	 * of a configuration file is already validated for secure applications,
8397c478bd9Sstevel@tonic-gate 	 * so if we're using a configuration file, we must be able to use all
8407c478bd9Sstevel@tonic-gate 	 * that it defines.
8417c478bd9Sstevel@tonic-gate 	 */
8427c478bd9Sstevel@tonic-gate 	if (info & LA_SER_CONFIG)
8437c478bd9Sstevel@tonic-gate 		return (1);
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	if ((info & LA_SER_MASK) == 0) {
8467c478bd9Sstevel@tonic-gate 		char	*str;
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 		/*
8497c478bd9Sstevel@tonic-gate 		 * If the path name specifies a file (rather than a directory),
8507c478bd9Sstevel@tonic-gate 		 * peel off the file before making the comparison.
8517c478bd9Sstevel@tonic-gate 		 */
8527c478bd9Sstevel@tonic-gate 		str = strrchr(opath, '/');
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 		/*
8553dbfc803SRod Evans 		 * Carry out some initial security checks.
8567c478bd9Sstevel@tonic-gate 		 *
8573dbfc803SRod Evans 		 *   .	a simple file name (one containing no "/") is fine, as
8583dbfc803SRod Evans 		 *	this file name will be combined with search paths to
859247b82a1SRod Evans 		 *	determine the complete path.  Note, a secure application
860247b82a1SRod Evans 		 *	may provide a configuration file, and this can only be
861247b82a1SRod Evans 		 *	a full path name (PN_FLG_FULLPATH).
8627c478bd9Sstevel@tonic-gate 		 *   .	a full path (one starting with "/") is fine, provided
8633dbfc803SRod Evans 		 *	this path name isn't a preload/audit path.
8643dbfc803SRod Evans 		 *   .	provided $ORIGIN expansion has not been employed, the
8653dbfc803SRod Evans 		 *	above categories of path are deemed secure.
8667c478bd9Sstevel@tonic-gate 		 */
86756deab07SRod Evans 		if ((((str == 0) && ((info & PD_FLG_FULLPATH) == 0)) ||
868247b82a1SRod Evans 		    ((*opath == '/') && (str != opath) &&
86956deab07SRod Evans 		    ((info & PD_FLG_EXTLOAD) == 0))) &&
87056deab07SRod Evans 		    ((flags & PD_TKN_ORIGIN) == 0))
8717c478bd9Sstevel@tonic-gate 			return (1);
8727c478bd9Sstevel@tonic-gate 
8733dbfc803SRod Evans 		/*
8743dbfc803SRod Evans 		 * Determine the directory name of the present path.
8753dbfc803SRod Evans 		 */
876247b82a1SRod Evans 		if (str) {
8777c478bd9Sstevel@tonic-gate 			if (str == opath)
8787c478bd9Sstevel@tonic-gate 				npath = (char *)MSG_ORIG(MSG_STR_SLASH);
8797c478bd9Sstevel@tonic-gate 			else {
8807c478bd9Sstevel@tonic-gate 				size_t	size;
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 				if ((size = str - opath) >= PATH_MAX)
8837c478bd9Sstevel@tonic-gate 					return (0);
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 				(void) strncpy(buffer, opath, size);
8867c478bd9Sstevel@tonic-gate 				buffer[size] = '\0';
8877c478bd9Sstevel@tonic-gate 				npath = buffer;
8887c478bd9Sstevel@tonic-gate 			}
8893dbfc803SRod Evans 
8903dbfc803SRod Evans 			/*
891247b82a1SRod Evans 			 * If $ORIGIN processing has been employed, then allow
892247b82a1SRod Evans 			 * any directory that has already been used to satisfy
893247b82a1SRod Evans 			 * other dependencies, to be used.
8943dbfc803SRod Evans 			 */
89556deab07SRod Evans 			if ((flags & PD_TKN_ORIGIN) &&
89608278a5eSRod Evans 			    pnavl_recorded(&spavl, npath, 0, NULL)) {
8973dbfc803SRod Evans 				DBG_CALL(Dbg_libs_insecure(lml, npath, 1));
8983dbfc803SRod Evans 				return (1);
8993dbfc803SRod Evans 			}
900247b82a1SRod Evans 		}
9017c478bd9Sstevel@tonic-gate 	} else {
9027c478bd9Sstevel@tonic-gate 		/*
9037c478bd9Sstevel@tonic-gate 		 * A search path, i.e., RPATH, configuration file path, etc. is
9047c478bd9Sstevel@tonic-gate 		 * used as is.  Exceptions to this are:
9057c478bd9Sstevel@tonic-gate 		 *
9063dbfc803SRod Evans 		 *   .	LD_LIBRARY_PATH.
9073dbfc803SRod Evans 		 *   .	any $ORIGIN expansion, unless used by a setuid ld.so.1
9083dbfc803SRod Evans 		 *	to find its own dependencies, or the path name has
9093dbfc803SRod Evans 		 *	already been used to find other dependencies.
9103dbfc803SRod Evans 		 *   .	any relative path.
9117c478bd9Sstevel@tonic-gate 		 */
9127c478bd9Sstevel@tonic-gate 		if (((info & LA_SER_LIBPATH) == 0) && (*opath == '/') &&
91356deab07SRod Evans 		    ((flags & PD_TKN_ORIGIN) == 0))
9147c478bd9Sstevel@tonic-gate 			return (1);
9157c478bd9Sstevel@tonic-gate 
9163dbfc803SRod Evans 		/*
9173dbfc803SRod Evans 		 * If $ORIGIN processing is requested, allow a setuid ld.so.1
9183dbfc803SRod Evans 		 * to use this path for its own dependencies.  Allow the
9193dbfc803SRod Evans 		 * application to use this path name only if the path name has
9203dbfc803SRod Evans 		 * already been used to locate other dependencies.
9213dbfc803SRod Evans 		 */
92256deab07SRod Evans 		if (flags & PD_TKN_ORIGIN) {
9233dbfc803SRod Evans 			if ((lml->lm_flags & LML_FLG_RTLDLM) &&
9243dbfc803SRod Evans 			    is_rtld_setuid())
9253dbfc803SRod Evans 				return (1);
92608278a5eSRod Evans 			else if (pnavl_recorded(&spavl, opath, 0, NULL)) {
9273dbfc803SRod Evans 				DBG_CALL(Dbg_libs_insecure(lml, opath, 1));
9283dbfc803SRod Evans 				return (1);
9293dbfc803SRod Evans 			}
9303dbfc803SRod Evans 		}
9317c478bd9Sstevel@tonic-gate 		npath = (char *)opath;
9327c478bd9Sstevel@tonic-gate 	}
9337c478bd9Sstevel@tonic-gate 
934247b82a1SRod Evans 	/*
935247b82a1SRod Evans 	 * Determine whether the present directory is trusted.
936247b82a1SRod Evans 	 */
937247b82a1SRod Evans 	if (npath) {
93856deab07SRod Evans 		salpp = LM_SECURE_DIRS(LIST(clmp)->lm_head)();
93956deab07SRod Evans 		for (ALIST_TRAVERSE(*salpp, idx, pdp)) {
94056deab07SRod Evans 			if (strcmp(npath, pdp->pd_pname) == 0)
9417c478bd9Sstevel@tonic-gate 				return (1);
9427c478bd9Sstevel@tonic-gate 		}
943247b82a1SRod Evans 	}
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 	/*
9467c478bd9Sstevel@tonic-gate 	 * The path is insecure, so depending on the caller, provide a
9477c478bd9Sstevel@tonic-gate 	 * diagnostic.  Preloaded, or audit libraries generate a warning, as
9487c478bd9Sstevel@tonic-gate 	 * the process will run without them.
9497c478bd9Sstevel@tonic-gate 	 */
95056deab07SRod Evans 	if (info & PD_FLG_EXTLOAD) {
9517c478bd9Sstevel@tonic-gate 		if (lml->lm_flags & LML_FLG_TRC_ENABLE) {
9527c478bd9Sstevel@tonic-gate 			if ((FLAGS1(clmp) & FL1_RT_LDDSTUB) == 0)
9537c478bd9Sstevel@tonic-gate 				(void) printf(MSG_INTL(MSG_LDD_FIL_ILLEGAL),
9547c478bd9Sstevel@tonic-gate 				    opath);
9557c478bd9Sstevel@tonic-gate 		} else
9565aefb655Srie 			eprintf(lml, ERR_WARNING, MSG_INTL(MSG_SEC_ILLEGAL),
9575aefb655Srie 			    opath);
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 		return (0);
9607c478bd9Sstevel@tonic-gate 	}
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 	/*
9637c478bd9Sstevel@tonic-gate 	 * Explicit file references are fatal.
9647c478bd9Sstevel@tonic-gate 	 */
9657c478bd9Sstevel@tonic-gate 	if ((info & LA_SER_MASK) == 0) {
9667c478bd9Sstevel@tonic-gate 		if (lml->lm_flags & LML_FLG_TRC_ENABLE) {
9677b2cbac6Srie 			/* BEGIN CSTYLED */
9687c478bd9Sstevel@tonic-gate 			if ((FLAGS1(clmp) & FL1_RT_LDDSTUB) == 0) {
9697c478bd9Sstevel@tonic-gate 				if (lml->lm_flags &
9707c478bd9Sstevel@tonic-gate 				    (LML_FLG_TRC_VERBOSE | LML_FLG_TRC_SEARCH))
9717257d1b4Sraf 					(void) printf(
9727257d1b4Sraf 					    MSG_INTL(MSG_LDD_FIL_FIND),
9737c478bd9Sstevel@tonic-gate 					    opath, NAME(clmp));
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 				if (((rtld_flags & RT_FL_SILENCERR) == 0) ||
9767c478bd9Sstevel@tonic-gate 				    (lml->lm_flags & LML_FLG_TRC_VERBOSE))
9777257d1b4Sraf 					(void) printf(
9787257d1b4Sraf 					    MSG_INTL(MSG_LDD_FIL_ILLEGAL),
9797c478bd9Sstevel@tonic-gate 					    opath);
9807c478bd9Sstevel@tonic-gate 			}
9817b2cbac6Srie 			/* END CSTYLED */
9827c478bd9Sstevel@tonic-gate 		} else
9835aefb655Srie 			eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), opath,
9847c478bd9Sstevel@tonic-gate 			    strerror(EACCES));
9857c478bd9Sstevel@tonic-gate 	} else {
9867c478bd9Sstevel@tonic-gate 		/*
9877c478bd9Sstevel@tonic-gate 		 * Search paths.
9887c478bd9Sstevel@tonic-gate 		 */
9893dbfc803SRod Evans 		DBG_CALL(Dbg_libs_insecure(lml, opath, 0));
9907c478bd9Sstevel@tonic-gate 		if ((lml->lm_flags & LML_FLG_TRC_SEARCH) &&
9917c478bd9Sstevel@tonic-gate 		    ((FLAGS1(clmp) & FL1_RT_LDDSTUB) == 0))
9927c478bd9Sstevel@tonic-gate 			(void) printf(MSG_INTL(MSG_LDD_PTH_IGNORE), opath);
9937c478bd9Sstevel@tonic-gate 	}
9947c478bd9Sstevel@tonic-gate 	return (0);
9957c478bd9Sstevel@tonic-gate }
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate /*
9989aa23310Srie  * Determine whether a path already exists within the callers Pnode list.
9999aa23310Srie  */
10009aa23310Srie inline static uint_t
is_path_unique(Alist * alp,const char * path)100156deab07SRod Evans is_path_unique(Alist *alp, const char *path)
10029aa23310Srie {
100356deab07SRod Evans 	Aliste	idx;
100456deab07SRod Evans 	Pdesc	*pdp;
100556deab07SRod Evans 
100656deab07SRod Evans 	for (ALIST_TRAVERSE(alp, idx, pdp)) {
100756deab07SRod Evans 		if (pdp->pd_plen && (strcmp(pdp->pd_pname, path) == 0))
100856deab07SRod Evans 			return (PD_FLG_DUPLICAT);
10099aa23310Srie 	}
10109aa23310Srie 	return (0);
10119aa23310Srie }
10129aa23310Srie 
10139aa23310Srie /*
10147c478bd9Sstevel@tonic-gate  * Expand one or more path names.  This routine is called for all path strings,
10157c478bd9Sstevel@tonic-gate  * i.e., NEEDED, rpaths, default search paths, configuration file search paths,
10167c478bd9Sstevel@tonic-gate  * filtees, etc.  The path may be a single path name, or a colon separated list
10177c478bd9Sstevel@tonic-gate  * of path names.  Each individual path name is processed for possible reserved
10187c478bd9Sstevel@tonic-gate  * token expansion.  All string nodes are maintained in allocated memory
10197c478bd9Sstevel@tonic-gate  * (regardless of whether they are constant (":"), or token expanded) to
102056deab07SRod Evans  * simplify path name descriptor removal.
10217c478bd9Sstevel@tonic-gate  *
10227c478bd9Sstevel@tonic-gate  * The info argument passes in auxiliary information regarding the callers
10237c478bd9Sstevel@tonic-gate  * intended use of the path names.  This information may be maintained in the
102456deab07SRod Evans  * path name descriptor element produced to describe the path name (i.e.,
102556deab07SRod Evans  * LA_SER_LIBPATH etc.), or may be used to determine additional security or
102656deab07SRod Evans  * diagnostic processing.
10277c478bd9Sstevel@tonic-gate  */
102856deab07SRod Evans int
expand_paths(Rt_map * clmp,const char * list,Alist ** alpp,Aliste alni,uint_t orig,uint_t omit)102956deab07SRod Evans expand_paths(Rt_map *clmp, const char *list, Alist **alpp, Aliste alni,
103056deab07SRod Evans     uint_t orig, uint_t omit)
10317c478bd9Sstevel@tonic-gate {
10327c478bd9Sstevel@tonic-gate 	char	*str, *olist = 0, *nlist = (char *)list;
1033a73372d3Sab196087 	int	fnull = FALSE;	/* TRUE if empty final path segment seen */
103456deab07SRod Evans 	Pdesc	*pdp = NULL;
10357c478bd9Sstevel@tonic-gate 
103656deab07SRod Evans 	for (str = nlist; *nlist || fnull; str = nlist) {
10377c478bd9Sstevel@tonic-gate 		char	*ostr;
103856deab07SRod Evans 		char	*elist = NULL;
10397c478bd9Sstevel@tonic-gate 		size_t	len, olen;
10407c478bd9Sstevel@tonic-gate 		uint_t	tkns = 0;
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 		if (*nlist == ';')
10437c478bd9Sstevel@tonic-gate 			++nlist, ++str;
1044a73372d3Sab196087 		if ((*nlist == ':') || fnull) {
1045a73372d3Sab196087 			/* If not a final null segment, check following one */
1046a73372d3Sab196087 			fnull = !(fnull || *(nlist + 1));
1047a73372d3Sab196087 
1048a73372d3Sab196087 			if (*nlist)
1049a73372d3Sab196087 				nlist++;
1050a73372d3Sab196087 
1051a73372d3Sab196087 			/*
1052a73372d3Sab196087 			 * When the shell sees a null PATH segment, it
1053a73372d3Sab196087 			 * treats it as if it were the cwd (.). We mimic
1054a73372d3Sab196087 			 * this behavior for LD_LIBRARY_PATH and runpaths
1055a73372d3Sab196087 			 * (mainly for backwards compatibility with previous
1056a73372d3Sab196087 			 * behavior). For other paths, this makes no sense,
1057a73372d3Sab196087 			 * so we simply ignore the segment.
1058a73372d3Sab196087 			 */
1059a73372d3Sab196087 			if (!(orig & (LA_SER_LIBPATH | LA_SER_RUNPATH)))
1060a73372d3Sab196087 				continue; /* Process next segment */
1061a73372d3Sab196087 
106256deab07SRod Evans 			str = (char *)MSG_ORIG(MSG_FMT_CWD);
10637c478bd9Sstevel@tonic-gate 			len = MSG_FMT_CWD_SIZE;
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate 		} else {
106656deab07SRod Evans 			uint_t	_tkns;
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 			len = 0;
10697c478bd9Sstevel@tonic-gate 			while (*nlist && (*nlist != ':') && (*nlist != ';')) {
107056deab07SRod Evans 				if (*nlist == '/')
107156deab07SRod Evans 					tkns |= PD_FLG_PNSLASH;
10727c478bd9Sstevel@tonic-gate 				nlist++, len++;
10737c478bd9Sstevel@tonic-gate 			}
10747c478bd9Sstevel@tonic-gate 
1075a73372d3Sab196087 			/* Check for a following final null segment */
1076a73372d3Sab196087 			fnull = (*nlist == ':') && !*(nlist + 1);
1077a73372d3Sab196087 
10787c478bd9Sstevel@tonic-gate 			if (*nlist)
10797c478bd9Sstevel@tonic-gate 				nlist++;
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate 			/*
10827c478bd9Sstevel@tonic-gate 			 * Expand the captured string.  Besides expanding the
10837c478bd9Sstevel@tonic-gate 			 * present path/file entry, we may have a new list to
10847c478bd9Sstevel@tonic-gate 			 * deal with (ISALIST expands to multiple new entries).
10857c478bd9Sstevel@tonic-gate 			 */
10867c478bd9Sstevel@tonic-gate 			elist = nlist;
10877c478bd9Sstevel@tonic-gate 			ostr = str;
10887c478bd9Sstevel@tonic-gate 			olen = len;
108956deab07SRod Evans 			if ((_tkns = expand(&str, &len, &elist, orig, omit,
10907c478bd9Sstevel@tonic-gate 			    clmp)) == 0)
10917b2cbac6Srie 				continue;
109256deab07SRod Evans 			tkns |= _tkns;
10937c478bd9Sstevel@tonic-gate 		}
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate 		/*
10967c478bd9Sstevel@tonic-gate 		 * If this a secure application, validation of the expanded
10977c478bd9Sstevel@tonic-gate 		 * path name may be necessary.
10987c478bd9Sstevel@tonic-gate 		 */
109956deab07SRod Evans 		if ((rtld_flags & RT_FL_SECURE) &&
110056deab07SRod Evans 		    (is_path_secure(str, clmp, orig, tkns) == 0))
11019aa23310Srie 			continue;
11029aa23310Srie 
11039aa23310Srie 		/*
11049aa23310Srie 		 * If required, ensure that the string is unique.  For search
11059aa23310Srie 		 * paths such as LD_LIBRARY_PATH, users often inherit multiple
11069aa23310Srie 		 * paths which result in unnecessary duplication.  Note, if
11079aa23310Srie 		 * we're debugging, any duplicate entry is retained and flagged
11089aa23310Srie 		 * so that the entry can be diagnosed later as part of unused
11099aa23310Srie 		 * processing.
11109aa23310Srie 		 */
111156deab07SRod Evans 		if (orig & PD_FLG_UNIQUE) {
11129aa23310Srie 			Word	tracing;
11139aa23310Srie 
11149aa23310Srie 			tracing = LIST(clmp)->lm_flags &
11159aa23310Srie 			    (LML_FLG_TRC_UNREF | LML_FLG_TRC_UNUSED);
111656deab07SRod Evans 			tkns |= is_path_unique(*alpp, str);
11179aa23310Srie 
11189aa23310Srie 			/*
11199aa23310Srie 			 * Note, use the debug strings rpl_debug and prm_debug
11209aa23310Srie 			 * as an indicator that debugging has been requested,
11219aa23310Srie 			 * rather than DBG_ENABLE(), as the initial use of
11229aa23310Srie 			 * LD_LIBRARY_PATH occurs in preparation for loading
11239aa23310Srie 			 * our debugging library.
11249aa23310Srie 			 */
112556deab07SRod Evans 			if ((tkns & PD_FLG_DUPLICAT) && (tracing == 0) &&
112656deab07SRod Evans 			    (rpl_debug == 0) && (prm_debug == 0))
11277c478bd9Sstevel@tonic-gate 				continue;
11287c478bd9Sstevel@tonic-gate 		}
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate 		/*
113156deab07SRod Evans 		 * Create a new pathname descriptor.
11327c478bd9Sstevel@tonic-gate 		 */
1133dde769a2SRod Evans 		if ((pdp = alist_append(alpp, NULL, sizeof (Pdesc),
1134dde769a2SRod Evans 		    alni)) == NULL)
113556deab07SRod Evans 			return (0);
11367c478bd9Sstevel@tonic-gate 
113756deab07SRod Evans 		pdp->pd_pname = str;
113856deab07SRod Evans 		pdp->pd_plen = len;
113956deab07SRod Evans 		pdp->pd_flags = (orig & LA_SER_MASK) | (tkns & PD_MSK_INHERIT);
11407c478bd9Sstevel@tonic-gate 
11417c478bd9Sstevel@tonic-gate 		/*
114256deab07SRod Evans 		 * If token expansion occurred, maintain the original string.
114356deab07SRod Evans 		 * This string can be used to provide a more informative error
114456deab07SRod Evans 		 * diagnostic for a file that fails to load, or for displaying
114556deab07SRod Evans 		 * unused search paths.
11467c478bd9Sstevel@tonic-gate 		 */
114756deab07SRod Evans 		if ((tkns & PD_MSK_EXPAND) && ((pdp->pd_oname =
114856deab07SRod Evans 		    stravl_insert(ostr, 0, (olen + 1), 1)) == NULL))
114956deab07SRod Evans 			return (0);
11507c478bd9Sstevel@tonic-gate 
115156deab07SRod Evans 		/*
115256deab07SRod Evans 		 * Now that any duplication of the original string has occurred,
115356deab07SRod Evans 		 * release any previous old listing.
115456deab07SRod Evans 		 */
115556deab07SRod Evans 		if (elist && (elist != nlist)) {
115656deab07SRod Evans 			if (olist)
115756deab07SRod Evans 				free(olist);
115856deab07SRod Evans 			nlist = olist = elist;
115956deab07SRod Evans 		}
11607c478bd9Sstevel@tonic-gate 	}
11617c478bd9Sstevel@tonic-gate 
11627c478bd9Sstevel@tonic-gate 	if (olist)
11637c478bd9Sstevel@tonic-gate 		free(olist);
11647c478bd9Sstevel@tonic-gate 
116556deab07SRod Evans 	/*
116656deab07SRod Evans 	 * If no paths could be determined (perhaps because of security), then
116756deab07SRod Evans 	 * indicate a failure.
116856deab07SRod Evans 	 */
116956deab07SRod Evans 	return (pdp != NULL);
117056deab07SRod Evans }
117156deab07SRod Evans 
117256deab07SRod Evans /*
117356deab07SRod Evans  * Establish an objects fully resolved path.
117456deab07SRod Evans  *
117556deab07SRod Evans  * When $ORIGIN was first introduced, the expansion of a relative path name was
117656deab07SRod Evans  * deferred until it was required.  However now we insure a full path name is
117756deab07SRod Evans  * always created - things like the analyzer wish to rely on librtld_db
117856deab07SRod Evans  * returning a full path.  The overhead of this is perceived to be low,
117956deab07SRod Evans  * providing the associated libc version of getcwd is available (see 4336878).
118056deab07SRod Evans  * This getcwd() was ported back to Solaris 8.1.
118156deab07SRod Evans  */
118256deab07SRod Evans size_t
fullpath(Rt_map * lmp,Fdesc * fdp)118356deab07SRod Evans fullpath(Rt_map *lmp, Fdesc *fdp)
118456deab07SRod Evans {
118556deab07SRod Evans 	const char	*name;
118656deab07SRod Evans 
118756deab07SRod Evans 	/*
118856deab07SRod Evans 	 * Determine whether this path name is already resolved.
118956deab07SRod Evans 	 */
119056deab07SRod Evans 	if (fdp && (fdp->fd_flags & FLG_FD_RESOLVED)) {
119156deab07SRod Evans 		/*
119256deab07SRod Evans 		 * If the resolved path differed from the original name, the
119356deab07SRod Evans 		 * resolved path would have been recorded as the fd_pname.
119456deab07SRod Evans 		 * Steal this path name from the file descriptor.  Otherwise,
119556deab07SRod Evans 		 * the path name is the same as the name of this object.
119656deab07SRod Evans 		 */
119756deab07SRod Evans 		if (fdp->fd_pname)
119856deab07SRod Evans 			PATHNAME(lmp) = fdp->fd_pname;
119956deab07SRod Evans 		else
120056deab07SRod Evans 			PATHNAME(lmp) = NAME(lmp);
120156deab07SRod Evans 	} else {
120256deab07SRod Evans 		/*
120356deab07SRod Evans 		 * If this path name has not yet been resolved, resolve the
120456deab07SRod Evans 		 * current name.
120556deab07SRod Evans 		 */
120656deab07SRod Evans 		char		_path[PATH_MAX];
120756deab07SRod Evans 		const char	*path;
120856deab07SRod Evans 		int		size, rsize;
120956deab07SRod Evans 
121056deab07SRod Evans 		if (fdp && fdp->fd_pname)
121156deab07SRod Evans 			PATHNAME(lmp) = fdp->fd_pname;
121256deab07SRod Evans 		else
121356deab07SRod Evans 			PATHNAME(lmp) = NAME(lmp);
121456deab07SRod Evans 
121556deab07SRod Evans 		name = path = PATHNAME(lmp);
121656deab07SRod Evans 		size = strlen(name);
121756deab07SRod Evans 
121856deab07SRod Evans 		if (path[0] != '/') {
121956deab07SRod Evans 			/*
122056deab07SRod Evans 			 * If we can't determine the current directory (possible
122156deab07SRod Evans 			 * if too many files are open - EMFILE), or if the
122256deab07SRod Evans 			 * created path is too big, simply revert back to the
122356deab07SRod Evans 			 * initial path name.
122456deab07SRod Evans 			 */
122556deab07SRod Evans 			if (getcwd(_path, (PATH_MAX - 2 - size)) != NULL) {
122656deab07SRod Evans 				(void) strcat(_path, MSG_ORIG(MSG_STR_SLASH));
122756deab07SRod Evans 				(void) strcat(_path, name);
122856deab07SRod Evans 				path = _path;
122956deab07SRod Evans 				size = strlen(path);
123056deab07SRod Evans 			}
123156deab07SRod Evans 		}
123256deab07SRod Evans 
123356deab07SRod Evans 		/*
123456deab07SRod Evans 		 * See if the path name can be reduced further.
123556deab07SRod Evans 		 */
123656deab07SRod Evans 		if ((rsize = resolvepath(path, _path, (PATH_MAX - 1))) > 0) {
123756deab07SRod Evans 			_path[rsize] = '\0';
123856deab07SRod Evans 			path = _path;
123956deab07SRod Evans 			size = rsize;
124056deab07SRod Evans 		}
124156deab07SRod Evans 
124256deab07SRod Evans 		/*
124356deab07SRod Evans 		 * If the path name is different from the original, duplicate it
124456deab07SRod Evans 		 * so that it is available in a core file.  If the duplication
124556deab07SRod Evans 		 * fails simply leave the original path name alone.
124656deab07SRod Evans 		 */
124756deab07SRod Evans 		if ((PATHNAME(lmp) =
124856deab07SRod Evans 		    stravl_insert(path, 0, (size + 1), 0)) == NULL)
124956deab07SRod Evans 			PATHNAME(lmp) = name;
125056deab07SRod Evans 	}
125156deab07SRod Evans 
125256deab07SRod Evans 	name = ORIGNAME(lmp) = PATHNAME(lmp);
125356deab07SRod Evans 
125456deab07SRod Evans 	/*
125556deab07SRod Evans 	 * Establish the directory name size - this also acts as a flag that the
125656deab07SRod Evans 	 * directory name has been computed.
125756deab07SRod Evans 	 */
125856deab07SRod Evans 	DIRSZ(lmp) = strrchr(name, '/') - name;
125956deab07SRod Evans 	return (DIRSZ(lmp));
12607c478bd9Sstevel@tonic-gate }
1261