X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/c91c86eb2613d4b3f21be4522fb140c49d267fd7..f5576df6fd6c54ac0836b6cc9634f63a156f325a:/usr/src/usr.bin/login/login.c diff --git a/usr/src/usr.bin/login/login.c b/usr/src/usr.bin/login/login.c index 1d81da5cb3..e0955381ec 100644 --- a/usr/src/usr.bin/login/login.c +++ b/usr/src/usr.bin/login/login.c @@ -1,28 +1,44 @@ -/* - * Copyright (c) 1980, 1987, 1988 The Regents of the University of California. - * All rights reserved. +/*- + * Copyright (c) 1980, 1987, 1988, 1991 The Regents of the University + * of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the University of California, Berkeley. The name of the - * University may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ #ifndef lint char copyright[] = -"@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\ +"@(#) Copyright (c) 1980, 1987, 1988, 1991 The Regents of the University of California.\n\ All rights reserved.\n"; #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)login.c 5.34 (Berkeley) %G%"; +static char sccsid[] = "@(#)login.c 5.73 (Berkeley) 6/29/91"; #endif /* not lint */ /* @@ -32,16 +48,13 @@ static char sccsid[] = "@(#)login.c 5.34 (Berkeley) %G%"; */ #include -#include #include #include #include #include -#include #include #include -#include #include #include #include @@ -49,64 +62,56 @@ static char sccsid[] = "@(#)login.c 5.34 (Berkeley) %G%"; #include #include #include -#include +#include +#include +#include "pathnames.h" #define TTYGRPNAME "tty" /* name of group to own ttys */ -#define MOTDFILE "/etc/motd" -#define MAILDIR "/usr/spool/mail" -#define NOLOGIN "/etc/nologin" -#define HUSHLOGIN ".hushlogin" -#define LASTLOG "/usr/adm/lastlog" -#define BSHELL "/bin/sh" - /* * This bounds the time given to login. Not a define so it can * be patched on machines where it's too small. */ int timeout = 300; +int rootlogin; +#ifdef KERBEROS +int notickets = 1; +char *instance; +char *krbtkfile_env; +int authok; +#endif struct passwd *pwd; int failures; -char term[64], *hostname, *username, *tty; - -struct sgttyb sgttyb; -struct tchars tc = { - CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK -}; -struct ltchars ltc = { - CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT -}; - -char *months[] = - { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", - "Sep", "Oct", "Nov", "Dec" }; +char term[64], *envinit[1], *hostname, *username, *tty; main(argc, argv) int argc; char **argv; { - extern int errno, optind; + extern int optind; extern char *optarg, **environ; struct timeval tp; - struct tm *ttp; struct group *gr; register int ch; register char *p; - int ask, fflag, hflag, pflag, cnt; - int quietlog, passwd_req, ioctlval, timedout(); - char *domain, *salt, *envinit[1], *ttyn, *pp; - char tbuf[MAXPATHLEN + 2]; + int ask, fflag, hflag, pflag, cnt, uid; + int quietlog, rval; + char *domain, *salt, *ttyn; + char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; + char localhost[MAXHOSTNAMELEN]; char *ctime(), *ttyname(), *stypeof(), *crypt(), *getpass(); time_t time(); off_t lseek(); + void timedout(); (void)signal(SIGALRM, timedout); (void)alarm((u_int)timeout); (void)signal(SIGQUIT, SIG_IGN); (void)signal(SIGINT, SIG_IGN); (void)setpriority(PRIO_PROCESS, 0, 0); - (void)quota(Q_SETUID, 0, 0, 0); + + openlog("login", LOG_ODELAY, LOG_AUTH); /* * -p is used by getty to tell login not to destroy the environment @@ -114,20 +119,23 @@ main(argc, argv) * -h is used by other servers to pass the name of the remote * host to login so that it may be placed in utmp and wtmp */ - (void)gethostname(tbuf, sizeof(tbuf)); - domain = index(tbuf, '.'); + domain = NULL; + if (gethostname(localhost, sizeof(localhost)) < 0) + syslog(LOG_ERR, "couldn't get local hostname: %m"); + else + domain = index(localhost, '.'); fflag = hflag = pflag = 0; - passwd_req = 1; + uid = getuid(); while ((ch = getopt(argc, argv, "fh:p")) != EOF) switch (ch) { case 'f': fflag = 1; break; case 'h': - if (getuid()) { - fprintf(stderr, - "login: -h for super-user only.\n"); + if (uid) { + (void)fprintf(stderr, + "login: -h option: %s\n", strerror(EPERM)); exit(1); } hflag = 1; @@ -141,7 +149,10 @@ main(argc, argv) break; case '?': default: - fprintf(stderr, "usage: login [-fp] [username]\n"); + if (!uid) + syslog(LOG_ERR, "invalid flag %c", ch); + (void)fprintf(stderr, + "usage: login [-fp] [-h hostname] [username]\n"); exit(1); } argc -= optind; @@ -152,42 +163,42 @@ main(argc, argv) } else ask = 1; - ioctlval = 0; - (void)ioctl(0, TIOCLSET, &ioctlval); - (void)ioctl(0, TIOCNXCL, 0); - (void)fcntl(0, F_SETFL, ioctlval); - (void)ioctl(0, TIOCGETP, &sgttyb); - sgttyb.sg_erase = CERASE; - sgttyb.sg_kill = CKILL; - (void)ioctl(0, TIOCSLTC, <c); - (void)ioctl(0, TIOCSETC, &tc); - (void)ioctl(0, TIOCSETP, &sgttyb); - for (cnt = getdtablesize(); cnt > 2; cnt--) close(cnt); ttyn = ttyname(0); - if (ttyn == NULL || *ttyn == '\0') - ttyn = "/dev/tty??"; + if (ttyn == NULL || *ttyn == '\0') { + (void)sprintf(tname, "%s??", _PATH_TTY); + ttyn = tname; + } if (tty = rindex(ttyn, '/')) ++tty; else tty = ttyn; - openlog("login", LOG_ODELAY, LOG_AUTH); - for (cnt = 0;; ask = 1) { - ioctlval = 0; - (void)ioctl(0, TIOCSETD, &ioctlval); - if (ask) { fflag = 0; getloginname(); } +#ifdef KERBEROS + if ((instance = index(username, '.')) != NULL) { + if (strncmp(instance, ".root", 5) == 0) + rootlogin++; + *instance++ = '\0'; + } else { + rootlogin = 0; + instance = ""; + } +#else + rootlogin = 0; +#endif + if (strlen(username) > UT_NAMESIZE) + username[UT_NAMESIZE] = '\0'; + /* - * Note if trying multiple user names; - * log failures for previous user name, - * but don't bother logging one failure + * Note if trying multiple user names; log failures for + * previous user name, but don't bother logging one failure * for nonexistent name (mistyped username). */ if (failures && strcmp(tbuf, username)) { @@ -196,49 +207,84 @@ main(argc, argv) failures = 0; } (void)strcpy(tbuf, username); + if (pwd = getpwnam(username)) salt = pwd->pw_passwd; else salt = "xx"; - /* if user not super-user, check for disabled logins */ - if (pwd == NULL || pwd->pw_uid) - checknologin(); - /* - * Disallow automatic login to root; if not invoked by - * root, disallow if the uid's differ. + * if we have a valid account name, and it doesn't have a + * password, or the -f option was specified and the caller + * is root or the caller isn't changing their uid, don't + * authenticate. */ - if (fflag && pwd) { - int uid = getuid(); - - passwd_req = pwd->pw_uid == 0 || - (uid && uid != pwd->pw_uid); + if (pwd && (*pwd->pw_passwd == '\0' || + fflag && (uid == 0 || uid == pwd->pw_uid))) + break; + fflag = 0; + if (pwd && pwd->pw_uid == 0) + rootlogin = 1; + + (void)setpriority(PRIO_PROCESS, 0, -4); + + p = getpass("Password:"); + + if (pwd) { +#ifdef KERBEROS + rval = klogin(pwd, instance, localhost, p); + if (rval == 0) + authok = 1; + else if (rval == 1) { + if (pwd->pw_uid != 0) + rootlogin = 0; + rval = strcmp(crypt(p, salt), pwd->pw_passwd); + } +#else + if (pwd->pw_uid != 0) + rootlogin = 0; +#ifdef DES + rval = strcmp(crypt(p, salt), pwd->pw_passwd); +#else + rval = strcmp(p, pwd->pw_passwd); +#endif +#endif } + bzero(p, strlen(p)); + + (void)setpriority(PRIO_PROCESS, 0, 0); /* - * If no pre-authentication and a password exists - * for this user, prompt for one and verify it. + * If trying to log in as root without Kerberos, + * but with insecure terminal, refuse the login attempt. */ - if (!passwd_req || (pwd && !*pwd->pw_passwd)) - break; - - setpriority(PRIO_PROCESS, 0, -4); - pp = getpass("Password:"); - p = crypt(pp, salt); - setpriority(PRIO_PROCESS, 0, 0); +#ifdef KERBEROS + if (authok == 0) +#endif + if (pwd && rootlogin && !rootterm(tty)) { + (void)fprintf(stderr, + "%s login refused on this terminal.\n", + pwd->pw_name); + if (hostname) + syslog(LOG_NOTICE, + "LOGIN %s REFUSED FROM %s ON TTY %s", + pwd->pw_name, hostname, tty); + else + syslog(LOG_NOTICE, + "LOGIN %s REFUSED ON TTY %s", + pwd->pw_name, tty); + continue; + } - (void) bzero(pp, strlen(pp)); - if (pwd && !strcmp(p, pwd->pw_passwd)) + if (pwd && !rval) break; - printf("Login incorrect\n"); + (void)printf("Login incorrect\n"); failures++; /* we allow 10 tries, but after 3 we start backing off */ if (++cnt > 3) { if (cnt >= 10) { badlogin(username); - (void)ioctl(0, TIOCHPCL, (struct sgttyb *)NULL); sleepexit(1); } sleep((u_int)((cnt - 3) * 5)); @@ -248,73 +294,46 @@ main(argc, argv) /* committed to login -- turn off timeout */ (void)alarm((u_int)0); - /* - * If valid so far and root is logging in, see if root logins on - * this terminal are permitted. - */ - if (pwd->pw_uid == 0 && !rootterm(tty)) { - if (hostname) - syslog(LOG_NOTICE, "ROOT LOGIN REFUSED FROM %s", - hostname); - else - syslog(LOG_NOTICE, "ROOT LOGIN REFUSED ON %s", tty); - printf("Login incorrect\n"); - sleepexit(1); - } + endpwent(); - if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) { - switch(errno) { - case EUSERS: - fprintf(stderr, - "Too many users logged on already.\nTry again later.\n"); - break; - case EPROCLIM: - fprintf(stderr, - "You have too many processes running.\n"); - break; - default: - perror("quota (Q_SETUID)"); - } - sleepexit(0); - } + /* if user not super-user, check for disabled logins */ + if (!rootlogin) + checknologin(); if (chdir(pwd->pw_dir) < 0) { - printf("No directory %s!\n", pwd->pw_dir); + (void)printf("No home directory %s!\n", pwd->pw_dir); if (chdir("/")) exit(0); pwd->pw_dir = "/"; - printf("Logging in with home = \"/\".\n"); + (void)printf("Logging in with home = \"/\".\n"); } -#define TWOWEEKS (14*24*60*60) + quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; + if (pwd->pw_change || pwd->pw_expire) (void)gettimeofday(&tp, (struct timezone *)NULL); if (pwd->pw_change) if (tp.tv_sec >= pwd->pw_change) { - printf("Sorry -- your password has expired.\n"); + (void)printf("Sorry -- your password has expired.\n"); sleepexit(1); - } - else if (tp.tv_sec - pwd->pw_change < TWOWEEKS) { - ttp = localtime(&pwd->pw_change); - printf("Warning: your password expires on %s %d, 19%d\n", - months[ttp->tm_mon], ttp->tm_mday, ttp->tm_year); - } + } else if (pwd->pw_change - tp.tv_sec < + 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) + (void)printf("Warning: your password expires on %s", + ctime(&pwd->pw_expire)); if (pwd->pw_expire) if (tp.tv_sec >= pwd->pw_expire) { - printf("Sorry -- your account has expired.\n"); + (void)printf("Sorry -- your account has expired.\n"); sleepexit(1); - } - else if (tp.tv_sec - pwd->pw_expire < TWOWEEKS) { - ttp = localtime(&pwd->pw_expire); - printf("Warning: your account expires on %s %d, 19%d\n", - months[ttp->tm_mon], ttp->tm_mday, ttp->tm_year); - } + } else if (pwd->pw_expire - tp.tv_sec < + 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) + (void)printf("Warning: your account expires on %s", + ctime(&pwd->pw_expire)); /* nothing else left to fail -- really log in */ { struct utmp utmp; - bzero((char *)&utmp, sizeof(utmp)); + bzero((void *)&utmp, sizeof(utmp)); (void)time(&utmp.ut_time); strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); if (hostname) @@ -323,32 +342,16 @@ main(argc, argv) login(&utmp); } - quietlog = access(HUSHLOGIN, F_OK) == 0; dolastlog(quietlog); - if (!hflag) { /* XXX */ - static struct winsize win = { 0, 0, 0, 0 }; - - (void)ioctl(0, TIOCSWINSZ, &win); - } - (void)chown(ttyn, pwd->pw_uid, (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); - (void)chmod(ttyn, 0620); (void)setgid(pwd->pw_gid); initgroups(username, pwd->pw_gid); - quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0); - (void)setuid(pwd->pw_uid); - if (*pwd->pw_shell == '\0') - pwd->pw_shell = BSHELL; - /* turn on new line discipline for the csh */ - else if (!strcmp(pwd->pw_shell, "/bin/csh")) { - ioctlval = NTTYDISC; - (void)ioctl(0, TIOCSETD, &ioctlval); - } + pwd->pw_shell = _PATH_BSHELL; /* destroy environment unless user has requested preservation */ if (!pflag) @@ -358,25 +361,42 @@ main(argc, argv) if (term[0] == '\0') strncpy(term, stypeof(tty), sizeof(term)); (void)setenv("TERM", term, 0); + (void)setenv("LOGNAME", pwd->pw_name, 1); (void)setenv("USER", pwd->pw_name, 1); - (void)setenv("PATH", "/usr/ucb:/bin:/usr/bin:", 0); + (void)setenv("PATH", _PATH_DEFPATH, 0); +#ifdef KERBEROS + if (krbtkfile_env) + (void)setenv("KRBTKFILE", krbtkfile_env, 1); +#endif if (tty[sizeof("tty")-1] == 'd') syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); - if (pwd->pw_uid == 0) + /* if fflag is on, assume caller/authenticator has logged root login */ + if (rootlogin && fflag == 0) if (hostname) - syslog(LOG_NOTICE, "ROOT LOGIN ON %s FROM %s", - tty, hostname); + syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s", + username, tty, hostname); else - syslog(LOG_NOTICE, "ROOT LOGIN ON %s", tty); + syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s", username, tty); + +#ifdef KERBEROS + if (!quietlog && notickets == 1) + (void)printf("Warning: no Kerberos tickets issued.\n"); +#endif if (!quietlog) { struct stat st; + printf("%s%s", + "386BSD Release 0.1 by William and Lynne Jolitz.\n", +"Copyright (c) 1989,1990,1991,1992 William F. Jolitz. All rights reserved.\n\ +Based in part on work by the 386BSD User Community and the\n\ +BSD Networking Software, Release 2 by UCB EECS Department.\n"); + motd(); - (void)sprintf(tbuf, "%s/%s", MAILDIR, pwd->pw_name); + (void)sprintf(tbuf, "%s/%s", _PATH_MAILDIR, pwd->pw_name); if (stat(tbuf, &st) == 0 && st.st_size != 0) - printf("You have %smail.\n", + (void)printf("You have %smail.\n", (st.st_mtime > st.st_atime) ? "new " : ""); } @@ -388,31 +408,46 @@ main(argc, argv) tbuf[0] = '-'; strcpy(tbuf + 1, (p = rindex(pwd->pw_shell, '/')) ? p + 1 : pwd->pw_shell); + + if (setlogin(pwd->pw_name) < 0) + syslog(LOG_ERR, "setlogin() failure: %m"); + + /* discard permissions last so can't get killed and drop core */ + if (rootlogin) + (void) setuid(0); + else + (void) setuid(pwd->pw_uid); + execlp(pwd->pw_shell, tbuf, 0); - fprintf(stderr, "login: no shell: "); - perror(pwd->pw_shell); - exit(0); + (void)fprintf(stderr, "%s: %s\n", pwd->pw_shell, strerror(errno)); + exit(1); } +#ifdef KERBEROS +#define NBUFSIZ (UT_NAMESIZE + 1 + 5) /* .root suffix */ +#else +#define NBUFSIZ (UT_NAMESIZE + 1) +#endif + getloginname() { register int ch; register char *p; - static char nbuf[UT_NAMESIZE + 1]; + static char nbuf[NBUFSIZ]; for (;;) { - printf("login: "); + (void)printf("login: "); for (p = nbuf; (ch = getchar()) != '\n'; ) { if (ch == EOF) { badlogin(username); exit(0); } - if (p < nbuf + UT_NAMESIZE) + if (p < nbuf + (NBUFSIZ - 1)) *p++ = ch; } if (p > nbuf) if (nbuf[0] == '-') - fprintf(stderr, + (void)fprintf(stderr, "login names may not start with '-'.\n"); else { *p = '\0'; @@ -422,9 +457,10 @@ getloginname() } } +void timedout() { - fprintf(stderr, "Login timed out after %d seconds\n", timeout); + (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout); exit(0); } @@ -441,10 +477,11 @@ jmp_buf motdinterrupt; motd() { register int fd, nchars; - int (*oldint)(), sigint(); + sig_t oldint; + void sigint(); char tbuf[8192]; - if ((fd = open(MOTDFILE, O_RDONLY, 0)) < 0) + if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0) return; oldint = signal(SIGINT, sigint); if (setjmp(motdinterrupt) == 0) @@ -454,6 +491,7 @@ motd() (void)close(fd); } +void sigint() { longjmp(motdinterrupt, 1); @@ -464,7 +502,7 @@ checknologin() register int fd, nchars; char tbuf[8192]; - if ((fd = open(NOLOGIN, O_RDONLY, 0)) >= 0) { + if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) { while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) (void)write(fileno(stdout), tbuf, nchars); sleepexit(0); @@ -478,23 +516,23 @@ dolastlog(quiet) int fd; char *ctime(); - if ((fd = open(LASTLOG, O_RDWR, 0)) >= 0) { + if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); if (!quiet) { if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && ll.ll_time != 0) { - printf("Last login: %.*s ", + (void)printf("Last login: %.*s ", 24-5, (char *)ctime(&ll.ll_time)); if (*ll.ll_host != '\0') - printf("from %.*s\n", + (void)printf("from %.*s\n", sizeof(ll.ll_host), ll.ll_host); else - printf("on %.*s\n", + (void)printf("on %.*s\n", sizeof(ll.ll_line), ll.ll_line); } (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); } - bzero((char *)&ll, sizeof(ll)); + bzero((void *)&ll, sizeof(ll)); (void)time(&ll.ll_time); strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); if (hostname) @@ -509,12 +547,19 @@ badlogin(name) { if (failures == 0) return; - if (hostname) - syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s, %s", + if (hostname) { + syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s", + failures, failures > 1 ? "S" : "", hostname); + syslog(LOG_AUTHPRIV|LOG_NOTICE, + "%d LOGIN FAILURE%s FROM %s, %s", failures, failures > 1 ? "S" : "", hostname, name); - else - syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s, %s", + } else { + syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s", + failures, failures > 1 ? "S" : "", tty); + syslog(LOG_AUTHPRIV|LOG_NOTICE, + "%d LOGIN FAILURE%s ON %s, %s", failures, failures > 1 ? "S" : "", tty, name); + } } #undef UNKNOWN @@ -529,23 +574,6 @@ stypeof(ttyid) return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN); } -getstr(buf, cnt, err) - char *buf, *err; - int cnt; -{ - char ch; - - do { - if (read(0, &ch, sizeof(ch)) != sizeof(ch)) - exit(1); - if (--cnt < 0) { - fprintf(stderr, "%s too long\r\n", err); - sleepexit(1); - } - *buf++ = ch; - } while (ch); -} - sleepexit(eval) int eval; {