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
shellname(const char * name,char buf[MAXPATHLEN])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
usage(void)88 usage(void)
89 {
90 (void) fprintf(stderr, gettext("pfexec [-P privset] cmd [arg ..]\n"));
91 exit(EXIT_FAILURE);
92 }
93
94 int
main(int argc,char ** argv)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 }
180