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 * Copyright 2014 Gary Mills 23 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* 27 * New implementation of pfexec(1) and all of the profile shells. 28 * 29 * The algorithm is as follows: 30 * first try to derive the shell's path from getexecname(); 31 * note that this requires a *hard* link to the program, so 32 * if we find that we are actually executing pfexec, we start 33 * looking at argv[0]. 34 * argv[0] is also our fallback in case getexecname doesn't find it. 35 */ 36 #include <sys/param.h> 37 #include <alloca.h> 38 #include <errno.h> 39 #include <locale.h> 40 #include <priv.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 46 #define PFEXEC "pfexec" 47 #ifndef TEXT_DOMAIN 48 #define TEXT_DOMAIN "SYS_TEST" 49 #endif 50 51 #define RES_PFEXEC 1 52 #define RES_OK 0 53 #define RES_FAILURE -1 54 55 /* 56 * Return the shellname 57 */ 58 int 59 shellname(const char *name, char buf[MAXPATHLEN]) 60 { 61 const char *cmd = strrchr(name, '/'); 62 63 if (cmd == NULL) 64 cmd = name; 65 else 66 cmd++; 67 68 if (strncmp(cmd, "pf", 2) != 0) 69 return (RES_FAILURE); 70 71 if (strcmp(cmd, PFEXEC) == 0) 72 return (RES_PFEXEC); 73 74 if (strlen(name) >= MAXPATHLEN) 75 return (RES_FAILURE); 76 77 if (cmd == name) { 78 (void) strlcpy(buf, cmd + 2, MAXPATHLEN); 79 } else { 80 (void) strncpy(buf, name, cmd - name); 81 (void) strcpy(buf + (cmd - name), cmd + 2); 82 } 83 return (RES_OK); 84 85 } 86 87 static void 88 usage(void) 89 { 90 (void) fprintf(stderr, gettext("pfexec [-P privset] cmd [arg ..]\n")); 91 exit(EXIT_FAILURE); 92 } 93 94 int 95 main(int argc, char **argv) 96 { 97 char *cmd; 98 char *pset = NULL; 99 char pathbuf[MAXPATHLEN]; 100 int c; 101 priv_set_t *wanted; 102 int oflag; 103 104 oflag = getpflags(PRIV_PFEXEC); 105 if (setpflags(PRIV_PFEXEC, 1) != 0) { 106 (void) fprintf(stderr, 107 gettext("pfexec: unable to set PFEXEC flag: %s\n"), 108 strerror(errno)); 109 exit(1); 110 } 111 112 if (*argv[0] == '-') 113 cmd = argv[0] + 1; 114 else 115 cmd = argv[0]; 116 117 /* Strip "pf" from argv[0], it confuses some shells. */ 118 if (strncmp(cmd, "pf", 2) == 0) { 119 argv[0] += 2; 120 /* argv[0] will need to start with '-' again. */ 121 if (argv[0][-2] == '-') 122 *argv[0] = '-'; 123 } 124 125 /* If this fails, we just continue with plan B */ 126 if (shellname(getexecname(), pathbuf) == RES_OK) 127 (void) execv(pathbuf, argv); 128 129 switch (shellname(cmd, pathbuf)) { 130 case RES_OK: 131 (void) execv(pathbuf, argv); 132 (void) fprintf(stderr, 133 gettext("pfexec: unable to execute %s: %s\n"), 134 pathbuf, strerror(errno)); 135 return (1); 136 case RES_PFEXEC: 137 case RES_FAILURE: 138 while ((c = getopt(argc, argv, "P:")) != EOF) { 139 switch (c) { 140 case 'P': 141 if (pset == NULL) { 142 pset = optarg; 143 break; 144 } 145 /* FALLTHROUGH */ 146 default: 147 usage(); 148 } 149 } 150 argc -= optind; 151 argv += optind; 152 if (argc < 1) 153 usage(); 154 155 if (pset != NULL) { 156 if ((wanted = priv_str_to_set(pset, ",", NULL)) == 157 NULL) { 158 (void) fprintf(stderr, 159 gettext("pfexec: error parsing " 160 "privileges: %s\n"), strerror(errno)); 161 exit(EXIT_FAILURE); 162 } 163 if (setppriv(PRIV_ON, PRIV_INHERITABLE, wanted) != 0) { 164 (void) fprintf(stderr, 165 gettext("pfexec: error setting " 166 "privileges: %s\n"), strerror(errno)); 167 exit(EXIT_FAILURE); 168 } 169 (void) setpflags(PRIV_PFEXEC, oflag); 170 } 171 172 (void) execvp(argv[0], argv); 173 (void) fprintf(stderr, 174 gettext("pfexec: unable to execute %s: %s\n"), 175 argv[0], strerror(errno)); 176 return (1); 177 } 178 return (1); 179 }