pfexec.c revision 12273:63678502e95e
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 */
57int
58shellname(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
86static void
87usage(void)
88{
89	(void) fprintf(stderr, gettext("pfexec [-P privset] cmd [arg ..]\n"));
90	exit(EXIT_FAILURE);
91}
92
93int
94main(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