4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
30 #pragma ident "%Z%%M% %I% %E% SMI"
36 * execute commands set up by a uux command,
37 * usually from a remote machine - set by uucp.
41 #define LOGNAME "LOGNAME=uucp"
43 #define LOGNAME "USER=uucp"
50 #define USAGEPREFIX "Usage:"
51 #define USAGE "[-x DEBUG] [-s SYSTEM]"
53 char _Xfile
[MAXFULLNAME
];
54 char _Cmd
[2 * BUFSIZ
]; /* build up command buffer */
55 int _CargType
; /* argument type of next C argument */
57 static void retosndr(), uucpst();
59 static int doFileChk();
60 void cleanup(), xprocess();
63 main(argc
, argv
, envp
)
69 struct limits limitval
;
71 char dirname
[MAXFULLNAME
], lockname
[MAXFULLNAME
];
74 /* Set locale environment variables local definitions */
75 (void) setlocale(LC_ALL
, "");
76 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
77 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
79 (void) textdomain(TEXT_DOMAIN
);
81 (void) signal(SIGILL
, onintr
);
82 (void) signal(SIGTRAP
, onintr
);
83 (void) signal(SIGIOT
, onintr
);
84 (void) signal(SIGEMT
, onintr
);
85 (void) signal(SIGFPE
, onintr
);
86 (void) signal(SIGBUS
, onintr
);
87 (void) signal(SIGSEGV
, onintr
);
88 (void) signal(SIGSYS
, onintr
);
89 (void) signal(SIGPIPE
, onintr
);
90 (void) signal(SIGTERM
, SIG_IGN
);
93 (void) strcpy(Logfile
, LOGUUXQT
);
96 * get local system name
99 Nstat
.t_qtime
= time((time_t *)0);
100 (void) strcpy(Progname
, "uuxqt");
105 dirname
[0] = dirname
[MAXFULLNAME
-1] = NULLCHAR
;
106 while ((ret
= getopt(argc
, argv
, "s:x:")) != EOF
) {
113 Debug
= atoi(optarg
);
120 * fake out uuxqt and use the argument as if
121 * it were the spool directory for the purpose
122 * of determining what subdirectories to search
123 * EX: mkdir /tmp/foo; touch /tmp/foo/[baz, gorp]
125 * this will cause uuxqt to only run on the sub
126 * baz and gorp in the Spool directory. Trust me.
128 (void) strlcpy(dirname
, optarg
,
129 (MAXFULLNAME
- sizeof (SEQLOCK
)));
133 (void) fprintf(stderr
, "%s %s %s\n",
134 gettext(USAGEPREFIX
), Progname
, gettext(USAGE
));
138 if (argc
!= optind
) {
139 (void) fprintf(stderr
, "%s %s %s\n",
140 gettext(USAGEPREFIX
), Progname
, gettext(USAGE
));
144 DEBUG(4, "\n\n** START **\n%s", "");
147 if (scanlimit("uuxqt", &limitval
) == FAIL
) {
148 DEBUG(1, "No limits for uuxqt in %s\n", LIMITS
);
150 maxnumb
= limitval
.totalmax
;
152 DEBUG(4, "Non-positive limit for uuxqt in %s\n", LIMITS
);
153 DEBUG(1, "No limits for uuxqt\n%s", "");
155 DEBUG(4, "Uuxqt limit %d -- ", maxnumb
);
156 ret
= cuantos(X_LOCKPRE
, X_LOCKDIR
);
157 DEBUG(4, "found %d -- ", ret
);
158 if (maxnumb
>= 0 && ret
>= maxnumb
) {
159 DEBUG(4, "exiting.%s\n", "");
162 DEBUG(4, "continuing.%s\n", "");
167 * determine user who started uuxqt (in principle)
169 strcpy(User
, "uucp"); /* in case all else fails (can't happen) */
171 Euid
= geteuid(); /* this should be UUCPUID */
175 (void) setuid(UUCPUID
);
178 DEBUG(4, "User - %s\n", User
);
179 guinfo(Uid
, Loginuser
);
183 DEBUG(4, "process\n%s", "");
185 fp1
= opendir(Spool
);
186 ASSERT(fp1
!= NULL
, Ct_OPEN
, Spool
, errno
);
187 if (dirname
[0] != NULLCHAR
) {
188 /* look for special characters in remote name */
189 if (strpbrk(dirname
, Shchar
) != NULL
) {
190 /* ignore naughty name */
191 DEBUG(4, "Bad remote name '%s'", dirname
);
192 errent("BAD REMOTE NAME", dirname
, 0, __FILE__
, __LINE__
);
198 (void) snprintf(lockname
, sizeof (lockname
), "%s.%s",
200 if (mklock(lockname
) == SUCCESS
) {
205 while (gdirf(fp1
, dirname
, Spool
) == TRUE
) {
206 if (strpbrk(dirname
, Shchar
) != NULL
) {
207 /* skip naughty names */
208 errent("BAD REMOTE NAME", dirname
, 0,
212 (void) snprintf(lockname
, sizeof (lockname
), "%s.%s",
214 if (mklock(lockname
) != SUCCESS
)
236 * catch signal then cleanup and exit
243 (void) signal(inter
, SIG_IGN
);
244 (void) sprintf(str
, "QSIGNAL %d", inter
);
245 logent(str
, "QCAUGHT");
246 acEndexe(cpucycle(), PARTIAL
); /* stop collecting accounting log */
250 #define XCACHESIZE (4096 / (MAXBASENAME + 1))
251 static char xcache
[XCACHESIZE
][MAXBASENAME
+ 1]; /* cache for X. files */
252 static int xcachesize
= 0; /* how many left? */
255 * stash an X. file so we can process them sorted first by grade, then by
262 if (xcachesize
< XCACHESIZE
) {
263 DEBUG(4, "stashing %s\n", file
);
264 (void) strlcpy(xcache
[xcachesize
++], file
, (MAXBASENAME
+ 1));
270 * comparison routine for for qsort()
276 /* assumes file name is X.siteG1234 */
277 /* use -strcmp() so that xstash is sorted largest first */
278 /* pull files out of the stash from largest index to smallest */
280 return (-strcmp((char *)f1
+ strlen((char *)f1
) - 5,
281 (char *)f2
+ strlen((char *)f2
) - 5));
286 * sort the cached X. files,
287 * largest (last) to smallest (next to be processed)
292 DEBUG(4, "xsort: first was %s\n", xcache
[0]);
293 qsort(xcache
, xcachesize
, MAXBASENAME
+ 1, xcompare
);
294 DEBUG(4, "xsort: first is %s\n", xcache
[0]);
299 * return smallest X. file in cache
300 * (hint: it's the last one in the array)
306 if (xcachesize
> 0) {
307 strlcpy(file
, xcache
[--xcachesize
], (MAXBASENAME
+ 1));
308 DEBUG(4, "xget: returning %s\n", file
);
311 /* avoid horror of xcachesize < 0 (impossible, you say?)! */
319 * get a file to execute
320 * file -> a read to return filename in
323 * 1 -> file to execute
331 if (xcachesize
== 0) {
332 /* open spool directory */
334 /* this was an ASSERT, but it's not so bad as all that */
338 /* scan spool directory looking for X. files to stash */
339 while (gnamef(pdir
, file
) == TRUE
) {
340 DEBUG(4, "gt_Xfile got %s\n", file
);
341 /* look for x prefix */
342 if (file
[0] != XQTPRE
)
345 /* check to see if required files have arrived */
348 if (xcachesize
>= XCACHESIZE
)
359 * check for needed files
360 * file -> name of file to check
363 * 1 -> all files ready
371 char buf
[BUFSIZ
], rqfile
[MAXNAMESIZE
];
373 fp
= fopen(file
, "r");
377 while (fgets(buf
, BUFSIZ
, fp
) != NULL
) {
378 DEBUG(4, "%s\n", buf
);
381 * look at required files
383 if (buf
[0] != X_RQDFILE
)
385 (void) sscanf(&buf
[1], "%63s", rqfile
);
395 if (stat(rqfile
, &stbuf
) == -1) {
406 * remove execute files to x-directory
416 char buf
[BUFSIZ
], file
[MAXNAMESIZE
], tfile
[MAXNAMESIZE
];
417 char tfull
[MAXFULLNAME
];
419 if ((fp
= fopen(_Xfile
, "r")) == NULL
) {
420 DEBUG(4, "rm_Xfiles: can't read %s\n", _Xfile
);
425 * (void) unlink each file belonging to job
427 while (fgets(buf
, BUFSIZ
, fp
) != NULL
) {
428 if (buf
[0] != X_RQDFILE
)
430 if (sscanf(&buf
[1], "%63s%63s", file
, tfile
) < 2)
432 (void) snprintf(tfull
, sizeof (tfull
), "%s/%s", XQTDIR
, tfile
);
433 (void) unlink(tfull
);
439 * move execute files to x-directory
448 char buf
[BUFSIZ
], ffile
[MAXFULLNAME
], tfile
[MAXNAMESIZE
];
449 char tfull
[MAXFULLNAME
];
451 if ((fp
= fopen(_Xfile
, "r")) == NULL
) {
452 DEBUG(4, "mv_Xfiles: can't read %s\n", _Xfile
);
456 while (fgets(buf
, BUFSIZ
, fp
) != NULL
) {
457 if (buf
[0] != X_RQDFILE
)
459 if (sscanf(&buf
[1], "%63s%63s", ffile
, tfile
) < 2)
463 * expand file names and move to
465 * Make files readable by anyone
468 (void) snprintf(tfull
, sizeof (tfull
), "%s/%s", XQTDIR
, tfile
);
470 if (chkpth(ffile
, CK_READ
) == FAIL
)
471 continue; /* execution will fail later */
472 if (chkpth(tfull
, CK_WRITE
) == FAIL
) {
474 * tfull will have been canonicalized. If
475 * it still points to XQTDIR, allow us to
478 if (!PREFIX(XQTDIR
, tfull
))
479 continue; /* execution will fail later */
480 /* otherwise, keep going */
483 ASSERT(xmv(ffile
, tfull
) == 0, "XMV ERROR", tfull
, errno
);
484 chmod(tfull
, PUB_FILEMODE
);
490 * undo what mv_Xfiles did
499 char buf
[BUFSIZ
], ffile
[MAXNAMESIZE
], tfile
[MAXNAMESIZE
];
500 char tfull
[MAXFULLNAME
], ffull
[MAXFULLNAME
], xfull
[MAXFULLNAME
];
502 (void) snprintf(xfull
, MAXFULLNAME
, "%s/%s", RemSpool
, _Xfile
);
503 if ((fp
= fopen(xfull
, "r")) == NULL
) {
504 DEBUG(4, "unmv_Xfiles: can't read %s\n", xfull
);
508 while (fgets(buf
, BUFSIZ
, fp
) != NULL
) {
509 if (buf
[0] != X_RQDFILE
)
511 if (sscanf(&buf
[1], "%63s%63s", ffile
, tfile
) < 2)
515 * expand file names and move back to
517 * Make files readable by uucp
519 (void) snprintf(ffull
, MAXFULLNAME
, "%s/%s", RemSpool
, ffile
);
520 /* i know we're in .Xqtdir, but ... */
521 (void) snprintf(tfull
, MAXFULLNAME
, "%s/%s", XQTDIR
, tfile
);
523 if (chkpth(ffull
, CK_WRITE
) == FAIL
||
524 chkpth(tfull
, CK_READ
) == FAIL
)
527 ASSERT(xmv(tfull
, ffull
) == 0, "XMV ERROR", ffull
, errno
);
528 (void) chmod(ffull
, (mode_t
)0600);
534 * chkpart - checks the string (ptr points to it) for illegal command or
535 * file permission restriction - called recursively
536 * to check lines that have `string` or (string) form.
537 * _Cmd is the buffer where the command is built up.
538 * _CargType is the type of the next C line argument
541 * BAD_FILE if a non permitted file is found
542 * BAD_COMMAND if non permitted command is found
549 char prm
[BUFSIZ
], whitesp
[BUFSIZ
], rqtcmd
[BUFSIZ
], xcmd
[BUFSIZ
];
550 char savechar
[2]; /* one character string with NULL */
553 /* _CargType is the arg type for this iteration (cmd or file) */
554 while ((ptr
= getprm(ptr
, whitesp
, prm
)) != NULL
) {
555 DEBUG(4, "prm='%s'\n", prm
);
558 /* End of command delimiter */
563 (void) strlcat(_Cmd
, whitesp
, sizeof (_Cmd
));
564 (void) strlcat(_Cmd
, prm
, sizeof (_Cmd
));
565 _CargType
= C_COMMAND
;
568 /* Other delimiter */
571 (void) strlcat(_Cmd
, whitesp
, sizeof (_Cmd
));
572 (void) strlcat(_Cmd
, prm
, sizeof (_Cmd
));
575 case '`': /* don't allow any ` commands */
577 return (BAD_COMMAND
);
579 /* Some allowable quoted string */
585 savechar
[1] = NULLCHAR
;
586 /* put leading white space & first char into command */
587 (void) strlcat(_Cmd
, whitesp
, sizeof (_Cmd
));
588 (void) strlcat(_Cmd
, savechar
, sizeof (_Cmd
));
589 savechar
[0] = prm
[strlen(prm
)-1];
590 prm
[strlen(prm
)-1] = NULLCHAR
; /* delete last character */
593 if (ret
= chkpart(prm
+1)) { /* failed */
596 /* put last char into command */
597 (void) strlcat(_Cmd
, savechar
, sizeof (_Cmd
));
601 if (*(prm
+1) == '>') {
602 (void) strlcat(_Cmd
, whitesp
, sizeof (_Cmd
));
603 (void) strlcat(_Cmd
, prm
, sizeof (_Cmd
));
606 /* fall through if not "2>" */
608 default: /* check for command or file */
612 if (_CargType
== C_COMMAND
) {
613 (void) strlcpy(rqtcmd
, prm
, sizeof (rqtcmd
));
616 if ((cmdOK(rqtcmd
, xcmd
)) == FALSE
)
617 return (BAD_COMMAND
);
618 (void) strlcat(_Cmd
, whitesp
, sizeof (_Cmd
));
619 (void) strlcat(_Cmd
, xcmd
, sizeof (_Cmd
));
624 (void) strlcpy(rqtcmd
, prm
, sizeof (rqtcmd
));
627 if (chkFile(rqtcmd
)) {
630 (void) strlcat(_Cmd
, whitesp
, sizeof (_Cmd
));
631 (void) strlcat(_Cmd
, rqtcmd
, sizeof (_Cmd
));
634 if (whitesp
[0] != '\0')
635 /* restore any trailing white space */
636 (void) strlcat(_Cmd
, whitesp
, sizeof (_Cmd
));
637 return (0); /* all ok */
641 * chkFile - try to find a path name in the prm.
642 * if found, check it for access permission.
644 * check file access permissions
645 * if ! in name assume that access on local machine is required
648 * BAD_FILE - not permitted
655 char *p
, buf
[BUFSIZ
];
657 (void) strlcpy(buf
, prm
, sizeof (buf
));
668 return (chkFile(buf
+1));
675 if ((p
= strchr(buf
, '!')) == NULL
) { /* no "!", look for "/" */
676 if ((p
= strchr(buf
, '/')) == NULL
) { /* ok */
685 /* there is at least one '!' - see if it refers to my system */
686 if (PREFIX(Myname
, buf
)) /* my system so far, check further */
687 return (chkFile(p
+1)); /* recurse with thing after '!' */
688 else /* not my system - not my worry */
693 * doFileChk - check file path permission
694 * NOTE: file is assumed to be a buffer that expfile an
697 * BAD_FILE - not allowed
702 doFileChk(char *file
)
705 DEBUG(7, "fullname: %s\n", file
);
706 if (chkpth(file
, CK_READ
) == FAIL
||
707 chkpth(file
, CK_WRITE
) == FAIL
)
715 * return stuff to user
716 * user -> user to notify
717 * rmt -> system name where user resides
718 * file -> file to return (generally contains input)
719 * cmd -> command that was to be executed
720 * buf -> user friendly face saving uplifting edifying missive
721 * errfile -> stderr output from cmd xeqn
726 retosndr(user
, rmt
, file
, cmd
, buf
, errfile
)
727 char *user
, *rmt
, *file
, *cmd
, *buf
, *errfile
;
729 char ruser
[BUFSIZ
], msg
[BUFSIZ
], subj
[BUFSIZ
];
731 (void) snprintf(msg
, sizeof (msg
), "%s\t[%s %s (%s)]\n\t%s\n%s\n",
732 gettext("remote execution"), gettext("uucp job"),
733 *Jobid
? Jobid
: &_Xfile
[2], timeStamp(), cmd
, buf
);
735 DEBUG(5, "retosndr %s, ", msg
);
737 if (EQUALS(rmt
, Myname
))
738 (void) strlcpy(ruser
, user
, sizeof (ruser
));
740 (void) snprintf(ruser
, sizeof (ruser
), "%s!%s", rmt
, user
);
742 (void) strlcpy(subj
, gettext("remote execution status"), sizeof (subj
));
743 mailst(ruser
, subj
, msg
, file
, errfile
);
748 * uucpst - send the status message back using a uucp command
749 * NOTE - this would be better if the file could be appended.
750 * - suggestion for the future - if rmail would take a file name
751 * instead of just person, then that facility would be correct,
752 * and this routine would not be needed.
756 uucpst(rmt
, tofile
, errfile
, cmd
, buf
)
757 char *rmt
, *tofile
, *errfile
, *cmd
, *buf
;
759 char arg
[MAXFULLNAME
], tmp
[NAMESIZE
], msg
[BUFSIZ
];
764 (void) snprintf(msg
, sizeof (msg
), "%s %s (%s) %s\n\t%s\n%s\n",
765 gettext("uucp job"), *Jobid
? Jobid
: &_Xfile
[2], timeStamp(),
766 gettext("remote execution"), cmd
, buf
);
768 (void) snprintf(tmp
, sizeof (tmp
), "%s.%ld", rmt
, (long)getpid());
769 if ((fp
= fopen(tmp
, "w")) == NULL
)
771 (void) fprintf(fp
, "%s\n", msg
);
773 /* copy back stderr */
774 if (*errfile
!= '\0' && NOTEMPTY(errfile
) &&
775 (fi
= fopen(errfile
, "r")) != NULL
) {
776 fputs("\n\t===== stderr was =====\n", fp
);
777 if (xfappend(fi
, fp
) != SUCCESS
)
778 fputs("\n\t===== well, i tried =====\n", fp
);
785 (void) snprintf(arg
, sizeof (arg
), "%s!%s", rmt
, tofile
);
789 if ((pid
= vfork()) == 0) {
793 (void) open("/dev/null", 2);
794 (void) open("/dev/null", 2);
795 (void) open("/dev/null", 2);
796 (void) signal(SIGINT
, SIG_IGN
);
797 (void) signal(SIGHUP
, SIG_IGN
);
798 (void) signal(SIGQUIT
, SIG_IGN
);
801 (void) execle("/usr/bin/uucp", "UUCP",
802 "-C", tmp
, arg
, (char *)0, Env
);
809 while ((ret
= wait(&status
)) != pid
)
810 if (ret
== -1 && errno
!= EINTR
)
820 char fdgrade(); /* returns default service grade on system */
821 int return_stdin
; /* return stdin for failed commands */
822 int cmdok
, ret
, badfiles
;
824 int send_zero
; /* return successful completion status */
825 int send_nonzero
; /* return unsuccessful completion status */
826 int send_nothing
; /* request for no exit status */
827 int store_status
; /* store status of command in local file */
829 char dqueue
; /* var to hold the default service grade */
830 char *errname
= ""; /* name of local stderr output file */
832 char sendsys
[MAXNAMESIZE
];
833 char dfile
[MAXFULLNAME
], cfile
[MAXFULLNAME
], incmd
[BUFSIZ
];
834 char errDfile
[BUFSIZ
];
835 char fin
[MAXFULLNAME
];
836 char fout
[MAXFULLNAME
], sysout
[NAMESIZE
];
837 char ferr
[MAXFULLNAME
], syserr
[NAMESIZE
];
838 char file
[MAXFULLNAME
], tempname
[NAMESIZE
];
839 char _Sfile
[MAXFULLNAME
]; /* name of local file for status */
842 char buf
[BUFSIZ
], user
[BUFSIZ
], retaddr
[BUFSIZ
], retuser
[BUFSIZ
],
844 char origsys
[MAXFULLNAME
], origuser
[MAXFULLNAME
];
846 (void) strlcpy(Rmtname
, dirname
, sizeof (Rmtname
));
848 (void) mchFind(Rmtname
);
849 while (gt_Xfile(_Xfile
, RemSpool
) > 0) {
850 DEBUG(4, "_Xfile - %s\n", _Xfile
);
852 if ((xfp
= fopen(_Xfile
, "r")) == NULL
) {
856 ASSERT(xfp
!= NULL
, Ct_OPEN
, _Xfile
, errno
);
858 if (stat(_Xfile
, &sb
) != -1)
859 Nstat
.t_qtime
= sb
.st_mtime
;
861 * initialize to defaults
863 (void) strlcpy(user
, User
, sizeof (user
));
864 (void) strcpy(fin
, "/dev/null");
865 (void) strcpy(fout
, "/dev/null");
866 (void) strcpy(ferr
, "/dev/null");
867 (void) sprintf(sysout
, "%.*s", MAXBASENAME
, Myname
);
868 (void) sprintf(syserr
, "%.*s", MAXBASENAME
, Myname
);
870 *incmd
= *retaddr
= *retuser
= *Jobid
= NULLCHAR
;
872 send_zero
= send_nonzero
= send_nothing
= 0;
876 while (fgets(buf
, BUFSIZ
, xfp
) != NULL
) {
885 * The utmpx username field is 32 characters long;
886 * UUCP usage truncates system name to 14 bytes.
888 (void) sscanf(&buf
[1], "%32s%14s", user
, origsys
);
889 (void) strlcpy(origuser
, user
, sizeof (origuser
));
896 (void) sscanf(&buf
[1], "%256s", fin
);
898 if (chkpth(fin
, CK_READ
)) {
899 DEBUG(4, "badfile - in: %s\n", fin
);
908 (void) sscanf(&buf
[1], "%256s%14s", fout
, sysout
);
909 if ((p
= strpbrk(sysout
, "!/")) != NULL
)
910 *p
= NULLCHAR
; /* these are dangerous */
911 if (*sysout
!= NULLCHAR
&& !EQUALS(sysout
, Myname
))
915 if (chkpth(fout
, CK_WRITE
)) {
917 DEBUG(4, "badfile - out: %s\n", fout
);
921 case X_STDERR
: /* standard error */
922 (void) sscanf(&buf
[1], "%256s%14s", ferr
, syserr
);
923 if ((p
= strpbrk(syserr
, "!/")) != NULL
)
924 *p
= NULLCHAR
; /* these are dangerous */
925 if (*syserr
!= NULLCHAR
&& !EQUALS(syserr
, Myname
))
929 if (chkpth(ferr
, CK_WRITE
)) {
931 DEBUG(4, "badfile - error: %s\n", ferr
);
936 case X_CMD
: /* command to execute */
937 (void) strlcpy(incmd
, &buf
[2], sizeof (incmd
));
938 if (*(incmd
+ strlen(incmd
) - 1) == '\n')
939 *(incmd
+ strlen(incmd
) - 1) = NULLCHAR
;
942 case X_MAILF
: /* put status in _Sfile */
944 (void) sscanf(&buf
[1], "%256s", _Sfile
);
947 case X_SENDNOTHING
: /* no failure notification */
951 case X_SENDZERO
: /* success notification */
955 case X_NONZERO
: /* failure notification */
959 case X_BRINGBACK
: /* return stdin on command failure */
966 * return address -- is user's name
967 * put "Rmtname!" in front of it so mail
968 * will always get back to remote system.
970 (void) sscanf(&buf
[1], "%s", retuser
);
973 * Creates string of Rmtname!Rmtname!user which
975 * (void) strcat(strcat(strcpy(retaddr, Rmtname), "!"),
982 * job id for notification
983 * (should be MAXBASENAME, not 14, but no can do)
985 (void) sscanf(&buf
[1], "%14s", Jobid
);
994 DEBUG(4, "fin - %s, ", fin
);
995 DEBUG(4, "fout - %s, ", fout
);
996 DEBUG(4, "ferr - %s, ", ferr
);
997 DEBUG(4, "sysout - %s, ", sysout
);
998 DEBUG(4, "syserr - %s, ", syserr
);
999 DEBUG(4, "user - %s\n", user
);
1000 DEBUG(4, "incmd - %s\n", incmd
);
1002 scRexe(origsys
, origuser
, Loginuser
, incmd
);
1004 if (retuser
[0] != NULLCHAR
)
1005 (void) strlcpy(user
, retuser
, sizeof (user
)); /* pick on this guy */
1007 /* get rid of stuff that can be dangerous */
1008 if ((p
= strpbrk(user
, Shchar
)) != NULL
) {
1012 if (incmd
[0] == NULLCHAR
) {
1013 /* this is a bad X. file - just get rid of it */
1019 * send_nothing must be explicitly requested to avert failure status
1020 * send_zero must be explicitly requested for success notification
1030 * generate a temporary file (if necessary)
1031 * to hold output to be shipped back
1033 if (EQUALS(fout
, "/dev/null"))
1034 (void) strcpy(dfile
, "/dev/null");
1036 gename(DATAPRE
, sysout
, 'O', tempname
);
1037 (void) snprintf(dfile
, sizeof (dfile
), "%s/%s", WORKSPACE
,
1042 * generate a temporary file (if necessary)
1043 * to hold errors to be shipped back
1046 * This is what really should be done. However for compatibility
1047 * for the interim at least, we will always create temp file
1048 * so we can return error output. If this temp file IS conditionally
1049 * created, we must remove the unlink() of errDfile at the end
1050 * because it may REALLY be /dev/null.
1051 * if (EQUALS(ferr, "/dev/null"))
1052 * (void) strcpy(errDfile, "/dev/null");
1055 gename(DATAPRE
, syserr
, 'E', tempname
);
1056 (void) snprintf(errDfile
, sizeof (errDfile
), "%s/%s",
1057 WORKSPACE
, tempname
);
1062 /* initialize command line */
1063 /* set up two environment variables, remote machine name */
1064 /* and remote user name if available from R line */
1066 * xcu4 requires that uucp *does* expand wildcards and uux *does not*
1067 * expand wild cards... Further restrictions are that uux must work
1068 * with every other uucp / uux that initiated a request, so nothing
1069 * strange can been done to communicate that it was uucp that sent
1070 * the request and not uux, What we settle on here is looking for
1071 * the command name uucp and expanding wildcards in only that case.
1072 * It is true that a user can spoof this using uux, but in reality
1073 * this would be identical to using the uucp command to start with.
1075 if (strncmp(incmd
, "uucp ", 5) == 0) {
1076 (void) snprintf(_Cmd
, sizeof (_Cmd
),
1077 "%s %s UU_MACHINE=%s UU_USER=%s "
1078 " export UU_MACHINE UU_USER PATH; ",
1079 PATH
, LOGNAME
, Rmtname
, user
);
1081 (void) snprintf(_Cmd
, sizeof (_Cmd
),
1082 "%s %s UU_MACHINE=%s UU_USER=%s "
1083 " export UU_MACHINE UU_USER PATH; set -f; ",
1084 PATH
, LOGNAME
, Rmtname
, user
);
1088 * check to see if command can be executed
1090 _CargType
= C_COMMAND
; /* the first thing is a command */
1091 cmdok
= chkpart(incmd
);
1093 if (badfiles
|| (cmdok
== BAD_COMMAND
) || cmdok
== BAD_FILE
) {
1094 if (cmdok
== BAD_COMMAND
) {
1095 (void) snprintf(lbuf
, sizeof (lbuf
), "%s!%s XQT DENIED",
1097 (void) snprintf(msgbuf
, sizeof (msgbuf
),
1098 "execution permission denied to %s!%s", Rmtname
, user
);
1100 (void) snprintf(lbuf
, sizeof (lbuf
),
1101 "%s!%s XQT - STDIN/STDOUT/FILE ACCESS DENIED",
1103 (void) snprintf(msgbuf
, sizeof (msgbuf
),
1104 "file access denied to %s!%s", Rmtname
, user
);
1106 logent(incmd
, lbuf
);
1107 DEBUG(4, "bad command %s\n", incmd
);
1109 scWlog(); /* log security vialotion */
1112 retosndr(user
, Rmtname
, return_stdin
? fin
: "",
1115 uucpst(Rmtname
, _Sfile
, "", incmd
, msgbuf
);
1119 (void) snprintf(lbuf
, sizeof (lbuf
), "%s!%s XQT", Rmtname
, user
);
1121 DEBUG(4, "cmd %s\n", _Cmd
);
1123 /* move files to execute directory and change to that directory */
1127 ASSERT(chdir(XQTDIR
) == 0, Ct_CHDIR
, XQTDIR
, errno
);
1128 acRexe(&_Xfile
[2], origsys
, origuser
, Myname
, Loginuser
, incmd
);
1130 /* invoke shell to execute command */
1133 DEBUG(7, "full cmd: %s\n", _Cmd
);
1136 ret
= shio(_Cmd
, fin
, dfile
, errDfile
);
1138 acEndexe(cpucycle(), COMPLETE
);
1140 acEndexe(cpucycle(), PARTIAL
);
1143 if (ret
== -1) { /* -1 means the fork() failed */
1144 unmv_Xfiles(); /* put things back */
1145 errent(Ct_FORK
, buf
, errno
, __FILE__
, __LINE__
);
1149 if (ret
== 0) { /* exit == signal == 0 */
1150 (void) strcpy(msgbuf
, "exited normally");
1151 } else { /* exit != 0 */
1152 int exitcode
= (ret
>> 8) & 0377;
1156 (void) snprintf(msgbuf
, sizeof (msgbuf
),
1157 "exited with status %d", exitcode
);
1160 (void) snprintf(msgbuf
, sizeof (msgbuf
),
1161 "terminated by signal %d", ret
& 0177);
1163 DEBUG(5, "%s\n", msgbuf
);
1164 (void) snprintf(lbuf
, sizeof (lbuf
), "%s - %s", incmd
, msgbuf
);
1165 logent(lbuf
, "COMMAND FAIL");
1168 /* change back to spool directory */
1177 * We used to append stderr to stdout. Since stderr can
1178 * now be specified separately, never append it to stdout.
1179 * It can still be gotten via -s status file option.
1182 if (!EQUALS(fout
, "/dev/null")) {
1184 * if output is on this machine copy output
1185 * there, otherwise spawn job to send to send
1189 if (EQUALS(sysout
, Myname
)) {
1190 if ((xmv(dfile
, fout
)) != 0) {
1191 logent("FAILED", "COPY");
1193 (void) snprintf(msgbuf
+ strlen(msgbuf
),
1194 (sizeof (msgbuf
) - strlen(msgbuf
)),
1195 "\nCould not move stdout to %s,", fout
);
1196 if (putinpub(fout
, dfile
, origuser
) == 0)
1197 (void) snprintf(msgbuf
+ strlen(msgbuf
),
1198 (sizeof (msgbuf
) - strlen(msgbuf
)),
1199 "\n\tstdout left in %s.", fout
);
1201 (void) strlcat(msgbuf
, " stdout lost.",
1207 if (eaccess(GRADES
, 04) != -1)
1211 gename(CMDPRE
, sysout
, dqueue
, tempname
);
1212 (void) snprintf(cfile
, sizeof (cfile
), "%s/%s",
1213 WORKSPACE
, tempname
);
1214 fp
= fdopen(ret
= creat(cfile
, CFILEMODE
), "w");
1215 ASSERT(ret
>= 0 && fp
!= NULL
, Ct_OPEN
, cfile
, errno
);
1216 bname
= BASENAME(dfile
, '/');
1217 (void) fprintf(fp
, "S %s %s %s -d %s 0666\n",
1218 bname
, fout
, user
, bname
);
1220 (void) snprintf(sendsys
, sizeof (sendsys
), "%s/%c", sysout
,
1222 sendsys
[MAXNAMESIZE
-1] = '\0';
1223 wfcommit(dfile
, BASENAME(dfile
, '/'), sendsys
);
1224 wfcommit(cfile
, BASENAME(cfile
, '/'), sendsys
);
1227 if (!EQUALS(ferr
, "/dev/null")) {
1229 * if stderr is on this machine copy output
1230 * there, otherwise spawn job to send to send
1233 if (EQUALS(syserr
, Myname
)) {
1235 if ((xmv(errDfile
, ferr
)) != 0) {
1236 logent("FAILED", "COPY");
1238 (void) snprintf(msgbuf
+ strlen(msgbuf
),
1239 (sizeof (msgbuf
) - strlen(msgbuf
)),
1240 "\nCould not move stderr to %s,", ferr
);
1241 if (putinpub(ferr
, errDfile
, origuser
) == 0) {
1242 (void) snprintf(msgbuf
+strlen(msgbuf
),
1243 (sizeof (msgbuf
) - strlen(msgbuf
)),
1244 "\n\tstderr left in %s", ferr
);
1247 (void) strlcat(msgbuf
, " stderr lost.",
1254 if (eaccess(GRADES
, 04) != -1)
1258 gename(CMDPRE
, syserr
, dqueue
, tempname
);
1259 (void) snprintf(cfile
, sizeof (cfile
), "%s/%s",
1260 WORKSPACE
, tempname
);
1261 fp
= fdopen(ret
= creat(cfile
, CFILEMODE
), "w");
1262 ASSERT(ret
>= 0 && fp
!= NULL
, Ct_OPEN
, cfile
, errno
);
1263 bname
= BASENAME(errDfile
, '/');
1264 (void) fprintf(fp
, "S %s %s %s -d %s 0666\n",
1265 bname
, ferr
, user
, bname
);
1267 (void) snprintf(sendsys
, sizeof (sendsys
), "%s/%c",
1269 sendsys
[MAXNAMESIZE
-1] = '\0';
1270 wfcommit(errDfile
, BASENAME(errDfile
, '/'), sendsys
);
1271 wfcommit(cfile
, BASENAME(cfile
, '/'), sendsys
);
1275 * If we conditionally create stderr tempfile, we must
1276 * remove this unlink() since errDfile may REALLY be /dev/null
1283 retosndr(user
, Rmtname
, "", incmd
, msgbuf
, "");
1285 uucpst(Rmtname
, _Sfile
, "", incmd
, msgbuf
);
1288 retosndr(user
, Rmtname
, return_stdin
? fin
: "",
1289 incmd
, msgbuf
, errname
);
1291 uucpst(Rmtname
, _Sfile
, errname
, incmd
, msgbuf
);
1296 /* delete job files in spool directory */
1297 xfp
= fopen(_Xfile
, "r");
1298 ASSERT(xfp
!= NULL
, Ct_OPEN
, _Xfile
, errno
);
1299 while (fgets(buf
, BUFSIZ
, xfp
) != NULL
) {
1300 if (buf
[0] != X_RQDFILE
)
1302 (void) sscanf(&buf
[1], "%63s", file
);
1304 if (chkpth(file
, CK_WRITE
) != FAIL
)
1305 (void) unlink(file
);
1307 (void) unlink(_Xfile
);