]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - gnu/libexec/uucp/libunix/xqtsub.c
This commit was generated by cvs2svn to compensate for changes in r52746,
[FreeBSD/FreeBSD.git] / gnu / libexec / uucp / libunix / xqtsub.c
1 /* xqtsub.c
2    System dependent functions used only by uuxqt.
3
4    Copyright (C) 1991, 1992, 1993, 1995 Ian Lance Taylor
5
6    This file is part of the Taylor UUCP package.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2 of the
11    License, or (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21
22    The author of the program may be contacted at ian@airs.com or
23    c/o Cygnus Support, 48 Grove Street, Somerville, MA 02144.
24    */
25
26 #include "uucp.h"
27
28 #if USE_RCS_ID
29 const char xqtsub_rcsid[] = "$FreeBSD$";
30 #endif
31
32 #include "uudefs.h"
33 #include "uuconf.h"
34 #include "system.h"
35 #include "sysdep.h"
36
37 #include <ctype.h>
38 #include <errno.h>
39
40 #if HAVE_FCNTL_H
41 #include <fcntl.h>
42 #else
43 #if HAVE_SYS_FILE_H
44 #include <sys/file.h>
45 #endif
46 #endif
47
48 #ifndef O_RDONLY
49 #define O_RDONLY 0
50 #define O_WRONLY 1
51 #define O_RDWR 2
52 #endif
53
54 #ifndef O_NOCTTY
55 #define O_NOCTTY 0
56 #endif
57
58 #ifndef FD_CLOEXEC
59 #define FD_CLOEXEC 1
60 #endif
61
62 #if HAVE_OPENDIR
63 #if HAVE_DIRENT_H
64 #include <dirent.h>
65 #else /* ! HAVE_DIRENT_H */
66 #include <sys/dir.h>
67 #define dirent direct
68 #endif /* ! HAVE_DIRENT_H */
69 #endif /* HAVE_OPENDIR */
70
71 /* Get a value for EX_TEMPFAIL.  */
72
73 #if HAVE_SYSEXITS_H
74 #include <sysexits.h>
75 #endif
76
77 #ifndef EX_TEMPFAIL
78 #define EX_TEMPFAIL 75
79 #endif
80 \f
81 /* Get the full pathname of the command to execute, given the list of
82    permitted commands and the allowed path.  */
83
84 char *
85 zsysdep_find_command (zcmd, pzcmds, pzpath, pferr)
86      const char *zcmd;
87      char **pzcmds;
88      char **pzpath;
89      boolean *pferr;
90 {
91   char **pz;
92   struct stat s;
93
94   *pferr = FALSE;
95
96   for (pz = pzcmds; *pz != NULL; pz++)
97     {
98       char *zslash;
99
100       if (strcmp (*pz, "ALL") == 0)
101         break;
102
103       zslash = strrchr (*pz, '/');
104       if (zslash != NULL)
105         ++zslash;
106       else
107         zslash = *pz;
108       if (strcmp (zslash, zcmd) == 0
109           || strcmp (*pz, zcmd) == 0)
110         {
111           /* If we already have an absolute path, we can get out
112              immediately.  */
113           if (**pz == '/')
114             {
115               /* Quick error check.  */
116               if (stat (*pz, &s) != 0)
117                 {
118                   ulog (LOG_ERROR, "%s: %s", *pz, strerror (errno));
119                   *pferr = TRUE;
120                   return NULL;
121                 }
122               return zbufcpy (*pz);
123             }
124           break;
125         }
126     }
127
128   /* If we didn't find this command, get out.  */
129   if (*pz == NULL)
130     return NULL;
131
132   /* We didn't find an absolute pathname, so we must look through
133      the path.  */
134   for (pz = pzpath; *pz != NULL; pz++)
135     {
136       char *zname;
137
138       zname = zsysdep_in_dir (*pz, zcmd);
139       if (stat (zname, &s) == 0)
140         return zname;
141     }
142
143   return NULL;
144 }
145 \f
146 /* Expand a local filename for uuxqt.  This is special because uuxqt
147    only wants to expand filenames that start with ~ (it does not want
148    to prepend the current directory to other names) and if the ~ is
149    double, it is turned into a single ~.  This returns NULL to
150    indicate that no change was required; it has no way to return
151    error.  */
152
153 char *
154 zsysdep_xqt_local_file (qsys, zfile)
155      const struct uuconf_system *qsys;
156      const char *zfile;
157 {
158   if (*zfile != '~')
159     return NULL;
160   if (zfile[1] == '~')
161     {
162       size_t clen;
163       char *zret;
164
165       clen = strlen (zfile);
166       zret = zbufalc (clen);
167       memcpy (zret, zfile + 1, clen);
168       return zret;
169     }
170   return zsysdep_local_file (zfile, qsys->uuconf_zpubdir,
171                              (boolean *) NULL);
172 }
173 \f
174 #if ! ALLOW_FILENAME_ARGUMENTS
175
176 /* Check to see whether an argument specifies a file name; if it does,
177    make sure that the file may legally be sent and/or received.  For
178    Unix, we do not permit any occurrence of "/../" in the name, nor
179    may it start with "../".  Otherwise, if it starts with "/" we check
180    against the list of permitted files.  */
181
182 boolean
183 fsysdep_xqt_check_file (qsys, zfile)
184      const struct uuconf_system *qsys;
185      const char *zfile;
186 {
187   size_t clen;
188
189   /* Disallow exact "..", prefix "../", suffix "/..", internal "/../",
190      and restricted absolute paths.  */
191   clen = strlen (zfile);
192   if ((clen == sizeof ".." - 1
193        && strcmp (zfile, "..") == 0)
194       || strncmp (zfile, "../", sizeof "../" - 1) == 0
195       || (clen >= sizeof "/.." - 1
196           && strcmp (zfile + clen - (sizeof "/.." - 1), "/..") == 0)
197       || strstr (zfile, "/../") != NULL
198       || (*zfile == '/'
199           && (! fin_directory_list (zfile, qsys->uuconf_pzremote_send,
200                                     qsys->uuconf_zpubdir, TRUE, FALSE,
201                                     (const char *) NULL)
202               || ! fin_directory_list (zfile, qsys->uuconf_pzremote_receive,
203                                        qsys->uuconf_zpubdir, TRUE, FALSE,
204                                        (const char *) NULL))))
205     {
206       ulog (LOG_ERROR, "Not permitted to refer to file \"%s\"", zfile);
207       return FALSE;
208     }
209
210   return TRUE;
211 }
212
213 #endif /* ! ALLOW_FILENAME_ARGUMENTS */
214 \f
215 /* Invoke the command specified by an execute file.  */
216
217 /*ARGSUSED*/
218 boolean
219 fsysdep_execute (qsys, zuser, pazargs, zfullcmd, zinput, zoutput,
220                  fshell, iseq, pzerror, pftemp)
221      const struct uuconf_system *qsys;
222      const char *zuser;
223      const char **pazargs;
224      const char *zfullcmd;
225      const char *zinput;
226      const char *zoutput;
227      boolean fshell;
228      int iseq;
229      char **pzerror;
230      boolean *pftemp;
231 {
232   int aidescs[3];
233   boolean ferr;
234   pid_t ipid;
235   int ierr;
236   char abxqtdir[sizeof XQTDIR + 4];
237   const char *zxqtdir;
238   int istat;
239   char *zpath;
240 #if ALLOW_SH_EXECUTION
241   const char *azshargs[4];
242 #endif
243
244   *pzerror = NULL;
245   *pftemp = FALSE;
246
247   aidescs[0] = SPAWN_NULL;
248   aidescs[1] = SPAWN_NULL;
249   aidescs[2] = SPAWN_NULL;
250
251   ferr = FALSE;
252
253   if (zinput != NULL)
254     {
255       aidescs[0] = open ((char *) zinput, O_RDONLY | O_NOCTTY, 0);
256       if (aidescs[0] < 0)
257         {
258           ulog (LOG_ERROR, "open (%s): %s", zinput, strerror (errno));
259           ferr = TRUE;
260         }
261       else if (fcntl (aidescs[0], F_SETFD,
262                       fcntl (aidescs[0], F_GETFD, 0) | FD_CLOEXEC) < 0)
263         {
264           ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
265           ferr = TRUE;
266         }       
267     }
268   
269   if (! ferr && zoutput != NULL)
270     {
271       aidescs[1] = creat ((char *) zoutput, IPRIVATE_FILE_MODE);
272       if (aidescs[1] < 0)
273         {
274           ulog (LOG_ERROR, "creat (%s): %s", zoutput, strerror (errno));
275           *pftemp = TRUE;
276           ferr = TRUE;
277         }
278       else if (fcntl (aidescs[1], F_SETFD,
279                       fcntl (aidescs[1], F_GETFD, 0) | FD_CLOEXEC) < 0)
280         {
281           ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
282           ferr = TRUE;
283         }       
284     }
285
286   if (! ferr)
287     {
288       *pzerror = zstemp_file (qsys);
289       aidescs[2] = creat (*pzerror, IPRIVATE_FILE_MODE);
290       if (aidescs[2] < 0)
291         {
292           if (errno == ENOENT)
293             {
294               if (! fsysdep_make_dirs (*pzerror, FALSE))
295                 {
296                   *pftemp = TRUE;
297                   ferr = TRUE;
298                 }
299               else
300                 aidescs[2] = creat (*pzerror, IPRIVATE_FILE_MODE);
301             }
302           if (! ferr && aidescs[2] < 0)
303             {
304               ulog (LOG_ERROR, "creat (%s): %s", *pzerror, strerror (errno));
305               *pftemp = TRUE;
306               ferr = TRUE;
307             }
308         }
309       if (! ferr
310           && fcntl (aidescs[2], F_SETFD,
311                     fcntl (aidescs[2], F_GETFD, 0) | FD_CLOEXEC) < 0)
312         {
313           ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
314           ferr = TRUE;
315         }       
316     }
317
318   if (iseq == 0)
319     zxqtdir = XQTDIR;
320   else
321     {
322       sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
323       zxqtdir = abxqtdir;
324     }
325
326   if (ferr)
327     {
328       if (aidescs[0] != SPAWN_NULL)
329         (void) close (aidescs[0]);
330       if (aidescs[1] != SPAWN_NULL)
331         (void) close (aidescs[1]);
332       if (aidescs[2] != SPAWN_NULL)
333         (void) close (aidescs[2]);
334       ubuffree (*pzerror);
335       return FALSE;
336     }
337
338 #if ALLOW_SH_EXECUTION
339   if (fshell)
340     {
341       azshargs[0] = "/bin/sh";
342       azshargs[1] = "-c";
343       azshargs[2] = zfullcmd;
344       azshargs[3] = NULL;
345       pazargs = azshargs;
346     }
347 #else
348   fshell = FALSE;
349 #endif
350
351   if (qsys->uuconf_pzpath == NULL)
352     zpath = NULL;
353   else
354     {
355       size_t c;
356       char **pz;
357
358       c = 0;
359       for (pz = qsys->uuconf_pzpath; *pz != NULL; pz++)
360         c += strlen (*pz) + 1;
361       zpath = zbufalc (c);
362       *zpath = '\0';
363       for (pz = qsys->uuconf_pzpath; *pz != NULL; pz++)
364         {
365           strcat (zpath, *pz);
366           if (pz[1] != NULL)
367             strcat (zpath, ":");
368         }
369     }
370
371   /* Pass zchdir as zxqtdir, fnosigs as TRUE, fshell as TRUE if we
372      aren't already using the shell.  */
373   ipid = ixsspawn (pazargs, aidescs, TRUE, FALSE, zxqtdir, TRUE,
374                    ! fshell, zpath, qsys->uuconf_zname, zuser);
375
376   ierr = errno;
377
378   ubuffree (zpath);
379
380   if (aidescs[0] != SPAWN_NULL)
381     (void) close (aidescs[0]);
382   if (aidescs[1] != SPAWN_NULL)
383     (void) close (aidescs[1]);
384   if (aidescs[2] != SPAWN_NULL)
385     (void) close (aidescs[2]);
386
387   if (ipid < 0)
388     {
389       ulog (LOG_ERROR, "ixsspawn: %s", strerror (ierr));
390       *pftemp = TRUE;
391       return FALSE;
392     }
393
394   istat = ixswait ((unsigned long) ipid, "Execution");
395
396   if (istat == EX_TEMPFAIL)
397     *pftemp = TRUE;
398
399   return istat == 0;
400 }
401 \f
402 /* Lock a uuxqt process.  */
403
404 int
405 ixsysdep_lock_uuxqt (zcmd, cmaxuuxqts)
406      const char *zcmd;
407      int cmaxuuxqts;
408 {
409   char ab[sizeof "LCK.XQT.9999"];
410   int i;
411
412   if (cmaxuuxqts <= 0 || cmaxuuxqts >= 10000)
413     cmaxuuxqts = 9999;
414   for (i = 0; i < cmaxuuxqts; i++)
415     {
416       sprintf (ab, "LCK.XQT.%d", i);
417       if (fsdo_lock (ab, TRUE, (boolean *) NULL))
418         break;
419     }
420   if (i >= cmaxuuxqts)
421     return -1;
422
423   if (zcmd != NULL)
424     {
425       char abcmd[sizeof "LXQ.123456789"];
426
427       sprintf (abcmd, "LXQ.%.9s", zcmd);
428       abcmd[strcspn (abcmd, " \t/")] = '\0';
429       if (! fsdo_lock (abcmd, TRUE, (boolean *) NULL))
430         {
431           (void) fsdo_unlock (ab, TRUE);
432           return -1;
433         }
434     }
435
436   return i;
437 }
438
439 /* Unlock a uuxqt process.  */
440
441 boolean
442 fsysdep_unlock_uuxqt (iseq, zcmd, cmaxuuxqts)
443      int iseq;
444      const char *zcmd;
445      int cmaxuuxqts;
446 {
447   char ab[sizeof "LCK.XQT.9999"];
448   boolean fret;
449
450   fret = TRUE;
451
452   sprintf (ab, "LCK.XQT.%d", iseq);
453   if (! fsdo_unlock (ab, TRUE))
454     fret = FALSE;
455
456   if (zcmd != NULL)
457     {
458       char abcmd[sizeof "LXQ.123456789"];
459
460       sprintf (abcmd, "LXQ.%.9s", zcmd);
461       abcmd[strcspn (abcmd, " \t/")] = '\0';
462       if (! fsdo_unlock (abcmd, TRUE))
463         fret = FALSE;
464     }
465
466   return fret;
467 }
468
469 /* See whether a particular uuxqt command is locked (this depends on
470    the implementation of fsdo_lock).  */
471
472 boolean
473 fsysdep_uuxqt_locked (zcmd)
474      const char *zcmd;
475 {
476   char ab[sizeof "LXQ.123456789"];
477   struct stat s;
478
479   sprintf (ab, "LXQ.%.9s", zcmd);
480   return stat (ab, &s) == 0;
481 }
482
483 /* Lock a particular execute file.  */
484
485 boolean
486 fsysdep_lock_uuxqt_file (zfile)
487      const char *zfile;
488 {
489   char *zcopy, *z;
490   boolean fret;
491
492   zcopy = zbufcpy (zfile);
493
494   z = strrchr (zcopy, '/');
495   if (z == NULL)
496     *zcopy = 'L';
497   else
498     *(z + 1) = 'L';
499
500   fret = fsdo_lock (zcopy, TRUE, (boolean *) NULL);
501   ubuffree (zcopy);
502   return fret;
503 }
504
505 /* Unlock a particular execute file.  */
506
507 boolean
508 fsysdep_unlock_uuxqt_file (zfile)
509      const char *zfile;
510 {
511   char *zcopy, *z;
512   boolean fret;
513
514   zcopy = zbufcpy (zfile);
515
516   z = strrchr (zcopy, '/');
517   if (z == NULL)
518     *zcopy = 'L';
519   else
520     *(z + 1) = 'L';
521
522   fret = fsdo_unlock (zcopy, TRUE);
523   ubuffree (zcopy);
524   return fret;
525 }
526
527 /* Lock the execute directory.  Since we use a different directory
528    depending on which LCK.XQT.dddd file we got, there is actually no
529    need to create a lock file.  We do make sure that the directory
530    exists, though.  */
531
532 boolean
533 fsysdep_lock_uuxqt_dir (iseq)
534      int iseq;
535 {
536   const char *zxqtdir;
537   char abxqtdir[sizeof XQTDIR + 4];
538
539   if (iseq == 0)
540     zxqtdir = XQTDIR;
541   else
542     {
543       sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
544       zxqtdir = abxqtdir;
545     }
546
547   if (mkdir (zxqtdir, S_IRWXU) < 0
548       && errno != EEXIST
549       && errno != EISDIR)
550     {
551       ulog (LOG_ERROR, "mkdir (%s): %s", zxqtdir, strerror (errno));
552       return FALSE;
553     }
554
555   return TRUE;
556 }
557
558 /* Unlock the execute directory and clear it out.  The lock is
559    actually the LCK.XQT.dddd file, so we don't unlock it, but we do
560    remove all the files.  */
561
562 boolean
563 fsysdep_unlock_uuxqt_dir (iseq)
564      int iseq;
565 {
566   const char *zxqtdir;
567   char abxqtdir[sizeof XQTDIR + 4];
568   DIR *qdir;
569
570   if (iseq == 0)
571     zxqtdir = XQTDIR;
572   else
573     {
574       sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
575       zxqtdir = abxqtdir;
576     }
577
578   qdir = opendir ((char *) zxqtdir);
579   if (qdir != NULL)
580     {
581       struct dirent *qentry;
582
583       while ((qentry = readdir (qdir)) != NULL)
584         {
585           char *z;
586
587           if (strcmp (qentry->d_name, ".") == 0
588               || strcmp (qentry->d_name, "..") == 0)
589             continue;
590           z = zsysdep_in_dir (zxqtdir, qentry->d_name);
591           if (remove (z) < 0)
592             {
593               int ierr;
594
595               ierr = errno;
596               if (! fsysdep_directory (z))
597                 ulog (LOG_ERROR, "remove (%s): %s", z,
598                       strerror (ierr));
599               else
600                 (void) fsysdep_rmdir (z);
601             }
602           ubuffree (z);
603         }
604
605       closedir (qdir);
606     }
607
608   return TRUE;
609 }
610 \f
611 /* Move files into the execution directory.  */
612
613 boolean
614 fsysdep_move_uuxqt_files (cfiles, pzfrom, pzto, fto, iseq, pzinput)
615      int cfiles;
616      const char *const *pzfrom;
617      const char *const *pzto;
618      boolean fto;
619      int iseq;
620      char **pzinput;
621 {
622   char *zinput;
623   const char *zxqtdir;
624   char abxqtdir[sizeof XQTDIR + 4];
625   int i;
626
627   if (pzinput == NULL)
628     zinput = NULL;
629   else
630     zinput = *pzinput;
631
632   if (iseq == 0)
633     zxqtdir = XQTDIR;
634   else
635     {
636       sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
637       zxqtdir = abxqtdir;
638     }
639
640   for (i = 0; i < cfiles; i++)
641     {
642       const char *zfrom, *zto;
643       char *zfree;
644
645       if (pzto[i] == NULL)
646         continue;
647
648       zfree = zsysdep_in_dir (zxqtdir, pzto[i]);
649
650       zfrom = pzfrom[i];
651       zto = zfree;
652
653       if (zinput != NULL && strcmp (zinput, zfrom) == 0)
654         {
655           *pzinput = zbufcpy (zto);
656           zinput = NULL;
657         }
658
659       if (! fto)
660         {
661           const char *ztemp;
662           
663           ztemp = zfrom;
664           zfrom = zto;
665           zto = ztemp;
666           (void) chmod (zfrom, IPRIVATE_FILE_MODE);
667         }
668
669       if (rename (zfrom, zto) < 0)
670         {
671 #if HAVE_RENAME
672           /* On some systems the system call rename seems to fail for
673              arbitrary reasons.  To get around this, we always try to
674              copy the file by hand if the rename failed.  */
675           errno = EXDEV;
676 #endif
677
678           if (errno != EXDEV)
679             {
680               ulog (LOG_ERROR, "rename (%s, %s): %s", zfrom, zto,
681                     strerror (errno));
682               ubuffree (zfree);
683               break;
684             }
685
686           if (! fcopy_file (zfrom, zto, FALSE, FALSE, FALSE))
687             {
688               ubuffree (zfree);
689               break;
690             }
691           if (remove (zfrom) < 0)
692             ulog (LOG_ERROR, "remove (%s): %s", zfrom,
693                   strerror (errno));
694         }
695
696       if (fto)
697         (void) chmod (zto, IPUBLIC_FILE_MODE);
698
699       ubuffree (zfree);
700     }
701
702   if (i < cfiles)
703     {
704       if (fto)
705         (void) fsysdep_move_uuxqt_files (i, pzfrom, pzto, FALSE, iseq,
706                                          (char **) NULL);
707       return FALSE;
708     }
709
710   return TRUE;
711 }