xref: /openbsd/usr.sbin/tokenadm/tokenadm.c (revision 404b540a)
1 /*	$OpenBSD: tokenadm.c,v 1.9 2007/03/15 22:31:14 jmc 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, "BDERT1dem:r")) != -1)
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)) == 0)
157 					errx(1, "%s: unknown mode", optarg+1);
158 				dmode |= c;
159 			} else {
160 				if ((c = token_mode(optarg)) == 0)
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 [-1BDdEeRrT] [-m [-]mode] [user ...]\n",
209 			tt->name);
210 		exit(1);
211 	}
212 
213 	argv += optind - 1;
214 	while (*++argv)
215 		switch (what) {
216 		case LIST:
217 			if (tokendb_getrec(*argv, &tokenrec)) {
218 				printf("%s: no such user\n", *argv);
219 				break;
220 			}
221 			print_record(&tokenrec, how);
222 			break;
223 		case REMOVE:
224 			if (tokendb_delrec(*argv)) {
225 				warnx("%s: could not remove", *argv);
226 				errors++;
227 			}
228 			break;
229 		case DISABLE:
230 			if (process_record(*argv, ~TOKEN_ENABLED, 0)) {
231 				warnx("%s: could not disable", *argv);
232 				++errors;
233 			}
234 			if (emode || dmode)
235 				goto modech;
236 			break;
237 		case ENABLE:
238 			if (process_record(*argv, ~TOKEN_ENABLED, TOKEN_ENABLED)) {
239 				warnx("%s: could not enable", *argv);
240 				++errors;
241 			}
242 			if (emode || dmode)
243 				goto modech;
244 			break;
245 		modech:
246 		case MODECH:
247 			if (process_modes(*argv, ~dmode, emode)) {
248 				warnx("%s: could not change modes", *argv);
249 				++errors;
250 			}
251 			break;
252 		}
253 
254 	if (what == LIST)
255 		print_record(NULL, how);
256 
257 	exit(errors);
258 }
259 
260 /*
261  * Process a user record
262  */
263 
264 static	int
265 process_record(char *username, unsigned and_mask, unsigned or_mask)
266 {
267 	int	count = 0;
268 	TOKENDB_Rec tokenrec;
269 
270 retry:
271 	switch (tokendb_lockrec(username, &tokenrec, TOKEN_LOCKED)) {
272 	case 0:
273 		tokenrec.flags &= and_mask;
274 		tokenrec.flags |= or_mask;
275 		tokenrec.flags &= ~TOKEN_LOCKED;
276 		if (!tokendb_putrec(username, &tokenrec))
277 			return (0);
278 		else
279 			return (-1);
280 	case 1:
281 		sleep(1);
282 		if (count++ < 60)
283 			goto retry;
284 		if (force_unlock(username))
285 			return (1);
286 		goto retry;
287 
288 	case ENOENT:
289 		warnx("%s: nonexistent user", username);
290 		return (1);
291 	default:
292 		return (-1);
293 	}
294 }
295 
296 static	int
297 process_modes(char *username, unsigned and_mask, unsigned or_mask)
298 {
299 	int	count = 0;
300 	TOKENDB_Rec tokenrec;
301 
302 retry:
303 	switch (tokendb_lockrec(username, &tokenrec, TOKEN_LOCKED)) {
304 	case 0:
305 		tokenrec.mode &= and_mask;
306 		tokenrec.mode |= or_mask;
307 		/*
308 		 * When ever we set up for rim mode (even if we are
309 		 * already set up for it) reset the rim key
310 		 */
311 		if (or_mask & TOKEN_RIM)
312 			memset(tokenrec.rim, 0, sizeof(tokenrec.rim));
313 		tokenrec.flags &= ~TOKEN_LOCKED;
314 		if (!tokendb_putrec(username, &tokenrec))
315 			return (0);
316 		else
317 			return (-1);
318 	case 1:
319 		sleep(1);
320 		if (count++ < 60)
321 			goto retry;
322 		if (force_unlock(username))
323 			return (1);
324 		goto retry;
325 
326 	case ENOENT:
327 		warnx("%s: nonexistent user", username);
328 		return (1);
329 	default:
330 		return (-1);
331 	}
332 }
333 
334 /*
335  * Force remove a user record-level lock.
336  */
337 
338 static	int
339 force_unlock(char *username)
340 {
341 	TOKENDB_Rec tokenrec;
342 
343 	if (tokendb_getrec(username, &tokenrec))
344 		return (-1);
345 
346 	tokenrec.flags &= ~TOKEN_LOCKED;
347 	tokenrec.flags &= ~TOKEN_LOGIN;
348 
349 	if (tokendb_putrec(username, &tokenrec))
350 		return (1);
351 
352 	return (0);
353 }
354 
355 /*
356  * Print a database record according to user a specified format
357  */
358 
359 static	void
360 print_record(TOKENDB_Rec *rec, how_t how)
361 {
362 	static int count = 0;
363 	int i;
364 
365 	if (rec == NULL) {
366 		if ((count & 3) && (how & (TERSE|ONECOL)) == TERSE)
367 			printf("\n");
368 		return;
369 	}
370 
371 	if (rec->flags & TOKEN_ENABLED) {
372 		if ((how & ENONLY) == 0)
373 			return;
374 	} else {
375 		if ((how & DISONLY) == 0)
376 			return;
377 	}
378 
379 	switch (how & (TERSE|ONECOL)) {
380 	case 0:
381 	case ONECOL:
382 		printf("%-16s %-8s", rec->uname,
383 		  rec->flags & TOKEN_ENABLED ? "enabled" : "disabled");
384 
385 		for (i = 1; i; i <<= 1)
386 			if (rec->mode & i)
387 				printf(" %s", token_getmode(i));
388 		printf("\n");
389 		break;
390 	case TERSE:
391 		if ((count & 3) == 3)
392 			printf("%s\n", rec->uname);
393 		else
394 			printf("%-16s ", rec->uname);
395 		break;
396 	case TERSE|ONECOL:
397 		printf("%s\n", rec->uname);
398 		break;
399 	}
400 	++count;
401 }
402