2 System dependent functions used only by uuxqt.
4 Copyright (C) 1991, 1992, 1993, 1995 Ian Lance Taylor
6 This file is part of the Taylor UUCP package.
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.
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.
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.
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.
29 const char xqtsub_rcsid[] = "$FreeBSD$";
65 #else /* ! HAVE_DIRENT_H */
68 #endif /* ! HAVE_DIRENT_H */
69 #endif /* HAVE_OPENDIR */
71 /* Get a value for EX_TEMPFAIL. */
78 #define EX_TEMPFAIL 75
81 /* Get the full pathname of the command to execute, given the list of
82 permitted commands and the allowed path. */
85 zsysdep_find_command (zcmd, pzcmds, pzpath, pferr)
96 for (pz = pzcmds; *pz != NULL; pz++)
100 if (strcmp (*pz, "ALL") == 0)
103 zslash = strrchr (*pz, '/');
108 if (strcmp (zslash, zcmd) == 0
109 || strcmp (*pz, zcmd) == 0)
111 /* If we already have an absolute path, we can get out
115 /* Quick error check. */
116 if (stat (*pz, &s) != 0)
118 ulog (LOG_ERROR, "%s: %s", *pz, strerror (errno));
122 return zbufcpy (*pz);
128 /* If we didn't find this command, get out. */
132 /* We didn't find an absolute pathname, so we must look through
134 for (pz = pzpath; *pz != NULL; pz++)
138 zname = zsysdep_in_dir (*pz, zcmd);
139 if (stat (zname, &s) == 0)
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
154 zsysdep_xqt_local_file (qsys, zfile)
155 const struct uuconf_system *qsys;
165 clen = strlen (zfile);
166 zret = zbufalc (clen);
167 memcpy (zret, zfile + 1, clen);
170 return zsysdep_local_file (zfile, qsys->uuconf_zpubdir,
174 #if ! ALLOW_FILENAME_ARGUMENTS
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. */
183 fsysdep_xqt_check_file (qsys, zfile)
184 const struct uuconf_system *qsys;
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
199 && (! fin_directory_list (zfile, qsys->uuconf_pzremote_send,
200 qsys->uuconf_zpubdir, TRUE, FALSE,
202 || ! fin_directory_list (zfile, qsys->uuconf_pzremote_receive,
203 qsys->uuconf_zpubdir, TRUE, FALSE,
204 (const char *) NULL))))
206 ulog (LOG_ERROR, "Not permitted to refer to file \"%s\"", zfile);
213 #endif /* ! ALLOW_FILENAME_ARGUMENTS */
215 /* Invoke the command specified by an execute file. */
219 fsysdep_execute (qsys, zuser, pazargs, zfullcmd, zinput, zoutput,
220 fshell, iseq, pzerror, pftemp)
221 const struct uuconf_system *qsys;
223 const char **pazargs;
224 const char *zfullcmd;
236 char abxqtdir[sizeof XQTDIR + 4];
240 #if ALLOW_SH_EXECUTION
241 const char *azshargs[4];
247 aidescs[0] = SPAWN_NULL;
248 aidescs[1] = SPAWN_NULL;
249 aidescs[2] = SPAWN_NULL;
255 aidescs[0] = open ((char *) zinput, O_RDONLY | O_NOCTTY, 0);
258 ulog (LOG_ERROR, "open (%s): %s", zinput, strerror (errno));
261 else if (fcntl (aidescs[0], F_SETFD,
262 fcntl (aidescs[0], F_GETFD, 0) | FD_CLOEXEC) < 0)
264 ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
269 if (! ferr && zoutput != NULL)
271 aidescs[1] = creat ((char *) zoutput, IPRIVATE_FILE_MODE);
274 ulog (LOG_ERROR, "creat (%s): %s", zoutput, strerror (errno));
278 else if (fcntl (aidescs[1], F_SETFD,
279 fcntl (aidescs[1], F_GETFD, 0) | FD_CLOEXEC) < 0)
281 ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
288 *pzerror = zstemp_file (qsys);
289 aidescs[2] = creat (*pzerror, IPRIVATE_FILE_MODE);
294 if (! fsysdep_make_dirs (*pzerror, FALSE))
300 aidescs[2] = creat (*pzerror, IPRIVATE_FILE_MODE);
302 if (! ferr && aidescs[2] < 0)
304 ulog (LOG_ERROR, "creat (%s): %s", *pzerror, strerror (errno));
310 && fcntl (aidescs[2], F_SETFD,
311 fcntl (aidescs[2], F_GETFD, 0) | FD_CLOEXEC) < 0)
313 ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
322 sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
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]);
338 #if ALLOW_SH_EXECUTION
341 azshargs[0] = "/bin/sh";
343 azshargs[2] = zfullcmd;
351 if (qsys->uuconf_pzpath == NULL)
359 for (pz = qsys->uuconf_pzpath; *pz != NULL; pz++)
360 c += strlen (*pz) + 1;
363 for (pz = qsys->uuconf_pzpath; *pz != NULL; pz++)
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);
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]);
389 ulog (LOG_ERROR, "ixsspawn: %s", strerror (ierr));
394 istat = ixswait ((unsigned long) ipid, "Execution");
396 if (istat == EX_TEMPFAIL)
402 /* Lock a uuxqt process. */
405 ixsysdep_lock_uuxqt (zcmd, cmaxuuxqts)
409 char ab[sizeof "LCK.XQT.9999"];
412 if (cmaxuuxqts <= 0 || cmaxuuxqts >= 10000)
414 for (i = 0; i < cmaxuuxqts; i++)
416 sprintf (ab, "LCK.XQT.%d", i);
417 if (fsdo_lock (ab, TRUE, (boolean *) NULL))
425 char abcmd[sizeof "LXQ.123456789"];
427 sprintf (abcmd, "LXQ.%.9s", zcmd);
428 abcmd[strcspn (abcmd, " \t/")] = '\0';
429 if (! fsdo_lock (abcmd, TRUE, (boolean *) NULL))
431 (void) fsdo_unlock (ab, TRUE);
439 /* Unlock a uuxqt process. */
442 fsysdep_unlock_uuxqt (iseq, zcmd, cmaxuuxqts)
447 char ab[sizeof "LCK.XQT.9999"];
452 sprintf (ab, "LCK.XQT.%d", iseq);
453 if (! fsdo_unlock (ab, TRUE))
458 char abcmd[sizeof "LXQ.123456789"];
460 sprintf (abcmd, "LXQ.%.9s", zcmd);
461 abcmd[strcspn (abcmd, " \t/")] = '\0';
462 if (! fsdo_unlock (abcmd, TRUE))
469 /* See whether a particular uuxqt command is locked (this depends on
470 the implementation of fsdo_lock). */
473 fsysdep_uuxqt_locked (zcmd)
476 char ab[sizeof "LXQ.123456789"];
479 sprintf (ab, "LXQ.%.9s", zcmd);
480 return stat (ab, &s) == 0;
483 /* Lock a particular execute file. */
486 fsysdep_lock_uuxqt_file (zfile)
492 zcopy = zbufcpy (zfile);
494 z = strrchr (zcopy, '/');
500 fret = fsdo_lock (zcopy, TRUE, (boolean *) NULL);
505 /* Unlock a particular execute file. */
508 fsysdep_unlock_uuxqt_file (zfile)
514 zcopy = zbufcpy (zfile);
516 z = strrchr (zcopy, '/');
522 fret = fsdo_unlock (zcopy, TRUE);
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
533 fsysdep_lock_uuxqt_dir (iseq)
537 char abxqtdir[sizeof XQTDIR + 4];
543 sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
547 if (mkdir (zxqtdir, S_IRWXU) < 0
551 ulog (LOG_ERROR, "mkdir (%s): %s", zxqtdir, strerror (errno));
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. */
563 fsysdep_unlock_uuxqt_dir (iseq)
567 char abxqtdir[sizeof XQTDIR + 4];
574 sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
578 qdir = opendir ((char *) zxqtdir);
581 struct dirent *qentry;
583 while ((qentry = readdir (qdir)) != NULL)
587 if (strcmp (qentry->d_name, ".") == 0
588 || strcmp (qentry->d_name, "..") == 0)
590 z = zsysdep_in_dir (zxqtdir, qentry->d_name);
596 if (! fsysdep_directory (z))
597 ulog (LOG_ERROR, "remove (%s): %s", z,
600 (void) fsysdep_rmdir (z);
611 /* Move files into the execution directory. */
614 fsysdep_move_uuxqt_files (cfiles, pzfrom, pzto, fto, iseq, pzinput)
616 const char *const *pzfrom;
617 const char *const *pzto;
624 char abxqtdir[sizeof XQTDIR + 4];
636 sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
640 for (i = 0; i < cfiles; i++)
642 const char *zfrom, *zto;
648 zfree = zsysdep_in_dir (zxqtdir, pzto[i]);
653 if (zinput != NULL && strcmp (zinput, zfrom) == 0)
655 *pzinput = zbufcpy (zto);
666 (void) chmod (zfrom, IPRIVATE_FILE_MODE);
669 if (rename (zfrom, zto) < 0)
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. */
680 ulog (LOG_ERROR, "rename (%s, %s): %s", zfrom, zto,
686 if (! fcopy_file (zfrom, zto, FALSE, FALSE, FALSE))
691 if (remove (zfrom) < 0)
692 ulog (LOG_ERROR, "remove (%s): %s", zfrom,
697 (void) chmod (zto, IPUBLIC_FILE_MODE);
705 (void) fsysdep_move_uuxqt_files (i, pzfrom, pzto, FALSE, iseq,