xref: /openbsd/usr.sbin/tokenadm/tokenadm.c (revision 133306f0)
1 /*	$OpenBSD: tokenadm.c,v 1.1 2000/12/20 02:08:09 millert 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: tokenadm.c,v 1.2 1996/10/17 00:54:28 prb Exp $
35  */
36 
37 #include <sys/param.h>
38 #include <sys/resource.h>
39 #include <sys/time.h>
40 
41 #include <err.h>
42 #include <errno.h>
43 #include <stdio.h>
44 #include <syslog.h>
45 #include <stdlib.h>
46 #include <unistd.h>
47 #include <string.h>
48 
49 #include "token.h"
50 #include "tokendb.h"
51 
52 
53 typedef enum { LIST, ENABLE, DISABLE, REMOVE, MODECH } what_t;
54 typedef enum {
55 	NOBANNER = 0x01,
56 	TERSE = 0x02,
57 	ENONLY = 0x04,
58 	DISONLY = 0x08,
59 	ONECOL = 0x10,
60 	REVERSE = 0x20,
61 	} how_t;
62 
63 static	int	force_unlock(char *);
64 static	int	process_record(char *, unsigned, unsigned);
65 static	int	process_modes(char *, unsigned, unsigned);
66 static  void	print_record(TOKENDB_Rec *, how_t);
67 
68 extern	int
69 main(int argc, char **argv)
70 {
71 	int c, errors;
72 	u_int emode, dmode, pmode;
73 	struct rlimit cds;
74 	what_t what;
75 	how_t how;
76 	TOKENDB_Rec tokenrec;
77 
78 	what = LIST;
79 	emode = dmode = 0;
80 	pmode = 0;
81 	errors = 0;
82 	how = 0;
83 
84 	(void)signal(SIGQUIT, SIG_IGN);
85 	(void)signal(SIGINT, SIG_IGN);
86 	(void)setpriority(PRIO_PROCESS, 0, 0);
87 
88 	openlog(NULL, LOG_ODELAY, LOG_AUTH);
89 
90 	if (token_init(argv[0]) < 0) {
91 		syslog(LOG_ERR, "unknown token type");
92 		errx(1, "unknown token type");
93 	}
94 
95 	/*
96 	 * Make sure we never dump core as we might have a
97 	 * valid user shared-secret in memory.
98 	 */
99 
100 	cds.rlim_cur = 0;
101 	cds.rlim_max = 0;
102 	if (setrlimit(RLIMIT_CORE, &cds) < 0)
103 		syslog(LOG_ERR, "couldn't set core dump size to 0: %m");
104 
105     	while ((c = getopt(argc, argv, "BDERT1bdem:ru")) != EOF)
106 		switch (c) {
107 		case 'B':
108 			if (what != LIST)
109 				goto usage;
110 			how |= NOBANNER;
111 			break;
112 		case 'T':
113 			if (what != LIST)
114 				goto usage;
115 			how |= TERSE;
116 			break;
117 		case '1':
118 			if (what != LIST)
119 				goto usage;
120 			how |= ONECOL;
121 			break;
122 		case 'D':
123 			if (what != LIST)
124 				goto usage;
125 			how |= DISONLY;
126 			break;
127 		case 'E':
128 			if (what != LIST)
129 				goto usage;
130 			how |= ENONLY;
131 			break;
132 		case 'R':
133 			if (what != LIST)
134 				goto usage;
135 			how |= REVERSE;
136 			break;
137 		case 'd':
138 			if (what != LIST || how)
139 				goto usage;
140 			what = DISABLE;
141 			break;
142 		case 'e':
143 			if (what != LIST || how)
144 				goto usage;
145 			what = ENABLE;
146 			break;
147 		case 'r':
148 			if (what != LIST || emode || dmode || how)
149 				goto usage;
150 			what = REMOVE;
151 			break;
152 		case 'm':
153 			if (what == REMOVE || how)
154 				goto usage;
155 			if (*optarg == '-') {
156 				if ((c = token_mode(optarg+1)) == NULL)
157 					errx(1, "%s: unknown mode", optarg+1);
158 				dmode |= c;
159 			} else {
160 				if ((c = token_mode(optarg)) == NULL)
161 					errx(1, "%s: unknown mode", optarg);
162 				emode |= c;
163 			}
164 			break;
165 		default:
166 			goto usage;
167 		}
168 
169 	if (what == LIST && (dmode || emode))
170 		what = MODECH;
171 
172 	if (what == LIST) {
173 		if ((how & (ENONLY|DISONLY)) == 0)
174 			how |= ENONLY|DISONLY;
175 		if (!(how & NOBANNER)) {
176 			if ((how & (TERSE|ONECOL)) == (TERSE|ONECOL)) {
177 				printf("User\n");
178 				printf("----------------\n");
179 			} else if (how & (TERSE)) {
180 				printf("User             ");
181 				printf("User             ");
182 				printf("User             ");
183 				printf("User\n");
184 				printf("---------------- ");
185 				printf("---------------- ");
186 				printf("---------------- ");
187 				printf("----------------\n");
188 			} else {
189 				printf("User             Status   Modes\n");
190 				printf("---------------- -------- -----\n");
191 			}
192 		}
193 
194 		if (optind >= argc) {
195 			if (tokendb_firstrec(how & REVERSE, &tokenrec))
196 				exit(0);
197 			do
198 				print_record(&tokenrec, how);
199 			while (tokendb_nextrec(how & REVERSE, &tokenrec) == 0);
200 			print_record(NULL, how);
201 			exit(0);
202 		}
203 	}
204 
205 	if (optind >= argc) {
206 usage:
207 		fprintf(stderr,
208 		    "Usage: %sadm [-BDERT1 | -d | -e | -r] [-m mode] user [...]\n",
209 			tt->name);
210 		exit(1);
211 	}
212 
213 
214 	argv += optind - 1;
215 	while (*++argv)
216 		switch(what) {
217 		case LIST:
218 			if (tokendb_getrec(*argv, &tokenrec)) {
219 				printf("%s: no such user\n", *argv);
220 				break;
221 			}
222 			print_record(&tokenrec, how);
223 			break;
224 		case REMOVE:
225 			if (tokendb_delrec(*argv)) {
226 				warnx("%s: could not remove", *argv);
227 				errors++;
228 			}
229 			break;
230 		case DISABLE:
231 			if (process_record(*argv, ~TOKEN_ENABLED, 0)) {
232 				warnx("%s: could not disable", *argv);
233 				++errors;
234 			}
235 			if (emode || dmode)
236 				goto modech;
237 			break;
238 		case ENABLE:
239 			if (process_record(*argv, ~TOKEN_ENABLED, 0)) {
240 				warnx("%s: could not enable", *argv);
241 				++errors;
242 			}
243 			if (emode || dmode)
244 				goto modech;
245 			break;
246 		modech:
247 		case MODECH:
248 			if (process_modes(*argv, ~dmode, emode)) {
249 				warnx("%s: could not change modes", *argv);
250 				++errors;
251 			}
252 			break;
253 		}
254 
255 	if (what == LIST)
256 		print_record(NULL, how);
257 
258 	exit(errors);
259 }
260 
261 /*
262  * Process a user record
263  */
264 
265 static	int
266 process_record(char *username, unsigned and_mask, unsigned or_mask)
267 {
268 	int	count = 0;
269 	TOKENDB_Rec tokenrec;
270 
271 retry:
272 	switch (tokendb_lockrec(username, &tokenrec, TOKEN_LOCKED)) {
273 	case 0:
274 		tokenrec.flags &= and_mask;
275 		tokenrec.flags |= or_mask;
276 		tokenrec.flags &= ~TOKEN_LOCKED;
277 		if (!tokendb_putrec(username, &tokenrec))
278 			return (0);
279 		else
280 			return (-1);
281 	case 1:
282 		sleep(1);
283 		if (count++ < 60)
284 			goto retry;
285 		if (force_unlock(username))
286 			return (1);
287 		goto retry;
288 
289 	case ENOENT:
290 		warnx("%s: nonexistent user", username);
291 		return (1);
292 	default:
293 		return (-1);
294 	}
295 }
296 
297 static	int
298 process_modes(char *username, unsigned and_mask, unsigned or_mask)
299 {
300 	int	count = 0;
301 	TOKENDB_Rec tokenrec;
302 
303 retry:
304 	switch (tokendb_lockrec(username, &tokenrec, TOKEN_LOCKED)) {
305 	case 0:
306 		tokenrec.mode &= and_mask;
307 		tokenrec.mode |= or_mask;
308 		/*
309 		 * When ever we set up for rim mode (even if we are
310 		 * already set up for it) reset the rim key
311 		 */
312 		if (or_mask & TOKEN_RIM)
313 			memset(tokenrec.rim, 0, sizeof(tokenrec.rim));
314 		tokenrec.flags &= ~TOKEN_LOCKED;
315 		if (!tokendb_putrec(username, &tokenrec))
316 			return (0);
317 		else
318 			return (-1);
319 	case 1:
320 		sleep(1);
321 		if (count++ < 60)
322 			goto retry;
323 		if (force_unlock(username))
324 			return (1);
325 		goto retry;
326 
327 	case ENOENT:
328 		warnx("%s: nonexistent user", username);
329 		return (1);
330 	default:
331 		return (-1);
332 	}
333 }
334 
335 /*
336  * Force remove a user record-level lock.
337  */
338 
339 static	int
340 force_unlock(char *username)
341 {
342 	TOKENDB_Rec tokenrec;
343 
344 	if (tokendb_getrec(username, &tokenrec))
345 		return (-1);
346 
347 	tokenrec.flags &= ~TOKEN_LOCKED;
348 	tokenrec.flags &= ~TOKEN_LOGIN;
349 
350 	if (tokendb_putrec(username, &tokenrec))
351 		return (1);
352 
353 	return (0);
354 }
355 
356 /*
357  * Print a database record according to user a specified format
358  */
359 
360 static	void
361 print_record(TOKENDB_Rec *rec, how_t how)
362 {
363 	static int count = 0;
364 	int i;
365 
366 	if (rec == NULL) {
367 		if ((count & 3) && (how & (TERSE|ONECOL)) == TERSE)
368 			printf("\n");
369 		return;
370 	}
371 
372 	if (rec->flags & TOKEN_ENABLED) {
373 		if ((how & ENONLY) == 0)
374 			return;
375 	} else {
376 		if ((how & DISONLY) == 0)
377 			return;
378 	}
379 
380 	switch (how & (TERSE|ONECOL)) {
381 	case 0:
382 	case ONECOL:
383 		printf("%-16s %-8s", rec->uname,
384 		  rec->flags & TOKEN_ENABLED ? "enabled" : "disabled");
385 
386 		for (i = 1; i; i <<= 1)
387 			if (rec->mode & i)
388 				printf(" %s", token_getmode(i));
389 		printf("\n");
390 		break;
391 	case TERSE:
392 		if ((count & 3) == 3)
393 			printf("%s\n", rec->uname);
394 		else
395 			printf("%-16s ", rec->uname);
396 		break;
397 	case TERSE|ONECOL:
398 		printf("%s\n", rec->uname);
399 		break;
400 	}
401 	++count;
402 }
403