xref: /illumos-gate/usr/src/cmd/pfexec/pfexec.c (revision 511ef1d6)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5f48205beScasper  * Common Development and Distribution License (the "License").
6f48205beScasper  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*511ef1d6SGary Mills  * Copyright 2014 Gary Mills
23134a1f4eSCasper H.S. Dik  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
26134a1f4eSCasper H.S. Dik /*
27134a1f4eSCasper H.S. Dik  * New implementation of pfexec(1) and all of the profile shells.
28134a1f4eSCasper H.S. Dik  *
29134a1f4eSCasper H.S. Dik  * The algorithm is as follows:
30134a1f4eSCasper H.S. Dik  * 	first try to derive the shell's path from getexecname();
31134a1f4eSCasper H.S. Dik  *	note that this requires a *hard* link to the program, so
32134a1f4eSCasper H.S. Dik  *	if we find that we are actually executing pfexec, we start
33134a1f4eSCasper H.S. Dik  *	looking at argv[0].
34134a1f4eSCasper H.S. Dik  *	argv[0] is also our fallback in case getexecname doesn't find it.
35134a1f4eSCasper H.S. Dik  */
36134a1f4eSCasper H.S. Dik #include <sys/param.h>
37134a1f4eSCasper H.S. Dik #include <alloca.h>
387c478bd9Sstevel@tonic-gate #include <errno.h>
397c478bd9Sstevel@tonic-gate #include <locale.h>
40134a1f4eSCasper H.S. Dik #include <priv.h>
41134a1f4eSCasper H.S. Dik #include <stdio.h>
427c478bd9Sstevel@tonic-gate #include <stdlib.h>
437c478bd9Sstevel@tonic-gate #include <string.h>
44134a1f4eSCasper H.S. Dik #include <unistd.h>
46134a1f4eSCasper H.S. Dik #define	PFEXEC	"pfexec"
47134a1f4eSCasper H.S. Dik #ifndef TEXT_DOMAIN
487c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"
497c478bd9Sstevel@tonic-gate #endif
51134a1f4eSCasper H.S. Dik #define	RES_PFEXEC	1
52134a1f4eSCasper H.S. Dik #define	RES_OK		0
53134a1f4eSCasper H.S. Dik #define	RES_FAILURE	-1
557c478bd9Sstevel@tonic-gate /*
56134a1f4eSCasper H.S. Dik  * Return the shellname
577c478bd9Sstevel@tonic-gate  */
58134a1f4eSCasper H.S. Dik int
shellname(const char * name,char buf[MAXPATHLEN])59134a1f4eSCasper H.S. Dik shellname(const char *name, char buf[MAXPATHLEN])
607c478bd9Sstevel@tonic-gate {
61134a1f4eSCasper H.S. Dik 	const char *cmd = strrchr(name, '/');
63134a1f4eSCasper H.S. Dik 	if (cmd == NULL)
64134a1f4eSCasper H.S. Dik 		cmd = name;
65134a1f4eSCasper H.S. Dik 	else
66134a1f4eSCasper H.S. Dik 		cmd++;
68134a1f4eSCasper H.S. Dik 	if (strncmp(cmd, "pf", 2) != 0)
69134a1f4eSCasper H.S. Dik 		return (RES_FAILURE);
71134a1f4eSCasper H.S. Dik 	if (strcmp(cmd, PFEXEC) == 0)
72134a1f4eSCasper H.S. Dik 		return (RES_PFEXEC);
74134a1f4eSCasper H.S. Dik 	if (strlen(name) >= MAXPATHLEN)
75134a1f4eSCasper H.S. Dik 		return (RES_FAILURE);
77134a1f4eSCasper H.S. Dik 	if (cmd == name) {
78134a1f4eSCasper H.S. Dik 		(void) strlcpy(buf, cmd + 2, MAXPATHLEN);
79134a1f4eSCasper H.S. Dik 	} else {
80134a1f4eSCasper H.S. Dik 		(void) strncpy(buf, name, cmd - name);
81134a1f4eSCasper H.S. Dik 		(void) strcpy(buf + (cmd - name), cmd + 2);
827c478bd9Sstevel@tonic-gate 	}
83134a1f4eSCasper H.S. Dik 	return (RES_OK);
857c478bd9Sstevel@tonic-gate }
877c478bd9Sstevel@tonic-gate static void
usage(void)887c478bd9Sstevel@tonic-gate usage(void)
897c478bd9Sstevel@tonic-gate {
907c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("pfexec [-P privset] cmd [arg ..]\n"));
917c478bd9Sstevel@tonic-gate 	exit(EXIT_FAILURE);
927c478bd9Sstevel@tonic-gate }
94134a1f4eSCasper H.S. Dik int
main(int argc,char ** argv)95134a1f4eSCasper H.S. Dik main(int argc, char **argv)
967c478bd9Sstevel@tonic-gate {
97134a1f4eSCasper H.S. Dik 	char *cmd;
98134a1f4eSCasper H.S. Dik 	char *pset = NULL;
99134a1f4eSCasper H.S. Dik 	char pathbuf[MAXPATHLEN];
100134a1f4eSCasper H.S. Dik 	int c;
101134a1f4eSCasper H.S. Dik 	priv_set_t *wanted;
102134a1f4eSCasper H.S. Dik 	int oflag;
103134a1f4eSCasper H.S. Dik 
104134a1f4eSCasper H.S. Dik 	oflag = getpflags(PRIV_PFEXEC);
105134a1f4eSCasper H.S. Dik 	if (setpflags(PRIV_PFEXEC, 1) != 0) {
106*511ef1d6SGary Mills 		(void) fprintf(stderr,
107*511ef1d6SGary Mills 		    gettext("pfexec: unable to set PFEXEC flag: %s\n"),
108*511ef1d6SGary Mills 		    strerror(errno));
109134a1f4eSCasper H.S. Dik 		exit(1);
110134a1f4eSCasper H.S. Dik 	}
111134a1f4eSCasper H.S. Dik 
112134a1f4eSCasper H.S. Dik 	if (*argv[0] == '-')
113134a1f4eSCasper H.S. Dik 		cmd = argv[0] + 1;
114134a1f4eSCasper H.S. Dik 	else
115134a1f4eSCasper H.S. Dik 		cmd = argv[0];
116134a1f4eSCasper H.S. Dik 
117134a1f4eSCasper H.S. Dik 	/* Strip "pf" from argv[0], it confuses some shells. */
118134a1f4eSCasper H.S. Dik 	if (strncmp(cmd, "pf", 2) == 0) {
119134a1f4eSCasper H.S. Dik 		argv[0] += 2;
120134a1f4eSCasper H.S. Dik 		/* argv[0] will need to start with '-' again. */
121134a1f4eSCasper H.S. Dik 		if (argv[0][-2] == '-')
122134a1f4eSCasper H.S. Dik 			*argv[0] = '-';
123134a1f4eSCasper H.S. Dik 	}
124134a1f4eSCasper H.S. Dik 
125134a1f4eSCasper H.S. Dik 	/* If this fails, we just continue with plan B */
126134a1f4eSCasper H.S. Dik 	if (shellname(getexecname(), pathbuf) == RES_OK)
127134a1f4eSCasper H.S. Dik 		(void) execv(pathbuf, argv);
128134a1f4eSCasper H.S. Dik 
129134a1f4eSCasper H.S. Dik 	switch (shellname(cmd, pathbuf)) {
130134a1f4eSCasper H.S. Dik 	case RES_OK:
131134a1f4eSCasper H.S. Dik 		(void) execv(pathbuf, argv);
132*511ef1d6SGary Mills 		(void) fprintf(stderr,
133*511ef1d6SGary Mills 		    gettext("pfexec: unable to execute %s: %s\n"),
134*511ef1d6SGary Mills 		    pathbuf, strerror(errno));
135134a1f4eSCasper H.S. Dik 		return (1);
136134a1f4eSCasper H.S. Dik 	case RES_PFEXEC:
137134a1f4eSCasper H.S. Dik 	case RES_FAILURE:
138134a1f4eSCasper H.S. Dik 		while ((c = getopt(argc, argv, "P:")) != EOF) {
139134a1f4eSCasper H.S. Dik 			switch (c) {
140134a1f4eSCasper H.S. Dik 			case 'P':
141134a1f4eSCasper H.S. Dik 				if (pset == NULL) {
142134a1f4eSCasper H.S. Dik 					pset = optarg;
143134a1f4eSCasper H.S. Dik 					break;
144134a1f4eSCasper H.S. Dik 				}
145134a1f4eSCasper H.S. Dik 				/* FALLTHROUGH */
146134a1f4eSCasper H.S. Dik 			default:
147134a1f4eSCasper H.S. Dik 				usage();
148134a1f4eSCasper H.S. Dik 			}
1497c478bd9Sstevel@tonic-gate 		}
150134a1f4eSCasper H.S. Dik 		argc -= optind;
151134a1f4eSCasper H.S. Dik 		argv += optind;
152134a1f4eSCasper H.S. Dik 		if (argc < 1)
153134a1f4eSCasper H.S. Dik 			usage();
155134a1f4eSCasper H.S. Dik 		if (pset != NULL) {
156*511ef1d6SGary Mills 			if ((wanted = priv_str_to_set(pset, ",", NULL)) ==
157*511ef1d6SGary Mills 			    NULL) {
158*511ef1d6SGary Mills 				(void) fprintf(stderr,
159*511ef1d6SGary Mills 				    gettext("pfexec: error parsing "
160*511ef1d6SGary Mills 				    "privileges: %s\n"), strerror(errno));
161*511ef1d6SGary Mills 				exit(EXIT_FAILURE);
162*511ef1d6SGary Mills 			}
163134a1f4eSCasper H.S. Dik 			if (setppriv(PRIV_ON, PRIV_INHERITABLE, wanted) != 0) {
164134a1f4eSCasper H.S. Dik 				(void) fprintf(stderr,
165*511ef1d6SGary Mills 				    gettext("pfexec: error setting "
166*511ef1d6SGary Mills 				    "privileges: %s\n"), strerror(errno));
167134a1f4eSCasper H.S. Dik 				exit(EXIT_FAILURE);
1687c478bd9Sstevel@tonic-gate 			}
169134a1f4eSCasper H.S. Dik 			(void) setpflags(PRIV_PFEXEC, oflag);
1707c478bd9Sstevel@tonic-gate 		}
172134a1f4eSCasper H.S. Dik 		(void) execvp(argv[0], argv);
173*511ef1d6SGary Mills 		(void) fprintf(stderr,
174*511ef1d6SGary Mills 		    gettext("pfexec: unable to execute %s: %s\n"),
175*511ef1d6SGary Mills 		    argv[0], strerror(errno));
176134a1f4eSCasper H.S. Dik 		return (1);
1777c478bd9Sstevel@tonic-gate 	}
178134a1f4eSCasper H.S. Dik 	return (1);
1797c478bd9Sstevel@tonic-gate }