diff --git a/find_path.c b/find_path.c index b52045178..294c9283e 100644 --- a/find_path.c +++ b/find_path.c @@ -1,15 +1,5 @@ /* - * CU sudo version 1.3.1 (based on Root Group sudo version 1.1) - * - * This software comes with no waranty whatsoever, use at your own risk. - * - * Please send bugs, changes, problems to sudo-bugs.cs.colorado.edu - * - */ - -/* - * sudo version 1.1 allows users to execute commands as root - * Copyright (C) 1991 The Root Group, Inc. + * CU sudo version 1.3.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,21 +15,14 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + * Please send bugs, changes, problems to sudo-bugs.cs.colorado.edu + * ******************************************************************* * - * This module contains the find_path() command that returns + * This module contains the find_path() function that returns * a pointer to a static area with the absolute path of the - * command or NULL if the command is not found in the path - * - * I also added the strdup() function in here after I found most - * systems don't have it... - * - * Jeff Nieusma Thu Mar 21 23:11:23 MST 1991 - */ - -/* - * Most of this code has been rewritten to fix bugs and bears little - * resemblence to the original. + * command or NULL if the command is not found in the path. + * NOTE: if "." or "" exists in PATH it will be searched last. * * Todd C. Miller (millert@colorado.edu) Sat Sep 4 12:22:04 MDT 1993 */ @@ -94,6 +77,12 @@ extern char *strdup(); #endif /* _S_IFLNK */ +/* + * Globals + */ +static char * realpath_exec __P((char *, char *, char *)); + + /******************************************************************* * * find_path() @@ -106,11 +95,10 @@ char *find_path(file) { register char *n; /* for traversing path */ char *path = NULL; /* contents of PATH env var */ - char fn[MAXPATHLEN + 1]; /* filename (path + file) */ - struct stat statbuf; /* for stat(2) */ - int statfailed; /* stat(2) return value */ + char *oldpath; /* so we can free path later */ + char *result = NULL; /* result of path/file lookup */ + static char command[MAXPATHLEN]; /* resolved pathname */ int checkdot = 0; /* check current dir? */ - char *qualify(); if (strlen(file) > MAXPATHLEN) { (void) fprintf(stderr, "%s: path too long: %s\n", Argv[0], file); @@ -120,8 +108,9 @@ char *find_path(file) /* * do we need to search the path? */ + /* XXX - check return val here? */ if (strchr(file, '/')) - return (qualify(file)); + return((char *) realpath(file, command)); /* * grab PATH out of environment and make a local copy @@ -130,9 +119,10 @@ char *find_path(file) return (NULL); if ((path = strdup(path)) == NULL) { - perror("find_path: malloc"); + fprintf(stderr, "sudo: out of memory!\n"); exit(1); } + oldpath=path; do { if ((n = strchr(path, ':'))) @@ -148,19 +138,11 @@ char *find_path(file) continue; } - (void) sprintf(fn, "%s/%s", path, file); - /* - * stat the file to make sure it exists and is executable + * resolve the path and exit the loop if found */ - statfailed = stat(fn, &statbuf); - if (!statfailed && (statbuf.st_mode & 0000111)) - return (qualify(fn)); - else if (statfailed && errno != ENOENT && errno != ENOTDIR && - errno != EINVAL && errno != EPERM && errno != EACCES) { - fprintf(stderr, "sudo: Can't stat %s: ", fn); - perror(""); - } + if ((result = realpath_exec(path, file, command))) + break; path = n + 1; @@ -169,160 +151,45 @@ char *find_path(file) /* * check current dir if dot was in the PATH */ - if (checkdot) { - (void) sprintf(fn, "./%s", file); + if (!result && checkdot) + result = realpath_exec(".", file, command); - /* - * stat the file to make sure it exists and is executable - */ - statfailed = stat(fn, &statbuf); - if (!statfailed && (statbuf.st_mode & 0000111)) - return (qualify(fn)); - else if (statfailed && errno != ENOENT && errno != ENOTDIR && - errno != EINVAL && errno != EPERM && errno != EACCES) { - fprintf(stderr, "sudo: Can't stat %s: ", fn); - perror(""); - return (NULL); - } - } - return (NULL); + (void) free(oldpath); + return (result); } -/****************************************************************** +/******************************************************************* * - * qualify() + * realpath_exec() * - * this function takes a path and makes it fully qualified and resolves - * all symbolic links, returning the fully qualfied path. + * This function calls realpath() to resolve the path and checks + * so see that file is executable. Returns the resolved path on + * success and NULL on failure (or if file is not executable). */ -char *qualify(n) - char *n; /* name to make fully qualified */ +static char * realpath_exec(path, file, command) + char * path; + char * file; + char * command; { - char *beg = NULL; /* begining of a path component */ - char *end; /* end of a path component */ - static char full[MAXPATHLEN + 1]; /* the fully qualified name */ - char name[MAXPATHLEN + 1]; /* local copy of n */ - struct stat statbuf; /* for lstat() */ - char *tmp; /* temporary pointer */ + char fn[MAXPATHLEN]; /* filename (path + file) */ + struct stat statbuf; /* for stat(2) */ - /* - * is it a bogus path? - */ - if (stat(n, &statbuf)) { - if (errno != ENOENT && errno != EPERM && errno != EACCES) { - fprintf(stderr, "sudo: Can't stat %s: ", n); - perror(""); - } - return (NULL); + (void) sprintf(fn, "%s/%s", path, file); + + /* resolve the path */ + errno = 0; + if (realpath(fn, command)) { + /* stat the file to make sure it is executable */ + if (stat(command, &statbuf) == 0 && (statbuf.st_mode & 0000111)) + return(command); + } else if (errno && errno != ENOENT && errno != ENOTDIR && errno != EINVAL + && errno != EPERM && errno != EACCES) { + /* realpath() got an error */ + fprintf(stderr, "sudo: Error resolving %s: ", fn); + perror(""); } - /* - * if n is relative, fill full with working dir - */ - if (*n != '/') - (void) strcpy(full, cwd); - else - full[0] = '\0'; - - (void) strcpy(name, n); /* working copy... */ - - do { /* while (end) */ - if (beg) - beg = end + 1; /* skip past the NULL */ - else - beg = name; /* just starting out... */ - - /* - * find and terminate end of path component - */ - if ((end = strchr(beg, '/'))) - *end = '\0'; - - if (beg == end) - continue; - else if (!strcmp(beg, ".")); /* ignore "." */ - else if (!strcmp(beg, "..")) { - if ((tmp = strrchr(full, '/'))) - *tmp = '\0'; - } else { - strcat(full, "/"); - strcat(full, beg); /* copy in new component */ - } - - /* - * if we used ../.. to go past the root dir just continue - */ - if (!full[0]) - continue; - - /* - * check for symbolic links - */ - if (lstat(full, &statbuf)) { - fprintf(stderr, "sudo: Can't lstat %s: ", full); - perror(""); - return (NULL); - } - - if ((statbuf.st_mode & _S_IFMT) == _S_IFLNK) { - int linklen; /* length of link contents */ - char newname[MAXPATHLEN + 1]; /* temp storage to build new - * name */ - - linklen = readlink(full, newname, sizeof(newname)); - newname[linklen] = '\0'; - - /* check to make sure we don't go past MAXPATHLEN */ - ++end; - if (end != (char *) 1) { - if (linklen + strlen(end) >= MAXPATHLEN) { - (void )fprintf(stderr, "%s: path too long: %s/%s\n", - Argv[0], newname, end); - exit(1); - } - strcat(newname, "/"); - strcat(newname, end); /* copy what's left of end */ - } - if (newname[0] == '/') /* reset full if necesary */ - full[0] = '\0'; - else if ((tmp = strrchr(full, '/'))) - *tmp = '\0'; /* remove component from full */ - - strcpy(name, newname); /* reset name with new path */ - beg = NULL; /* since we have a new name */ - } - } while (end); - - /* - * if we resolved to "/" full[0] will be NULL - */ - if (!full[0]) - strcpy(full, "/"); - - return ((char *) full); + return(NULL); } - - -#ifndef HAVE_STRDUP -/****************************************************************** - * - * strdup() - * - * this function returns a pointer a string copied into - * a malloc()ed buffer - */ - -char *strdup(s1) - char *s1; -{ - char *s; - - if ((s = (char *) malloc(strlen(s1) + 1)) == NULL) - return (NULL); - - (void) strcpy(s, s1); - return (s); -} -#endif /* !HAVE_STRDUP */