static char sccsid
[] = "@(#)cico.c 5.14 (Berkeley) 4/14/86";
#if defined(VMS) && defined(BSDTCP)
/* Arguments to setdebug(): */
#define DBG_TEMP 0 /* Create a temporary audit file */
#define DBG_PERM 1 /* Create a permanent audit file */
#define DBG_CLEAN 2 /* Cleanup, discard temp file */
int turntime
= 30 * 60; /* 30 minutes expressed in seconds */
extern char MaxGrade
, DefMaxGrade
;
extern char Myfullname
[];
* this program is used to place a call to a
* remote machine, login, and copy files between the two machines.
char wkpre
[NAMESIZE
], file
[NAMESIZE
];
char msg
[MAXFULLNAME
], *q
;
extern onintr(), timeout(), dbg_signal();
char rflags
[MAXFULLNAME
];
strcpy(Progname
, "uucico");
sigsetmask(0); /* in case we inherit blocked signals */
signal(SIGPIPE
, onintr
); /* 4.1a tcp-ip stupidity */
signal(SIGFPE
, dbg_signal
);
ret
= guinfo(getuid(), User
, msg
);
ASSERT(ret
== 0, "BAD UID", CNULL
, ret
);
while(argc
>1 && argv
[1][0] == '-'){
MaxGrade
= DefMaxGrade
= argv
[1][2];
Role
= atoi(&argv
[1][2]);
strncpy(Rmtname
, &argv
[1][2], MAXBASENAME
);
Rmtname
[MAXBASENAME
] = '\0';
Debug
= atoi(&argv
[1][2]);
turntime
= atoi(&argv
[1][2])*60;/* minutes to seconds */
case 'L': /* local calls only */
Hostnumber
= inet_addr(&argv
[1][2]);
printf("unknown flag %s (ignored)\n", argv
[1]);
fprintf(stderr
, "unknown argument %s (ignored)\n", argv
[1]);
if (Debug
&& Role
== MASTER
)
* detach uucico from controlling terminal
* to defend against rlogind sending us a SIGKILL (!!!)
if (Role
== MASTER
&& (ret
= open("/dev/tty", 2)) >= 0) {
ioctl(ret
, TIOCNOTTY
, STBNULL
);
if (getpgrp(0) == 0) { /* We have no controlling terminal */
ASSERT(ret
>= 0, "CHDIR FAILED", Spool
, ret
);
setdebug ((Role
== SLAVE
) ? DBG_TEMP
: DBG_PERM
);
logent ("Local Enabled", "DEBUG");
* First time through: If we're the slave, do initial checking.
/* check for /etc/nologin */
if (access(NOLOGIN
, 0) == 0) {
logent(NOLOGIN
, "UUCICO SHUTDOWN");
logent("DEBUGGING", "continuing anyway");
* Determine if we are on TCPIP
DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL
);
ret
= ioctl(Ifn
, TCGETA
, &Savettyb
);
Savettyb
.c_cflag
= (Savettyb
.c_cflag
& ~CS8
) | CS7
;
Savettyb
.c_oflag
|= OPOST
;
Savettyb
.c_lflag
|= (ISIG
|ICANON
|ECHO
);
ret
= ioctl(Ifn
, TIOCGETP
, &Savettyb
);
Savettyb
.sg_flags
|= ECHO
;
Savettyb
.sg_flags
&= ~RAW
;
* Initial Message -- tell them we're here, and who we are.
sprintf(msg
, "here=%s", Myfullname
);
signal(SIGALRM
, timeout
);
ret
= ioctl(Ifn
, TCSETA
, &Savettyb
);
ret
= ioctl(Ifn
, TIOCSETP
, &Savettyb
);
ret
= ioctl(Ifn
, TCSETA
, &Savettyb
);
ret
= ioctl(Ifn
, TIOCSETP
, &Savettyb
);
strncpy(Rmtname
, q
, MAXBASENAME
);
Rmtname
[MAXBASENAME
] = '\0';
* Now that we know who they are, give the audit file the right
DEBUG(4, "sys-%s\n", Rmtname
);
/* The versys will also do an alias on the incoming name */
/* If we don't know them, we won't talk to them... */
logent(Rmtname
, "UNKNOWN HOST");
omsg('R', "You are unknown to me", Ofn
);
/* we must make sure they are really who they say they
* are. We compare the hostnumber with the number in the hosts
* table for the site they claim to be.
char *cpnt
, *inet_ntoa();
extern char PhoneNumber
[];
from
.sin_addr
.s_addr
= Hostnumber
;
from
.sin_family
= AF_INET
;
if (getpeername(Ifn
, &from
, &fromlen
) < 0) {
logent(Rmtname
, "NOT A TCP CONNECTION");
omsg('R', "NOT TCP", Ofn
);
hp
= gethostbyaddr(&from
.sin_addr
,
sizeof (struct in_addr
), from
.sin_family
);
/* security break or just old host table? */
logent(Rmtname
, "UNKNOWN IP-HOST Name =");
cpnt
= inet_ntoa(from
.sin_addr
),
logent(cpnt
, "UNKNOWN IP-HOST Number =");
sprintf(wkpre
, "%s/%s isn't in my host table",
logent(Rmtname
,"Request from IP-Host name =");
* The following is to determine if the name given us by
* the Remote uucico matches any of the names
* given its network number (remote machine) in our
* We could check the aliases, but that won't work in
* all cases (like if you are running the domain
* server, where you don't get any aliases). The only
* reliable way I can think of that works in ALL cases
* is too look up the site in L.sys and see if the
* sitename matches what we would call him if we
/* PhoneNumber contains the official network name of the host we are checking. (set in versys.c) */
if (sncncmp(PhoneNumber
, hp
->h_name
, SYSNSIZE
) == 0) {
logent(q
,"Found in host Tables");
logent(hp
->h_name
, "FORGED HOSTNAME");
logent(inet_ntoa(from
.sin_addr
), "ORIGINATED AT");
logent(PhoneNumber
, "SHOULD BE");
sprintf(wkpre
, "You're not who you claim to be: %s != %s", hp
->h_name
, PhoneNumber
);
else if (callback(Loginuser
)) {
logent("CALLBACK", "REQUIRED");
/* set up for call back */
systat(Rmtname
, SS_CALLBACK
, "CALLING BACK");
gename(CMDPRE
, Rmtname
, 'C', file
);
close(creat(subfile(file
), 0666));
logent("Remote Enabled", "DEBUG");
DEBUG(1, "Remote debug request ignored\n",
MaxGrade
= DefMaxGrade
= *++p
;
DEBUG(4, "MaxGrade set to %c\n", MaxGrade
);
if (strncmp(p
, "grade", 5) == 0) {
MaxGrade
= DefMaxGrade
= *p
++;
DEBUG(4, "MaxGrade set to %c\n", MaxGrade
);
if (callok(Rmtname
) == SS_BADSEQ
) {
logent("BADSEQ", "PREVIOUS");
omsg('R', "BADSEQ", Ofn
);
if ((ret
= gnxseq(Rmtname
)) == seq
) {
systat(Rmtname
, Stattype
[7], Stattext
[7]);
logent("BAD SEQ", "FAILED HANDSHAKE");
omsg('R', "BADSEQ", Ofn
);
if(setjmp(Pipebuf
)) { /* come here on SIGPIPE */
ret
= gnsys(Rmtname
, Spool
, CMDPRE
);
} else if (Role
== MASTER
&& callok(Rmtname
) != 0) {
logent("SYSTEM STATUS", "CAN NOT CALL");
sprintf(wkpre
, "%c.%.*s", CMDPRE
, SYSNSIZE
, Rmtname
);
signal(SIGQUIT
, SIG_IGN
);
/* check for /etc/nologin */
if (access(NOLOGIN
, 0) == 0) {
logent(NOLOGIN
, "UUCICO SHUTDOWN");
logent("DEBUGGING", "continuing anyway");
if (Ifn
!= -1 && Role
== MASTER
) {
write(Ofn
, EOTMSG
, strlen(EOTMSG
));
sprintf(msg
, "call to %s ", Rmtname
);
if (mlock(Rmtname
) != SUCCESS
) {
Ofn
= Ifn
= conn(Rmtname
);
/* avoid excessive 'wrong time' info */
if (Stattype
[-Ofn
] != SS_WRONGTIME
){
systat(Rmtname
, Stattype
[-Ofn
], Stattext
[-Ofn
]);
logent(msg
, "SUCCEEDED");
* Determine if we are on TCPIP
DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL
);
signal(SIGALRM
, timeout
);
logent("imsg 1", _FAILED
);
if (MaxGrade
!= '\177') {
DEBUG(2, "Max Grade this transfer is %c\n", MaxGrade
);
sprintf(msg
, "%s -Q%d -p%c -vgrade=%c %s",
Myname
, seq
, MaxGrade
, MaxGrade
, rflags
);
sprintf(msg
, "%s -Q%d %s", Myname
, seq
, rflags
);
DEBUG(4, "msg-%s\n", msg
);
logent("imsg 2", _FAILED
);
logent("BAD SEQ", "FAILED HANDSHAKE");
systat(Rmtname
, SS_BADSEQ
, Stattext
[SS_BADSEQ
]);
if (strcmp(&msg
[1], "OK") != SAME
) {
logent(&msg
[1], "FAILED HANDSHAKE");
systat(Rmtname
, SS_INPROGRESS
,
strcmp(&msg
[1], "CB") == SAME
?
"AWAITING CALLBACK": "FAILED HANDSHAKE");
DEBUG(1, "Rmtname %s, ", Rmtname
);
DEBUG(1, "Role %s, ", Role
? "MASTER" : "SLAVE");
DEBUG(1, "Ifn - %d, ", Ifn
);
DEBUG(1, "Loginuser - %s\n", Loginuser
);
logent("startup", _FAILED
);
systat(Rmtname
, SS_FAIL
, ret
> 0 ? "CONVERSATION FAILED" :
sprintf(startupmsg
, "startup %s %d baud", &ttyn
[5],
logent(startupmsg
, "OK");
systat(Rmtname
, SS_INPROGRESS
, "TALKING");
ret
= cntrl(Role
, wkpre
);
DEBUG(1, "cntrl - %d\n", ret
);
signal(SIGALRM
, timeout
);
logent("conversation complete", "OK");
logent("conversation complete", _FAILED
);
systat(Rmtname
, SS_FAIL
, "CONVERSATION FAILED");
DEBUG(4, "send OO %d,", ret
);
* cleanup and exit with "code" status
sleep(5); /* Wait for any pending output */
Savettyb
.c_cflag
|= HUPCL
;
(void) ioctl(0, TCSETA
, &Savettyb
);
(void) ioctl(0, TIOCHPCL
, STBNULL
);
(void) ioctl(0, TIOCCDTR
, STBNULL
);
(void) ioctl(0, TIOCSDTR
, STBNULL
);
(void) ioctl(0, TIOCGETP
, &Hupvec
);
(void) ioctl(0, TIOCSETP
, &Hupvec
);
(void) ioctl(0, TIOCSETP
, &Savettyb
);
/* make *sure* exclusive access is off */
(void) ioctl(0, TIOCNXCL
, STBNULL
);
write(Ofn
, EOTMSG
, strlen(EOTMSG
));
/* reenable logins on dialout */
DEBUG(1, "exit code %d\n", code
);
* on interrupt - remove locks and exit
sprintf(str
, "SIGNAL %d", inter
);
if (*Rmtname
&& strncmp(Rmtname
, Myname
, MAXBASENAME
))
systat(Rmtname
, SS_FAIL
, str
);
if (inter
== SIGPIPE
&& !onesys
)
* (SIGFPE, ugh), and toggle debugging between 0 and 30.
* Handy for looking in on long running uucicos.
Debug
= (Debug
== 0) ? 30 : 0;
logent("Signal Enabled", "DEBUG");
* Check debugging requests, and open RMTDEBUG audit file if necessary. If an
* audit file is needed, the parm argument indicates how to create the file:
* DBG_TEMP - Open a temporary file, with filename = RMTDEBUG/pid.
* DBG_PERM - Open a permanent audit file, filename = RMTDEBUG/Rmtname.
* If a temp file already exists, it is mv'ed to be permanent.
* DBG_CLEAN - Cleanup; unlink temp files.
* Restrictions - this code can only cope with one open debug file at a time.
* Each call creates a new file; if an old one of the same name exists it will
char buf
[BUFSIZ
]; /* Buffer for building filenames */
static char *temp
= NULL
; /* Ptr to temporary file name */
static int auditopen
= 0; /* Set to 1 when we open a file */
struct stat stbuf
; /* File status buffer */
* If movement or cleanup of a temp file is indicated, we do it no
if (temp
!= CNULL
&& parm
== DBG_PERM
) {
sprintf(buf
, "%s/%s", RMTDEBUG
, Rmtname
);
if (link(temp
, buf
) != 0) {
assert("RMTDEBUG LINK FAIL", temp
, errno
);
return; /* Gotta be in debug to come here. */
* If we haven't opened a file already, we can just return if it's
* alright to use the stderr we came in with. We can if:
* Role == MASTER, and Stderr is a regular file, a TTY or a pipe.
* Caution: Detecting when stderr is a pipe is tricky, because the 4.2
* man page for fstat(2) disagrees with reality, and System V leaves it
* undefined, which means different implementations act differently.
if (!auditopen
&& Role
== MASTER
) {
if (isatty(fileno(stderr
)))
else if (fstat(fileno(stderr
), &stbuf
) == 0) {
/* Is Regular File or Fifo */
if ((stbuf
.st_mode
& 0060000) == 0)
if ((stbuf
.st_mode
& S_IFMT
) == S_IFREG
||
stbuf
.st_mode
== 0) /* Is a pipe */
/* Is Regular File or Pipe */
if ((stbuf
.st_mode
& S_IFMT
) == S_IFREG
)
* We need RMTDEBUG directory to do auditing. If the file doesn't exist,
* then we forget about debugging; if it exists but has improper owner-
* ship or modes, we gripe about it in ERRLOG.
if (stat(RMTDEBUG
, &stbuf
) != SUCCESS
) {
if ((geteuid() != stbuf
.st_uid
) || /* We must own it */
((stbuf
.st_mode
& 0170700) != 040700)) { /* Directory, rwx */
assert("INVALID RMTDEBUG DIRECTORY:", RMTDEBUG
, stbuf
.st_mode
);
sprintf(buf
, "%s/%d", RMTDEBUG
, getpid());
temp
= malloc(strlen (buf
) + 1);
assert("RMTDEBUG MALLOC ERROR:", temp
, errno
);
sprintf(buf
, "%s/%s", RMTDEBUG
, Rmtname
);
if (freopen(buf
, "w", stderr
) != stderr
) {
assert("FAILED RMTDEBUG FILE OPEN:", buf
, errno
);
logent(Rmtname
, "TIMEOUT");
if (*Rmtname
&& strncmp(Rmtname
, Myname
, MAXBASENAME
)) {
systat(Rmtname
, SS_FAIL
, "TIMEOUT");