xref: /openbsd-src/usr.sbin/tokenadm/tokenadm.c (revision fe266b8dbb140fb7855a7f892731e868a51d6828)
1*fe266b8dSbluhm /*	$OpenBSD: tokenadm.c,v 1.12 2016/03/22 00:06:55 bluhm Exp $	*/
2851d2d47Smillert 
3851d2d47Smillert /*-
4851d2d47Smillert  * Copyright (c) 1995 Migration Associates Corp. All Rights Reserved
5851d2d47Smillert  *
6851d2d47Smillert  * Redistribution and use in source and binary forms, with or without
7851d2d47Smillert  * modification, are permitted provided that the following conditions
8851d2d47Smillert  * are met:
9851d2d47Smillert  * 1. Redistributions of source code must retain the above copyright
10851d2d47Smillert  *    notice, this list of conditions and the following disclaimer.
11851d2d47Smillert  * 2. Redistributions in binary form must reproduce the above copyright
12851d2d47Smillert  *    notice, this list of conditions and the following disclaimer in the
13851d2d47Smillert  *    documentation and/or other materials provided with the distribution.
14851d2d47Smillert  * 3. All advertising materials mentioning features or use of this software
15851d2d47Smillert  *    must display the following acknowledgement:
16851d2d47Smillert  *      This product includes software developed by Berkeley Software Design,
17851d2d47Smillert  *      Inc.
18851d2d47Smillert  * 4. The name of Berkeley Software Design, Inc.  may not be used to endorse
19851d2d47Smillert  *    or promote products derived from this software without specific prior
20851d2d47Smillert  *    written permission.
21851d2d47Smillert  *
22851d2d47Smillert  * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND
23851d2d47Smillert  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24851d2d47Smillert  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25851d2d47Smillert  * ARE DISCLAIMED.  IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE
26851d2d47Smillert  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27851d2d47Smillert  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28851d2d47Smillert  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29851d2d47Smillert  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30851d2d47Smillert  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31851d2d47Smillert  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32851d2d47Smillert  * SUCH DAMAGE.
33851d2d47Smillert  *
34851d2d47Smillert  *	BSDI $From: tokenadm.c,v 1.2 1996/10/17 00:54:28 prb Exp $
35851d2d47Smillert  */
36851d2d47Smillert 
37b9fc9a72Sderaadt #include <sys/signal.h>
38851d2d47Smillert #include <sys/resource.h>
39851d2d47Smillert #include <sys/time.h>
40851d2d47Smillert 
41851d2d47Smillert #include <err.h>
42851d2d47Smillert #include <errno.h>
43851d2d47Smillert #include <stdio.h>
44851d2d47Smillert #include <syslog.h>
45851d2d47Smillert #include <stdlib.h>
46851d2d47Smillert #include <unistd.h>
47b9fc9a72Sderaadt #include <limits.h>
48851d2d47Smillert #include <string.h>
49851d2d47Smillert 
50851d2d47Smillert #include "token.h"
51851d2d47Smillert #include "tokendb.h"
52851d2d47Smillert 
53851d2d47Smillert 
54851d2d47Smillert typedef enum { LIST, ENABLE, DISABLE, REMOVE, MODECH } what_t;
55851d2d47Smillert typedef enum {
56851d2d47Smillert 	NOBANNER = 0x01,
57851d2d47Smillert 	TERSE = 0x02,
58851d2d47Smillert 	ENONLY = 0x04,
59851d2d47Smillert 	DISONLY = 0x08,
60851d2d47Smillert 	ONECOL = 0x10,
614f67eb1dSderaadt 	REVERSE = 0x20
62851d2d47Smillert } how_t;
63851d2d47Smillert 
64851d2d47Smillert static	int	force_unlock(char *);
65851d2d47Smillert static	int	process_record(char *, unsigned, unsigned);
66851d2d47Smillert static	int	process_modes(char *, unsigned, unsigned);
67851d2d47Smillert static  void	print_record(TOKENDB_Rec *, how_t);
68851d2d47Smillert 
69851d2d47Smillert extern	int
main(int argc,char ** argv)70851d2d47Smillert main(int argc, char **argv)
71851d2d47Smillert {
72851d2d47Smillert 	int c, errors;
73851d2d47Smillert 	u_int emode, dmode, pmode;
74851d2d47Smillert 	struct rlimit cds;
75851d2d47Smillert 	what_t what;
76851d2d47Smillert 	how_t how;
77851d2d47Smillert 	TOKENDB_Rec tokenrec;
78851d2d47Smillert 
79851d2d47Smillert 	what = LIST;
80851d2d47Smillert 	emode = dmode = 0;
81851d2d47Smillert 	pmode = 0;
82851d2d47Smillert 	errors = 0;
83851d2d47Smillert 	how = 0;
84851d2d47Smillert 
85851d2d47Smillert 	(void)signal(SIGQUIT, SIG_IGN);
86851d2d47Smillert 	(void)signal(SIGINT, SIG_IGN);
87851d2d47Smillert 	(void)setpriority(PRIO_PROCESS, 0, 0);
88851d2d47Smillert 
89851d2d47Smillert 	openlog(NULL, LOG_ODELAY, LOG_AUTH);
90851d2d47Smillert 
91851d2d47Smillert 	/*
92851d2d47Smillert 	 * Make sure we never dump core as we might have a
93851d2d47Smillert 	 * valid user shared-secret in memory.
94851d2d47Smillert 	 */
95851d2d47Smillert 
96851d2d47Smillert 	cds.rlim_cur = 0;
97851d2d47Smillert 	cds.rlim_max = 0;
98851d2d47Smillert 	if (setrlimit(RLIMIT_CORE, &cds) < 0)
99851d2d47Smillert 		syslog(LOG_ERR, "couldn't set core dump size to 0: %m");
100851d2d47Smillert 
1010ef08ec4Smestre 	if (pledge("stdio rpath wpath cpath fattr flock getpw", NULL) == -1)
1020ef08ec4Smestre 		err(1, "pledge");
1030ef08ec4Smestre 
104*fe266b8dSbluhm 	if (token_init(argv[0]) < 0) {
105*fe266b8dSbluhm 		syslog(LOG_ERR, "unknown token type");
106*fe266b8dSbluhm 		errx(1, "unknown token type");
107*fe266b8dSbluhm 	}
108*fe266b8dSbluhm 
10967e491c4Saaron 	while ((c = getopt(argc, argv, "BDERT1dem:r")) != -1)
110851d2d47Smillert 		switch (c) {
111851d2d47Smillert 		case 'B':
112851d2d47Smillert 			if (what != LIST)
113851d2d47Smillert 				goto usage;
114851d2d47Smillert 			how |= NOBANNER;
115851d2d47Smillert 			break;
116851d2d47Smillert 		case 'T':
117851d2d47Smillert 			if (what != LIST)
118851d2d47Smillert 				goto usage;
119851d2d47Smillert 			how |= TERSE;
120851d2d47Smillert 			break;
121851d2d47Smillert 		case '1':
122851d2d47Smillert 			if (what != LIST)
123851d2d47Smillert 				goto usage;
124851d2d47Smillert 			how |= ONECOL;
125851d2d47Smillert 			break;
126851d2d47Smillert 		case 'D':
127851d2d47Smillert 			if (what != LIST)
128851d2d47Smillert 				goto usage;
129851d2d47Smillert 			how |= DISONLY;
130851d2d47Smillert 			break;
131851d2d47Smillert 		case 'E':
132851d2d47Smillert 			if (what != LIST)
133851d2d47Smillert 				goto usage;
134851d2d47Smillert 			how |= ENONLY;
135851d2d47Smillert 			break;
136851d2d47Smillert 		case 'R':
137851d2d47Smillert 			if (what != LIST)
138851d2d47Smillert 				goto usage;
139851d2d47Smillert 			how |= REVERSE;
140851d2d47Smillert 			break;
141851d2d47Smillert 		case 'd':
142851d2d47Smillert 			if (what != LIST || how)
143851d2d47Smillert 				goto usage;
144851d2d47Smillert 			what = DISABLE;
145851d2d47Smillert 			break;
146851d2d47Smillert 		case 'e':
147851d2d47Smillert 			if (what != LIST || how)
148851d2d47Smillert 				goto usage;
149851d2d47Smillert 			what = ENABLE;
150851d2d47Smillert 			break;
151851d2d47Smillert 		case 'r':
152851d2d47Smillert 			if (what != LIST || emode || dmode || how)
153851d2d47Smillert 				goto usage;
154851d2d47Smillert 			what = REMOVE;
155851d2d47Smillert 			break;
156851d2d47Smillert 		case 'm':
157851d2d47Smillert 			if (what == REMOVE || how)
158851d2d47Smillert 				goto usage;
159851d2d47Smillert 			if (*optarg == '-') {
160cd1e9566Savsm 				if ((c = token_mode(optarg+1)) == 0)
161851d2d47Smillert 					errx(1, "%s: unknown mode", optarg+1);
162851d2d47Smillert 				dmode |= c;
163851d2d47Smillert 			} else {
164cd1e9566Savsm 				if ((c = token_mode(optarg)) == 0)
165851d2d47Smillert 					errx(1, "%s: unknown mode", optarg);
166851d2d47Smillert 				emode |= c;
167851d2d47Smillert 			}
168851d2d47Smillert 			break;
169851d2d47Smillert 		default:
170851d2d47Smillert 			goto usage;
171851d2d47Smillert 		}
172851d2d47Smillert 
173851d2d47Smillert 	if (what == LIST && (dmode || emode))
174851d2d47Smillert 		what = MODECH;
175851d2d47Smillert 
176851d2d47Smillert 	if (what == LIST) {
177851d2d47Smillert 		if ((how & (ENONLY|DISONLY)) == 0)
178851d2d47Smillert 			how |= ENONLY|DISONLY;
179851d2d47Smillert 		if (!(how & NOBANNER)) {
180851d2d47Smillert 			if ((how & (TERSE|ONECOL)) == (TERSE|ONECOL)) {
181851d2d47Smillert 				printf("User\n");
182851d2d47Smillert 				printf("----------------\n");
183851d2d47Smillert 			} else if (how & (TERSE)) {
184851d2d47Smillert 				printf("User             ");
185851d2d47Smillert 				printf("User             ");
186851d2d47Smillert 				printf("User             ");
187851d2d47Smillert 				printf("User\n");
188851d2d47Smillert 				printf("---------------- ");
189851d2d47Smillert 				printf("---------------- ");
190851d2d47Smillert 				printf("---------------- ");
191851d2d47Smillert 				printf("----------------\n");
192851d2d47Smillert 			} else {
193851d2d47Smillert 				printf("User             Status   Modes\n");
194851d2d47Smillert 				printf("---------------- -------- -----\n");
195851d2d47Smillert 			}
196851d2d47Smillert 		}
197851d2d47Smillert 
198851d2d47Smillert 		if (optind >= argc) {
199851d2d47Smillert 			if (tokendb_firstrec(how & REVERSE, &tokenrec))
200851d2d47Smillert 				exit(0);
201851d2d47Smillert 			do
202851d2d47Smillert 				print_record(&tokenrec, how);
203851d2d47Smillert 			while (tokendb_nextrec(how & REVERSE, &tokenrec) == 0);
204851d2d47Smillert 			print_record(NULL, how);
205851d2d47Smillert 			exit(0);
206851d2d47Smillert 		}
207851d2d47Smillert 	}
208851d2d47Smillert 
209851d2d47Smillert 	if (optind >= argc) {
210851d2d47Smillert usage:
211851d2d47Smillert 		fprintf(stderr,
212d4acc1c4Sjmc 		    "usage: %sadm [-1BDdEeRrT] [-m [-]mode] [user ...]\n",
213851d2d47Smillert 			tt->name);
214851d2d47Smillert 		exit(1);
215851d2d47Smillert 	}
216851d2d47Smillert 
217851d2d47Smillert 	argv += optind - 1;
218851d2d47Smillert 	while (*++argv)
219851d2d47Smillert 		switch (what) {
220851d2d47Smillert 		case LIST:
221851d2d47Smillert 			if (tokendb_getrec(*argv, &tokenrec)) {
222851d2d47Smillert 				printf("%s: no such user\n", *argv);
223851d2d47Smillert 				break;
224851d2d47Smillert 			}
225851d2d47Smillert 			print_record(&tokenrec, how);
226851d2d47Smillert 			break;
227851d2d47Smillert 		case REMOVE:
228851d2d47Smillert 			if (tokendb_delrec(*argv)) {
229851d2d47Smillert 				warnx("%s: could not remove", *argv);
230851d2d47Smillert 				errors++;
231851d2d47Smillert 			}
232851d2d47Smillert 			break;
233851d2d47Smillert 		case DISABLE:
234851d2d47Smillert 			if (process_record(*argv, ~TOKEN_ENABLED, 0)) {
235851d2d47Smillert 				warnx("%s: could not disable", *argv);
236851d2d47Smillert 				++errors;
237851d2d47Smillert 			}
238851d2d47Smillert 			if (emode || dmode)
239851d2d47Smillert 				goto modech;
240851d2d47Smillert 			break;
241851d2d47Smillert 		case ENABLE:
2420f7bc442Smarkus 			if (process_record(*argv, ~TOKEN_ENABLED, TOKEN_ENABLED)) {
243851d2d47Smillert 				warnx("%s: could not enable", *argv);
244851d2d47Smillert 				++errors;
245851d2d47Smillert 			}
246851d2d47Smillert 			if (emode || dmode)
247851d2d47Smillert 				goto modech;
248851d2d47Smillert 			break;
249851d2d47Smillert 		modech:
250851d2d47Smillert 		case MODECH:
251851d2d47Smillert 			if (process_modes(*argv, ~dmode, emode)) {
252851d2d47Smillert 				warnx("%s: could not change modes", *argv);
253851d2d47Smillert 				++errors;
254851d2d47Smillert 			}
255851d2d47Smillert 			break;
256851d2d47Smillert 		}
257851d2d47Smillert 
258851d2d47Smillert 	if (what == LIST)
259851d2d47Smillert 		print_record(NULL, how);
260851d2d47Smillert 
261851d2d47Smillert 	exit(errors);
262851d2d47Smillert }
263851d2d47Smillert 
264851d2d47Smillert /*
265851d2d47Smillert  * Process a user record
266851d2d47Smillert  */
267851d2d47Smillert 
268851d2d47Smillert static	int
process_record(char * username,unsigned and_mask,unsigned or_mask)269851d2d47Smillert process_record(char *username, unsigned and_mask, unsigned or_mask)
270851d2d47Smillert {
271851d2d47Smillert 	int	count = 0;
272851d2d47Smillert 	TOKENDB_Rec tokenrec;
273851d2d47Smillert 
274851d2d47Smillert retry:
275851d2d47Smillert 	switch (tokendb_lockrec(username, &tokenrec, TOKEN_LOCKED)) {
276851d2d47Smillert 	case 0:
277851d2d47Smillert 		tokenrec.flags &= and_mask;
278851d2d47Smillert 		tokenrec.flags |= or_mask;
279851d2d47Smillert 		tokenrec.flags &= ~TOKEN_LOCKED;
280851d2d47Smillert 		if (!tokendb_putrec(username, &tokenrec))
281851d2d47Smillert 			return (0);
282851d2d47Smillert 		else
283851d2d47Smillert 			return (-1);
284851d2d47Smillert 	case 1:
285851d2d47Smillert 		sleep(1);
286851d2d47Smillert 		if (count++ < 60)
287851d2d47Smillert 			goto retry;
288851d2d47Smillert 		if (force_unlock(username))
289851d2d47Smillert 			return (1);
290851d2d47Smillert 		goto retry;
291851d2d47Smillert 
292851d2d47Smillert 	case ENOENT:
293851d2d47Smillert 		warnx("%s: nonexistent user", username);
294851d2d47Smillert 		return (1);
295851d2d47Smillert 	default:
296851d2d47Smillert 		return (-1);
297851d2d47Smillert 	}
298851d2d47Smillert }
299851d2d47Smillert 
300851d2d47Smillert static	int
process_modes(char * username,unsigned and_mask,unsigned or_mask)301851d2d47Smillert process_modes(char *username, unsigned and_mask, unsigned or_mask)
302851d2d47Smillert {
303851d2d47Smillert 	int	count = 0;
304851d2d47Smillert 	TOKENDB_Rec tokenrec;
305851d2d47Smillert 
306851d2d47Smillert retry:
307851d2d47Smillert 	switch (tokendb_lockrec(username, &tokenrec, TOKEN_LOCKED)) {
308851d2d47Smillert 	case 0:
309851d2d47Smillert 		tokenrec.mode &= and_mask;
310851d2d47Smillert 		tokenrec.mode |= or_mask;
311851d2d47Smillert 		/*
312851d2d47Smillert 		 * When ever we set up for rim mode (even if we are
313851d2d47Smillert 		 * already set up for it) reset the rim key
314851d2d47Smillert 		 */
315851d2d47Smillert 		if (or_mask & TOKEN_RIM)
316851d2d47Smillert 			memset(tokenrec.rim, 0, sizeof(tokenrec.rim));
317851d2d47Smillert 		tokenrec.flags &= ~TOKEN_LOCKED;
318851d2d47Smillert 		if (!tokendb_putrec(username, &tokenrec))
319851d2d47Smillert 			return (0);
320851d2d47Smillert 		else
321851d2d47Smillert 			return (-1);
322851d2d47Smillert 	case 1:
323851d2d47Smillert 		sleep(1);
324851d2d47Smillert 		if (count++ < 60)
325851d2d47Smillert 			goto retry;
326851d2d47Smillert 		if (force_unlock(username))
327851d2d47Smillert 			return (1);
328851d2d47Smillert 		goto retry;
329851d2d47Smillert 
330851d2d47Smillert 	case ENOENT:
331851d2d47Smillert 		warnx("%s: nonexistent user", username);
332851d2d47Smillert 		return (1);
333851d2d47Smillert 	default:
334851d2d47Smillert 		return (-1);
335851d2d47Smillert 	}
336851d2d47Smillert }
337851d2d47Smillert 
338851d2d47Smillert /*
339851d2d47Smillert  * Force remove a user record-level lock.
340851d2d47Smillert  */
341851d2d47Smillert 
342851d2d47Smillert static	int
force_unlock(char * username)343851d2d47Smillert force_unlock(char *username)
344851d2d47Smillert {
345851d2d47Smillert 	TOKENDB_Rec tokenrec;
346851d2d47Smillert 
347851d2d47Smillert 	if (tokendb_getrec(username, &tokenrec))
348851d2d47Smillert 		return (-1);
349851d2d47Smillert 
350851d2d47Smillert 	tokenrec.flags &= ~TOKEN_LOCKED;
351851d2d47Smillert 	tokenrec.flags &= ~TOKEN_LOGIN;
352851d2d47Smillert 
353851d2d47Smillert 	if (tokendb_putrec(username, &tokenrec))
354851d2d47Smillert 		return (1);
355851d2d47Smillert 
356851d2d47Smillert 	return (0);
357851d2d47Smillert }
358851d2d47Smillert 
359851d2d47Smillert /*
360851d2d47Smillert  * Print a database record according to user a specified format
361851d2d47Smillert  */
362851d2d47Smillert 
363851d2d47Smillert static	void
print_record(TOKENDB_Rec * rec,how_t how)364851d2d47Smillert print_record(TOKENDB_Rec *rec, how_t how)
365851d2d47Smillert {
366851d2d47Smillert 	static int count = 0;
367851d2d47Smillert 	int i;
368851d2d47Smillert 
369851d2d47Smillert 	if (rec == NULL) {
370851d2d47Smillert 		if ((count & 3) && (how & (TERSE|ONECOL)) == TERSE)
371851d2d47Smillert 			printf("\n");
372851d2d47Smillert 		return;
373851d2d47Smillert 	}
374851d2d47Smillert 
375851d2d47Smillert 	if (rec->flags & TOKEN_ENABLED) {
376851d2d47Smillert 		if ((how & ENONLY) == 0)
377851d2d47Smillert 			return;
378851d2d47Smillert 	} else {
379851d2d47Smillert 		if ((how & DISONLY) == 0)
380851d2d47Smillert 			return;
381851d2d47Smillert 	}
382851d2d47Smillert 
383851d2d47Smillert 	switch (how & (TERSE|ONECOL)) {
384851d2d47Smillert 	case 0:
385851d2d47Smillert 	case ONECOL:
386851d2d47Smillert 		printf("%-16s %-8s", rec->uname,
387851d2d47Smillert 		  rec->flags & TOKEN_ENABLED ? "enabled" : "disabled");
388851d2d47Smillert 
389851d2d47Smillert 		for (i = 1; i; i <<= 1)
390851d2d47Smillert 			if (rec->mode & i)
391851d2d47Smillert 				printf(" %s", token_getmode(i));
392851d2d47Smillert 		printf("\n");
393851d2d47Smillert 		break;
394851d2d47Smillert 	case TERSE:
395851d2d47Smillert 		if ((count & 3) == 3)
396851d2d47Smillert 			printf("%s\n", rec->uname);
397851d2d47Smillert 		else
398851d2d47Smillert 			printf("%-16s ", rec->uname);
399851d2d47Smillert 		break;
400851d2d47Smillert 	case TERSE|ONECOL:
401851d2d47Smillert 		printf("%s\n", rec->uname);
402851d2d47Smillert 		break;
403851d2d47Smillert 	}
404851d2d47Smillert 	++count;
405851d2d47Smillert }
406