home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) Dave Settle 1987
- * All rights reserved.
- * Permission is granted to do anything with this program, except remove
- * this copyright notice, or sell it for profit.
- *
- * Problems, suggestions, bug fixes etc, to:
- *
- * Dave Settle, SMB Business Software, Thorn EMI Datasolve
- *
- * UUCP:
- * dave@smb.co.uk
- * ...!mcvax!ukc!nott-cs!smb!dave
- *
- * SMAIL: Voice:
- * SMB Business Software +44 623 651651
- * High Street
- * Mansfield Telex:
- * Nottingham NG18 1ES 37392 TECSMG
- * England
- * Fax:
- * +44 623 659947
- *
- * modem.c: a bi-directional "getty" to allow incoming calls AND outgoing
- * uucico's
- *
- * Modified by Rick Richardson for HDB uucp and AT&T Aztec protocol
- *
- * Modified by Jack Bonn for state logic (allows autoanswer on/off at
- * a given time for each day of the week)
- *
- * Modified by Dave Settle:
- *
- * Code fixes:
- * hangup routine added, to make sure phone is down before script, and
- * after user disconnects.
- * Parameterised send-expect routines.
- * Minor bug fix to dread()
- * Re-enable SIGALRM in wakeup()
- * Catch all signals, to enable crashes to be detected.
- * Chmod device back to 666, so that we can use it afterwards.
- * Oct 87: fixup modem control with CLOCAL, so that remote disconnect
- * can be detected and dealt with.
- * Oct 87: fix autologout to send series of signals, not just SIGHUP
- * Oct 87: Clean up code, and distribute to other source files.
- * Nov 87: Fix lurking bug in 'expect'. Clean code for 'lint'.
- * Nov 87: Ignore SIHGUP's generated by 'hangup'.
- * Dec 87: Force getty NOT to hangup the line before login.
- * Jan 87: Open stdio file descriptors.
- *
- *
- */
- #include <sys/types.h>
- #include <stdio.h>
- #include <signal.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <termio.h>
- #include <sys/stat.h>
- #include <time.h>
-
- #ifdef WATCHIT
- #include <pwd.h>
- struct passwd *getpwuid();
- #endif
-
- #define MAINDEF
- #include "modem.h" /* variable definitions */
- /*
- * wakeup gets called when the alarm goes off
- */
- wakeup(){
- signal(SIGALRM, wakeup);
- }
-
- fault(sig){
- printf("Crashed with signal %d\n", sig);
- closedown(sig);
- }
-
- closedown(sig){
- time_t now;
- now = time((long *) 0);
- /*
- * [Nov 87]: Since we're about to hang up the phone,
- * ignore the signal that this is going to generate.
- */
- signal(SIGHUP, SIG_IGN);
- if(sig) printf("Caught signal %d\n", sig);
- printf("Closedown at %s", asctime(localtime(&now)));
- /*
- * Oct 87: new addition for SIGHUP. We receive this signal when the line
- * is disconnected by a remote caller. Since the line is dead, so should
- * the shell be (it got SIGHUP same as us); log it out anyway, even if it's
- * trying to ignore it.
- */
- if((sig == SIGHUP) && shell) autologout(shell);
- /*
- * change the value in utmp back to our pid.
- */
- if(shell) uchange(shell, getpid()); /* back to normal */
- /*
- * clear modem line, which should also hangup the phone (if it wasn't already).
- */
- hangup(dev);
- close(dev);
- /*
- * chmod the device back to 666, so that uucico and cu can access it.
- * NOTE: I prefer this to chown(uucp), which does not allow "cu" access.
- */
- chmod(dname,0666); /* uucp access */
- unlink(lockf);
- if(status) printf("Logout status 0x%x\n", status);
- fclose(stdout);
- exit(0);
- }
-
- main(argc, argv, envp)
- char **argv, **envp;
- {
- long t;
- char *arg[5], *speed;
- int baud, i;
- struct conv *p;
- struct stat sbuf;
- time_t now, mtime;
- #ifdef WATCHIT
- FILE *procs;
- struct passwd *pw;
- char psbuff[128];
- #endif
- #ifdef SPEEDCONFIG
- char c, buff[8];
- #endif
- #ifdef STATES
- time_t delta, suicide;
- int state;
- #endif
- FILE *lock;
- /*
- * catch and report all signals, but apply special treatment to legal signals
- * Any program bugs get reported this way. You can get a core dump by sending
- * it SIGFPE.
- */
- for(i=1;i<SIGUSR1;i++) signal(i, fault);
-
- signal(SIGHUP, SIG_IGN);
- signal(SIGINT, SIG_IGN);
- signal(SIGQUIT, SIG_IGN);
- signal(SIGFPE, SIG_DFL); /* you can get a core dump here */
- signal(SIGALRM, wakeup);
- signal(SIGTERM, closedown);
- /*
- * Open the standard I/O file descriptors, if not already open.
- * Running from init, we don't have a terminal, so output to LOGFILE.
- */
- if((i = open("/dev/null", 0)) == 0) {
- open("/dev/null", 1);
- open("/dev/null", 1);
- }
- else close(i);
- freopen(LOGFILE, "a", stdout);
- #ifdef SETBUF
- setbuf(stdout, NULL); /* if setvbuf broken */
- #else
- setvbuf(stdout, NULL, _IOLBF, 0);
- #endif
-
- if (argc < 2)
- {
- printf("Usage: %s <tty> [<speed>]\n", argv[0]);
- sleep(5);
- exit(5);
- }
-
- sprintf(dname, "/dev/%s", argv[1]);
- #if defined(OL3B2)
- sprintf(lockf, "/usr/spool/locks/LCK..%s", argv[1]);
- #else
- #if defined(HDB)
- sprintf(lockf, "/usr/spool/locks/LCK.L.%s", argv[1]);
- #else
- sprintf(lockf, "/usr/spool/uucp/LCK..%s", argv[1]);
- #endif
- #endif
- /*
- * do not start while device is locked
- */
- while(locked()) sleep(30);
- if((dev = open(dname, O_RDWR | O_NDELAY)) == -1) {
- perror(dname);
- sleep(5); /* don't go crazy with respawns */
- exit(4);
- }
-
- /*
- * setup correct time zone
- */
- putenv(TIMEZONE);
- /*
- * set terminal parameters
- * Additional argument (if present) can be used to force an initial speed
- * (Thanks rick)
- */
- if(argc > 2) speed = argv[2];
- else speed = DEFSPEED;
- baud = findspeed(speed);
- init_term(dev, baud);
- /*
- * send-expect strings - at the end, someone has connected to the modem
- */
- #ifdef STATES
- /*
- * find out when the next state change is due to occur. At this point, we exit.
- * The next initiation will set the modem up differently.
- */
- delta = duration(&state);
- suicide = time((long *) 0) + delta;
- #endif
- for(p = ring; p->c_send; p++) {
- #ifdef STATES
- if(!applicable(p, state)) continue;
- #endif
- send(p->c_send, mywrite);
- #ifdef STATES
- if(expect(p->c_expect, (int)(p->c_wait ? min(p->c_wait, delta) : delta), myread)) {
- #else
- if(expect(p->c_expect, p->c_wait, myread)) {
- #endif
- t = time((long *) 0);
- #ifdef STATES
- if(t >= suicide) {
- printf("Exit due to state change\n");
- exit(0);
- }
- #endif
- printf("Incoming call failed to connect on %s", asctime(localtime(&t)));
- /*
- * we don't have to do anything special here, since no locks have been setup.
- * However, since the main problems appear to be non-responding modems, send
- * it some sort of 'un-wedging' sequence
- */
- send(RESET, mywrite);
- sleep(3);
- hangup(dev);
- sleep(10);
- ioctl(dev, TCFLSH, 2); /* Flush both queues */
- exit(3);
- /*NOTREACHED*/
- }
- }
- signal(SIGALRM, wakeup);
- /*
- * OK - incoming call connected. Find speed (if possible), create lock file,
- * then spawn getty.
- * At this point, we also trap hangups, so that we can clean up after
- * any incoming calls. (Hangups are now detected by the hardware).
- */
- signal(SIGHUP, closedown);
- #ifdef SPEEDCONFIG
- dread(dev, &c, 1);
- if(c == '\r') speed = "300";
- else {
- dread(dev, buff, 4);
- if(!strcmp(buff, "1200")) speed = "1200";
- if(!strcmp(buff, "2400")) speed = "2400";
- if(!strcmp(buff, "1275")) speed = "1200";
- if(!strcmp(buff, "7512")) speed = "1200";
- }
- baud = findspeed(speed);
- #endif
-
- t = time((long *)0);
- printf("Call connected at %s on %s", speed, asctime(localtime(&t)));
- /*
- * Someone has rung in - lock the device.
- */
- lock = fopen(lockf, "w");
- /*
- * hand over to "getty"
- */
- arg[0] = "getty";
- arg[1] = "-h";
- arg[2] = argv[1];
- arg[3] = speed;
- arg[4] = NULL;
-
- if(shell = fork()) {
- /*
- * change the utmp pid to the "getty" process, so that it can login
- */
- uchange(getpid(), shell); /* change utmp entry */
- #if defined(OL3B2)
- fprintf(lock," %d\n", shell);
- #else
- #if defined(HDB)
- fprintf(lock,"%d\n", shell);
- #else
- fwrite((char *) &shell, sizeof shell, 1, lock);
- #endif
- #endif
- fclose(lock);
- /*
- * wait for logout from shell.
- * if terminal is idle for IDLETIME, force a logout anyway
- */
- alarm(SPYTIME);
- while((wait(&status) == -1) && (errno == EINTR)) {
- if(stat(dname, &sbuf) == -1) {
- perror(dname);
- continue;
- }
- now = time((long *)0);
- mtime = max(sbuf.st_atime, sbuf.st_mtime);
-
- if((now - mtime) >= IDLETIME) {
- write(dev, "autologout\r\n", 12);
- printf("Device idle - autologout at %s\n",
- asctime(localtime(&now)));
- uchange(shell, getpid());
- autologout(shell);
- break;
- }
-
- #ifdef WATCHIT
- t = time((long *) 0);
- pw = getpwuid((int) sbuf.st_uid);
- printf("Logon user is %s on %s", pw->pw_name,
- asctime(localtime(&t)));
- procs = popen("ps -ef", "r");
- while(fgets(psbuff, sizeof psbuff, procs))
- if(partof(psbuff, argv[1]) && partof(psbuff, pw->pw_name))
- printf("%s", psbuff);
- pclose(procs);
- #endif
- alarm(SPYTIME);
- }
- t = time((long *) 0);
- printf("Call disconnected on %s", asctime(localtime(&t)));
- closedown(0); /* remove locks etc */
- /*NOTREACHED*/
- }
- else {
- sleep(1); /* allow changes to utmp */
- /*
- * Re-do the termio settings, so that we can login.
- * CLOCAL is removed at this point, so that a hangup will generate SIGHUP.
- * Close all the files which we have open - getty expects none.
- */
- login_term(dev, baud);
- for(i=0;i<20;i++) close(i);
- #ifdef DEBUG
- printf("%d: /etc/getty %s %s\n", getpid(), arg[1], arg[2]);
- #endif
- execve("/etc/getty", arg, envp);
- printf("can't exec getty\n");
- exit(1);
- /* NOTREACHED */
- }
- }
- /*
- * check for presence of lock file
- * return 1 if locked.
- */
- locked(){
- struct stat sb;
- if(stat(lockf, &sb) == -1) return(0);
- #ifdef DEBUG
- printf("%s locked\n", lockf);
- #endif
- return(1);
- }
- #ifdef WATCHIT
- /*
- * partof: look for str in text. Has a bug if you look for ...xxx...
- */
- partof(text, str)
- char *text, *str;
- {
- char *needle, *p;
- for(p = text, needle = str; *p ; p++) {
- if(*p != *needle) needle = str;
- if(*p == *needle) needle++;
- if(*needle == '\0') return(1);
- }
- return(0);
- }
- #endif
- /*
- * autologout: log out the child shell. Sends SIGHUP, SIGTERM, SIGKILL
- * until the child exits.
- */
- autologout(child)
- {
- kill(child, SIGHUP);
- alarm(GRACETIME);
- if(wait(&status) == -1) {
- kill(child, SIGTERM);
- alarm(GRACETIME);
- if(wait(&status) == -1) {
- kill(child, SIGKILL);
- alarm(GRACETIME);
- if(wait(&status) == -1) {
- printf("Cannot kill child pid %d\n", child);
- status = 0;
- }
- }
- }
- alarm(0);
- }
-