|
|
1.1 root 1: /* xqtsub.c
2: System dependent functions used only by uuxqt.
3:
4: Copyright (C) 1991, 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA.
21:
22: The author of the program may be contacted at [email protected] or
23: c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
24: */
25:
26: #include "uucp.h"
27:
28: #if USE_RCS_ID
29: const char xqtsub_rcsid[] = "$Id: xqtsub.c,v 1.1 93/07/30 08:03:41 bin Exp Locker: bin $";
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:
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:
93: *pferr = FALSE;
94:
95: for (pz = pzcmds; *pz != NULL; pz++)
96: {
97: char *zslash;
98:
99: if (strcmp (*pz, "ALL") == 0)
100: break;
101:
102: zslash = strrchr (*pz, '/');
103: if (zslash != NULL)
104: ++zslash;
105: else
106: zslash = *pz;
107: if (strcmp (zslash, zcmd) == 0
108: || strcmp (*pz, zcmd) == 0)
109: {
110: /* If we already have an absolute path, we can get out
111: immediately. */
112: if (**pz == '/')
113: return zbufcpy (*pz);
114: break;
115: }
116: }
117:
118: /* If we didn't find this command, get out. */
119: if (*pz == NULL)
120: return NULL;
121:
122: /* We didn't find an absolute pathname, so we must look through
123: the path. */
124: for (pz = pzpath; *pz != NULL; pz++)
125: {
126: char *zname;
127: struct stat s;
128:
129: zname = zsysdep_in_dir (*pz, zcmd);
130: if (stat (zname, &s) == 0)
131: return zname;
132: }
133:
134: *pferr = FALSE;
135: return NULL;
136: }
137:
138: /* Expand a local filename for uuxqt. This is special because uuxqt
139: only wants to expand filenames that start with ~ (it does not want
140: to prepend the current directory to other names) and if the ~ is
141: double, it is turned into a single ~. This returns NULL to
142: indicate that no change was required; it has no way to return
143: error. */
144:
145: char *
146: zsysdep_xqt_local_file (qsys, zfile)
147: const struct uuconf_system *qsys;
148: const char *zfile;
149: {
150: if (*zfile != '~')
151: return NULL;
152: if (zfile[1] == '~')
153: {
154: size_t clen;
155: char *zret;
156:
157: clen = strlen (zfile);
158: zret = zbufalc (clen);
159: memcpy (zret, zfile + 1, clen);
160: return zret;
161: }
162: return zsysdep_local_file (zfile, qsys->uuconf_zpubdir);
163: }
164:
165: #if ! ALLOW_FILENAME_ARGUMENTS
166:
167: /* Check to see whether an argument specifies a file name; if it does,
168: make sure that the file may legally be sent and/or received. For
169: Unix, we do not permit any occurrence of "/../" in the name, nor
170: may it start with "../". Otherwise, if it starts with "/" we check
171: against the list of permitted files. */
172:
173: boolean
174: fsysdep_xqt_check_file (qsys, zfile)
175: const struct uuconf_system *qsys;
176: const char *zfile;
177: {
178: size_t clen;
179:
180: clen = strlen (zfile);
181: if ((clen == sizeof "../" - 1
182: && strcmp (zfile, "../") == 0)
183: || (clen >= sizeof "/.." - 1
184: && strcmp (zfile + clen - (sizeof "/.." - 1), "/..") == 0)
185: || strstr (zfile, "/../") != NULL
186: || (*zfile == '/'
187: && (! fin_directory_list (zfile, qsys->uuconf_pzremote_send,
188: qsys->uuconf_zpubdir, TRUE, FALSE,
189: (const char *) NULL)
190: || ! fin_directory_list (zfile, qsys->uuconf_pzremote_receive,
191: qsys->uuconf_zpubdir, TRUE, FALSE,
192: (const char *) NULL))))
193: {
194: ulog (LOG_ERROR, "Not permitted to refer to file \"%s\"", zfile);
195: return FALSE;
196: }
197:
198: return TRUE;
199: }
200:
201: #endif /* ! ALLOW_FILENAME_ARGUMENTS */
202:
203: /* Invoke the command specified by an execute file. */
204:
205: /*ARGSUSED*/
206: boolean
207: fsysdep_execute (qsys, zuser, pazargs, zfullcmd, zinput, zoutput,
208: fshell, iseq, pzerror, pftemp)
209: const struct uuconf_system *qsys;
210: const char *zuser;
211: const char **pazargs;
212: const char *zfullcmd;
213: const char *zinput;
214: const char *zoutput;
215: boolean fshell;
216: int iseq;
217: char **pzerror;
218: boolean *pftemp;
219: {
220: int aidescs[3];
221: boolean ferr;
222: pid_t ipid;
223: int ierr;
224: char abxqtdir[sizeof XQTDIR + 4];
225: const char *zxqtdir;
226: int istat;
227: char *zpath;
228: #if ALLOW_SH_EXECUTION
229: const char *azshargs[4];
230: #endif
231:
232: *pzerror = NULL;
233: *pftemp = FALSE;
234:
235: aidescs[0] = SPAWN_NULL;
236: aidescs[1] = SPAWN_NULL;
237: aidescs[2] = SPAWN_NULL;
238:
239: ferr = FALSE;
240:
241: if (zinput != NULL)
242: {
243: aidescs[0] = open ((char *) zinput, O_RDONLY | O_NOCTTY, 0);
244: if (aidescs[0] < 0)
245: {
246: ulog (LOG_ERROR, "open (%s): %s", zinput, strerror (errno));
247: ferr = TRUE;
248: }
249: else if (fcntl (aidescs[0], F_SETFD,
250: fcntl (aidescs[0], F_GETFD, 0) | FD_CLOEXEC) < 0)
251: {
252: ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
253: ferr = TRUE;
254: }
255: }
256:
257: if (! ferr && zoutput != NULL)
258: {
259: aidescs[1] = creat ((char *) zoutput, IPRIVATE_FILE_MODE);
260: if (aidescs[1] < 0)
261: {
262: ulog (LOG_ERROR, "creat (%s): %s", zoutput, strerror (errno));
263: *pftemp = TRUE;
264: ferr = TRUE;
265: }
266: else if (fcntl (aidescs[1], F_SETFD,
267: fcntl (aidescs[1], F_GETFD, 0) | FD_CLOEXEC) < 0)
268: {
269: ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
270: ferr = TRUE;
271: }
272: }
273:
274: if (! ferr)
275: {
276: *pzerror = zstemp_file (qsys);
277: aidescs[2] = creat (*pzerror, IPRIVATE_FILE_MODE);
278: if (aidescs[2] < 0)
279: {
280: if (errno == ENOENT)
281: {
282: if (! fsysdep_make_dirs (*pzerror, FALSE))
283: {
284: *pftemp = TRUE;
285: ferr = TRUE;
286: }
287: else
288: aidescs[2] = creat (*pzerror, IPRIVATE_FILE_MODE);
289: }
290: if (! ferr && aidescs[2] < 0)
291: {
292: ulog (LOG_ERROR, "creat (%s): %s", *pzerror, strerror (errno));
293: *pftemp = TRUE;
294: ferr = TRUE;
295: }
296: }
297: if (! ferr
298: && fcntl (aidescs[2], F_SETFD,
299: fcntl (aidescs[2], F_GETFD, 0) | FD_CLOEXEC) < 0)
300: {
301: ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
302: ferr = TRUE;
303: }
304: }
305:
306: if (iseq == 0)
307: zxqtdir = XQTDIR;
308: else
309: {
310: sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
311: zxqtdir = abxqtdir;
312: }
313:
314: if (ferr)
315: {
316: if (aidescs[0] != SPAWN_NULL)
317: (void) close (aidescs[0]);
318: if (aidescs[1] != SPAWN_NULL)
319: (void) close (aidescs[1]);
320: if (aidescs[2] != SPAWN_NULL)
321: (void) close (aidescs[2]);
322: ubuffree (*pzerror);
323: return FALSE;
324: }
325:
326: #if ALLOW_SH_EXECUTION
327: if (fshell)
328: {
329: azshargs[0] = "/bin/sh";
330: azshargs[1] = "-c";
331: azshargs[2] = zfullcmd;
332: azshargs[3] = NULL;
333: pazargs = azshargs;
334: }
335: #else
336: fshell = FALSE;
337: #endif
338:
339: if (qsys->uuconf_pzpath == NULL)
340: zpath = NULL;
341: else
342: {
343: size_t c;
344: char **pz;
345:
346: c = 0;
347: for (pz = qsys->uuconf_pzpath; *pz != NULL; pz++)
348: c += strlen (*pz) + 1;
349: zpath = zbufalc (c);
350: *zpath = '\0';
351: for (pz = qsys->uuconf_pzpath; *pz != NULL; pz++)
352: {
353: strcat (zpath, *pz);
354: if (pz[1] != NULL)
355: strcat (zpath, ":");
356: }
357: }
358:
359: /* Pass zchdir as zxqtdir, fnosigs as TRUE, fshell as TRUE if we
360: aren't already using the shell. */
361: ipid = ixsspawn (pazargs, aidescs, FALSE, FALSE, zxqtdir, TRUE,
362: ! fshell, zpath, qsys->uuconf_zname, zuser);
363:
364: ierr = errno;
365:
366: ubuffree (zpath);
367:
368: if (aidescs[0] != SPAWN_NULL)
369: (void) close (aidescs[0]);
370: if (aidescs[1] != SPAWN_NULL)
371: (void) close (aidescs[1]);
372: if (aidescs[2] != SPAWN_NULL)
373: (void) close (aidescs[2]);
374:
375: if (ipid < 0)
376: {
377: ulog (LOG_ERROR, "ixsspawn: %s", strerror (ierr));
378: *pftemp = TRUE;
379: return FALSE;
380: }
381:
382: istat = ixswait ((unsigned long) ipid, "Execution");
383:
384: if (istat == EX_TEMPFAIL)
385: *pftemp = TRUE;
386:
387: return istat == 0;
388: }
389:
390: /* Lock a uuxqt process. */
391:
392: int
393: ixsysdep_lock_uuxqt (zcmd, cmaxuuxqts)
394: const char *zcmd;
395: int cmaxuuxqts;
396: {
397: char ab[sizeof "LCK.XQT.9999"];
398: int i;
399:
400: if (cmaxuuxqts <= 0 || cmaxuuxqts >= 10000)
401: cmaxuuxqts = 9999;
402: for (i = 0; i < cmaxuuxqts; i++)
403: {
404: sprintf (ab, "LCK.XQT.%d", i);
405: if (fsdo_lock (ab, TRUE, (boolean *) NULL))
406: break;
407: }
408: if (i >= cmaxuuxqts)
409: return -1;
410:
411: if (zcmd != NULL)
412: {
413: char abcmd[sizeof "LXQ.123456789"];
414:
415: sprintf (abcmd, "LXQ.%.9s", zcmd);
416: abcmd[strcspn (abcmd, " \t/")] = '\0';
417: if (! fsdo_lock (abcmd, TRUE, (boolean *) NULL))
418: {
419: (void) fsdo_unlock (ab, TRUE);
420: return -1;
421: }
422: }
423:
424: return i;
425: }
426:
427: /* Unlock a uuxqt process. */
428:
429: boolean
430: fsysdep_unlock_uuxqt (iseq, zcmd, cmaxuuxqts)
431: int iseq;
432: const char *zcmd;
433: int cmaxuuxqts;
434: {
435: char ab[sizeof "LCK.XQT.9999"];
436: boolean fret;
437:
438: fret = TRUE;
439:
440: sprintf (ab, "LCK.XQT.%d", iseq);
441: if (! fsdo_unlock (ab, TRUE))
442: fret = FALSE;
443:
444: if (zcmd != NULL)
445: {
446: char abcmd[sizeof "LXQ.123456789"];
447:
448: sprintf (abcmd, "LXQ.%.9s", zcmd);
449: abcmd[strcspn (abcmd, " \t/")] = '\0';
450: if (! fsdo_unlock (abcmd, TRUE))
451: fret = FALSE;
452: }
453:
454: return fret;
455: }
456:
457: /* See whether a particular uuxqt command is locked (this depends on
458: the implementation of fsdo_lock). */
459:
460: boolean
461: fsysdep_uuxqt_locked (zcmd)
462: const char *zcmd;
463: {
464: char ab[sizeof "LXQ.123456789"];
465: struct stat s;
466:
467: sprintf (ab, "LXQ.%.9s", zcmd);
468: return stat (ab, &s) == 0;
469: }
470:
471: /* Lock a particular execute file. */
472:
473: boolean
474: fsysdep_lock_uuxqt_file (zfile)
475: const char *zfile;
476: {
477: char *zcopy, *z;
478: boolean fret;
479:
480: zcopy = zbufcpy (zfile);
481:
482: z = strrchr (zcopy, '/');
483: if (z == NULL)
484: *zcopy = 'L';
485: else
486: *(z + 1) = 'L';
487:
488: fret = fsdo_lock (zcopy, TRUE, (boolean *) NULL);
489: ubuffree (zcopy);
490: return fret;
491: }
492:
493: /* Unlock a particular execute file. */
494:
495: boolean
496: fsysdep_unlock_uuxqt_file (zfile)
497: const char *zfile;
498: {
499: char *zcopy, *z;
500: boolean fret;
501:
502: zcopy = zbufcpy (zfile);
503:
504: z = strrchr (zcopy, '/');
505: if (z == NULL)
506: *zcopy = 'L';
507: else
508: *(z + 1) = 'L';
509:
510: fret = fsdo_unlock (zcopy, TRUE);
511: ubuffree (zcopy);
512: return fret;
513: }
514:
515: /* Lock the execute directory. Since we use a different directory
516: depending on which LCK.XQT.dddd file we got, there is actually no
517: need to create a lock file. We do make sure that the directory
518: exists, though. */
519:
520: boolean
521: fsysdep_lock_uuxqt_dir (iseq)
522: int iseq;
523: {
524: const char *zxqtdir;
525: char abxqtdir[sizeof XQTDIR + 4];
526:
527: if (iseq == 0)
528: zxqtdir = XQTDIR;
529: else
530: {
531: sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
532: zxqtdir = abxqtdir;
533: }
534:
535: if (mkdir (zxqtdir, S_IRWXU) < 0
536: && errno != EEXIST)
537: {
538: ulog (LOG_ERROR, "mkdir (%s): %s", zxqtdir, strerror (errno));
539: return FALSE;
540: }
541:
542: return TRUE;
543: }
544:
545: /* Unlock the execute directory and clear it out. The lock is
546: actually the LCK.XQT.dddd file, so we don't unlock it, but we do
547: remove all the files. */
548:
549: boolean
550: fsysdep_unlock_uuxqt_dir (iseq)
551: int iseq;
552: {
553: const char *zxqtdir;
554: char abxqtdir[sizeof XQTDIR + 4];
555: DIR *qdir;
556:
557: if (iseq == 0)
558: zxqtdir = XQTDIR;
559: else
560: {
561: sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
562: zxqtdir = abxqtdir;
563: }
564:
565: qdir = opendir ((char *) zxqtdir);
566: if (qdir != NULL)
567: {
568: struct dirent *qentry;
569:
570: while ((qentry = readdir (qdir)) != NULL)
571: {
572: char *z;
573:
574: if (strcmp (qentry->d_name, ".") == 0
575: || strcmp (qentry->d_name, "..") == 0)
576: continue;
577: z = zsysdep_in_dir (zxqtdir, qentry->d_name);
578: if (remove (z) < 0)
579: {
580: int ierr;
581:
582: ierr = errno;
583: if (! fsysdep_directory (z))
584: ulog (LOG_ERROR, "remove (%s): %s", z,
585: strerror (ierr));
586: else
587: (void) fsysdep_rmdir (z);
588: }
589: ubuffree (z);
590: }
591:
592: closedir (qdir);
593: }
594:
595: return TRUE;
596: }
597:
598: /* Move files into the execution directory. */
599:
600: boolean
601: fsysdep_move_uuxqt_files (cfiles, pzfrom, pzto, fto, iseq, pzinput)
602: int cfiles;
603: const char *const *pzfrom;
604: const char *const *pzto;
605: boolean fto;
606: int iseq;
607: char **pzinput;
608: {
609: char *zinput;
610: const char *zxqtdir;
611: char abxqtdir[sizeof XQTDIR + 4];
612: int i;
613:
614: if (pzinput == NULL)
615: zinput = NULL;
616: else
617: zinput = *pzinput;
618:
619: if (iseq == 0)
620: zxqtdir = XQTDIR;
621: else
622: {
623: sprintf (abxqtdir, "%s%04d", XQTDIR, iseq);
624: zxqtdir = abxqtdir;
625: }
626:
627: for (i = 0; i < cfiles; i++)
628: {
629: const char *zfrom, *zto;
630: char *zfree;
631:
632: if (pzto[i] == NULL)
633: continue;
634:
635: zfree = zsysdep_in_dir (zxqtdir, pzto[i]);
636:
637: zfrom = pzfrom[i];
638: zto = zfree;
639:
640: if (zinput != NULL && strcmp (zinput, zfrom) == 0)
641: {
642: *pzinput = zbufcpy (zto);
643: zinput = NULL;
644: }
645:
646: if (! fto)
647: {
648: const char *ztemp;
649:
650: ztemp = zfrom;
651: zfrom = zto;
652: zto = ztemp;
653: (void) chmod (zfrom, IPRIVATE_FILE_MODE);
654: }
655:
656: if (rename (zfrom, zto) < 0)
657: {
658: #if HAVE_RENAME
659: /* On some systems the system call rename seems to fail for
660: arbitrary reasons. To get around this, we always try to
661: copy the file by hand if the rename failed. */
662: errno = EXDEV;
663: #endif
664:
665: if (errno != EXDEV)
666: {
667: ulog (LOG_ERROR, "rename (%s, %s): %s", zfrom, zto,
668: strerror (errno));
669: ubuffree (zfree);
670: break;
671: }
672:
673: if (! fcopy_file (zfrom, zto, FALSE, FALSE))
674: {
675: ubuffree (zfree);
676: break;
677: }
678: if (remove (zfrom) < 0)
679: ulog (LOG_ERROR, "remove (%s): %s", zfrom,
680: strerror (errno));
681: }
682:
683: if (fto)
684: (void) chmod (zto, IPUBLIC_FILE_MODE);
685:
686: ubuffree (zfree);
687: }
688:
689: if (i < cfiles)
690: {
691: if (fto)
692: (void) fsysdep_move_uuxqt_files (i, pzfrom, pzto, FALSE, iseq,
693: (char **) NULL);
694: return FALSE;
695: }
696:
697: return TRUE;
698: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.