1/*	$OpenBSD: tokeninit.c,v 1.13 2017/05/03 09:51:39 mestre Exp $	*/
2
3/*-
4 * Copyright (c) 1995 Migration Associates Corp. 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: tokeninit.c,v 1.1 1996/08/26 20:27:28 prb Exp
35 */
36
37#include <sys/signal.h>
38#include <sys/resource.h>
39#include <sys/time.h>
40
41#include <err.h>
42#include <stdio.h>
43#include <syslog.h>
44#include <stdlib.h>
45#include <unistd.h>
46#include <limits.h>
47#include <string.h>
48#include <readpassphrase.h>
49
50#include "token.h"
51#include "tokendb.h"
52
53static	char	*prompt_for_secret(int, char*);
54static	int	parse_secret(int, char *, unsigned char *);
55
56int
57main(int argc, char **argv)
58{
59	unsigned int cmd = TOKEN_INITUSER;
60	int	c;
61	int	errors = 0;
62	int	verbose = 0;
63	int	hexformat = 0;
64	int	modes = 0;
65	char	seed[80];
66	unsigned char	secret[9];
67	char	*optstr;
68	char	*p = NULL;
69
70	struct rlimit cds;
71
72	(void)signal(SIGQUIT, SIG_IGN);
73	(void)signal(SIGINT, SIG_IGN);
74	(void)setpriority(PRIO_PROCESS, 0, 0);
75
76	openlog(NULL, LOG_ODELAY, LOG_AUTH);
77
78	/*
79	 * Make sure we never dump core as we might have a
80	 * valid user shared-secret in memory.
81	 */
82
83	cds.rlim_cur = 0;
84	cds.rlim_max = 0;
85	if (setrlimit(RLIMIT_CORE, &cds) < 0)
86		syslog(LOG_ERR, "couldn't set core dump size to 0: %m");
87
88	if (pledge("stdio rpath wpath cpath fattr flock getpw tty", NULL) == -1)
89		err(1, "pledge");
90
91	if (token_init(argv[0]) < 0) {
92		syslog(LOG_ERR, "unknown token type");
93		errx(1, "unknown token type");
94	}
95
96	if (tt->options & TOKEN_HEXINIT)
97		optstr = "fhm:sv";
98	else
99		optstr = "fm:sv";
100
101	while ((c = getopt(argc, argv, optstr)) != -1)
102		switch (c) {
103		case 'f':	/* force initialize existing user account */
104			cmd |= TOKEN_FORCEINIT;
105			break;
106
107		case 'h':
108			hexformat = 1;
109			break;
110
111		case 'm':
112			if ((c = token_mode(optarg)))
113				modes |= c;
114			else
115				errx(1, "unknown mode");
116			break;
117
118		case 's':	/* generate seed during initialization */
119			cmd |= TOKEN_GENSECRET;
120			break;
121
122		case 'v':	/* verbose */
123			verbose = 1;
124			break;
125		default:
126			fprintf(stderr,
127			   "usage: %sinit [-f%ssv] [-m mode] user ...\n",
128			    tt->name, (tt->options & TOKEN_HEXINIT) ? "h" : "");
129			exit(1);
130		}
131
132	if ((modes & ~TOKEN_RIM) == 0)
133		modes |= tt->defmode;
134
135	argc -= optind;
136	argv = &argv[optind];
137
138	while (argc--) {
139		if (verbose) {
140			printf("Adding %s to %s database\n", *argv, tt->proper);
141			fflush(stdout);
142		}
143		if (!(cmd & TOKEN_GENSECRET)) {
144			p = prompt_for_secret(hexformat, *argv);
145			if (!readpassphrase(p, seed, sizeof(seed), RPP_ECHO_ON) ||
146			    seed[0] == '\0') {
147				fprintf(stderr,
148				    "%sinit: No seed supplied for token.\n",
149				    tt->name);
150				exit(1);
151			}
152			explicit_bzero(secret, sizeof(secret));
153			if (parse_secret(hexformat, seed, secret)) {
154				fprintf(stderr,
155				    "%sinit: Invalid secret entered.\n",
156				    tt->name);
157				exit(1);
158			}
159		}
160		switch (tokenuserinit(cmd, *argv, secret, modes)) {
161		case 0:
162			syslog(LOG_INFO, "User %s initialized in %s database",
163			    *argv, tt->proper);
164			break;
165		case 1:
166			warnx("%s already exists in %s database!",
167			    *argv, tt->proper);
168			syslog(LOG_INFO, "%s already exists in %s database",
169			    *argv, tt->proper);
170			errors++;
171			break;
172		case -1:
173			warnx("Error initializing user %s in %s database.",
174			    *argv, tt->proper);
175			syslog(LOG_INFO,
176			    "Error initializing user %s in %s database: %m",
177			    *argv, tt->proper);
178			errors++;
179		}
180		argv++;
181	}
182	exit(errors);
183}
184
185/*
186 * Parse the 8 octal numbers or a 16 digit hex string into a token secret
187 */
188
189static	int
190parse_secret(int hexformat, char *seed, unsigned char *secret)
191{
192	int i;
193	unsigned int tmp[8];
194
195	if (hexformat) {
196		if ((i = sscanf(seed, "%02x %02x %02x %02x %02x %02x %02x %02x",
197		    &tmp[0], &tmp[1], &tmp[2], &tmp[3],
198		    &tmp[4], &tmp[5], &tmp[6], &tmp[7])) != 8)
199			return (-1);
200	} else {
201		if ((i = sscanf(seed, "%o %o %o %o %o %o %o %o",
202		    &tmp[0], &tmp[1], &tmp[2], &tmp[3],
203		    &tmp[4], &tmp[5], &tmp[6], &tmp[7])) != 8)
204			return (-1);
205	}
206	for (i=0; i < 8; i++)
207		secret[i] = tmp[i] & 0xff;
208
209	return (0);
210}
211
212/*
213 * Prompt user for seed for token
214 */
215
216static	char *
217prompt_for_secret(int hexformat, char* username)
218{
219	static char prompt[1024];
220	if (hexformat)
221		snprintf(prompt, sizeof prompt,
222		    "Enter a 16 digit hexadecimal number "
223		    "as a seed for %s\'s token:\n", username);
224	else
225		snprintf(prompt, sizeof prompt,
226		    "Enter a series of 8 3-digit octal numbers "
227		    "as a seed for %s\'s token:\n", username);
228	return prompt;
229}
230