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