1/* 2 * Copyright (c) 1996, 1998-2005, 2010 3 * Todd C. Miller <Todd.Miller@courtesan.com> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * 17 * Sponsored in part by the Defense Advanced Research Projects 18 * Agency (DARPA) and Air Force Research Laboratory, Air Force 19 * Materiel Command, USAF, under agreement number F39502-99-1-0512. 20 */ 21 22#include <config.h> 23 24#include <sys/types.h> 25#include <sys/param.h> 26#include <sys/stat.h> 27#include <stdio.h> 28#ifdef STDC_HEADERS 29# include <stdlib.h> 30# include <stddef.h> 31#else 32# ifdef HAVE_STDLIB_H 33# include <stdlib.h> 34# endif 35#endif /* STDC_HEADERS */ 36#ifdef HAVE_STRING_H 37# include <string.h> 38#endif /* HAVE_STRING_H */ 39#ifdef HAVE_STRINGS_H 40# include <strings.h> 41#endif /* HAVE_STRINGS_H */ 42#ifdef HAVE_UNISTD_H 43# include <unistd.h> 44#endif /* HAVE_UNISTD_H */ 45 46#include "sudo.h" 47 48/* 49 * This function finds the full pathname for a command and 50 * stores it in a statically allocated array, filling in a pointer 51 * to the array. Returns FOUND if the command was found, NOT_FOUND 52 * if it was not found, or NOT_FOUND_DOT if it would have been found 53 * but it is in '.' and IGNORE_DOT is set. 54 */ 55int 56find_path(infile, outfile, sbp, path, ignore_dot) 57 char *infile; /* file to find */ 58 char **outfile; /* result parameter */ 59 struct stat *sbp; /* stat result parameter */ 60 char *path; /* path to search */ 61 int ignore_dot; /* don't check cwd */ 62{ 63 static char command[PATH_MAX]; /* qualified filename */ 64 char *n; /* for traversing path */ 65 char *origpath; /* so we can free path later */ 66 int found = FALSE; /* did we find the command? */ 67 int checkdot = FALSE; /* check current dir? */ 68 int len; /* length parameter */ 69 70 if (strlen(infile) >= PATH_MAX) 71 errorx(1, "%s: File name too long", infile); 72 73 /* 74 * If we were given a fully qualified or relative path 75 * there is no need to look at $PATH. 76 */ 77 if (strchr(infile, '/')) { 78 strlcpy(command, infile, sizeof(command)); /* paranoia */ 79 if (sudo_goodpath(command, sbp)) { 80 *outfile = command; 81 return FOUND; 82 } else 83 return NOT_FOUND; 84 } 85 86 if (path == NULL) 87 return NOT_FOUND; 88 path = estrdup(path); 89 origpath = path; 90 91 do { 92 if ((n = strchr(path, ':'))) 93 *n = '\0'; 94 95 /* 96 * Search current dir last if it is in PATH This will miss sneaky 97 * things like using './' or './/' 98 */ 99 if (*path == '\0' || (*path == '.' && *(path + 1) == '\0')) { 100 checkdot = 1; 101 path = n + 1; 102 continue; 103 } 104 105 /* 106 * Resolve the path and exit the loop if found. 107 */ 108 len = snprintf(command, sizeof(command), "%s/%s", path, infile); 109 if (len <= 0 || len >= sizeof(command)) 110 errorx(1, "%s: File name too long", infile); 111 if ((found = sudo_goodpath(command, sbp))) 112 break; 113 114 path = n + 1; 115 116 } while (n); 117 efree(origpath); 118 119 /* 120 * Check current dir if dot was in the PATH 121 */ 122 if (!found && checkdot) { 123 len = snprintf(command, sizeof(command), "./%s", infile); 124 if (len <= 0 || len >= sizeof(command)) 125 errorx(1, "%s: File name too long", infile); 126 found = sudo_goodpath(command, sbp); 127 if (found && ignore_dot) 128 return NOT_FOUND_DOT; 129 } 130 131 if (found) { 132 *outfile = command; 133 return FOUND; 134 } else 135 return NOT_FOUND; 136} 137