]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - usr.sbin/mount_portalfs/pt_pipe.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / usr.sbin / mount_portalfs / pt_pipe.c
1 /*-
2  * Copyright (C) 2005 Diomidis Spinellis. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <ctype.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/syslog.h>
41
42 #include "portald.h"
43
44 /* Usage conventions for the pipe's endpoints. */
45 #define READ_END        0
46 #define WRITE_END       1
47
48 static int  errlog(void);
49 static int  parse_argv(char *args, char **argv);
50
51 int portal_pipe(struct portal_cred *pcr, char *key, char **v,
52     int kso __unused, int *fdp)
53 {
54         int fd[2];              /* Pipe endpoints. */
55         int caller_end;         /* The pipe end we will use. */
56         int process_end;        /* The pipe end the spawned process will use. */
57         int redirect_fd;        /* The fd to redirect on the spawned process. */
58         char pbuf[MAXPATHLEN];
59         int error = 0;
60         int i;
61         char **argv;
62         int argc;
63         struct portal_cred save_area;
64
65         /* Validate open mode, and assign roles. */
66         if ((pcr->pcr_flag & FWRITE) && (pcr->pcr_flag & FREAD))
67                 /* Don't allow both on a single fd. */
68                 return (EINVAL);
69         else if (pcr->pcr_flag & FREAD) {
70                 /*
71                  * The caller reads from the pipe,
72                  * the spawned process writes to it.
73                  */
74                 caller_end = READ_END;
75                 process_end = WRITE_END;
76                 redirect_fd = STDOUT_FILENO;
77         } else if (pcr->pcr_flag & FWRITE) {
78                 /*
79                  * The caller writes to the pipe,
80                  * the spawned process reads from it.
81                  */
82                 caller_end = WRITE_END;
83                 process_end = READ_END;
84                 redirect_fd = STDIN_FILENO;
85         } else
86                 return (EINVAL);
87
88         /* Get and check command line. */
89         pbuf[0] = '/';
90         strcpy(pbuf+1, key + (v[1] ? strlen(v[1]) : 0));
91         argc = parse_argv(pbuf, NULL);
92         if (argc == 0)
93                 return (ENOENT);
94
95         /* Swap priviledges. */
96         if (set_user_credentials(pcr, &save_area) < 0)
97                 return (errno);
98
99         /* Redirect and spawn the specified process. */
100         fd[READ_END] = fd[WRITE_END] = -1;
101         if (pipe(fd) < 0) {
102                 error = errno;
103                 goto done;
104         }
105         switch (fork()) {
106         case -1: /* Error */
107                 error = errno;
108                 break;
109         default: /* Parent */
110                 (void)close(fd[process_end]);
111                 break;
112         case 0: /* Child */
113                 argv = (char **)malloc((argc + 1) * sizeof(char *));
114                 if (argv == 0) {
115                         syslog(LOG_ALERT,
116                             "malloc: failed to get space for %d pointers",
117                             argc + 1);
118                         exit(EXIT_FAILURE);
119                 }
120                 parse_argv(pbuf, argv);
121
122                 if (dup2(fd[process_end], redirect_fd) < 0) {
123                         syslog(LOG_ERR, "dup2: %m");
124                         exit(EXIT_FAILURE);
125                 }
126                 (void)close(fd[caller_end]);
127                 (void)close(fd[process_end]);
128                 if (errlog() < 0) {
129                         syslog(LOG_ERR, "errlog: %m");
130                         exit(EXIT_FAILURE);
131                 }
132                 if (execv(argv[0], argv) < 0) {
133                         syslog(LOG_ERR, "execv(%s): %m", argv[0]);
134                         exit(EXIT_FAILURE);
135                 }
136                 /* NOTREACHED */
137         }
138
139 done:
140         /* Re-establish our priviledges. */
141         if (restore_credentials(&save_area) < 0)
142                 error = errno;
143
144         /* Set return fd value. */
145         if (error == 0)
146                 *fdp = fd[caller_end];
147         else {
148                 for (i = 0; i < 2; i++)
149                         if (fd[i] >= 0)
150                                 (void)close(fd[i]);
151                 *fdp = -1;
152         }
153
154         return (error);
155 }
156
157 /*
158  * Redirect stderr to the system log.
159  * Return 0 if ok.
160  * Return -1 with errno set on error.
161  */
162 static int
163 errlog(void)
164 {
165         int fd[2];
166         char buff[1024];
167         FILE *f;
168         int ret = 0;
169
170         if (pipe(fd) < 0)
171                 return (-1);
172         switch (fork()) {
173         case -1: /* Error */
174                 return (-1);
175         case 0: /* Child */
176                 if ((f = fdopen(fd[READ_END], "r")) == NULL) {
177                         syslog(LOG_ERR, "fdopen: %m");
178                         exit(EXIT_FAILURE);
179                 }
180                 (void)close(fd[WRITE_END]);
181                 while (fgets(buff, sizeof(buff), f) != NULL)
182                         syslog(LOG_ERR, "exec: %s", buff);
183                 exit(EXIT_SUCCESS);
184                 /* NOTREACHED */
185         default: /* Parent */
186                 if (dup2(fd[WRITE_END], STDERR_FILENO) < 0)
187                         ret = -1;
188                 (void)close(fd[READ_END]);
189                 (void)close(fd[WRITE_END]);
190                 break;
191         }
192         return (ret);
193 }
194
195 /*
196  * Parse the args string as a space-separated argument vector.
197  * If argv is not NULL, split the string into its constituent
198  * components, and set argv to point to the beginning  of each
199  * string component; NULL-terminating argv.
200  * Return the number of string components.
201  */
202 static int
203 parse_argv(char *args, char **argv)
204 {
205         int count = 0;
206         char *p;
207         enum {WORD, SPACE} state = SPACE;
208
209         for (p = args; *p; p++)
210                 switch (state) {
211                 case WORD:
212                         if (isspace(*p)) {
213                                 if (argv)
214                                         *p = '\0';
215                                 state = SPACE;
216                         }
217                         break;
218                 case SPACE:
219                         if (!isspace(*p)) {
220                                 if (argv)
221                                         argv[count] = p;
222                                 count++;
223                                 state = WORD;
224                         }
225                 }
226         if (argv)
227                 argv[count] = NULL;
228         return (count);
229 }