/* @(#)ct.c 1.7 */ /* * ct [-h] [-v] [-w n] [-s speed] telno ... * * dials the given telephone number, waits for the * modem to answer, and initiates a login process. * */ #include <errno.h> #include <fcntl.h> #include <pwd.h> #include <signal.h> #include <stdio.h> #include <sys/termio.h> #include <time.h> #include <sys/types.h> #include <sys/dir.h> #include <sys/stat.h> #include <utmp.h> #define ROOT 0 #define SYS 3 #define TTYMOD 0666 #define DEV "/dev/" #define LCK "/usr/spool/uucp/LCK.." #define LEGAL "0123456789-*:#;e<w=f" char log[] = "/usr/adm/ctlog", getty[] = "/etc/getty", acu[sizeof DEV + DIRSIZ - 5] = DEV, tty[sizeof DEV + DIRSIZ - 5] = DEV, lock[sizeof LCK + DIRSIZ - 5] = LCK, devtab[] = "/usr/lib/uucp/L-devices"; extern int optind; extern char *optarg; int pid, status, verbose; char *num, *WTMP = WTMP_FILE, *wspeed = "300"; FILE *fdl, *Ldevices; int disconnect(); char *strcpy(), *strncpy(), *strchr(); long time(); void exit(), rewind(); unsigned alarm(), sleep(); struct passwd *getpwuid(); struct termio termio; time_t Log_on, Log_elpsd; main(argc, argv) char *argv[]; { register int c, dn = 0; register char *dp, *aptr; char tbuf[32]; int dl, count, hangup = 1, max = -1; (void) signal(SIGHUP, SIG_IGN); (void) signal(SIGQUIT, SIG_IGN); if ((Ldevices = fopen(devtab, "r")) == NULL) { (void) fprintf(stderr, "ct: can't open %s\n", devtab); exit(1); } while ((c = getopt(argc, argv, "hvw:s:")) != EOF) switch (c) { case 'h': hangup = 0; break; case 'v': verbose = 1; break; case 'w': max = atoi(optarg); break; case 's': wspeed = optarg; break; case '?': dn++; break; } if (dn || optind == argc) { (void) fputs("Usage: ct [-h] [-v] [-w n] [-s speed] telno ...\n", stderr); exit(1); } dn = 0; for (count = argc - 1; count >= optind; --count) { num = argv[count]; if (strlen(num) >= sizeof tbuf - 1) { (void) fprintf(stderr, "ct: phone number too long -- %s\n", num); ++dn; } if (strspn(num, LEGAL) < strlen(num)) { (void) fprintf(stderr, "ct: bad phone number -- %s\n", num); ++dn; } } if (dn) exit(1); for (count = 0; ; ) { dn = gdev(); if (count == 0) { if (dn >= 0) (void) fprintf(stderr, "Allocated dialer at %s baud\n", wspeed); else { (void) fprintf(stderr, "%d busy dialer", -dn); if (dn < -1) (void) fputc('s', stderr); (void) fprintf(stderr, " at %s baud\n", wspeed); if (max <= 0) { if (!isatty(fileno(stdin))) max = 0; if (max < 0) { (void) fputs("Wait for dialer? ", stderr); if ((c = getchar()) == EOF || tolower(c) != 'y') exit(1); while (c != '\n') c = getchar(); (void) fputs("Time, in minutes? ", stderr); (void) scanf("%d", &max); while (getchar() != '\n'); } if (max <= 0) exit(1); } else (void) fputs("Waiting for dialer\n", stderr); } if (!isatty(fileno(stdin))) hangup = 0; if (hangup) { (void) fputs("Confirm hang-up? ", stderr); if ((c = getchar()) == EOF || tolower(c) != 'y') if (dn >= 0) error(); else exit(1); while (c != '\n') c = getchar(); if (isatty(fileno(stdout))) verbose = 0; (void) ioctl(0, TCSETAW, &termio); (void) sleep(5); } (void) close(2); (void) dup(1); } if (dn >= 0) break; if (verbose && count) { (void) fputs("Dialer", stderr); if (dn == -1) (void) fputs(" is", stderr); else (void) fputs("s are", stderr); (void) fprintf(stderr, " busy (%d minute", count); if (count > 1) (void) fputc('s', stderr); (void) fputs(")\n", stderr); } if (count++ >= max) { if (verbose) (void) fputs("*** TIMEOUT ***\n", stderr); exit(1); } (void) sleep(60); } if (count && verbose) (void) fputs("Allocated dialer\n", stderr); if (verbose) (void) fprintf(stderr, "acu=\"%s\" tty=\"%s\"\n", acu, tty); (void) close(Ldevices); if ((dl = open(tty, O_RDWR | O_NDELAY)) < 0) { if (!hangup || verbose) (void) fprintf(stderr, "ct: can't open %s\n", tty); error(); } for (count = optind; count < argc; count++) { if ((aptr = strchr(strcpy(tbuf, num), '\0'))[-1] != '-') { *aptr++ = '-'; *aptr = '\0'; } if (verbose) (void) fprintf(stderr, "Dialing %s\n", tbuf); if (write(dn, num, (unsigned) strlen(num)) >= 0) break; if (!hangup || verbose) (void) fprintf(stderr, "ct: write error on %s\n", acu); (void) close(dn); if ((dn = open(acu, O_WRONLY)) < 0) { if (!hangup || verbose) (void) fprintf(stderr, "ct: reopen error on %s\n", acu); error(); } num = argv[count + 1]; } (void) close(dn); if (count == argc) error(); fdl = fopen(tty, "r+"); (void) close(dl); if (verbose) (void) fputs("Connected\n", stderr); (void) signal(SIGINT, disconnect); (void) signal(SIGTERM, disconnect); (void) signal(SIGALRM, disconnect); (void) sleep(2); (void) close(0); Log_on = time((long *) 0); for (;;) { if ((pid = fork()) == 0) { startat(); (void) setpgrp(); (void) execl(getty, "getty", "-h", "-t60", &tty[5], wspeed, 0); } if (pid <= 0) { if (pid < 0 && (!hangup || verbose)) (void) fputs("ct: can't fork for getty\n", stderr); error(); } while (wait(&status) != pid); if ((status & 0xff00) < 0) { if (!hangup || verbose) (void) fputs("ct: can't exec getty\n", stderr); error(); } if (fdl != NULL) { rewind(fdl); (void) fputs("\nReconnect? ", fdl); rewind(fdl); (void) alarm(20); c = getc(fdl); (void) alarm(0); if (c == EOF || tolower(c) == 'n') disconnect(); while (c != '\n') c = getc(fdl); } } } disconnect() { register int pid, hrs, mins, secs; register char *aptr; extern char *ctime(), *getenv(); (void) signal(SIGINT, SIG_IGN); (void) signal(SIGTERM, SIG_IGN); Log_elpsd = time((long *) 0) - Log_on; (void) unlink(lock); (void) ioctl(fileno(fdl), TCSETA, &termio); (void) fclose(fdl); if (verbose) (void) fputs("Disconnected\n", stderr); stopat(num); if (chown(tty, ROOT, SYS) < 0 || chmod(tty, TTYMOD) < 0) { if (verbose) (void) fprintf(stderr, "Can't chown/chmod on %s\n", tty); exit(1); } exit(0); } error() { (void) unlink(lock); exit(-1); } gdev() { register char *lspeed; register int dn; char Lbuf[80], *getarg(); int lck, pid, exists = 0; (void) fseek(Ldevices, (long) 0, 0); while (fgets(Lbuf, sizeof Lbuf, Ldevices) != NULL) { if (strchr("# \t\n", Lbuf[0]) != NULL) continue; if (strcmp(getarg(Lbuf), "ACU")) continue; (void) strncpy(&tty[5], getarg((char *) 0), sizeof tty - 6); (void) strncpy(&acu[5], getarg((char *) 0), sizeof acu - 6); lspeed = getarg((char *) 0); if (strcmp(wspeed, lspeed) != 0) continue; exists++; (void) strcpy(&lock[21], &tty[5]); if ((lck = open(lock, O_WRONLY | O_CREAT | O_EXCL, 0444)) >= 0 && (dn = open(acu, O_WRONLY)) >= 0) { (void) signal(SIGINT, error); (void) signal(SIGTERM, error); pid = getpid(); (void) write(lck, (char *) &pid, sizeof (pid)); (void) close(lck); return dn; } } if (exists) return -exists; (void) fprintf(stderr, "No %s baud dialers on this system\n", wspeed); error(); /*NOTREACHED*/ } char * getarg(p) register char *p; { register char *q; static char *savepoint; if (p == (char *) 0) p = savepoint; while (*p == ' ' || *p == '\t') p++; q = p; while (*p != ' ' && *p != '\t' && *p != '\0' && *p != '\n') p++; *p = '\0'; savepoint = ++p; return q; } /* * Create an entry in utmp file if one does not already exist. */ startat() { struct utmp utmpbuf ; register struct utmp *u,*oldu ; struct utmp *getutid() ; extern char *WTMP ; FILE *fp ; /* Set up the prototype for the utmp structure we want to write. */ u = &utmpbuf ; zero(&u->ut_user[0],sizeof(u->ut_user)) ; zero(&u->ut_line[0],sizeof(u->ut_line)) ; /* Fill in the various fields of the utmp structure. */ u->ut_id[0] = tty[8] ; u->ut_id[1] = tty[9] ; u->ut_id[2] = '\0' ; u->ut_id[3] = '\0' ; u->ut_pid = getpid() ; u->ut_exit.e_termination = 0 ; u->ut_exit.e_exit = 0 ; u->ut_type = INIT_PROCESS ; time(&u->ut_time) ; setutent() ; /* Start at beginning of utmp file. */ /* For INIT_PROCESSes put in the name of the program in the */ /* "ut_user" field. */ strncpy(&u->ut_user[0],"getty",sizeof(u->ut_user)) ; strncpy(&u->ut_line[0],(tty+5),sizeof(u->ut_line)); /* Write out the updated entry to utmp file. */ pututline(u) ; /* Now attempt to add to the end of the wtmp file. Do not create */ /* if it doesn't already exist. ** Note ** This is the reason */ /* "r+" is used instead of "a+". "r+" won't create a file, while */ /* "a+" will. */ if ((fp = fopen(WTMP,"r+")) != NULL) { fseek(fp,0L,2) ; /* Seek to end of file */ fwrite(u,sizeof(*u),1,fp) ; fclose(fp) ; } endutent() ; } /* * Change utmp file entry to "dead". * Make entry in ct log. */ stopat(num) char *num; { register long stopt; struct utmp utmpbuf ; register struct utmp *u,*oldu ; struct utmp *getutid() ; extern char *WTMP ; FILE *fp ; stopt = time((long *)0); /* Set up the prototype for the utmp structure we want to write. */ u = &utmpbuf ; zero(&u->ut_user[0],sizeof(u->ut_user)) ; zero(&u->ut_line[0],sizeof(u->ut_line)) ; /* Fill in the various fields of the utmp structure. */ u->ut_id[0] = tty[8] ; u->ut_id[1] = tty[9] ; u->ut_id[2] = '\0' ; u->ut_id[3] = '\0' ; u->ut_pid = pid ; strncpy(&u->ut_line[0],(tty+5),sizeof(u->ut_line)); u->ut_type = USER_PROCESS ; /* Find the old entry in the utmp file with the user name and */ /* copy it back. */ if (u = getutid(u)) { utmpbuf = *u ; u = &utmpbuf ; } u->ut_exit.e_termination = status & 0xff ; u->ut_exit.e_exit = (status >> 8) & 0xff ; u->ut_type = DEAD_PROCESS ; time(&u->ut_time) ; /* Write out the updated entry to utmp file. */ pututline(u) ; /* Now attempt to add to the end of the wtmp file. Do not create */ /* if it doesn't already exist. ** Note ** This is the reason */ /* "r+" is used instead of "a+". "r+" won't create a file, while */ /* "a+" will. */ if ((fp = fopen(WTMP,"r+")) != NULL) { fseek(fp,0L,2) ; /* Seek to end of file */ fwrite(u,sizeof(*u),1,fp) ; fclose(fp) ; } endutent() ; /* Do the log accounting */ if (exists(log) && (fp = fopen (log, "a")) != NULL) { char *aptr; int hrs, mins, secs; extern char *ctime (), *getenv (); *getenv ("TZ") = '\0'; (aptr = ctime (&Log_on))[16] = '\0'; hrs = Log_elpsd / 3600; mins = (Log_elpsd %= 3600) / 60; secs = Log_elpsd % 60; (void) fprintf (fp, "%-8s ", getpwuid (getuid ())->pw_name); (void) fprintf (fp, "(%4s) %s ", wspeed, aptr); if (hrs) (void) fprintf (fp, "%2d:%.2d", hrs, mins); else (void) fprintf (fp, " %2d", mins); (void) fprintf (fp, ":%.2d %s\n", secs, num); (void) fclose (fp); } } exists(file) char *file; { struct stat statb; extern errno; if (stat(file, &statb) == -1 && errno == ENOENT) return(0); return(1); } trunc(str, chr) register char *str; register char chr; { for (;*str;str++) { if (*str == chr) { *str = '\0'; break; } } } zero(adr,size) register char *adr ; register int size ; { while (size--) *adr++ = '\0' ; }