pt_pipe.c revision 143402
1169691Skan/*- 2169691Skan * Copyright (C) 2005 Diomidis Spinellis. All rights reserved. 3169691Skan * 4169691Skan * Redistribution and use in source and binary forms, with or without 5169691Skan * modification, are permitted provided that the following conditions 6169691Skan * are met: 7169691Skan * 1. Redistributions of source code must retain the above copyright 8169691Skan * notice, this list of conditions and the following disclaimer. 9169691Skan * 2. Redistributions in binary form must reproduce the above copyright 10169691Skan * notice, this list of conditions and the following disclaimer in the 11169691Skan * documentation and/or other materials provided with the distribution. 12169691Skan * 13169691Skan * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14169691Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15169691Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16169691Skan * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17169691Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18169691Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19169691Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20169691Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21169691Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22169691Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23169691Skan * SUCH DAMAGE. 24169691Skan * 25169691Skan */ 26169691Skan 27169691Skan#include <sys/cdefs.h> 28169691Skan__FBSDID("$FreeBSD: head/usr.sbin/mount_portalfs/pt_pipe.c 143402 2005-03-11 08:39:58Z dds $"); 29169691Skan 30169691Skan#include <ctype.h> 31169691Skan#include <errno.h> 32169691Skan#include <fcntl.h> 33169691Skan#include <stdio.h> 34169691Skan#include <stdlib.h> 35169691Skan#include <string.h> 36169691Skan#include <unistd.h> 37169691Skan 38169691Skan#include <sys/types.h> 39169691Skan#include <sys/param.h> 40169691Skan#include <sys/syslog.h> 41169691Skan 42169691Skan#include "portald.h" 43169691Skan 44169691Skan/* Usage conventions for the pipe's endpoints. */ 45169691Skan#define READ_END 0 46169691Skan#define WRITE_END 1 47169691Skan 48169691Skanstatic int errlog(void); 49169691Skanstatic int parse_argv(char *args, char **argv); 50169691Skan 51169691Skanint portal_pipe(pcr, key, v, so, fdp) 52169691Skanstruct portal_cred *pcr; 53169691Skanchar *key; 54169691Skanchar **v; 55169691Skanint so; 56169691Skanint *fdp; 57169691Skan{ 58169691Skan int fd[2]; /* Pipe endpoints. */ 59169691Skan int caller_end; /* The pipe end we will use. */ 60169691Skan int process_end; /* The pipe end the spawned process will use. */ 61169691Skan int redirect_fd; /* The fd to redirect on the spawned process. */ 62169691Skan char pbuf[MAXPATHLEN]; 63169691Skan int error = 0; 64169691Skan int i; 65169691Skan char **argv; 66169691Skan int argc; 67169691Skan struct portal_cred save_area; 68169691Skan 69169691Skan /* Validate open mode, and assign roles. */ 70169691Skan if ((pcr->pcr_flag & FWRITE) && (pcr->pcr_flag & FREAD)) 71169691Skan /* Don't allow both on a single fd. */ 72169691Skan return (EINVAL); 73169691Skan else if (pcr->pcr_flag & FREAD) { 74169691Skan /* 75169691Skan * The caller reads from the pipe, 76169691Skan * the spawned process writes to it. 77169691Skan */ 78169691Skan caller_end = READ_END; 79169691Skan process_end = WRITE_END; 80169691Skan redirect_fd = STDOUT_FILENO; 81169691Skan } else if (pcr->pcr_flag & FWRITE) { 82169691Skan /* 83169691Skan * The caller writes to the pipe, 84169691Skan * the spawned process reads from it. 85169691Skan */ 86169691Skan caller_end = WRITE_END; 87169691Skan process_end = READ_END; 88169691Skan redirect_fd = STDIN_FILENO; 89169691Skan } else 90169691Skan return (EINVAL); 91169691Skan 92169691Skan /* Get and check command line. */ 93169691Skan pbuf[0] = '/'; 94169691Skan strcpy(pbuf+1, key + (v[1] ? strlen(v[1]) : 0)); 95169691Skan argc = parse_argv(pbuf, NULL); 96169691Skan if (argc == 0) 97169691Skan return (ENOENT); 98169691Skan 99169691Skan /* Swap priviledges. */ 100169691Skan if (set_user_credentials(pcr, &save_area) < 0) 101169691Skan return (errno); 102169691Skan 103169691Skan /* Redirect and spawn the specified process. */ 104169691Skan fd[READ_END] = fd[WRITE_END] = -1; 105169691Skan if (pipe(fd) < 0) { 106169691Skan error = errno; 107169691Skan goto done; 108169691Skan } 109169691Skan switch (fork()) { 110169691Skan case -1: /* Error */ 111169691Skan error = errno; 112169691Skan break; 113169691Skan default: /* Parent */ 114169691Skan (void)close(fd[process_end]); 115169691Skan break; 116169691Skan case 0: /* Child */ 117169691Skan argv = (char **)malloc((argc + 1) * sizeof(char *)); 118169691Skan if (argv == 0) { 119169691Skan syslog(LOG_ALERT, 120169691Skan "malloc: failed to get space for %d pointers", 121169691Skan argc + 1); 122169691Skan exit(EXIT_FAILURE); 123169691Skan } 124169691Skan parse_argv(pbuf, argv); 125169691Skan 126169691Skan if (dup2(fd[process_end], redirect_fd) < 0) { 127169691Skan syslog(LOG_ERR, "dup2: %m"); 128169691Skan exit(EXIT_FAILURE); 129169691Skan } 130169691Skan (void)close(fd[caller_end]); 131169691Skan (void)close(fd[process_end]); 132169691Skan if (errlog() < 0) { 133169691Skan syslog(LOG_ERR, "errlog: %m"); 134169691Skan exit(EXIT_FAILURE); 135169691Skan } 136169691Skan if (execv(argv[0], argv) < 0) { 137169691Skan syslog(LOG_ERR, "execv(%s): %m", argv[0]); 138169691Skan exit(EXIT_FAILURE); 139169691Skan } 140169691Skan /* NOTREACHED */ 141169691Skan } 142169691Skan 143169691Skandone: 144169691Skan /* Re-establish our priviledges. */ 145169691Skan if (restore_credentials(&save_area) < 0) 146169691Skan error = errno; 147169691Skan 148169691Skan /* Set return fd value. */ 149169691Skan if (error == 0) 150169691Skan *fdp = fd[caller_end]; 151169691Skan else { 152169691Skan for (i = 0; i < 2; i++) 153169691Skan if (fd[i] >= 0) 154169691Skan (void)close(fd[i]); 155169691Skan *fdp = -1; 156169691Skan } 157169691Skan 158169691Skan return (error); 159169691Skan} 160169691Skan 161169691Skan/* 162169691Skan * Redirect stderr to the system log. 163169691Skan * Return 0 if ok. 164169691Skan * Return -1 with errno set on error. 165169691Skan */ 166169691Skanstatic int 167169691Skanerrlog(void) 168169691Skan{ 169169691Skan int fd[2]; 170169691Skan char buff[1024]; 171169691Skan FILE *f; 172169691Skan int ret = 0; 173169691Skan 174169691Skan if (pipe(fd) < 0) 175169691Skan return (-1); 176169691Skan switch (fork()) { 177169691Skan case -1: /* Error */ 178169691Skan return (-1); 179169691Skan case 0: /* Child */ 180169691Skan if ((f = fdopen(fd[READ_END], "r")) == NULL) { 181169691Skan syslog(LOG_ERR, "fdopen: %m"); 182169691Skan exit(EXIT_FAILURE); 183169691Skan } 184169691Skan (void)close(fd[WRITE_END]); 185169691Skan while (fgets(buff, sizeof(buff), f) != NULL) 186169691Skan syslog(LOG_ERR, "exec: %s", buff); 187169691Skan exit(EXIT_SUCCESS); 188169691Skan /* NOTREACHED */ 189169691Skan default: /* Parent */ 190169691Skan if (dup2(fd[WRITE_END], STDERR_FILENO) < 0) 191169691Skan ret = -1; 192169691Skan (void)close(fd[READ_END]); 193169691Skan (void)close(fd[WRITE_END]); 194169691Skan break; 195169691Skan } 196169691Skan return (ret); 197169691Skan} 198169691Skan 199169691Skan/* 200169691Skan * Parse the args string as a space-separated argument vector. 201169691Skan * If argv is not NULL, split the string into its constituent 202169691Skan * components, and set argv to point to the beginning of each 203169691Skan * string component; NULL-terminating argv. 204169691Skan * Return the number of string components. 205169691Skan */ 206169691Skanstatic int 207169691Skanparse_argv(char *args, char **argv) 208169691Skan{ 209169691Skan int count = 0; 210169691Skan char *p; 211169691Skan enum {WORD, SPACE} state = SPACE; 212169691Skan 213169691Skan for (p = args; *p; p++) 214169691Skan switch (state) { 215169691Skan case WORD: 216169691Skan if (isspace(*p)) { 217169691Skan if (argv) 218169691Skan *p = '\0'; 219169691Skan state = SPACE; 220169691Skan } 221169691Skan break; 222169691Skan case SPACE: 223169691Skan if (!isspace(*p)) { 224169691Skan if (argv) 225169691Skan argv[count] = p; 226169691Skan count++; 227169691Skan state = WORD; 228169691Skan } 229169691Skan } 230169691Skan if (argv) 231169691Skan argv[count] = NULL; 232169691Skan return (count); 233169691Skan} 234169691Skan