/* Time-stamp: "Sat 30 Jan 1999, 13:01:51 EST by drk@sgi.com (David Kaelbling)" * * A stripped-down version of skeylogin, intended for use as an IRIX * login SITECHECK program. A SITECHECK program must be executable, * owned by root, and not writable by others. * * Usage: keyauth name [ remhost [ rusername ] ] * Prompt for an s/key password and authenticate it. Return status: * 0: Success; user was authenticated, log in. * 1: Failure; exit login. * 2: Failure; try again (don't exit login). * other: Use normal UNIX authentication. */ #ifdef _BSD_SIGNALS #undef _BSD_SIGNALS #endif #ifdef _BSD_COMPAT #undef _BSD_COMPAT #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "skey.h" #define SCPYN(a, b) strncpy(a, b, sizeof(a)), a[sizeof(a)-1]='\0' #define NMAX 32 /* Should be >= sizeof(utmpx.ut_user) */ #define SITE_OK 0 #define SITE_FAIL 1 #define SITE_AGAIN 2 #define SITE_CONTINUE 3 /* * This bounds the time given to login. We initialize it here * so it can be patched on machines where it's too small. */ int timeout = 300; char *readskeypass(char *buf, int n); static void timedout(void); static int authfile(char *host); static int isaddr(register char *s); static long aton(register char *s); static int rdnets(long host); void main(int argc, char *argv[]) { struct passwd *pwd; char lusername[NMAX+1]; char host[MAXHOSTNAMELEN]; char rusername[NMAX+1]; char skeyprompt[80]; struct skey skey; int skey_status; char buf[LINE_MAX]; *host = *rusername = *skeyprompt = '\0'; /* Save the username */ if (argc > 1) { SCPYN(lusername, argv[1]); if (*lusername == '-') { puts("user names may not start with '-'."); exit(SITE_FAIL); } argc--; argv++; } else { puts("missing user name argument."); exit(SITE_FAIL); } /* Save the remotehost */ if (argc > 1) { SCPYN(host, argv[1]); if (*host == '-') { puts("remote host name may not start with '-'."); exit(SITE_FAIL); } argc--; argv++; } /* Save the remote username */ if (argc > 1) { SCPYN(rusername, argv[1]); if (*rusername == '-') { puts("remote user names may not start with '-'."); exit(SITE_FAIL); } argc--; argv++; } /* Check for extra args. */ if (argc > 1) { puts("too many arguments."); exit(SITE_FAIL); } /* If this is a local login use normal password authentication. */ if (authfile(host)) exit(SITE_CONTINUE); /* Punt back to login if this user does not have a password. */ pwd = getpwnam(lusername); if (pwd && *pwd->pw_passwd == '\0') exit(SITE_CONTINUE); /* Issue an s/key challenge */ if (feof(stdin)) exit(SITE_FAIL); skey_status = skeychallenge(&skey, lusername, skeyprompt); printf("%s\n", skeyprompt); printf("(s/key required)\nPassword:"); fflush(stdout); /* Read password */ signal(SIGALRM, timedout); alarm(timeout); readskeypass(buf, sizeof(buf)); alarm(0); /* Did S/Key authentication succeed? */ if (skey_status == 0 && skeyverify(&skey, buf) == 0 && pwd && *pwd->pw_passwd != '*' && *pwd->pw_passwd != '#') { if (skey.n < 5) puts("Warning! Change password soon"); exit(SITE_OK); } puts("Login incorrect"); exit(SITE_AGAIN); } static void timedout(void) { printf("\nLogin timed out after %d seconds\n", timeout); exit(SITE_FAIL); } /* * Turn host into an IP address and then look it up in the authorization * database to determine if ordinary password logins are OK. */ static int authfile(char *host) { long n; struct hostent *hp; char **lp; if (*host == '\0') { /* Local login, okay */ return 1; } if (isaddr(host)) { n = aton(host); return rdnets(n); } else { hp = gethostbyname(host); if (hp == NULL) { printf("Unknown host %s\n", host); return 0; } for (lp = hp->h_addr_list; *lp != NULL; lp++) { memcpy((char *)&n, *lp, sizeof(n)); n = ntohl(n); if (rdnets(n)) return 1; } return 0; } } /* * Return non-zero if "host" is permitted to use normal password login. */ static int rdnets(long host) { FILE *fp; char buf[LINE_MAX], *cp; long pattern, mask; int permit_it; fp = fopen("/etc/skey.access", "r"); if (fp == NULL) return 0; while(fgets(buf, sizeof(buf), fp), !feof(fp)) { if (*buf == '#') continue; /* Comment */ cp = strtok(buf, " \t"); if (cp == NULL) continue; /* two choices: permit or deny */ if (strncasecmp(cp, "permit", 4) == 0) { permit_it = 1; } else if (strncasecmp(cp, "deny" , 4) == 0) { permit_it = 0; } else { continue; /* ignore this it is not permit/deny */ } cp = strtok(NULL, " \t"); if (cp == NULL) continue; /* Invalid line */ pattern = aton(cp); cp = strtok(NULL, " \t"); if (cp == NULL) continue; /* Invalid line */ mask = aton(cp); if ((host & mask) == pattern) { fclose(fp); return permit_it; } } fclose(fp); return 0; } /* * Return non-zero if string appears to be an IP address in dotted decimal; * return 0 otherwise (i.e., if string is a domain name) */ static int isaddr(register char *s) { char c; if (s == NULL) return 1; /* Can't happen */ while((c = *s++) != '\0') { if (c != '[' && c != ']' && !isdigit(c) && c != '.') return 0; } return 1; } /* * Convert Internet address in ascii dotted-decimal format (44.0.0.1) to * binary IP address */ static long aton(register char *s) { long n = 0; register int i; if (s == NULL) return 0; for (i = 24; i >= 0; i -= 8) { /* Skip any leading stuff (e.g., spaces, '[') */ while(*s != '\0' && !isdigit(*s)) s++; if (*s == '\0') break; n |= atol(s) << i; if ((s = strchr(s, '.')) == NULL) break; s++; } return n; }