xref: /illumos-gate/usr/src/cmd/pfexec/pfexec.c (revision afab0816ecb604f0099a09ad8ee398f0d7b77b1c)
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