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