xref: /illumos-gate/usr/src/cmd/sgs/rtld/common/paths.c (revision 80422caf)
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  */
51 void
set_dirs(Alist ** alpp,Spath_defn * sdp,uint_t flags)52 set_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 
68 static void
print_default_dirs(Lm_list * lml,Alist * alp,int search)69 print_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  */
109 static Alist **
get_dir_list(uchar_t rules,Rt_map * lmp,uint_t flags)110 get_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  */
300 Pdesc *
get_next_dir(Spath_desc * sdp,Rt_map * lmp,uint_t flags)301 get_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  */
342 uint_t
expand(char ** name,size_t * len,char ** list,uint_t orig,uint_t omit,Rt_map * lmp)343 expand(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 				str = strchr(oname, ':');
712 				if (str != NULL) {
713 					size_t	slen = str - oname;
714 
715 					(void) strncpy(buf, oname, slen);
716 					buf[slen] = '\0';
717 					str = buf;
718 				} else
719 					str = oname;
720 
721 				eprintf(lml, ERR_FATAL,
722 				    MSG_INTL(MSG_ERR_EXPAND2), NAME(lmp),
723 				    str, token);
724 				return (0);
725 			}
726 		}
727 		_optr = optr;
728 	}
729 
730 	/*
731 	 * First make sure the current length is shorter than PATH_MAX.  We may
732 	 * arrive here if the given path contains '$' characters which are not
733 	 * the lead of a reserved token.
734 	 */
735 	if (nlen >= PATH_MAX) {
736 		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ERR_EXPAND1), NAME(lmp),
737 		    oname);
738 		return (0);
739 	}
740 
741 	/*
742 	 * If any ISALIST processing has occurred not only do we return the
743 	 * expanded node we're presently working on, but we can also update the
744 	 * remaining list so that it is effectively prepended with this node
745 	 * expanded to all remaining ISALIST options.  Note that we can only
746 	 * handle one ISALIST per node.  For more than one ISALIST to be
747 	 * processed we'd need a better algorithm than above to replace the
748 	 * newly generated list.  Whether we want to encourage the number of
749 	 * path name permutations this would provide is another question.  So,
750 	 * for now if more than one ISALIST is encountered we return the
751 	 * original node untouched.
752 	 */
753 	if (isa && isaflag) {
754 		if (isaflag == 1) {
755 			if (list)
756 				*list = _list;
757 		} else {
758 			flags &= ~PD_TKN_ISALIST;
759 			if ((nptr = (char *)stravl_insert(*name, 0,
760 			    (*len + 1), 1)) == NULL)
761 				return (0);
762 			*name = nptr;
763 			return (TKN_NONE);
764 		}
765 	}
766 
767 	/*
768 	 * Copy any remaining string. Terminate the new string with a null as
769 	 * this string can be displayed via debugging diagnostics.
770 	 */
771 	if ((_len = (optr - _optr)) != 0) {
772 		if ((nlen += _len) < PATH_MAX) {
773 			(void) strncpy(nptr, _optr, _len);
774 			nptr = nptr + _len;
775 		} else {
776 			eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ERR_EXPAND1),
777 			    NAME(lmp), oname);
778 			return (0);
779 		}
780 	}
781 	*nptr = '\0';
782 
783 	/*
784 	 * A path that has been expanded is typically used to create full
785 	 * path names for objects that will be opened.  The final path name is
786 	 * resolved to simplify it, and set the stage for possible $ORIGIN
787 	 * processing.  Therefore, it's usually unnecessary to resolve the path
788 	 * at this point.  However, if a configuration file, containing
789 	 * directory information is in use, then we might need to lookup this
790 	 * path in the configuration file.  To keep the number of path name
791 	 * resolutions to a minimum, only resolve paths that contain "./".  The
792 	 * use of "$ORIGIN/../lib" will probably only match a configuration file
793 	 * entry after resolution.
794 	 */
795 	if (list && (rtld_flags & RT_FL_DIRCFG) && (flags & TKN_DOTSLASH)) {
796 		int	len;
797 
798 		if ((len = resolvepath(_name, _name, (PATH_MAX - 1))) >= 0) {
799 			nlen = (size_t)len;
800 			_name[nlen] = '\0';
801 			flags |= PD_TKN_RESOLVED;
802 		}
803 	}
804 
805 	/*
806 	 * Allocate a new string if necessary.
807 	 *
808 	 * If any form of token expansion, or string resolution has occurred,
809 	 * the storage must be allocated for the new string.
810 	 *
811 	 * If we're processing a substring, for example, any string besides the
812 	 * last string within a search path "A:B:C", then this substring needs
813 	 * to be isolated with a null terminator.  However, if this search path
814 	 * was created from a previous ISALIST expansion, then all strings must
815 	 * be allocated, as the isalist expansion will be freed after expansion
816 	 * processing.
817 	 */
818 	if ((nptr = (char *)stravl_insert(_name, 0, (nlen + 1), 1)) == NULL)
819 		return (0);
820 	*name = nptr;
821 	*len = nlen;
822 	return (flags ? flags : TKN_NONE);
823 }
824 
825 /*
826  * Determine whether a path name is secure.
827  */
828 int
is_path_secure(char * opath,Rt_map * clmp,uint_t info,uint_t flags)829 is_path_secure(char *opath, Rt_map *clmp, uint_t info, uint_t flags)
830 {
831 	Alist		**salpp;
832 	Aliste		idx;
833 	char		buffer[PATH_MAX], *npath = NULL;
834 	Lm_list		*lml = LIST(clmp);
835 	Pdesc		*pdp;
836 
837 	/*
838 	 * If a path name originates from a configuration file, use it.  The use
839 	 * of a configuration file is already validated for secure applications,
840 	 * so if we're using a configuration file, we must be able to use all
841 	 * that it defines.
842 	 */
843 	if (info & LA_SER_CONFIG)
844 		return (1);
845 
846 	if ((info & LA_SER_MASK) == 0) {
847 		char	*str;
848 
849 		/*
850 		 * If the path name specifies a file (rather than a directory),
851 		 * peel off the file before making the comparison.
852 		 */
853 		str = strrchr(opath, '/');
854 
855 		/*
856 		 * Carry out some initial security checks.
857 		 *
858 		 *   .	a simple file name (one containing no "/") is fine, as
859 		 *	this file name will be combined with search paths to
860 		 *	determine the complete path.  Note, a secure application
861 		 *	may provide a configuration file, and this can only be
862 		 *	a full path name (PN_FLG_FULLPATH).
863 		 *   .	a full path (one starting with "/") is fine, provided
864 		 *	this path name isn't a preload/audit path.
865 		 *   .	provided $ORIGIN expansion has not been employed, the
866 		 *	above categories of path are deemed secure.
867 		 */
868 		if ((((str == 0) && ((info & PD_FLG_FULLPATH) == 0)) ||
869 		    ((*opath == '/') && (str != opath) &&
870 		    ((info & PD_FLG_EXTLOAD) == 0))) &&
871 		    ((flags & PD_TKN_ORIGIN) == 0))
872 			return (1);
873 
874 		/*
875 		 * Determine the directory name of the present path.
876 		 */
877 		if (str) {
878 			if (str == opath)
879 				npath = (char *)MSG_ORIG(MSG_STR_SLASH);
880 			else {
881 				size_t	size;
882 
883 				if ((size = str - opath) >= PATH_MAX)
884 					return (0);
885 
886 				(void) strncpy(buffer, opath, size);
887 				buffer[size] = '\0';
888 				npath = buffer;
889 			}
890 
891 			/*
892 			 * If $ORIGIN processing has been employed, then allow
893 			 * any directory that has already been used to satisfy
894 			 * other dependencies, to be used.
895 			 */
896 			if ((flags & PD_TKN_ORIGIN) &&
897 			    pnavl_recorded(&spavl, npath, 0, NULL)) {
898 				DBG_CALL(Dbg_libs_insecure(lml, npath, 1));
899 				return (1);
900 			}
901 		}
902 	} else {
903 		/*
904 		 * A search path, i.e., RPATH, configuration file path, etc. is
905 		 * used as is.  Exceptions to this are:
906 		 *
907 		 *   .	LD_LIBRARY_PATH.
908 		 *   .	any $ORIGIN expansion, unless used by a setuid ld.so.1
909 		 *	to find its own dependencies, or the path name has
910 		 *	already been used to find other dependencies.
911 		 *   .	any relative path.
912 		 */
913 		if (((info & LA_SER_LIBPATH) == 0) && (*opath == '/') &&
914 		    ((flags & PD_TKN_ORIGIN) == 0))
915 			return (1);
916 
917 		/*
918 		 * If $ORIGIN processing is requested, allow a setuid ld.so.1
919 		 * to use this path for its own dependencies.  Allow the
920 		 * application to use this path name only if the path name has
921 		 * already been used to locate other dependencies.
922 		 */
923 		if (flags & PD_TKN_ORIGIN) {
924 			if ((lml->lm_flags & LML_FLG_RTLDLM) &&
925 			    is_rtld_setuid())
926 				return (1);
927 			else if (pnavl_recorded(&spavl, opath, 0, NULL)) {
928 				DBG_CALL(Dbg_libs_insecure(lml, opath, 1));
929 				return (1);
930 			}
931 		}
932 		npath = (char *)opath;
933 	}
934 
935 	/*
936 	 * Determine whether the present directory is trusted.
937 	 */
938 	if (npath) {
939 		salpp = LM_SECURE_DIRS(LIST(clmp)->lm_head)();
940 		for (ALIST_TRAVERSE(*salpp, idx, pdp)) {
941 			if (strcmp(npath, pdp->pd_pname) == 0)
942 				return (1);
943 		}
944 	}
945 
946 	/*
947 	 * The path is insecure, so depending on the caller, provide a
948 	 * diagnostic.  Preloaded, or audit libraries generate a warning, as
949 	 * the process will run without them.
950 	 */
951 	if (info & PD_FLG_EXTLOAD) {
952 		if (lml->lm_flags & LML_FLG_TRC_ENABLE) {
953 			if ((FLAGS1(clmp) & FL1_RT_LDDSTUB) == 0)
954 				(void) printf(MSG_INTL(MSG_LDD_FIL_ILLEGAL),
955 				    opath);
956 		} else
957 			eprintf(lml, ERR_WARNING, MSG_INTL(MSG_SEC_ILLEGAL),
958 			    opath);
959 
960 		return (0);
961 	}
962 
963 	/*
964 	 * Explicit file references are fatal.
965 	 */
966 	if ((info & LA_SER_MASK) == 0) {
967 		if (lml->lm_flags & LML_FLG_TRC_ENABLE) {
968 			/* BEGIN CSTYLED */
969 			if ((FLAGS1(clmp) & FL1_RT_LDDSTUB) == 0) {
970 				if (lml->lm_flags &
971 				    (LML_FLG_TRC_VERBOSE | LML_FLG_TRC_SEARCH))
972 					(void) printf(
973 					    MSG_INTL(MSG_LDD_FIL_FIND),
974 					    opath, NAME(clmp));
975 
976 				if (((rtld_flags & RT_FL_SILENCERR) == 0) ||
977 				    (lml->lm_flags & LML_FLG_TRC_VERBOSE))
978 					(void) printf(
979 					    MSG_INTL(MSG_LDD_FIL_ILLEGAL),
980 					    opath);
981 			}
982 			/* END CSTYLED */
983 		} else
984 			eprintf(lml, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), opath,
985 			    strerror(EACCES));
986 	} else {
987 		/*
988 		 * Search paths.
989 		 */
990 		DBG_CALL(Dbg_libs_insecure(lml, opath, 0));
991 		if ((lml->lm_flags & LML_FLG_TRC_SEARCH) &&
992 		    ((FLAGS1(clmp) & FL1_RT_LDDSTUB) == 0))
993 			(void) printf(MSG_INTL(MSG_LDD_PTH_IGNORE), opath);
994 	}
995 	return (0);
996 }
997 
998 /*
999  * Determine whether a path already exists within the callers Pnode list.
1000  */
1001 inline static uint_t
is_path_unique(Alist * alp,const char * path)1002 is_path_unique(Alist *alp, const char *path)
1003 {
1004 	Aliste	idx;
1005 	Pdesc	*pdp;
1006 
1007 	for (ALIST_TRAVERSE(alp, idx, pdp)) {
1008 		if (pdp->pd_plen && (strcmp(pdp->pd_pname, path) == 0))
1009 			return (PD_FLG_DUPLICAT);
1010 	}
1011 	return (0);
1012 }
1013 
1014 /*
1015  * Expand one or more path names.  This routine is called for all path strings,
1016  * i.e., NEEDED, rpaths, default search paths, configuration file search paths,
1017  * filtees, etc.  The path may be a single path name, or a colon separated list
1018  * of path names.  Each individual path name is processed for possible reserved
1019  * token expansion.  All string nodes are maintained in allocated memory
1020  * (regardless of whether they are constant (":"), or token expanded) to
1021  * simplify path name descriptor removal.
1022  *
1023  * The info argument passes in auxiliary information regarding the callers
1024  * intended use of the path names.  This information may be maintained in the
1025  * path name descriptor element produced to describe the path name (i.e.,
1026  * LA_SER_LIBPATH etc.), or may be used to determine additional security or
1027  * diagnostic processing.
1028  */
1029 int
expand_paths(Rt_map * clmp,const char * list,Alist ** alpp,Aliste alni,uint_t orig,uint_t omit)1030 expand_paths(Rt_map *clmp, const char *list, Alist **alpp, Aliste alni,
1031     uint_t orig, uint_t omit)
1032 {
1033 	char	*str, *olist = 0, *nlist = (char *)list;
1034 	int	fnull = FALSE;	/* TRUE if empty final path segment seen */
1035 	Pdesc	*pdp = NULL;
1036 
1037 	for (str = nlist; *nlist || fnull; str = nlist) {
1038 		char	*ostr;
1039 		char	*elist = NULL;
1040 		size_t	len, olen;
1041 		uint_t	tkns = 0;
1042 
1043 		if (*nlist == ';')
1044 			++nlist, ++str;
1045 		if ((*nlist == ':') || fnull) {
1046 			/* If not a final null segment, check following one */
1047 			fnull = !(fnull || *(nlist + 1));
1048 
1049 			if (*nlist)
1050 				nlist++;
1051 
1052 			/*
1053 			 * When the shell sees a null PATH segment, it
1054 			 * treats it as if it were the cwd (.). We mimic
1055 			 * this behavior for LD_LIBRARY_PATH and runpaths
1056 			 * (mainly for backwards compatibility with previous
1057 			 * behavior). For other paths, this makes no sense,
1058 			 * so we simply ignore the segment.
1059 			 */
1060 			if (!(orig & (LA_SER_LIBPATH | LA_SER_RUNPATH)))
1061 				continue; /* Process next segment */
1062 
1063 			str = (char *)MSG_ORIG(MSG_FMT_CWD);
1064 			len = MSG_FMT_CWD_SIZE;
1065 
1066 		} else {
1067 			uint_t	_tkns;
1068 
1069 			len = 0;
1070 			while (*nlist && (*nlist != ':') && (*nlist != ';')) {
1071 				if (*nlist == '/')
1072 					tkns |= PD_FLG_PNSLASH;
1073 				nlist++, len++;
1074 			}
1075 
1076 			/* Check for a following final null segment */
1077 			fnull = (*nlist == ':') && !*(nlist + 1);
1078 
1079 			if (*nlist)
1080 				nlist++;
1081 
1082 			/*
1083 			 * Expand the captured string.  Besides expanding the
1084 			 * present path/file entry, we may have a new list to
1085 			 * deal with (ISALIST expands to multiple new entries).
1086 			 */
1087 			elist = nlist;
1088 			ostr = str;
1089 			olen = len;
1090 			if ((_tkns = expand(&str, &len, &elist, orig, omit,
1091 			    clmp)) == 0)
1092 				continue;
1093 			tkns |= _tkns;
1094 		}
1095 
1096 		/*
1097 		 * If this a secure application, validation of the expanded
1098 		 * path name may be necessary.
1099 		 */
1100 		if ((rtld_flags & RT_FL_SECURE) &&
1101 		    (is_path_secure(str, clmp, orig, tkns) == 0))
1102 			continue;
1103 
1104 		/*
1105 		 * If required, ensure that the string is unique.  For search
1106 		 * paths such as LD_LIBRARY_PATH, users often inherit multiple
1107 		 * paths which result in unnecessary duplication.  Note, if
1108 		 * we're debugging, any duplicate entry is retained and flagged
1109 		 * so that the entry can be diagnosed later as part of unused
1110 		 * processing.
1111 		 */
1112 		if (orig & PD_FLG_UNIQUE) {
1113 			Word	tracing;
1114 
1115 			tracing = LIST(clmp)->lm_flags &
1116 			    (LML_FLG_TRC_UNREF | LML_FLG_TRC_UNUSED);
1117 			tkns |= is_path_unique(*alpp, str);
1118 
1119 			/*
1120 			 * Note, use the debug strings rpl_debug and prm_debug
1121 			 * as an indicator that debugging has been requested,
1122 			 * rather than DBG_ENABLE(), as the initial use of
1123 			 * LD_LIBRARY_PATH occurs in preparation for loading
1124 			 * our debugging library.
1125 			 */
1126 			if ((tkns & PD_FLG_DUPLICAT) && (tracing == 0) &&
1127 			    (rpl_debug == 0) && (prm_debug == 0))
1128 				continue;
1129 		}
1130 
1131 		/*
1132 		 * Create a new pathname descriptor.
1133 		 */
1134 		if ((pdp = alist_append(alpp, NULL, sizeof (Pdesc),
1135 		    alni)) == NULL)
1136 			return (0);
1137 
1138 		pdp->pd_pname = str;
1139 		pdp->pd_plen = len;
1140 		pdp->pd_flags = (orig & LA_SER_MASK) | (tkns & PD_MSK_INHERIT);
1141 
1142 		/*
1143 		 * If token expansion occurred, maintain the original string.
1144 		 * This string can be used to provide a more informative error
1145 		 * diagnostic for a file that fails to load, or for displaying
1146 		 * unused search paths.
1147 		 */
1148 		if ((tkns & PD_MSK_EXPAND) && ((pdp->pd_oname =
1149 		    stravl_insert(ostr, 0, (olen + 1), 1)) == NULL))
1150 			return (0);
1151 
1152 		/*
1153 		 * Now that any duplication of the original string has occurred,
1154 		 * release any previous old listing.
1155 		 */
1156 		if (elist && (elist != nlist)) {
1157 			if (olist)
1158 				free(olist);
1159 			nlist = olist = elist;
1160 		}
1161 	}
1162 
1163 	if (olist)
1164 		free(olist);
1165 
1166 	/*
1167 	 * If no paths could be determined (perhaps because of security), then
1168 	 * indicate a failure.
1169 	 */
1170 	return (pdp != NULL);
1171 }
1172 
1173 /*
1174  * Establish an objects fully resolved path.
1175  *
1176  * When $ORIGIN was first introduced, the expansion of a relative path name was
1177  * deferred until it was required.  However now we insure a full path name is
1178  * always created - things like the analyzer wish to rely on librtld_db
1179  * returning a full path.  The overhead of this is perceived to be low,
1180  * providing the associated libc version of getcwd is available (see 4336878).
1181  * This getcwd() was ported back to Solaris 8.1.
1182  */
1183 size_t
fullpath(Rt_map * lmp,Fdesc * fdp)1184 fullpath(Rt_map *lmp, Fdesc *fdp)
1185 {
1186 	const char	*name;
1187 
1188 	/*
1189 	 * Determine whether this path name is already resolved.
1190 	 */
1191 	if (fdp && (fdp->fd_flags & FLG_FD_RESOLVED)) {
1192 		/*
1193 		 * If the resolved path differed from the original name, the
1194 		 * resolved path would have been recorded as the fd_pname.
1195 		 * Steal this path name from the file descriptor.  Otherwise,
1196 		 * the path name is the same as the name of this object.
1197 		 */
1198 		if (fdp->fd_pname)
1199 			PATHNAME(lmp) = fdp->fd_pname;
1200 		else
1201 			PATHNAME(lmp) = NAME(lmp);
1202 	} else {
1203 		/*
1204 		 * If this path name has not yet been resolved, resolve the
1205 		 * current name.
1206 		 */
1207 		char		_path[PATH_MAX];
1208 		const char	*path;
1209 		int		size, rsize;
1210 
1211 		if (fdp && fdp->fd_pname)
1212 			PATHNAME(lmp) = fdp->fd_pname;
1213 		else
1214 			PATHNAME(lmp) = NAME(lmp);
1215 
1216 		name = path = PATHNAME(lmp);
1217 		size = strlen(name);
1218 
1219 		if (path[0] != '/') {
1220 			/*
1221 			 * If we can't determine the current directory (possible
1222 			 * if too many files are open - EMFILE), or if the
1223 			 * created path is too big, simply revert back to the
1224 			 * initial path name.
1225 			 */
1226 			if (getcwd(_path, (PATH_MAX - 2 - size)) != NULL) {
1227 				(void) strcat(_path, MSG_ORIG(MSG_STR_SLASH));
1228 				(void) strcat(_path, name);
1229 				path = _path;
1230 				size = strlen(path);
1231 			}
1232 		}
1233 
1234 		/*
1235 		 * See if the path name can be reduced further.
1236 		 */
1237 		if ((rsize = resolvepath(path, _path, (PATH_MAX - 1))) > 0) {
1238 			_path[rsize] = '\0';
1239 			path = _path;
1240 			size = rsize;
1241 		}
1242 
1243 		/*
1244 		 * If the path name is different from the original, duplicate it
1245 		 * so that it is available in a core file.  If the duplication
1246 		 * fails simply leave the original path name alone.
1247 		 */
1248 		if ((PATHNAME(lmp) =
1249 		    stravl_insert(path, 0, (size + 1), 0)) == NULL)
1250 			PATHNAME(lmp) = name;
1251 	}
1252 
1253 	name = ORIGNAME(lmp) = PATHNAME(lmp);
1254 
1255 	/*
1256 	 * Establish the directory name size - this also acts as a flag that the
1257 	 * directory name has been computed.
1258 	 */
1259 	DIRSZ(lmp) = strrchr(name, '/') - name;
1260 	return (DIRSZ(lmp));
1261 }
1262