]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/mount_portalfs/pt_pipe.c
This commit was generated by cvs2svn to compensate for changes in r154178,
[FreeBSD/FreeBSD.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(pcr, key, v, so, fdp)
52 struct portal_cred *pcr;
53 char *key;
54 char **v;
55 int so;
56 int *fdp;
57 {
58         int fd[2];              /* Pipe endpoints. */
59         int caller_end;         /* The pipe end we will use. */
60         int process_end;        /* The pipe end the spawned process will use. */
61         int redirect_fd;        /* The fd to redirect on the spawned process. */
62         char pbuf[MAXPATHLEN];
63         int error = 0;
64         int i;
65         char **argv;
66         int argc;
67         struct portal_cred save_area;
68
69         /* Validate open mode, and assign roles. */
70         if ((pcr->pcr_flag & FWRITE) && (pcr->pcr_flag & FREAD))
71                 /* Don't allow both on a single fd. */
72                 return (EINVAL);
73         else if (pcr->pcr_flag & FREAD) {
74                 /*
75                  * The caller reads from the pipe,
76                  * the spawned process writes to it.
77                  */
78                 caller_end = READ_END;
79                 process_end = WRITE_END;
80                 redirect_fd = STDOUT_FILENO;
81         } else if (pcr->pcr_flag & FWRITE) {
82                 /*
83                  * The caller writes to the pipe,
84                  * the spawned process reads from it.
85                  */
86                 caller_end = WRITE_END;
87                 process_end = READ_END;
88                 redirect_fd = STDIN_FILENO;
89         } else
90                 return (EINVAL);
91
92         /* Get and check command line. */
93         pbuf[0] = '/';
94         strcpy(pbuf+1, key + (v[1] ? strlen(v[1]) : 0));
95         argc = parse_argv(pbuf, NULL);
96         if (argc == 0)
97                 return (ENOENT);
98
99         /* Swap priviledges. */
100         if (set_user_credentials(pcr, &save_area) < 0)
101                 return (errno);
102
103         /* Redirect and spawn the specified process. */
104         fd[READ_END] = fd[WRITE_END] = -1;
105         if (pipe(fd) < 0) {
106                 error = errno;
107                 goto done;
108         }
109         switch (fork()) {
110         case -1: /* Error */
111                 error = errno;
112                 break;
113         default: /* Parent */
114                 (void)close(fd[process_end]);
115                 break;
116         case 0: /* Child */
117                 argv = (char **)malloc((argc + 1) * sizeof(char *));
118                 if (argv == 0) {
119                         syslog(LOG_ALERT,
120                             "malloc: failed to get space for %d pointers",
121                             argc + 1);
122                         exit(EXIT_FAILURE);
123                 }
124                 parse_argv(pbuf, argv);
125
126                 if (dup2(fd[process_end], redirect_fd) < 0) {
127                         syslog(LOG_ERR, "dup2: %m");
128                         exit(EXIT_FAILURE);
129                 }
130                 (void)close(fd[caller_end]);
131                 (void)close(fd[process_end]);
132                 if (errlog() < 0) {
133                         syslog(LOG_ERR, "errlog: %m");
134                         exit(EXIT_FAILURE);
135                 }
136                 if (execv(argv[0], argv) < 0) {
137                         syslog(LOG_ERR, "execv(%s): %m", argv[0]);
138                         exit(EXIT_FAILURE);
139                 }
140                 /* NOTREACHED */
141         }
142
143 done:
144         /* Re-establish our priviledges. */
145         if (restore_credentials(&save_area) < 0)
146                 error = errno;
147
148         /* Set return fd value. */
149         if (error == 0)
150                 *fdp = fd[caller_end];
151         else {
152                 for (i = 0; i < 2; i++)
153                         if (fd[i] >= 0)
154                                 (void)close(fd[i]);
155                 *fdp = -1;
156         }
157
158         return (error);
159 }
160
161 /*
162  * Redirect stderr to the system log.
163  * Return 0 if ok.
164  * Return -1 with errno set on error.
165  */
166 static int
167 errlog(void)
168 {
169         int fd[2];
170         char buff[1024];
171         FILE *f;
172         int ret = 0;
173
174         if (pipe(fd) < 0)
175                 return (-1);
176         switch (fork()) {
177         case -1: /* Error */
178                 return (-1);
179         case 0: /* Child */
180                 if ((f = fdopen(fd[READ_END], "r")) == NULL) {
181                         syslog(LOG_ERR, "fdopen: %m");
182                         exit(EXIT_FAILURE);
183                 }
184                 (void)close(fd[WRITE_END]);
185                 while (fgets(buff, sizeof(buff), f) != NULL)
186                         syslog(LOG_ERR, "exec: %s", buff);
187                 exit(EXIT_SUCCESS);
188                 /* NOTREACHED */
189         default: /* Parent */
190                 if (dup2(fd[WRITE_END], STDERR_FILENO) < 0)
191                         ret = -1;
192                 (void)close(fd[READ_END]);
193                 (void)close(fd[WRITE_END]);
194                 break;
195         }
196         return (ret);
197 }
198
199 /*
200  * Parse the args string as a space-separated argument vector.
201  * If argv is not NULL, split the string into its constituent
202  * components, and set argv to point to the beginning  of each
203  * string component; NULL-terminating argv.
204  * Return the number of string components.
205  */
206 static int
207 parse_argv(char *args, char **argv)
208 {
209         int count = 0;
210         char *p;
211         enum {WORD, SPACE} state = SPACE;
212
213         for (p = args; *p; p++)
214                 switch (state) {
215                 case WORD:
216                         if (isspace(*p)) {
217                                 if (argv)
218                                         *p = '\0';
219                                 state = SPACE;
220                         }
221                         break;
222                 case SPACE:
223                         if (!isspace(*p)) {
224                                 if (argv)
225                                         argv[count] = p;
226                                 count++;
227                                 state = WORD;
228                         }
229                 }
230         if (argv)
231                 argv[count] = NULL;
232         return (count);
233 }