/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2014 Gary Mills * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * New implementation of pfexec(1) and all of the profile shells. * * The algorithm is as follows: * first try to derive the shell's path from getexecname(); * note that this requires a *hard* link to the program, so * if we find that we are actually executing pfexec, we start * looking at argv[0]. * argv[0] is also our fallback in case getexecname doesn't find it. */ #include #include #include #include #include #include #include #include #include #define PFEXEC "pfexec" #ifndef TEXT_DOMAIN #define TEXT_DOMAIN "SYS_TEST" #endif #define RES_PFEXEC 1 #define RES_OK 0 #define RES_FAILURE -1 /* * Return the shellname */ int shellname(const char *name, char buf[MAXPATHLEN]) { const char *cmd = strrchr(name, '/'); if (cmd == NULL) cmd = name; else cmd++; if (strncmp(cmd, "pf", 2) != 0) return (RES_FAILURE); if (strcmp(cmd, PFEXEC) == 0) return (RES_PFEXEC); if (strlen(name) >= MAXPATHLEN) return (RES_FAILURE); if (cmd == name) { (void) strlcpy(buf, cmd + 2, MAXPATHLEN); } else { (void) strncpy(buf, name, cmd - name); (void) strcpy(buf + (cmd - name), cmd + 2); } return (RES_OK); } static void usage(void) { (void) fprintf(stderr, gettext("pfexec [-P privset] cmd [arg ..]\n")); exit(EXIT_FAILURE); } int main(int argc, char **argv) { char *cmd; char *pset = NULL; char pathbuf[MAXPATHLEN]; int c; priv_set_t *wanted; int oflag; oflag = getpflags(PRIV_PFEXEC); if (setpflags(PRIV_PFEXEC, 1) != 0) { (void) fprintf(stderr, gettext("pfexec: unable to set PFEXEC flag: %s\n"), strerror(errno)); exit(1); } if (*argv[0] == '-') cmd = argv[0] + 1; else cmd = argv[0]; /* Strip "pf" from argv[0], it confuses some shells. */ if (strncmp(cmd, "pf", 2) == 0) { argv[0] += 2; /* argv[0] will need to start with '-' again. */ if (argv[0][-2] == '-') *argv[0] = '-'; } /* If this fails, we just continue with plan B */ if (shellname(getexecname(), pathbuf) == RES_OK) (void) execv(pathbuf, argv); switch (shellname(cmd, pathbuf)) { case RES_OK: (void) execv(pathbuf, argv); (void) fprintf(stderr, gettext("pfexec: unable to execute %s: %s\n"), pathbuf, strerror(errno)); return (1); case RES_PFEXEC: case RES_FAILURE: while ((c = getopt(argc, argv, "P:")) != EOF) { switch (c) { case 'P': if (pset == NULL) { pset = optarg; break; } /* FALLTHROUGH */ default: usage(); } } argc -= optind; argv += optind; if (argc < 1) usage(); if (pset != NULL) { if ((wanted = priv_str_to_set(pset, ",", NULL)) == NULL) { (void) fprintf(stderr, gettext("pfexec: error parsing " "privileges: %s\n"), strerror(errno)); exit(EXIT_FAILURE); } if (setppriv(PRIV_ON, PRIV_INHERITABLE, wanted) != 0) { (void) fprintf(stderr, gettext("pfexec: error setting " "privileges: %s\n"), strerror(errno)); exit(EXIT_FAILURE); } (void) setpflags(PRIV_PFEXEC, oflag); } (void) execvp(argv[0], argv); (void) fprintf(stderr, gettext("pfexec: unable to execute %s: %s\n"), argv[0], strerror(errno)); return (1); } return (1); }