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