1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26/*
27 *	Copyright (c) 1988 AT&T
28 *	  All Rights Reserved
29 */
30/*
31 * Copyright (c) 2012, Joyent, Inc.  All rights reserved.
32 */
33
34/*
35 * PATH setup and search directory functions.
36 */
37
38#include	<stdio.h>
39#include	<unistd.h>
40#include	<limits.h>
41#include	<fcntl.h>
42#include	<string.h>
43#include	<debug.h>
44#include	<conv.h>
45#include	"_rtld.h"
46#include	"msg.h"
47
48/*
49 * Default and secure dependency search path initialization.
50 */
51void
52set_dirs(Alist **alpp, Spath_defn *sdp, uint_t flags)
53{
54	while (sdp->sd_name) {
55		Pdesc	*pdp;
56
57		if ((pdp = alist_append(alpp, NULL, sizeof (Pdesc),
58		    AL_CNT_SPATH)) == NULL)
59			return;
60
61		pdp->pd_pname = (char *)sdp->sd_name;
62		pdp->pd_plen = sdp->sd_len;
63		pdp->pd_flags = flags;
64		sdp++;
65	}
66}
67
68static void
69print_default_dirs(Lm_list *lml, Alist *alp, int search)
70{
71	uint_t	flags = 0;
72	int	num = 0;
73	Aliste	idx;
74	Pdesc	*pdp;
75
76	if (search)
77		(void) printf(MSG_INTL(MSG_LDD_PTH_BGNDFL));
78
79	for (ALIST_TRAVERSE(alp, idx, pdp)) {
80		flags = pdp->pd_flags;
81
82		if (search) {
83			const char	*fmt;
84
85			if (num++)
86				fmt = MSG_ORIG(MSG_LDD_FMT_PATHN);
87			else
88				fmt = MSG_ORIG(MSG_LDD_FMT_PATH1);
89
90			(void) printf(fmt, pdp->pd_pname);
91		} else
92			DBG_CALL(Dbg_libs_path(lml, pdp->pd_pname,
93			    pdp->pd_flags, config->c_name));
94	}
95
96	if (search) {
97		if (flags & LA_SER_CONFIG)
98			(void) printf(MSG_INTL(MSG_LDD_PTH_ENDDFLC),
99			    config->c_name);
100		else
101			(void) printf(MSG_INTL(MSG_LDD_PTH_ENDDFL));
102	}
103}
104
105/*
106 * Given a search rule type, return a list of directories to search according
107 * to the specified rule.
108 */
109static Alist **
110get_dir_list(uchar_t rules, Rt_map *lmp, uint_t flags)
111{
112	Alist	**dalpp = NULL;
113	Lm_list *lml = LIST(lmp);
114	int	search;
115
116	/*
117	 * Determine whether ldd -s is in effect - ignore when we're searching
118	 * for audit libraries as these will be added to their own link-map.
119	 */
120	if ((lml->lm_flags & LML_FLG_TRC_SEARCH) &&
121	    ((FLAGS1(lmp) & FL1_RT_LDDSTUB) == 0) &&
122	    ((flags & FLG_RT_AUDIT) == 0))
123		search = 1;
124	else
125		search = 0;
126
127	switch (rules) {
128	case RPLENV:
129		/*
130		 * Initialize the replaceable environment variable
131		 * (LD_LIBRARY_PATH) search path list.  Note, we always call
132		 * Dbg_libs_path() so that every library lookup diagnostic can
133		 * be preceded with the appropriate search path information.
134		 */
135		if (rpl_libpath) {
136			uint_t	mode = (LA_SER_LIBPATH | PD_FLG_UNIQUE);
137
138			/*
139			 * Note, this path may have originated from the users
140			 * environment or from a configuration file.
141			 */
142			if (env_info & ENV_INF_PATHCFG)
143				mode |= LA_SER_CONFIG;
144
145			DBG_CALL(Dbg_libs_path(lml, rpl_libpath, mode,
146			    config->c_name));
147
148			/*
149			 * For ldd(1) -s, indicate the search paths that'll
150			 * be used.  If this is a secure application then some
151			 * search paths may be ignored, therefore reset the
152			 * rpl_libdirs pointer each time so that the
153			 * diagnostics related to these unsecure directories
154			 * will be output for each image loaded.
155			 */
156			if (search) {
157				const char	*fmt;
158
159				if (env_info & ENV_INF_PATHCFG)
160					fmt = MSG_INTL(MSG_LDD_PTH_LIBPATHC);
161				else
162					fmt = MSG_INTL(MSG_LDD_PTH_LIBPATH);
163
164				(void) printf(fmt, rpl_libpath, config->c_name);
165			}
166			if (rpl_libdirs && (rtld_flags & RT_FL_SECURE) &&
167			    (search || DBG_ENABLED))
168				remove_alist(&rpl_libdirs, 1);
169
170			if (rpl_libdirs == NULL) {
171				/*
172				 * If this is a secure application we need to
173				 * be selective over what directories we use.
174				 */
175				(void) expand_paths(lmp, rpl_libpath,
176				    &rpl_libdirs, AL_CNT_SEARCH, mode,
177				    PD_TKN_CAP);
178			}
179			dalpp = &rpl_libdirs;
180		}
181		break;
182	case PRMENV:
183		/*
184		 * Initialize the permanent (LD_LIBRARY_PATH) search path list.
185		 * This can only originate from a configuration file.  To be
186		 * consistent with the debugging display of DEFENV (above),
187		 * always call Dbg_libs_path().
188		 */
189		if (prm_libpath) {
190			uint_t	mode =
191			    (LA_SER_LIBPATH | LA_SER_CONFIG | PD_FLG_UNIQUE);
192
193			DBG_CALL(Dbg_libs_path(lml, prm_libpath, mode,
194			    config->c_name));
195
196			/*
197			 * For ldd(1) -s, indicate the search paths that'll
198			 * be used.  If this is a secure application then some
199			 * search paths may be ignored, therefore reset the
200			 * prm_libdirs pointer each time so that the
201			 * diagnostics related to these unsecure directories
202			 * will be output for each image loaded.
203			 */
204			if (search)
205				(void) printf(MSG_INTL(MSG_LDD_PTH_LIBPATHC),
206				    prm_libpath, config->c_name);
207			if (prm_libdirs && (rtld_flags & RT_FL_SECURE) &&
208			    (search || DBG_ENABLED))
209				remove_alist(&prm_libdirs, 1);
210
211			if (prm_libdirs == NULL) {
212				/*
213				 * If this is a secure application we need to
214				 * be selective over what directories we use.
215				 */
216				(void) expand_paths(lmp, prm_libpath,
217				    &prm_libdirs, AL_CNT_SEARCH, mode,
218				    PD_TKN_CAP);
219			}
220			dalpp = &prm_libdirs;
221		}
222		break;
223	case RUNPATH:
224		/*
225		 * Initialize the runpath search path list.  To be consistent
226		 * with the debugging display of DEFENV (above), always call
227		 * Dbg_libs_path().
228		 */
229		if (RPATH(lmp)) {
230			DBG_CALL(Dbg_libs_path(lml, RPATH(lmp), LA_SER_RUNPATH,
231			    NAME(lmp)));
232
233			/*
234			 * For ldd(1) -s, indicate the search paths that'll
235			 * be used.  If this is a secure application then some
236			 * search paths may be ignored, therefore reset the
237			 * runlist pointer each time so that the diagnostics
238			 * related to these unsecure directories will be
239			 * output for each image loaded.
240			 */
241			if (search)
242				(void) printf(MSG_INTL(MSG_LDD_PTH_RUNPATH),
243				    RPATH(lmp), NAME(lmp));
244			if (RLIST(lmp) && (rtld_flags & RT_FL_SECURE) &&
245			    (search || DBG_ENABLED))
246				remove_alist(&RLIST(lmp), 1);
247
248			if (RLIST(lmp) == NULL) {
249				/*
250				 * If this is a secure application we need to
251				 * be selective over what directories we use.
252				 */
253				(void) expand_paths(lmp, RPATH(lmp),
254				    &RLIST(lmp), AL_CNT_SEARCH, LA_SER_RUNPATH,
255				    PD_TKN_CAP);
256			}
257			dalpp = &RLIST(lmp);
258		}
259		break;
260	case DEFAULT:
261		/*
262		 * If we have been requested to load an audit library through a
263		 * DT_DEPAUDIT entry, then we treat this the same way that we
264		 * handle a library that has been specified via a DT_NEEDED
265		 * entry -- we check the default directories and not the
266		 * secure directories.
267		 */
268		if ((FLAGS1(lmp) & FL1_RT_NODEFLIB) == 0) {
269			if ((rtld_flags & RT_FL_SECURE) &&
270			    ((flags & FLG_RT_PRELOAD) ||
271			    ((flags & FLG_RT_AUDIT) && !(FLAGS1(lmp) &
272			    FL1_RT_DEPAUD))))
273				dalpp = LM_SECURE_DIRS(lmp)();
274			else
275				dalpp = LM_DEFAULT_DIRS(lmp)();
276		}
277
278		/*
279		 * For ldd(1) -s, indicate the default paths that'll be used.
280		 */
281		if (dalpp && (search || DBG_ENABLED))
282			print_default_dirs(lml, *dalpp, search);
283		break;
284	default:
285		break;
286	}
287	return (dalpp);
288}
289
290/*
291 * Get the next directory in the search rules path.  The search path "cookie"
292 * provided by the caller (sdp) maintains the state of a search in progress.
293 *
294 * Typically, a search consists of a series of rules that govern the order of
295 * a search (ie. LD_LIBRARY_PATH, followed by RPATHS, followed by defaults).
296 * Each rule can establish a corresponding series of path names, which are
297 * maintained as an Alist.  The index within this Alist determines the present
298 * search directory.
299 */
300Pdesc *
301get_next_dir(Spath_desc *sdp, Rt_map *lmp, uint_t flags)
302{
303	/*
304	 * Make sure there are still rules to process.
305	 */
306	while (*sdp->sp_rule) {
307		Alist	*alp;
308
309		/*
310		 * If an Alist for this rule already exists, use if, otherwise
311		 * obtain an Alist for this rule.  Providing the Alist has
312		 * content, and the present Alist index is less than the number
313		 * of Alist members, return the associated path name descriptor.
314		 */
315		if ((sdp->sp_dalpp || ((sdp->sp_dalpp =
316		    get_dir_list(*sdp->sp_rule, lmp, flags)) != NULL)) &&
317		    ((alp = *sdp->sp_dalpp) != NULL) &&
318		    (alist_nitems(alp) > sdp->sp_idx)) {
319			return (alist_item(alp, sdp->sp_idx++));
320		}
321
322		/*
323		 * If no Alist for this rule exists, or if this is the last
324		 * element of this Alist, reset the Alist pointer and index,
325		 * and prepare for the next rule.
326		 */
327		sdp->sp_rule++;
328		sdp->sp_dalpp = NULL;
329		sdp->sp_idx = 0;
330	}
331
332	/*
333	 * All rules and search paths have been exhausted.
334	 */
335	return (NULL);
336}
337
338/*
339 * Process a directory (runpath) or filename (needed or filter) string looking
340 * for tokens to expand.  Allocate a new buffer for the string.
341 */
342uint_t
343expand(char **name, size_t *len, char **list, uint_t orig, uint_t omit,
344    Rt_map *lmp)
345{
346	char	_name[PATH_MAX];
347	char	*token = NULL, *oname, *ename, *optr, *_optr, *nptr, *_list;
348	size_t	olen = 0, nlen = 0, _len;
349	int	isaflag = 0;
350	uint_t	flags = 0;
351	Lm_list	*lml = LIST(lmp);
352
353	optr = _optr = oname = ename = *name;
354	ename += *len;
355	nptr = _name;
356
357	while ((olen < *len) && (nlen < PATH_MAX)) {
358		uint_t	_flags;
359
360		if ((*optr != '$') || ((olen - *len) == 1)) {
361			/*
362			 * When expanding paths while a configuration file
363			 * exists that contains directory information, determine
364			 * whether the path contains "./".  If so, we'll resolve
365			 * the path later to remove these relative entries.
366			 */
367			if ((rtld_flags & RT_FL_DIRCFG) &&
368			    (orig & LA_SER_MASK) && (*optr == '/') &&
369			    (optr != oname) && (*(optr - 1) == '.'))
370				flags |= TKN_DOTSLASH;
371
372			olen++, optr++;
373			continue;
374		}
375
376		/*
377		 * Copy any string we've presently passed over to the new
378		 * buffer.
379		 */
380		if ((_len = (optr - _optr)) != 0) {
381			if ((nlen += _len) < PATH_MAX) {
382				(void) strncpy(nptr, _optr, _len);
383				nptr = nptr + _len;
384			} else {
385				eprintf(lml, ERR_FATAL,
386				    MSG_INTL(MSG_ERR_EXPAND1), NAME(lmp),
387				    oname);
388				return (0);
389			}
390		}
391
392		/*
393		 * Skip the token delimiter and determine if a reserved token
394		 * match is found.
395		 */
396		olen++, optr++;
397		_flags = 0;
398		token = 0;
399
400		if (strncmp(optr, MSG_ORIG(MSG_TKN_ORIGIN),
401		    MSG_TKN_ORIGIN_SIZE) == 0) {
402			token = (char *)MSG_ORIG(MSG_TKN_ORIGIN);
403
404			/*
405			 * $ORIGIN expansion is required.  Determine this
406			 * objects basename.  Expansion of $ORIGIN is allowed
407			 * for secure applications but must be checked by the
408			 * caller to insure the expanded path matches a
409			 * registered secure name.
410			 */
411			if (((omit & PD_TKN_ORIGIN) == 0) &&
412			    (((_len = DIRSZ(lmp)) != 0) ||
413			    ((_len = fullpath(lmp, 0)) != 0))) {
414				if ((nlen += _len) < PATH_MAX) {
415					(void) strncpy(nptr,
416					    ORIGNAME(lmp), _len);
417					nptr = nptr +_len;
418					olen += MSG_TKN_ORIGIN_SIZE;
419					optr += MSG_TKN_ORIGIN_SIZE;
420					_flags |= PD_TKN_ORIGIN;
421				} else {
422					eprintf(lml, ERR_FATAL,
423					    MSG_INTL(MSG_ERR_EXPAND1),
424					    NAME(lmp), oname);
425					return (0);
426				}
427			}
428
429		} else if (strncmp(optr, MSG_ORIG(MSG_TKN_PLATFORM),
430		    MSG_TKN_PLATFORM_SIZE) == 0) {
431			Syscapset	*scapset;
432
433			if (FLAGS1(lmp) & FL1_RT_ALTCAP)
434				scapset = alt_scapset;
435			else
436				scapset = org_scapset;
437
438			token = (char *)MSG_ORIG(MSG_TKN_PLATFORM);
439
440			/*
441			 * $PLATFORM expansion required.
442			 */
443			if (((omit & PD_TKN_PLATFORM) == 0) &&
444			    ((scapset->sc_plat == NULL) &&
445			    (scapset->sc_platsz == 0)))
446				platform_name(scapset);
447
448			if (((omit & PD_TKN_PLATFORM) == 0) &&
449			    scapset->sc_plat) {
450				nlen += scapset->sc_platsz;
451				if (nlen < PATH_MAX) {
452					(void) strncpy(nptr, scapset->sc_plat,
453					    scapset->sc_platsz);
454					nptr = nptr + scapset->sc_platsz;
455					olen += MSG_TKN_PLATFORM_SIZE;
456					optr += MSG_TKN_PLATFORM_SIZE;
457					_flags |= PD_TKN_PLATFORM;
458				} else {
459					eprintf(lml, ERR_FATAL,
460					    MSG_INTL(MSG_ERR_EXPAND1),
461					    NAME(lmp), oname);
462					return (0);
463				}
464			}
465
466		} else if (strncmp(optr, MSG_ORIG(MSG_TKN_MACHINE),
467		    MSG_TKN_MACHINE_SIZE) == 0) {
468			Syscapset	*scapset;
469
470			if (FLAGS1(lmp) & FL1_RT_ALTCAP)
471				scapset = alt_scapset;
472			else
473				scapset = org_scapset;
474
475			token = (char *)MSG_ORIG(MSG_TKN_MACHINE);
476
477			/*
478			 * $MACHINE expansion required.
479			 */
480			if (((omit & PD_TKN_MACHINE) == 0) &&
481			    ((scapset->sc_mach == NULL) &&
482			    (scapset->sc_machsz == 0)))
483				machine_name(scapset);
484
485			if (((omit & PD_TKN_MACHINE) == 0) &&
486			    scapset->sc_mach) {
487				nlen += scapset->sc_machsz;
488				if (nlen < PATH_MAX) {
489					(void) strncpy(nptr, scapset->sc_mach,
490					    scapset->sc_machsz);
491					nptr = nptr + scapset->sc_machsz;
492					olen += MSG_TKN_MACHINE_SIZE;
493					optr += MSG_TKN_MACHINE_SIZE;
494					_flags |= PD_TKN_MACHINE;
495				} else {
496					eprintf(lml, ERR_FATAL,
497					    MSG_INTL(MSG_ERR_EXPAND1),
498					    NAME(lmp), oname);
499					return (0);
500				}
501			}
502
503		} else if (strncmp(optr, MSG_ORIG(MSG_TKN_OSNAME),
504		    MSG_TKN_OSNAME_SIZE) == 0) {
505			token = (char *)MSG_ORIG(MSG_TKN_OSNAME);
506
507			/*
508			 * $OSNAME expansion required.  This is established
509			 * from the sysname[] returned by uname(2).
510			 */
511			if (((omit & PD_TKN_OSNAME) == 0) && (uts == NULL))
512				uts = conv_uts();
513
514			if (((omit & PD_TKN_OSNAME) == 0) &&
515			    (uts && uts->uts_osnamesz)) {
516				if ((nlen += uts->uts_osnamesz) < PATH_MAX) {
517					(void) strncpy(nptr, uts->uts_osname,
518					    uts->uts_osnamesz);
519					nptr = nptr + uts->uts_osnamesz;
520					olen += MSG_TKN_OSNAME_SIZE;
521					optr += MSG_TKN_OSNAME_SIZE;
522					_flags |= PD_TKN_OSNAME;
523				} else {
524					eprintf(lml, ERR_FATAL,
525					    MSG_INTL(MSG_ERR_EXPAND1),
526					    NAME(lmp), oname);
527					return (0);
528				}
529			}
530
531		} else if (strncmp(optr, MSG_ORIG(MSG_TKN_OSREL),
532		    MSG_TKN_OSREL_SIZE) == 0) {
533			token = (char *)MSG_ORIG(MSG_TKN_OSREL);
534
535			/*
536			 * $OSREL expansion required.  This is established
537			 * from the release[] returned by uname(2).
538			 */
539			if (((omit & PD_TKN_OSREL) == 0) && (uts == 0))
540				uts = conv_uts();
541
542			if (((omit & PD_TKN_OSREL) == 0) &&
543			    (uts && uts->uts_osrelsz)) {
544				if ((nlen += uts->uts_osrelsz) < PATH_MAX) {
545					(void) strncpy(nptr, uts->uts_osrel,
546					    uts->uts_osrelsz);
547					nptr = nptr + uts->uts_osrelsz;
548					olen += MSG_TKN_OSREL_SIZE;
549					optr += MSG_TKN_OSREL_SIZE;
550					_flags |= PD_TKN_OSREL;
551				} else {
552					eprintf(lml, ERR_FATAL,
553					    MSG_INTL(MSG_ERR_EXPAND1),
554					    NAME(lmp), oname);
555					return (0);
556				}
557			}
558
559		} else if ((strncmp(optr, MSG_ORIG(MSG_TKN_ISALIST),
560		    MSG_TKN_ISALIST_SIZE) == 0)) {
561			int	ok;
562			token = (char *)MSG_ORIG(MSG_TKN_ISALIST);
563
564			/*
565			 * $ISALIST expansion required.  When accompanied with
566			 * a list pointer, this routine updates that pointer
567			 * with the new list of potential candidates.  Without
568			 * this list pointer, only the first expansion is
569			 * provided.  NOTE, that two $ISLIST expansions within
570			 * the same path aren't supported.
571			 */
572			if ((omit & PD_TKN_ISALIST) || isaflag++)
573				ok = 0;
574			else
575				ok = 1;
576
577			if (ok && (isa == NULL))
578				isa = conv_isalist();
579
580			if (ok && isa && isa->isa_listsz) {
581				size_t	no, mlen, tlen, hlen = olen - 1;
582				char	*lptr;
583				Isa_opt *opt = isa->isa_opt;
584
585				if ((nlen += opt->isa_namesz) < PATH_MAX) {
586					(void) strncpy(nptr,  opt->isa_name,
587					    opt->isa_namesz);
588					nptr = nptr + opt->isa_namesz;
589					olen += MSG_TKN_ISALIST_SIZE;
590					optr += MSG_TKN_ISALIST_SIZE;
591					_flags |= PD_TKN_ISALIST;
592				} else {
593					eprintf(lml, ERR_FATAL,
594					    MSG_INTL(MSG_ERR_EXPAND1),
595					    NAME(lmp), oname);
596					return (0);
597				}
598
599				if (list) {
600					tlen = *len - olen;
601					mlen = ((hlen + tlen) *
602					    (isa->isa_optno - 1)) +
603					    isa->isa_listsz - opt->isa_namesz +
604					    strlen(*list);
605					if ((_list = lptr =
606					    malloc(mlen)) == NULL)
607						return (0);
608
609					for (no = 1, opt++; no < isa->isa_optno;
610					    no++, opt++) {
611						(void) strncpy(lptr, *name,
612						    hlen);
613						lptr = lptr + hlen;
614						(void) strncpy(lptr,
615						    opt->isa_name,
616						    opt->isa_namesz);
617						lptr = lptr + opt->isa_namesz;
618						(void) strncpy(lptr, optr,
619						    tlen);
620						lptr = lptr + tlen;
621						*lptr++ = ':';
622					}
623					if (**list)
624						(void) strcpy(lptr, *list);
625					else
626						*--lptr = '\0';
627				}
628			}
629
630		} else if (strncmp(optr, MSG_ORIG(MSG_TKN_CAPABILITY),
631		    MSG_TKN_CAPABILITY_SIZE) == 0) {
632			char	*bptr = nptr - 1;
633			char	*eptr = optr + MSG_TKN_CAPABILITY_SIZE;
634			token = (char *)MSG_ORIG(MSG_TKN_CAPABILITY);
635
636			/*
637			 * $CAPABILITY expansion required.  Expansion is only
638			 * allowed for non-simple path names (must contain a
639			 * '/'), with the token itself being the last element
640			 * of the path.  Therefore, all we need do is test the
641			 * existence of the string "/$CAPABILITY\0".
642			 */
643			if (((omit & PD_TKN_CAP) == 0) &&
644			    ((bptr > _name) && (*bptr == '/') &&
645			    ((*eptr == '\0') || (*eptr == ':')))) {
646				/*
647				 * Decrement the present pointer so that the
648				 * directories trailing "/" gets nuked later.
649				 */
650				nptr--, nlen--;
651				olen += MSG_TKN_CAPABILITY_SIZE;
652				optr += MSG_TKN_CAPABILITY_SIZE;
653				_flags |= PD_TKN_CAP;
654			}
655
656		} else if (strncmp(optr, MSG_ORIG(MSG_TKN_HWCAP),
657		    MSG_TKN_HWCAP_SIZE) == 0) {
658			char	*bptr = nptr - 1;
659			char	*eptr = optr + MSG_TKN_HWCAP_SIZE;
660			token = (char *)MSG_ORIG(MSG_TKN_HWCAP);
661
662			/*
663			 * $HWCAP expansion required.  This token has been
664			 * superseeded by $CAPABILITY.  For compatibility with
665			 * older environments, only expand this token when hard-
666			 * ware capability information is available.   This
667			 * expansion is only allowed for non-simple path names
668			 * (must contain a '/'), with the token itself being the
669			 * last element of the path.  Therefore, all we need do
670			 * is test the existence of the string "/$HWCAP\0".
671			 */
672			if (((omit & PD_TKN_CAP) == 0) &&
673			    (rtld_flags2 & RT_FL2_HWCAP) &&
674			    ((bptr > _name) && (*bptr == '/') &&
675			    ((*eptr == '\0') || (*eptr == ':')))) {
676				/*
677				 * Decrement the present pointer so that the
678				 * directories trailing "/" gets nuked later.
679				 */
680				nptr--, nlen--;
681				olen += MSG_TKN_HWCAP_SIZE;
682				optr += MSG_TKN_HWCAP_SIZE;
683				_flags |= PD_TKN_CAP;
684			}
685
686		} else {
687			/*
688			 * If reserved token was not found, copy the
689			 * character.
690			 */
691			*nptr++ = '$';
692			nlen++;
693		}
694
695		/*
696		 * If a reserved token was found, and could not be expanded,
697		 * diagnose the error condition.
698		 */
699		if (token) {
700			if (_flags)
701				flags |= _flags;
702			else {
703				char	buf[PATH_MAX], *str;
704
705				/*
706				 * Note, the original string we're expanding
707				 * might contain a number of ':' separated
708				 * paths.  Isolate the path we're processing to
709				 * provide a more precise error diagnostic.
710				 */
711				if (str = strchr(oname, ':')) {
712					size_t	slen = str - oname;
713
714					(void) strncpy(buf, oname, slen);
715					buf[slen] = '\0';
716					str = buf;
717				} else
718					str = oname;
719
720				eprintf(lml, ERR_FATAL,
721				    MSG_INTL(MSG_ERR_EXPAND2), NAME(lmp),
722				    str, token);
723				return (0);
724			}
725		}
726		_optr = optr;
727	}
728
729	/*
730	 * First make sure the current length is shorter than PATH_MAX.  We may
731	 * arrive here if the given path contains '$' characters which are not
732	 * the lead of a reserved token.
733	 */
734	if (nlen >= PATH_MAX) {
735		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ERR_EXPAND1), NAME(lmp),
736		    oname);
737		return (0);
738	}
739
740	/*
741	 * If any ISALIST processing has occurred not only do we return the
742	 * expanded node we're presently working on, but we can also update the
743	 * remaining list so that it is effectively prepended with this node
744	 * expanded to all remaining ISALIST options.  Note that we can only
745	 * handle one ISALIST per node.  For more than one ISALIST to be
746	 * processed we'd need a better algorithm than above to replace the
747	 * newly generated list.  Whether we want to encourage the number of
748	 * path name permutations this would provide is another question.  So,
749	 * for now if more than one ISALIST is encountered we return the
750	 * original node untouched.
751	 */
752	if (isa && isaflag) {
753		if (isaflag == 1) {
754			if (list)
755				*list = _list;
756		} else {
757			flags &= ~PD_TKN_ISALIST;
758			if ((nptr = (char *)stravl_insert(*name, 0,
759			    (*len + 1), 1)) == NULL)
760				return (0);
761			*name = nptr;
762			return (TKN_NONE);
763		}
764	}
765
766	/*
767	 * Copy any remaining string. Terminate the new string with a null as
768	 * this string can be displayed via debugging diagnostics.
769	 */
770	if ((_len = (optr - _optr)) != 0) {
771		if ((nlen += _len) < PATH_MAX) {
772			(void) strncpy(nptr, _optr, _len);
773			nptr = nptr + _len;
774		} else {
775			eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ERR_EXPAND1),
776			    NAME(lmp), oname);
777			return (0);
778		}
779	}
780	*nptr = '\0';
781
782	/*
783	 * A path that has been expanded is typically used to create full
784	 * path names for objects that will be opened.  The final path name is
785	 * resolved to simplify it, and set the stage for possible $ORIGIN
786	 * processing.  Therefore, it's usually unnecessary to resolve the path
787	 * at this point.  However, if a configuration file, containing
788	 * directory information is in use, then we might need to lookup this
789	 * path in the configuration file.  To keep the number of path name
790	 * resolutions to a minimum, only resolve paths that contain "./".  The
791	 * use of "$ORIGIN/../lib" will probably only match a configuration file
792	 * entry after resolution.
793	 */
794	if (list && (rtld_flags & RT_FL_DIRCFG) && (flags & TKN_DOTSLASH)) {
795		int	len;
796
797		if ((len = resolvepath(_name, _name, (PATH_MAX - 1))) >= 0) {
798			nlen = (size_t)len;
799			_name[nlen] = '\0';
800			flags |= PD_TKN_RESOLVED;
801		}
802	}
803
804	/*
805	 * Allocate a new string if necessary.
806	 *
807	 * If any form of token expansion, or string resolution has occurred,
808	 * the storage must be allocated for the new string.
809	 *
810	 * If we're processing a substring, for example, any string besides the
811	 * last string within a search path "A:B:C", then this substring needs
812	 * to be isolated with a null terminator.  However, if this search path
813	 * was created from a previous ISALIST expansion, then all strings must
814	 * be allocated, as the isalist expansion will be freed after expansion
815	 * processing.
816	 */
817	if ((nptr = (char *)stravl_insert(_name, 0, (nlen + 1), 1)) == NULL)
818		return (0);
819	*name = nptr;
820	*len = nlen;
821	return (flags ? flags : TKN_NONE);
822}
823
824/*
825 * Determine whether a path name is secure.
826 */
827int
828is_path_secure(char *opath, Rt_map *clmp, uint_t info, uint_t flags)
829{
830	Alist		**salpp;
831	Aliste		idx;
832	char		buffer[PATH_MAX], *npath = NULL;
833	Lm_list		*lml = LIST(clmp);
834	Pdesc		*pdp;
835
836	/*
837	 * If a path name originates from a configuration file, use it.  The use
838	 * of a configuration file is already validated for secure applications,
839	 * so if we're using a configuration file, we must be able to use all
840	 * that it defines.
841	 */
842	if (info & LA_SER_CONFIG)
843		return (1);
844
845	if ((info & LA_SER_MASK) == 0) {
846		char	*str;
847
848		/*
849		 * If the path name specifies a file (rather than a directory),
850		 * peel off the file before making the comparison.
851		 */
852		str = strrchr(opath, '/');
853
854		/*
855		 * Carry out some initial security checks.
856		 *
857		 *   .	a simple file name (one containing no "/") is fine, as
858		 *	this file name will be combined with search paths to
859		 *	determine the complete path.  Note, a secure application
860		 *	may provide a configuration file, and this can only be
861		 *	a full path name (PN_FLG_FULLPATH).
862		 *   .	a full path (one starting with "/") is fine, provided
863		 *	this path name isn't a preload/audit path.
864		 *   .	provided $ORIGIN expansion has not been employed, the
865		 *	above categories of path are deemed secure.
866		 */
867		if ((((str == 0) && ((info & PD_FLG_FULLPATH) == 0)) ||
868		    ((*opath == '/') && (str != opath) &&
869		    ((info & PD_FLG_EXTLOAD) == 0))) &&
870		    ((flags & PD_TKN_ORIGIN) == 0))
871			return (1);
872
873		/*
874		 * Determine the directory name of the present path.
875		 */
876		if (str) {
877			if (str == opath)
878				npath = (char *)MSG_ORIG(MSG_STR_SLASH);
879			else {
880				size_t	size;
881
882				if ((size = str - opath) >= PATH_MAX)
883					return (0);
884
885				(void) strncpy(buffer, opath, size);
886				buffer[size] = '\0';
887				npath = buffer;
888			}
889
890			/*
891			 * If $ORIGIN processing has been employed, then allow
892			 * any directory that has already been used to satisfy
893			 * other dependencies, to be used.
894			 */
895			if ((flags & PD_TKN_ORIGIN) &&
896			    pnavl_recorded(&spavl, npath, 0, NULL)) {
897				DBG_CALL(Dbg_libs_insecure(lml, npath, 1));
898				return (1);
899			}
900		}
901	} else {
902		/*
903		 * A search path, i.e., RPATH, configuration file path, etc. is
904		 * used as is.  Exceptions to this are:
905		 *
906		 *   .	LD_LIBRARY_PATH.
907		 *   .	any $ORIGIN expansion, unless used by a setuid ld.so.1
908		 *	to find its own dependencies, or the path name has
909		 *	already been used to find other dependencies.
910		 *   .	any relative path.
911		 */
912		if (((info & LA_SER_LIBPATH) == 0) && (*opath == '/') &&
913		    ((flags & PD_TKN_ORIGIN) == 0))
914			return (1);
915
916		/*
917		 * If $ORIGIN processing is requested, allow a setuid ld.so.1
918		 * to use this path for its own dependencies.  Allow the
919		 * application to use this path name only if the path name has
920		 * already been used to locate other dependencies.
921		 */
922		if (flags & PD_TKN_ORIGIN) {
923			if ((lml->lm_flags & LML_FLG_RTLDLM) &&
924			    is_rtld_setuid())
925				return (1);
926			else if (pnavl_recorded(&spavl, opath, 0, NULL)) {
927				DBG_CALL(Dbg_libs_insecure(lml, opath, 1));
928				return (1);
929			}
930		}
931		npath = (char *)opath;
932	}
933
934	/*
935	 * Determine whether the present directory is trusted.
936	 */
937	if (npath) {
938		salpp = LM_SECURE_DIRS(LIST(clmp)->lm_head)();
939		for (ALIST_TRAVERSE(*salpp, idx, pdp)) {
940			if (strcmp(npath, pdp->pd_pname) == 0)
941				return (1);
942		}
943	}
944
945	/*
946	 * The path is insecure, so depending on the caller, provide a
947	 * diagnostic.  Preloaded, or audit libraries generate a warning, as
948	 * the process will run without them.
949	 */
950	if (info & PD_FLG_EXTLOAD) {
951		if (lml->lm_flags & LML_FLG_TRC_ENABLE) {
952			if ((FLAGS1(clmp) & FL1_RT_LDDSTUB) == 0)
953				(void) printf(MSG_INTL(MSG_LDD_FIL_ILLEGAL),
954				    opath);
955		} else
956			eprintf(lml, ERR_WARNING, MSG_INTL(MSG_SEC_ILLEGAL),
957			    opath);
958
959		return (0);
960	}
961
962	/*
963	 * Explicit file references are fatal.
964	 */
965	if ((info & LA_SER_MASK) == 0) {
966		if (lml->lm_flags & LML_FLG_TRC_ENABLE) {
967			/* BEGIN CSTYLED */
968			if ((FLAGS1(clmp) & FL1_RT_LDDSTUB) == 0) {
969				if (lml->lm_flags &
970				    (LML_FLG_TRC_VERBOSE | LML_FLG_TRC_SEARCH))
971					(void) printf(
972					    MSG_INTL(MSG_LDD_FIL_FIND),
973					    opath, NAME(clmp));
974
975				if (((rtld_flags & RT_FL_SILENCERR) == 0) ||
976				    (lml->lm_flags & LML_FLG_TRC_VERBOSE))
977					(void) printf(
978					    MSG_INTL(MSG_LDD_FIL_ILLEGAL),
979					    opath);
980			}
981			/* END CSTYLED */
982		} else
983			eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), opath,
984			    strerror(EACCES));
985	} else {
986		/*
987		 * Search paths.
988		 */
989		DBG_CALL(Dbg_libs_insecure(lml, opath, 0));
990		if ((lml->lm_flags & LML_FLG_TRC_SEARCH) &&
991		    ((FLAGS1(clmp) & FL1_RT_LDDSTUB) == 0))
992			(void) printf(MSG_INTL(MSG_LDD_PTH_IGNORE), opath);
993	}
994	return (0);
995}
996
997/*
998 * Determine whether a path already exists within the callers Pnode list.
999 */
1000inline static uint_t
1001is_path_unique(Alist *alp, const char *path)
1002{
1003	Aliste	idx;
1004	Pdesc	*pdp;
1005
1006	for (ALIST_TRAVERSE(alp, idx, pdp)) {
1007		if (pdp->pd_plen && (strcmp(pdp->pd_pname, path) == 0))
1008			return (PD_FLG_DUPLICAT);
1009	}
1010	return (0);
1011}
1012
1013/*
1014 * Expand one or more path names.  This routine is called for all path strings,
1015 * i.e., NEEDED, rpaths, default search paths, configuration file search paths,
1016 * filtees, etc.  The path may be a single path name, or a colon separated list
1017 * of path names.  Each individual path name is processed for possible reserved
1018 * token expansion.  All string nodes are maintained in allocated memory
1019 * (regardless of whether they are constant (":"), or token expanded) to
1020 * simplify path name descriptor removal.
1021 *
1022 * The info argument passes in auxiliary information regarding the callers
1023 * intended use of the path names.  This information may be maintained in the
1024 * path name descriptor element produced to describe the path name (i.e.,
1025 * LA_SER_LIBPATH etc.), or may be used to determine additional security or
1026 * diagnostic processing.
1027 */
1028int
1029expand_paths(Rt_map *clmp, const char *list, Alist **alpp, Aliste alni,
1030    uint_t orig, uint_t omit)
1031{
1032	char	*str, *olist = 0, *nlist = (char *)list;
1033	int	fnull = FALSE;	/* TRUE if empty final path segment seen */
1034	Pdesc	*pdp = NULL;
1035
1036	for (str = nlist; *nlist || fnull; str = nlist) {
1037		char	*ostr;
1038		char	*elist = NULL;
1039		size_t	len, olen;
1040		uint_t	tkns = 0;
1041
1042		if (*nlist == ';')
1043			++nlist, ++str;
1044		if ((*nlist == ':') || fnull) {
1045			/* If not a final null segment, check following one */
1046			fnull = !(fnull || *(nlist + 1));
1047
1048			if (*nlist)
1049				nlist++;
1050
1051			/*
1052			 * When the shell sees a null PATH segment, it
1053			 * treats it as if it were the cwd (.). We mimic
1054			 * this behavior for LD_LIBRARY_PATH and runpaths
1055			 * (mainly for backwards compatibility with previous
1056			 * behavior). For other paths, this makes no sense,
1057			 * so we simply ignore the segment.
1058			 */
1059			if (!(orig & (LA_SER_LIBPATH | LA_SER_RUNPATH)))
1060				continue; /* Process next segment */
1061
1062			str = (char *)MSG_ORIG(MSG_FMT_CWD);
1063			len = MSG_FMT_CWD_SIZE;
1064
1065		} else {
1066			uint_t	_tkns;
1067
1068			len = 0;
1069			while (*nlist && (*nlist != ':') && (*nlist != ';')) {
1070				if (*nlist == '/')
1071					tkns |= PD_FLG_PNSLASH;
1072				nlist++, len++;
1073			}
1074
1075			/* Check for a following final null segment */
1076			fnull = (*nlist == ':') && !*(nlist + 1);
1077
1078			if (*nlist)
1079				nlist++;
1080
1081			/*
1082			 * Expand the captured string.  Besides expanding the
1083			 * present path/file entry, we may have a new list to
1084			 * deal with (ISALIST expands to multiple new entries).
1085			 */
1086			elist = nlist;
1087			ostr = str;
1088			olen = len;
1089			if ((_tkns = expand(&str, &len, &elist, orig, omit,
1090			    clmp)) == 0)
1091				continue;
1092			tkns |= _tkns;
1093		}
1094
1095		/*
1096		 * If this a secure application, validation of the expanded
1097		 * path name may be necessary.
1098		 */
1099		if ((rtld_flags & RT_FL_SECURE) &&
1100		    (is_path_secure(str, clmp, orig, tkns) == 0))
1101			continue;
1102
1103		/*
1104		 * If required, ensure that the string is unique.  For search
1105		 * paths such as LD_LIBRARY_PATH, users often inherit multiple
1106		 * paths which result in unnecessary duplication.  Note, if
1107		 * we're debugging, any duplicate entry is retained and flagged
1108		 * so that the entry can be diagnosed later as part of unused
1109		 * processing.
1110		 */
1111		if (orig & PD_FLG_UNIQUE) {
1112			Word	tracing;
1113
1114			tracing = LIST(clmp)->lm_flags &
1115			    (LML_FLG_TRC_UNREF | LML_FLG_TRC_UNUSED);
1116			tkns |= is_path_unique(*alpp, str);
1117
1118			/*
1119			 * Note, use the debug strings rpl_debug and prm_debug
1120			 * as an indicator that debugging has been requested,
1121			 * rather than DBG_ENABLE(), as the initial use of
1122			 * LD_LIBRARY_PATH occurs in preparation for loading
1123			 * our debugging library.
1124			 */
1125			if ((tkns & PD_FLG_DUPLICAT) && (tracing == 0) &&
1126			    (rpl_debug == 0) && (prm_debug == 0))
1127				continue;
1128		}
1129
1130		/*
1131		 * Create a new pathname descriptor.
1132		 */
1133		if ((pdp = alist_append(alpp, NULL, sizeof (Pdesc),
1134		    alni)) == NULL)
1135			return (0);
1136
1137		pdp->pd_pname = str;
1138		pdp->pd_plen = len;
1139		pdp->pd_flags = (orig & LA_SER_MASK) | (tkns & PD_MSK_INHERIT);
1140
1141		/*
1142		 * If token expansion occurred, maintain the original string.
1143		 * This string can be used to provide a more informative error
1144		 * diagnostic for a file that fails to load, or for displaying
1145		 * unused search paths.
1146		 */
1147		if ((tkns & PD_MSK_EXPAND) && ((pdp->pd_oname =
1148		    stravl_insert(ostr, 0, (olen + 1), 1)) == NULL))
1149			return (0);
1150
1151		/*
1152		 * Now that any duplication of the original string has occurred,
1153		 * release any previous old listing.
1154		 */
1155		if (elist && (elist != nlist)) {
1156			if (olist)
1157				free(olist);
1158			nlist = olist = elist;
1159		}
1160	}
1161
1162	if (olist)
1163		free(olist);
1164
1165	/*
1166	 * If no paths could be determined (perhaps because of security), then
1167	 * indicate a failure.
1168	 */
1169	return (pdp != NULL);
1170}
1171
1172/*
1173 * Establish an objects fully resolved path.
1174 *
1175 * When $ORIGIN was first introduced, the expansion of a relative path name was
1176 * deferred until it was required.  However now we insure a full path name is
1177 * always created - things like the analyzer wish to rely on librtld_db
1178 * returning a full path.  The overhead of this is perceived to be low,
1179 * providing the associated libc version of getcwd is available (see 4336878).
1180 * This getcwd() was ported back to Solaris 8.1.
1181 */
1182size_t
1183fullpath(Rt_map *lmp, Fdesc *fdp)
1184{
1185	const char	*name;
1186
1187	/*
1188	 * Determine whether this path name is already resolved.
1189	 */
1190	if (fdp && (fdp->fd_flags & FLG_FD_RESOLVED)) {
1191		/*
1192		 * If the resolved path differed from the original name, the
1193		 * resolved path would have been recorded as the fd_pname.
1194		 * Steal this path name from the file descriptor.  Otherwise,
1195		 * the path name is the same as the name of this object.
1196		 */
1197		if (fdp->fd_pname)
1198			PATHNAME(lmp) = fdp->fd_pname;
1199		else
1200			PATHNAME(lmp) = NAME(lmp);
1201	} else {
1202		/*
1203		 * If this path name has not yet been resolved, resolve the
1204		 * current name.
1205		 */
1206		char		_path[PATH_MAX];
1207		const char	*path;
1208		int		size, rsize;
1209
1210		if (fdp && fdp->fd_pname)
1211			PATHNAME(lmp) = fdp->fd_pname;
1212		else
1213			PATHNAME(lmp) = NAME(lmp);
1214
1215		name = path = PATHNAME(lmp);
1216		size = strlen(name);
1217
1218		if (path[0] != '/') {
1219			/*
1220			 * If we can't determine the current directory (possible
1221			 * if too many files are open - EMFILE), or if the
1222			 * created path is too big, simply revert back to the
1223			 * initial path name.
1224			 */
1225			if (getcwd(_path, (PATH_MAX - 2 - size)) != NULL) {
1226				(void) strcat(_path, MSG_ORIG(MSG_STR_SLASH));
1227				(void) strcat(_path, name);
1228				path = _path;
1229				size = strlen(path);
1230			}
1231		}
1232
1233		/*
1234		 * See if the path name can be reduced further.
1235		 */
1236		if ((rsize = resolvepath(path, _path, (PATH_MAX - 1))) > 0) {
1237			_path[rsize] = '\0';
1238			path = _path;
1239			size = rsize;
1240		}
1241
1242		/*
1243		 * If the path name is different from the original, duplicate it
1244		 * so that it is available in a core file.  If the duplication
1245		 * fails simply leave the original path name alone.
1246		 */
1247		if ((PATHNAME(lmp) =
1248		    stravl_insert(path, 0, (size + 1), 0)) == NULL)
1249			PATHNAME(lmp) = name;
1250	}
1251
1252	name = ORIGNAME(lmp) = PATHNAME(lmp);
1253
1254	/*
1255	 * Establish the directory name size - this also acts as a flag that the
1256	 * directory name has been computed.
1257	 */
1258	DIRSZ(lmp) = strrchr(name, '/') - name;
1259	return (DIRSZ(lmp));
1260}
1261