login_skey.c revision 1.2
1/* $OpenBSD: login_skey.c,v 1.2 2001/06/20 22:18:06 millert Exp $ */ 2 3/*- 4 * Copyright (c) 1995 Berkeley Software Design, Inc. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Berkeley Software Design, 17 * Inc. 18 * 4. The name of Berkeley Software Design, Inc. may not be used to endorse 19 * or promote products derived from this software without specific prior 20 * written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * BSDI $From: login_skey.c,v 1.3 1996/09/04 05:24:56 prb Exp $ 35 */ 36#include <sys/types.h> 37#include <sys/param.h> 38#include <sys/stat.h> 39#include <sys/time.h> 40#include <sys/resource.h> 41 42#include <ctype.h> 43#include <fcntl.h> 44#include <paths.h> 45#include <pwd.h> 46#include <readpassphrase.h> 47#include <stdio.h> 48#include <stdlib.h> 49#include <string.h> 50#include <syslog.h> 51#include <unistd.h> 52 53#include <login_cap.h> 54#include <bsd_auth.h> 55#include <sha1.h> 56#include <skey.h> 57 58void timedout __P((int)); 59 60int 61main(argc, argv) 62 int argc; 63 char **argv; 64{ 65 FILE *back = NULL; 66 char *class = 0; 67 char *username = 0; 68 struct skey skey; 69 char skeyprompt[SKEY_MAX_CHALLENGE+17]; 70 char passbuf[SKEY_MAX_PW_LEN+1]; 71 int c, haskey; 72 int mode = 0; 73 char *instance; 74 75 skeyprompt[0] = '\0'; 76 77 (void)signal(SIGQUIT, SIG_IGN); 78 (void)signal(SIGINT, SIG_IGN); 79 (void)signal(SIGALRM, timedout); 80 (void)setpriority(PRIO_PROCESS, 0, 0); 81 82 openlog(NULL, LOG_ODELAY, LOG_AUTH); 83 84 while ((c = getopt(argc, argv, "ds:v:")) != EOF) 85 switch(c) { 86 case 'd': /* to remain undocumented */ 87 back = stdout; 88 break; 89 case 'v': 90 break; 91 case 's': /* service */ 92 if (strcmp(optarg, "login") == 0) 93 mode = 0; 94 else if (strcmp(optarg, "challenge") == 0) 95 mode = 1; 96 else if (strcmp(optarg, "response") == 0) 97 mode = 2; 98 else { 99 syslog(LOG_ERR, "%s: invalid service", optarg); 100 exit(1); 101 } 102 break; 103 default: 104 syslog(LOG_ERR, "usage error"); 105 exit(1); 106 } 107 108 switch(argc - optind) { 109 case 2: 110 class = argv[optind + 1]; 111 case 1: 112 username = argv[optind]; 113 break; 114 default: 115 syslog(LOG_ERR, "usage error"); 116 exit(1); 117 } 118 119 120 if (back == NULL && (back = fdopen(3, "r+")) == NULL) { 121 syslog(LOG_ERR, "reopening back channel: %m"); 122 exit(1); 123 } 124 125 if (mode == 2) { 126 mode = 0; 127 c = -1; 128 /* XXX - redo these loops! */ 129 while (++c < sizeof(skeyprompt) && 130 read(3, &skeyprompt[c], 1) == 1) { 131 if (skeyprompt[c] == '\0') { 132 mode++; 133 break; 134 } 135 } 136 if (mode == 1) { 137 c = -1; 138 while (++c < sizeof(passbuf) && 139 read(3, &passbuf[c], 1) == 1) { 140 if (passbuf[c] == '\0') { 141 mode++; 142 break; 143 } 144 } 145 } 146 if (mode < 2) { 147 syslog(LOG_ERR, "protocol error on back channel"); 148 exit(1); 149 } 150 /* 151 * Sigh. S/Key really is a stateful protocol. 152 * We must assume that a user will only try to 153 * authenticate one at a time and that this call to 154 * skeychallenge will produce the same results as 155 * the call to skeychallenge when mode was 1. 156 * 157 * Furthermore, RFC2289 requires that an entry be 158 * locked against a partial guess race which is 159 * simply not possible if the calling program queries 160 * the user for the passphrase itself. Oh well. 161 */ 162 haskey = (skeychallenge(&skey, username, skeyprompt) == 0); 163 } else { 164 /* 165 * Attempt an S/Key challenge. 166 * The OpenBSD skeychallenge() will always fill in a 167 * challenge, even if it has to cons one up. 168 */ 169 haskey = (skeychallenge(&skey, username, skeyprompt) == 0); 170 strcat(skeyprompt, "\nS/Key Password: "); 171 if (mode == 1) { 172 fprintf(back, BI_VALUE " challenge %s\n", 173 auth_mkvalue(skeyprompt)); 174 fprintf(back, BI_CHALLENGE "\n"); 175 exit(0); 176 } 177 178 /* Time out getting passphrase after 2 minutes to avoid a DoS */ 179 if (haskey) 180 alarm(120); 181 readpassphrase(skeyprompt, passbuf, sizeof(passbuf), 0); 182 if (passbuf[0] == '\0') 183 readpassphrase("S/Key Password [echo on]: ", 184 passbuf, sizeof(passbuf), RPP_ECHO_ON); 185 alarm(0); 186 } 187 188 if ((instance = strchr(username, '.'))) 189 *instance++ = '\0'; 190 191 if (haskey && skeyverify(&skey, passbuf) == 0) { 192 if (mode == 0) { 193 if (skey.n <= 1) 194 printf("Warning! You MUST change your " 195 "S/Key password now!\n"); 196 else if (skey.n < 5) 197 printf("Warning! Change S/Key password soon\n"); 198 } 199 fprintf(back, BI_AUTH "\n"); 200 if (instance && strcmp(instance, "root") == 0) 201 fprintf(back, BI_ROOTOKAY "\n"); 202 fprintf(back, BI_SECURE "\n"); 203 exit(0); 204 } 205 fprintf(back, BI_REJECT "\n"); 206 exit(1); 207} 208 209void 210timedout(signo) 211 int signo; 212{ 213 214 _exit(1); 215} 216