| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 | /* * chroot_realpath.c -- reslove pathname as if inside chroot * Based on realpath.c Copyright (C) 1993 Rick Sladkey <jrs@world.std.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING.LIB.  If not, * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * 2005/09/12: Dan Howell (modified from realpath.c to emulate chroot) */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <sys/types.h>#include <unistd.h>#include <stdio.h>#include <string.h>#include <strings.h>#include <limits.h>				/* for PATH_MAX */#include <sys/param.h>			/* for MAXPATHLEN */#include <errno.h>#ifndef __set_errno#define __set_errno(val) ((errno) = (val))#endif#include <sys/stat.h>			/* for S_IFLNK */#ifndef PATH_MAX#define PATH_MAX _POSIX_PATH_MAX#endif#define MAX_READLINKS 32char *chroot_realpath(const char *chroot, const char *path, char resolved_path[]){	char copy_path[PATH_MAX];	char link_path[PATH_MAX];	char got_path[PATH_MAX];	char *got_path_root = got_path;	char *new_path = got_path;	char *max_path;	int readlinks = 0;	int n;	int chroot_len;	/* Trivial case. */	if (chroot == NULL || *chroot == '\0' ||	    (*chroot == '/' && chroot[1] == '\0')) {		strcpy(resolved_path, path);		return resolved_path;	}	chroot_len = strlen(chroot);	if (chroot_len + strlen(path) >= PATH_MAX - 3) {		__set_errno(ENAMETOOLONG);		return NULL;	}	/* Make a copy of the source path since we may need to modify it. */	strcpy(copy_path, path);	path = copy_path;	max_path = copy_path + PATH_MAX - chroot_len - 3;	/* Start with the chroot path. */	strcpy(new_path, chroot);	new_path += chroot_len;	while (*new_path == '/' && new_path > got_path)		new_path--;	got_path_root = new_path;	*new_path++ = '/';	/* Expand each slash-separated pathname component. */	while (*path != '\0') {		/* Ignore stray "/". */		if (*path == '/') {			path++;			continue;		}		if (*path == '.') {			/* Ignore ".". */			if (path[1] == '\0' || path[1] == '/') {				path++;				continue;			}			if (path[1] == '.') {				if (path[2] == '\0' || path[2] == '/') {					path += 2;					/* Ignore ".." at root. */					if (new_path == got_path_root + 1)						continue;					/* Handle ".." by backing up. */					while ((--new_path)[-1] != '/');					continue;				}			}		}		/* Safely copy the next pathname component. */		while (*path != '\0' && *path != '/') {			if (path > max_path) {				__set_errno(ENAMETOOLONG);				return NULL;			}			*new_path++ = *path++;		}		if (*path == '\0')			/* Don't follow symlink for last pathname component. */			break;#ifdef S_IFLNK		/* Protect against infinite loops. */		if (readlinks++ > MAX_READLINKS) {			__set_errno(ELOOP);			return NULL;		}		/* See if latest pathname component is a symlink. */		*new_path = '\0';		n = readlink(got_path, link_path, PATH_MAX - 1);		if (n < 0) {			/* EINVAL means the file exists but isn't a symlink. */			if (errno != EINVAL) {				/* Make sure it's null terminated. */				*new_path = '\0';				strcpy(resolved_path, got_path);				return NULL;			}		} else {			/* Note: readlink doesn't add the null byte. */			link_path[n] = '\0';			if (*link_path == '/')				/* Start over for an absolute symlink. */				new_path = got_path_root;			else				/* Otherwise back up over this component. */				while (*(--new_path) != '/');			/* Safe sex check. */			if (strlen(path) + n >= PATH_MAX - 2) {				__set_errno(ENAMETOOLONG);				return NULL;			}			/* Insert symlink contents into path. */			strcat(link_path, path);			strcpy(copy_path, link_path);			path = copy_path;		}#endif							/* S_IFLNK */		*new_path++ = '/';	}	/* Delete trailing slash but don't whomp a lone slash. */	if (new_path != got_path + 1 && new_path[-1] == '/')		new_path--;	/* Make sure it's null terminated. */	*new_path = '\0';	strcpy(resolved_path, got_path);	return resolved_path;}
 |