home *** CD-ROM | disk | FTP | other *** search
- /* xqtsub.c
- System dependent functions used only by uuxqt.
-
- Copyright (C) 1991, 1992, 1993, 1995 Ian Lance Taylor
-
- This file is part of the Taylor UUCP package.
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- The author of the program may be contacted at ian@airs.com or
- c/o Cygnus Support, 48 Grove Street, Somerville, MA 02144.
- */
-
- #include "uucp.h"
-
- #if USE_RCS_ID
- const char xqtsub_rcsid[] = "$Id: xqtsub.c,v 1.18 1995/06/21 20:21:14 ian Rel $";
- #endif
-
- #include "uudefs.h"
- #include "uuconf.h"
- #include "system.h"
- #include "sysdep.h"
-
- #include <ctype.h>
- #include <errno.h>
-
- #if HAVE_FCNTL_H
- #include <fcntl.h>
- #else
- #if HAVE_SYS_FILE_H
- #include <sys/file.h>
- #endif
- #endif
-
- #ifndef O_RDONLY
- #define O_RDONLY 0
- #define O_WRONLY 1
- #define O_RDWR 2
- #endif
-
- #ifndef O_NOCTTY
- #define O_NOCTTY 0
- #endif
-
- #ifndef FD_CLOEXEC
- #define FD_CLOEXEC 1
- #endif
-
- #if HAVE_OPENDIR
- #if HAVE_DIRENT_H
- #include <dirent.h>
- #else /* ! HAVE_DIRENT_H */
- #include <sys/dir.h>
- #define dirent direct
- #endif /* ! HAVE_DIRENT_H */
- #endif /* HAVE_OPENDIR */
-
- /* Get a value for EX_TEMPFAIL. */
-
- #if HAVE_SYSEXITS_H
- #include <sysexits.h>
- #endif
-
- #ifndef EX_TEMPFAIL
- #define EX_TEMPFAIL 75
- #endif
-
- /* Get the full pathname of the command to execute, given the list of
- permitted commands and the allowed path. */
-
- char *
- zsysdep_find_command (zcmd, pzcmds, pzpath, pferr)
- const char *zcmd;
- char **pzcmds;
- char **pzpath;
- boolean *pferr;
- {
- char **pz;
- struct stat s;
-
- *pferr = FALSE;
-
- for (pz = pzcmds; *pz != NULL; pz++)
- {
- char *zslash;
-
- if (strcmp (*pz, "ALL") == 0)
- break;
-
- zslash = strrchr (*pz, '/');
- if (zslash != NULL)
- ++zslash;
- else
- zslash = *pz;
- if (strcmp (zslash, zcmd) == 0
- || strcmp (*pz, zcmd) == 0)
- {
- /* If we already have an absolute path, we can get out
- immediately. */
- if (**pz == '/')
- {
- /* Quick error check. */
- if (stat (*pz, &s) != 0)
- {
- ulog (LOG_ERROR, "%s: %s", *pz, strerror (errno));
- *pferr = TRUE;
- return NULL;
- }
- return zbufcpy (*pz);
- }
- break;
- }
- }
-
- /* If we didn't find this command, get out. */
- if (*pz == NULL)
- return NULL;
-
- /* We didn't find an absolute pathname, so we must look through
- the path. */
- for (pz = pzpath; *pz != NULL; pz++)
- {
- char *zname;
-
- zname = zsysdep_in_dir (*pz, zcmd);
- if (stat (zname, &s) == 0)
- return zname;
- }
-
- return NULL;
- }
-
- /* Expand a local filename for uuxqt. This is special because uuxqt
- only wants to expand filenames that start with ~ (it does not want
- to prepend the current directory to other names) and if the ~ is
- double, it is turned into a single ~. This returns NULL to
- indicate that no change was required; it has no way to return
- error. */
-
- char *
- zsysdep_xqt_local_file (qsys, zfile)
- const struct uuconf_system *qsys;
- const char *zfile;
- {
- if (*zfile != '~')
- return NULL;
- if (zfile[1] == '~')
- {
- size_t clen;
- char *zret;
-
- clen = strlen (zfile);
- zret = zbufalc (clen);
- memcpy (zret, zfile + 1, clen);
- return zret;
- }
- return zsysdep_local_file (zfile, qsys->uuconf_zpubdir,
- (boolean *) NULL);
- }
-
- #if ! ALLOW_FILENAME_ARGUMENTS
-
- /* Check to see whether an argument specifies a file name; if it does,
- make sure that the file may legally be sent and/or received. For
- Unix, we do not permit any occurrence of "/../" in the name, nor
- may it start with "../". Otherwise, if it starts with "/" we check
- against the list of permitted files. */
-
- boolean
- fsysdep_xqt_check_file (qsys, zfile)
- const struct uuconf_system *qsys;
- const char *zfile;
- {
- size_t clen;
-
- /* Disallow exact "..", prefix "../", suffix "/..", internal "/../",
- and restricted absolute paths. */
- clen = strlen (zfile);
- if ((clen == sizeof ".." - 1
- && strcmp (zfile, "..") == 0)
- || strncmp (zfile, "../", sizeof "../" - 1) == 0
- || (clen >= sizeof "/.." - 1
- && strcmp (zfile + clen - (sizeof "/.." - 1), "/..") == 0)
- || strstr (zfile, "/../") != NULL
- || (*zfile == '/'
- && (! fin_directory_list (zfile, qsys->uuconf_pzremote_send,
- qsys->uuconf_zpubdir, TRUE, FALSE,
- (const char *) NULL)
- || ! fin_directory_list (zfile, qsys->uuconf_pzremote_receive,
- qsys->uuconf_zpubdir, TRUE, FALSE,
- (const char *) NULL))))
- {
- ulog (LOG_ERROR, "Not permitted to refer to file \"%s\"", zfile);
- return FALSE;
- }
-
- return TRUE;
- }
-
- #endif /* ! ALLOW_FILENAME_ARGUMENTS */
-
- /* Invoke the command specified by an execute file. */
-
- /*ARGSUSED*/
- boolean
- fsysdep_execute (qsys, zuser, pazargs, zfullcmd, zinput, zoutput,
- fshell, iseq, pzerror, pftemp)
- const struct uuconf_system *qsys;
- const char *zuser;
- const char **pazargs;
- const char *zfullcmd;
- const char *zinput;
- const char *zoutput;
- boolean fshell;
- int iseq;
- char **pzerror;
- boolean *pftemp;
- {
- int aidescs[3];
- boolean ferr;
- pid_t ipid;
- int ierr;
- char abxqtdir[sizeof XQTDIR + 4];
- const char *zxqtdir;
- int istat;
- char *zpath;
- #if ALLOW_SH_EXECUTION
- const char *azshargs[4];
- #endif
-
- *pzerror = NULL;
- *pftemp = FALSE;
-
- aidescs[0] = SPAWN_NULL;
- aidescs[1] = SPAWN_NULL;
- aidescs[2] = SPAWN_NULL;
-
- ferr = FALSE;
-
- if (zinput != NULL)
- {
- aidescs[0] = open ((char *) zinput, O_RDONLY | O_NOCTTY, 0);
- if (aidescs[0] < 0)
- {
- ulog (LOG_ERROR, "open (%s): %s", zinput, strerror (errno));
- ferr = TRUE;
- }
- else if (fcntl (aidescs[0], F_SETFD,
- fcntl (aidescs[0], F_GETFD, 0) | FD_CLOEXEC) < 0)
- {
- ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
- ferr = TRUE;
- }
- }
-
- if (! ferr && zoutput != NULL)
- {
- aidescs[1] = creat ((char *) zoutput, IPRIVATE_FILE_MODE);
- if (aidescs[1] < 0)
- {
- ulog (LOG_ERROR, "creat (%s): %s", zoutput, strerror (errno));
- *pftemp = TRUE;
- ferr = TRUE;
- }
- else if (fcntl (aidescs[1], F_SETFD,
- fcntl (aidescs[1], F_GETFD, 0) | FD_CLOEXEC) < 0)
- {
- ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
- ferr = TRUE;
- }
- }
-
- if (! ferr)
- {
- *pzerror = zstemp_file (qsys);
- aidescs[2] = creat (*pzerror, IPRIVATE_FILE_MODE);
- if (aidescs[2] < 0)
- {
- if (errno == ENOENT)
- {
- if (! fsysdep_make_dirs (*pzerror, FALSE))
- {
- *pftemp = TRUE;
- ferr = TRUE;
- }
- else
- aidescs[2] = creat (*pzerror, IPRIVATE_FILE_MODE);
- }
- if (! ferr && aidescs[2] < 0)
- {
- ulog (LOG_ERROR, "creat (%s): %s", *pzerror, strerror (errno));
- *pftemp = TRUE;
- ferr = TRUE;
- }
- }
- if (! ferr
- && fcntl (aidescs[2], F_SETFD,
- fcntl (aidescs[2], F_GETFD, 0) | FD_CLOEXEC) < 0)
- {
- ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
- ferr = TRUE;
- }
- }
-
- if (iseq == 0)
- zxqtdir = XQTDIR;
- else
- {
- sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
- zxqtdir = abxqtdir;
- }
-
- if (ferr)
- {
- if (aidescs[0] != SPAWN_NULL)
- (void) close (aidescs[0]);
- if (aidescs[1] != SPAWN_NULL)
- (void) close (aidescs[1]);
- if (aidescs[2] != SPAWN_NULL)
- (void) close (aidescs[2]);
- ubuffree (*pzerror);
- return FALSE;
- }
-
- #if ALLOW_SH_EXECUTION
- if (fshell)
- {
- azshargs[0] = "/bin/sh";
- azshargs[1] = "-c";
- azshargs[2] = zfullcmd;
- azshargs[3] = NULL;
- pazargs = azshargs;
- }
- #else
- fshell = FALSE;
- #endif
-
- if (qsys->uuconf_pzpath == NULL)
- zpath = NULL;
- else
- {
- size_t c;
- char **pz;
-
- c = 0;
- for (pz = qsys->uuconf_pzpath; *pz != NULL; pz++)
- c += strlen (*pz) + 1;
- zpath = zbufalc (c);
- *zpath = '\0';
- for (pz = qsys->uuconf_pzpath; *pz != NULL; pz++)
- {
- strcat (zpath, *pz);
- if (pz[1] != NULL)
- strcat (zpath, ":");
- }
- }
-
- /* Pass zchdir as zxqtdir, fnosigs as TRUE, fshell as TRUE if we
- aren't already using the shell. */
- ipid = ixsspawn (pazargs, aidescs, TRUE, FALSE, zxqtdir, TRUE,
- ! fshell, zpath, qsys->uuconf_zname, zuser);
-
- ierr = errno;
-
- ubuffree (zpath);
-
- if (aidescs[0] != SPAWN_NULL)
- (void) close (aidescs[0]);
- if (aidescs[1] != SPAWN_NULL)
- (void) close (aidescs[1]);
- if (aidescs[2] != SPAWN_NULL)
- (void) close (aidescs[2]);
-
- if (ipid < 0)
- {
- ulog (LOG_ERROR, "ixsspawn: %s", strerror (ierr));
- *pftemp = TRUE;
- return FALSE;
- }
-
- istat = ixswait ((unsigned long) ipid, "Execution");
-
- if (istat == EX_TEMPFAIL)
- *pftemp = TRUE;
-
- return istat == 0;
- }
-
- /* Lock a uuxqt process. */
-
- int
- ixsysdep_lock_uuxqt (zcmd, cmaxuuxqts)
- const char *zcmd;
- int cmaxuuxqts;
- {
- char ab[sizeof "LCK.XQT.9999"];
- int i;
-
- if (cmaxuuxqts <= 0 || cmaxuuxqts >= 10000)
- cmaxuuxqts = 9999;
- for (i = 0; i < cmaxuuxqts; i++)
- {
- sprintf (ab, "LCK.XQT.%d", i);
- if (fsdo_lock (ab, TRUE, (boolean *) NULL))
- break;
- }
- if (i >= cmaxuuxqts)
- return -1;
-
- if (zcmd != NULL)
- {
- char abcmd[sizeof "LXQ.123456789"];
-
- sprintf (abcmd, "LXQ.%.9s", zcmd);
- abcmd[strcspn (abcmd, " \t/")] = '\0';
- if (! fsdo_lock (abcmd, TRUE, (boolean *) NULL))
- {
- (void) fsdo_unlock (ab, TRUE);
- return -1;
- }
- }
-
- return i;
- }
-
- /* Unlock a uuxqt process. */
-
- boolean
- fsysdep_unlock_uuxqt (iseq, zcmd, cmaxuuxqts)
- int iseq;
- const char *zcmd;
- int cmaxuuxqts;
- {
- char ab[sizeof "LCK.XQT.9999"];
- boolean fret;
-
- fret = TRUE;
-
- sprintf (ab, "LCK.XQT.%d", iseq);
- if (! fsdo_unlock (ab, TRUE))
- fret = FALSE;
-
- if (zcmd != NULL)
- {
- char abcmd[sizeof "LXQ.123456789"];
-
- sprintf (abcmd, "LXQ.%.9s", zcmd);
- abcmd[strcspn (abcmd, " \t/")] = '\0';
- if (! fsdo_unlock (abcmd, TRUE))
- fret = FALSE;
- }
-
- return fret;
- }
-
- /* See whether a particular uuxqt command is locked (this depends on
- the implementation of fsdo_lock). */
-
- boolean
- fsysdep_uuxqt_locked (zcmd)
- const char *zcmd;
- {
- char ab[sizeof "LXQ.123456789"];
- struct stat s;
-
- sprintf (ab, "LXQ.%.9s", zcmd);
- return stat (ab, &s) == 0;
- }
-
- /* Lock a particular execute file. */
-
- boolean
- fsysdep_lock_uuxqt_file (zfile)
- const char *zfile;
- {
- char *zcopy, *z;
- boolean fret;
-
- zcopy = zbufcpy (zfile);
-
- z = strrchr (zcopy, '/');
- if (z == NULL)
- *zcopy = 'L';
- else
- *(z + 1) = 'L';
-
- fret = fsdo_lock (zcopy, TRUE, (boolean *) NULL);
- ubuffree (zcopy);
- return fret;
- }
-
- /* Unlock a particular execute file. */
-
- boolean
- fsysdep_unlock_uuxqt_file (zfile)
- const char *zfile;
- {
- char *zcopy, *z;
- boolean fret;
-
- zcopy = zbufcpy (zfile);
-
- z = strrchr (zcopy, '/');
- if (z == NULL)
- *zcopy = 'L';
- else
- *(z + 1) = 'L';
-
- fret = fsdo_unlock (zcopy, TRUE);
- ubuffree (zcopy);
- return fret;
- }
-
- /* Lock the execute directory. Since we use a different directory
- depending on which LCK.XQT.dddd file we got, there is actually no
- need to create a lock file. We do make sure that the directory
- exists, though. */
-
- boolean
- fsysdep_lock_uuxqt_dir (iseq)
- int iseq;
- {
- const char *zxqtdir;
- char abxqtdir[sizeof XQTDIR + 4];
-
- if (iseq == 0)
- zxqtdir = XQTDIR;
- else
- {
- sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
- zxqtdir = abxqtdir;
- }
-
- if (mkdir (zxqtdir, S_IRWXU) < 0
- && errno != EEXIST
- && errno != EISDIR)
- {
- ulog (LOG_ERROR, "mkdir (%s): %s", zxqtdir, strerror (errno));
- return FALSE;
- }
-
- return TRUE;
- }
-
- /* Unlock the execute directory and clear it out. The lock is
- actually the LCK.XQT.dddd file, so we don't unlock it, but we do
- remove all the files. */
-
- boolean
- fsysdep_unlock_uuxqt_dir (iseq)
- int iseq;
- {
- const char *zxqtdir;
- char abxqtdir[sizeof XQTDIR + 4];
- DIR *qdir;
-
- if (iseq == 0)
- zxqtdir = XQTDIR;
- else
- {
- sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
- zxqtdir = abxqtdir;
- }
-
- qdir = opendir ((char *) zxqtdir);
- if (qdir != NULL)
- {
- struct dirent *qentry;
-
- while ((qentry = readdir (qdir)) != NULL)
- {
- char *z;
-
- if (strcmp (qentry->d_name, ".") == 0
- || strcmp (qentry->d_name, "..") == 0)
- continue;
- z = zsysdep_in_dir (zxqtdir, qentry->d_name);
- if (remove (z) < 0)
- {
- int ierr;
-
- ierr = errno;
- if (! fsysdep_directory (z))
- ulog (LOG_ERROR, "remove (%s): %s", z,
- strerror (ierr));
- else
- (void) fsysdep_rmdir (z);
- }
- ubuffree (z);
- }
-
- closedir (qdir);
- }
-
- return TRUE;
- }
-
- /* Move files into the execution directory. */
-
- boolean
- fsysdep_move_uuxqt_files (cfiles, pzfrom, pzto, fto, iseq, pzinput)
- int cfiles;
- const char *const *pzfrom;
- const char *const *pzto;
- boolean fto;
- int iseq;
- char **pzinput;
- {
- char *zinput;
- const char *zxqtdir;
- char abxqtdir[sizeof XQTDIR + 4];
- int i;
-
- if (pzinput == NULL)
- zinput = NULL;
- else
- zinput = *pzinput;
-
- if (iseq == 0)
- zxqtdir = XQTDIR;
- else
- {
- sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
- zxqtdir = abxqtdir;
- }
-
- for (i = 0; i < cfiles; i++)
- {
- const char *zfrom, *zto;
- char *zfree;
-
- if (pzto[i] == NULL)
- continue;
-
- zfree = zsysdep_in_dir (zxqtdir, pzto[i]);
-
- zfrom = pzfrom[i];
- zto = zfree;
-
- if (zinput != NULL && strcmp (zinput, zfrom) == 0)
- {
- *pzinput = zbufcpy (zto);
- zinput = NULL;
- }
-
- if (! fto)
- {
- const char *ztemp;
-
- ztemp = zfrom;
- zfrom = zto;
- zto = ztemp;
- (void) chmod (zfrom, IPRIVATE_FILE_MODE);
- }
-
- if (rename (zfrom, zto) < 0)
- {
- #if HAVE_RENAME
- /* On some systems the system call rename seems to fail for
- arbitrary reasons. To get around this, we always try to
- copy the file by hand if the rename failed. */
- errno = EXDEV;
- #endif
-
- if (errno != EXDEV)
- {
- ulog (LOG_ERROR, "rename (%s, %s): %s", zfrom, zto,
- strerror (errno));
- ubuffree (zfree);
- break;
- }
-
- if (! fcopy_file (zfrom, zto, FALSE, FALSE, FALSE))
- {
- ubuffree (zfree);
- break;
- }
- if (remove (zfrom) < 0)
- ulog (LOG_ERROR, "remove (%s): %s", zfrom,
- strerror (errno));
- }
-
- if (fto)
- (void) chmod (zto, IPUBLIC_FILE_MODE);
-
- ubuffree (zfree);
- }
-
- if (i < cfiles)
- {
- if (fto)
- (void) fsysdep_move_uuxqt_files (i, pzfrom, pzto, FALSE, iseq,
- (char **) NULL);
- return FALSE;
- }
-
- return TRUE;
- }
-