import from HEAD:
[freeradius.git] / src / main / exec.c
1 /*
2  * exec.c       Execute external programs.
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * Copyright 2000  The FreeRADIUS server project
21  * Copyright 2000  Michael J. Hartwick <hartwick@hartwick.com>
22  */
23 static const char rcsid[] = "$Id$";
24
25 #include "autoconf.h"
26
27 #include <sys/file.h>
28
29 #include <stdlib.h>
30 #include <string.h>
31 #include <fcntl.h>
32 #include <ctype.h>
33 #include <unistd.h>
34 #include <signal.h>
35
36 #ifdef HAVE_SYS_WAIT_H
37 #       include <sys/wait.h>
38 #endif
39 #ifndef WEXITSTATUS
40 #       define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
41 #endif
42 #ifndef WIFEXITED
43 #       define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
44 #endif
45
46 #include "radiusd.h"
47 #include "rad_assert.h"
48
49 /*
50  *      Execute a program on successful authentication.
51  *      Return 0 if exec_wait == 0.
52  *      Return the exit code of the called program if exec_wait != 0.
53  *      Return -1 on fork/other errors in the parent process.
54  */
55 int radius_exec_program(const char *cmd, REQUEST *request,
56                         int exec_wait,
57                         char *user_msg, int msg_len,
58                         VALUE_PAIR *input_pairs,
59                         VALUE_PAIR **output_pairs)
60 {
61         VALUE_PAIR *vp;
62         char answer[4096];
63         char *argv[256];
64         char *buf, *p;
65         int pd[2];
66         pid_t pid, child_pid;
67         int argc = -1;
68         int comma = 0;
69         int status;
70         int n, left, done;
71
72         if (user_msg) *user_msg = '\0';
73         if (output_pairs) *output_pairs = NULL;
74
75         /*
76          *      Open a pipe for child/parent communication, if
77          *      necessary.
78          */
79         if (exec_wait) {
80                 if (pipe(pd) != 0) {
81                         radlog(L_ERR|L_CONS, "Couldn't open pipe: %s",
82                                strerror(errno));
83                         return -1;
84                 }
85         } else {
86                 /*
87                  *      We're not waiting, so we don't look for a
88                  *      message, or VP's.
89                  */
90                 user_msg = NULL;
91                 output_pairs = NULL;
92         }
93
94         /*
95          *      Do the translation (as the parent) of the command to
96          *      execute.  This MAY involve calling other modules, so
97          *      we want to do it in the parent.
98          */
99         radius_xlat(answer, sizeof(answer), cmd, request, NULL);
100         buf = answer;
101
102         /*
103          *      Log the command if we are debugging something
104          */
105         DEBUG("Exec-Program: %s", buf);
106
107         /*
108          *      Build vector list of arguments and execute.
109          *
110          *      FIXME: This parsing gets excited over spaces in
111          *      the translated strings, e.g. User-Name = "aa bb"
112          *      is passed as two seperate arguments, instead of one.
113          *
114          *      What we SHOULD do instead is to split the exec program
115          *      buffer first, and then do the translation on every
116          *      subsequent string.
117          */
118         p = strtok(buf, " \t");
119         if (p) do {
120                 argv[++argc] = p;
121                 p = strtok(NULL, " \t");
122         } while(p != NULL);
123
124         argv[++argc] = p;
125         if (argc == 0) {
126                 radlog(L_ERR, "Exec-Program: empty command line.");
127                 return -1;
128         }
129
130         if ((pid = rad_fork(exec_wait)) == 0) {
131 #define MAX_ENVP 1024
132                 int devnull;
133                 char *envp[MAX_ENVP];
134                 int envlen;
135                 char buffer[1024];
136
137                 /*
138                  *      Child process.
139                  *
140                  *      We try to be fail-safe here.  So if ANYTHING
141                  *      goes wrong, we exit with status 1.
142                  */
143
144                 /*
145                  *      Open STDIN to /dev/null
146                  */
147                 devnull = open("/dev/null", O_RDWR);
148                 if (devnull < 0) {
149                         radlog(L_ERR|L_CONS, "Failed opening /dev/null: %s\n",
150                                strerror(errno));
151                         exit(1);
152                 }
153                 dup2(devnull, STDIN_FILENO);
154
155                 /*
156                  *      Only massage the pipe handles if the parent
157                  *      has created them.
158                  */
159                 if (exec_wait) {
160                         /*
161                          *      pd[0] is the FD the child will read from,
162                          *      which we don't want.
163                          */
164                         if (close(pd[0]) != 0) {
165                                 radlog(L_ERR|L_CONS, "Can't close pipe: %s",
166                                        strerror(errno));
167                                 exit(1);
168                         }
169
170                         /*
171                          *      pd[1] is the FD that the child will write to,
172                          *      so we make it STDOUT.
173                          */
174                         if (dup2(pd[1], STDOUT_FILENO) != 1) {
175                                 radlog(L_ERR|L_CONS, "Can't dup stdout: %s",
176                                        strerror(errno));
177                                 exit(1);
178                         }
179
180                 } else {        /* no pipe, STDOUT should be /dev/null */
181                         dup2(devnull, STDOUT_FILENO);
182                 }
183
184                 /*
185                  *      If we're not debugging, then we can't do
186                  *      anything with the error messages, so we throw
187                  *      them away.
188                  *
189                  *      If we are debugging, then we want the error
190                  *      messages to go to the STDERR of the server.
191                  */
192                 if (debug_flag == 0) {
193                         dup2(devnull, STDERR_FILENO);
194                 }
195                 close(devnull);
196
197                 /*
198                  *      The server may have MANY FD's open.  We don't
199                  *      want to leave dangling FD's for the child process
200                  *      to play funky games with, so we close them.
201                  */
202                 closefrom(3);
203
204                 /*
205                  *      Set up the environment variables.
206                  *      We're in the child, and it will exit in 4 lines
207                  *      anyhow, so memory allocation isn't an issue.
208                  */
209                 envlen = 0;
210
211                 for (vp = input_pairs; vp != NULL; vp = vp->next) {
212                         /*
213                          *      Hmm... maybe we shouldn't pass the
214                          *      user's password in an environment
215                          *      variable...
216                          */
217                         snprintf(buffer, sizeof(buffer), "%s=", vp->name);
218                         for (p = buffer; *p != '='; p++) {
219                                 if (*p == '-') {
220                                         *p = '_';
221                                 } else if (isalpha((int) *p)) {
222                                         *p = toupper(*p);
223                                 }
224                         }
225
226                         n = strlen(buffer);
227                         vp_prints_value(buffer+n, sizeof(buffer) - n, vp, 1);
228
229                         envp[envlen++] = strdup(buffer);
230
231                         /*
232                          *      Don't add too many attributes.
233                          */
234                         if (envlen == (MAX_ENVP - 1)) break;
235                 }
236                 envp[envlen] = NULL;
237                 execve(argv[0], argv, envp);
238                 radlog(L_ERR, "Exec-Program: FAILED to execute %s: %s",
239                        argv[0], strerror(errno));
240                 exit(1);
241         }
242
243         /*
244          *      Parent process.
245          */
246         if (pid < 0) {
247                 radlog(L_ERR|L_CONS, "Couldn't fork %s: %s",
248                        argv[0], strerror(errno));
249                 return -1;
250         }
251
252         /*
253          *      We're not waiting, exit, and ignore any child's
254          *      status.
255          */
256         if (!exec_wait) {
257                 return 0;
258         }
259
260         /*
261          *      Close the FD to which the child writes it's data.
262          *
263          *      If we can't close it, then we close pd[0], and return an
264          *      error.
265          */
266         if (close(pd[1]) != 0) {
267                 radlog(L_ERR|L_CONS, "Can't close pipe: %s", strerror(errno));
268                 close(pd[0]);
269                 return -1;
270         }
271
272         /*
273          *      Read from the pipe until we doesn't get any more or
274          *      until the message is full.
275          */
276         done = 0;
277         left = sizeof(answer) - 1;
278         while (1) {
279                 status = read(pd[0], answer + done, left);
280                 /*
281                  *      Nothing more to read: stop.
282                  */
283                 if (status == 0) {
284                         break;
285                 }
286
287                 /*
288                  *      Error: See if we have to continue.
289                  */
290                 if (status < 0) {
291                         /*
292                          *      We were interrupted: continue reading.
293                          */
294                         if (errno == EINTR) {
295                                 continue;
296                         }
297
298                         /*
299                          *      There was another error.  Most likely
300                          *      The child process has finished, and
301                          *      exited.
302                          */
303                         break;
304                 }
305
306                 done += status;
307                 left -= status;
308                 if (left <= 0) break;
309         }
310         answer[done] = 0;
311
312         /*
313          *      Make sure that the writer can't block while writing to
314          *      a pipe that no one is reading from anymore.
315          */
316         close(pd[0]);
317
318         DEBUG2("Exec-Program output: %s", answer);
319
320         /*
321          *      Parse the output, if any.
322          */
323         if (done) {
324                 n = T_INVALID;
325                 if (output_pairs) {
326                         /*
327                          *      For backwards compatibility, first check
328                          *      for plain text (user_msg).
329                          */
330                         vp = NULL;
331                         n = userparse(answer, &vp);
332                         if (vp) {
333                                 pairfree(&vp);
334                         }
335                 }
336
337                 if (n == T_INVALID) {
338                         radlog(L_DBG, "Exec-Program-Wait: plaintext: %s", answer);
339                         if (user_msg) {
340                                 strNcpy(user_msg, answer, msg_len);
341                         }
342                 } else {
343                         /*
344                          *      HACK: Replace '\n' with ',' so that
345                          *      userparse() can parse the buffer in
346                          *      one go (the proper way would be to
347                          *      fix userparse(), but oh well).
348                          */
349                         for (p = answer; *p; p++) {
350                                 if (*p == '\n') {
351                                         *p = comma ? ' ' : ',';
352                                         p++;
353                                         comma = 0;
354                                 }
355                                 if (*p == ',') comma++;
356                         }
357
358                         /*
359                          *  Replace any trailing comma by a NUL.
360                          */
361                         if (answer[strlen(answer) - 1] == ',') {
362                                 answer[strlen(answer) - 1] = '\0';
363                         }
364
365                         radlog(L_DBG,"Exec-Program-Wait: value-pairs: %s", answer);
366                         if (userparse(answer, &vp) == T_INVALID) {
367                                 radlog(L_ERR, "Exec-Program-Wait: %s: unparsable reply", cmd);
368
369                         } else {
370                                 /*
371                                  *      Tell the caller about the value
372                                  *      pairs.
373                                  */
374                                 *output_pairs = vp;
375                         }
376                 } /* else the answer was a set of VP's, not a text message */
377         } /* else we didn't read anything from the child. */
378
379         /*
380          *      Call rad_waitpid (should map to waitpid on non-threaded
381          *      or single-server systems).
382          */
383         child_pid = rad_waitpid(pid, &status, 0);
384         if (child_pid == pid) {
385                 if (WIFEXITED(status)) {
386                         status = WEXITSTATUS(status);
387                         radlog(L_DBG, "Exec-Program: returned: %d", status);
388                         return status;
389                 }
390         }
391
392         radlog(L_ERR|L_CONS, "Exec-Program: Abnormal child exit: %s",
393                strerror(errno));
394         return 1;
395 }