login_skey.c revision 1.3
1/*	$OpenBSD: login_skey.c,v 1.3 2001/06/25 22:10:29 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
74	skeyprompt[0] = '\0';
75
76	(void)signal(SIGQUIT, SIG_IGN);
77	(void)signal(SIGINT, SIG_IGN);
78	(void)signal(SIGALRM, timedout);
79	(void)setpriority(PRIO_PROCESS, 0, 0);
80
81	openlog(NULL, LOG_ODELAY, LOG_AUTH);
82
83    	while ((c = getopt(argc, argv, "ds:v:")) != EOF)
84		switch(c) {
85		case 'd':	/* to remain undocumented */
86			back = stdout;
87			break;
88		case 'v':
89			break;
90		case 's':	/* service */
91			if (strcmp(optarg, "login") == 0)
92				mode = 0;
93			else if (strcmp(optarg, "challenge") == 0)
94				mode = 1;
95			else if (strcmp(optarg, "response") == 0)
96				mode = 2;
97			else {
98				syslog(LOG_ERR, "%s: invalid service", optarg);
99				exit(1);
100			}
101			break;
102		default:
103			syslog(LOG_ERR, "usage error");
104			exit(1);
105		}
106
107	switch(argc - optind) {
108	case 2:
109		class = argv[optind + 1];
110	case 1:
111		username = argv[optind];
112		break;
113	default:
114		syslog(LOG_ERR, "usage error");
115		exit(1);
116	}
117
118
119	if (back == NULL && (back = fdopen(3, "r+")) == NULL)  {
120		syslog(LOG_ERR, "reopening back channel: %m");
121		exit(1);
122	}
123
124	if (mode == 2) {
125		mode = 0;
126		c = -1;
127		/* XXX - redo these loops! */
128		while (++c < sizeof(skeyprompt) &&
129		    read(3, &skeyprompt[c], 1) == 1) {
130			if (skeyprompt[c] == '\0') {
131				mode++;
132				break;
133			}
134		}
135		if (mode == 1) {
136			c = -1;
137			while (++c < sizeof(passbuf) &&
138			    read(3, &passbuf[c], 1) == 1) {
139				if (passbuf[c] == '\0') {
140					mode++;
141					break;
142				}
143			}
144		}
145		if (mode < 2) {
146			syslog(LOG_ERR, "protocol error on back channel");
147			exit(1);
148		}
149		/*
150		 * Sigh.  S/Key really is a stateful protocol.
151		 * We must assume that a user will only try to
152		 * authenticate one at a time and that this call to
153		 * skeychallenge will produce the same results as
154		 * the call to skeychallenge when mode was 1.
155		 *
156		 * Furthermore, RFC2289 requires that an entry be
157		 * locked against a partial guess race which is
158		 * simply not possible if the calling program queries
159		 * the user for the passphrase itself.  Oh well.
160		 */
161		haskey = (skeychallenge(&skey, username, skeyprompt) == 0);
162	} else {
163		/*
164		 * Attempt an S/Key challenge.
165		 * The OpenBSD skeychallenge() will always fill in a
166		 * challenge, even if it has to cons one up.
167		 */
168		haskey = (skeychallenge(&skey, username, skeyprompt) == 0);
169		strcat(skeyprompt, "\nS/Key Password: ");
170		if (mode == 1) {
171			fprintf(back, BI_VALUE " challenge %s\n",
172			    auth_mkvalue(skeyprompt));
173			fprintf(back, BI_CHALLENGE "\n");
174			exit(0);
175		}
176
177		/* Time out getting passphrase after 2 minutes to avoid a DoS */
178		if (haskey)
179			alarm(120);
180		readpassphrase(skeyprompt, passbuf, sizeof(passbuf), 0);
181		if (passbuf[0] == '\0')
182			readpassphrase("S/Key Password [echo on]: ",
183			    passbuf, sizeof(passbuf), RPP_ECHO_ON);
184		alarm(0);
185	}
186
187	if (haskey && skeyverify(&skey, passbuf) == 0) {
188		if (mode == 0) {
189			if (skey.n <= 1)
190				printf("Warning! You MUST change your "
191				    "S/Key password now!\n");
192			else if (skey.n < 5)
193				printf("Warning! Change S/Key password soon\n");
194		}
195		fprintf(back, BI_AUTH "\n");
196		fprintf(back, BI_SECURE "\n");
197		exit(0);
198	}
199	fprintf(back, BI_REJECT "\n");
200	exit(1);
201}
202
203void
204timedout(signo)
205	int signo;
206{
207
208	_exit(1);
209}
210