1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1988, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/types.h> 33 34 #include <err.h> 35 #include <errno.h> 36 #include <login_cap.h> 37 #include <pwd.h> 38 #include <stdbool.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <unistd.h> 43 44 #include "envopts.h" 45 46 extern char **environ; 47 48 int env_verbosity; 49 50 static void usage(void) __dead2; 51 52 /* 53 * Exit codes. 54 */ 55 #define EXIT_CANCELED 125 /* Internal error prior to exec attempt. */ 56 #define EXIT_CANNOT_INVOKE 126 /* Program located, but not usable. */ 57 #define EXIT_ENOENT 127 /* Could not find program to exec. */ 58 59 int 60 main(int argc, char **argv) 61 { 62 char *altpath, **ep, *p, **parg, term; 63 char *cleanenv[1]; 64 char *login_class, *login_name; 65 struct passwd *pw; 66 login_cap_t *lc; 67 bool login_as_user; 68 uid_t uid; 69 int ch, want_clear; 70 int rtrn; 71 72 altpath = NULL; 73 login_class = NULL; 74 login_name = NULL; 75 pw = NULL; 76 lc = NULL; 77 login_as_user = false; 78 want_clear = 0; 79 term = '\n'; 80 while ((ch = getopt(argc, argv, "-0iL:P:S:U:u:v")) != -1) 81 switch(ch) { 82 case '-': 83 case 'i': 84 want_clear = 1; 85 break; 86 case '0': 87 term = '\0'; 88 break; 89 case 'U': 90 login_as_user = true; 91 /* FALLTHROUGH */ 92 case 'L': 93 login_name = optarg; 94 break; 95 case 'P': 96 altpath = strdup(optarg); 97 break; 98 case 'S': 99 /* 100 * The -S option, for "split string on spaces, with 101 * support for some simple substitutions"... 102 */ 103 split_spaces(optarg, &optind, &argc, &argv); 104 break; 105 case 'u': 106 if (env_verbosity) 107 fprintf(stderr, "#env unset:\t%s\n", optarg); 108 rtrn = unsetenv(optarg); 109 if (rtrn == -1) 110 err(EXIT_FAILURE, "unsetenv %s", optarg); 111 break; 112 case 'v': 113 env_verbosity++; 114 if (env_verbosity > 1) 115 fprintf(stderr, "#env verbosity now at %d\n", 116 env_verbosity); 117 break; 118 case '?': 119 default: 120 usage(); 121 } 122 if (want_clear) { 123 environ = cleanenv; 124 cleanenv[0] = NULL; 125 if (env_verbosity) 126 fprintf(stderr, "#env clearing environ\n"); 127 } 128 if (login_name != NULL) { 129 login_class = strchr(login_name, '/'); 130 if (login_class) 131 *login_class++ = '\0'; 132 if (*login_name != '\0' && strcmp(login_name, "-") != 0) { 133 pw = getpwnam(login_name); 134 if (pw == NULL) { 135 char *endp = NULL; 136 errno = 0; 137 uid = strtoul(login_name, &endp, 10); 138 if (errno == 0 && *endp == '\0') 139 pw = getpwuid(uid); 140 } 141 if (pw == NULL) 142 errx(EXIT_FAILURE, "no such user: %s", login_name); 143 } 144 /* 145 * Note that it is safe for pw to be null here; the libutil 146 * code handles that, bypassing substitution of $ and using 147 * the class "default" if no class name is given either. 148 */ 149 if (login_class != NULL) { 150 lc = login_getclass(login_class); 151 if (lc == NULL) 152 errx(EXIT_FAILURE, "no such login class: %s", 153 login_class); 154 } else { 155 lc = login_getpwclass(pw); 156 if (lc == NULL) 157 errx(EXIT_FAILURE, "login_getpwclass failed"); 158 } 159 160 /* 161 * This is not done with setusercontext() because that will 162 * try and use ~/.login_conf even when we don't want it to. 163 */ 164 setclassenvironment(lc, pw, 1); 165 setclassenvironment(lc, pw, 0); 166 if (login_as_user) { 167 login_close(lc); 168 if ((lc = login_getuserclass(pw)) != NULL) { 169 setclassenvironment(lc, pw, 1); 170 setclassenvironment(lc, pw, 0); 171 } 172 } 173 endpwent(); 174 if (lc != NULL) 175 login_close(lc); 176 } 177 for (argv += optind; *argv && (p = strchr(*argv, '=')); ++argv) { 178 if (env_verbosity) 179 fprintf(stderr, "#env setenv:\t%s\n", *argv); 180 *p = '\0'; 181 rtrn = setenv(*argv, p + 1, 1); 182 *p = '='; 183 if (rtrn == -1) 184 err(EXIT_FAILURE, "setenv %s", *argv); 185 } 186 if (*argv) { 187 if (term == '\0') 188 errx(EXIT_CANCELED, "cannot specify command with -0"); 189 if (altpath) 190 search_paths(altpath, argv); 191 if (env_verbosity) { 192 fprintf(stderr, "#env executing:\t%s\n", *argv); 193 for (parg = argv, argc = 0; *parg; parg++, argc++) 194 fprintf(stderr, "#env arg[%d]=\t'%s'\n", 195 argc, *parg); 196 if (env_verbosity > 1) 197 sleep(1); 198 } 199 execvp(*argv, argv); 200 err(errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE, 201 "%s", *argv); 202 } 203 for (ep = environ; *ep; ep++) 204 (void)printf("%s%c", *ep, term); 205 exit(0); 206 } 207 208 static void 209 usage(void) 210 { 211 (void)fprintf(stderr, 212 "usage: env [-0iv] [-L|-U user[/class]] [-P utilpath] [-S string] [-u name]\n" 213 " [name=value ...] [utility [argument ...]]\n"); 214 exit(1); 215 } 216