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 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 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 ** 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 * 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 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 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 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 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 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