/* $OpenBSD: tokenadm.c,v 1.12 2016/03/22 00:06:55 bluhm Exp $ */ /*- * Copyright (c) 1995 Migration Associates Corp. All Rights Reserved * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Berkeley Software Design, * Inc. * 4. The name of Berkeley Software Design, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * BSDI $From: tokenadm.c,v 1.2 1996/10/17 00:54:28 prb Exp $ */ #include #include #include #include #include #include #include #include #include #include #include #include "token.h" #include "tokendb.h" typedef enum { LIST, ENABLE, DISABLE, REMOVE, MODECH } what_t; typedef enum { NOBANNER = 0x01, TERSE = 0x02, ENONLY = 0x04, DISONLY = 0x08, ONECOL = 0x10, REVERSE = 0x20 } how_t; static int force_unlock(char *); static int process_record(char *, unsigned, unsigned); static int process_modes(char *, unsigned, unsigned); static void print_record(TOKENDB_Rec *, how_t); extern int main(int argc, char **argv) { int c, errors; u_int emode, dmode, pmode; struct rlimit cds; what_t what; how_t how; TOKENDB_Rec tokenrec; what = LIST; emode = dmode = 0; pmode = 0; errors = 0; how = 0; (void)signal(SIGQUIT, SIG_IGN); (void)signal(SIGINT, SIG_IGN); (void)setpriority(PRIO_PROCESS, 0, 0); openlog(NULL, LOG_ODELAY, LOG_AUTH); /* * Make sure we never dump core as we might have a * valid user shared-secret in memory. */ cds.rlim_cur = 0; cds.rlim_max = 0; if (setrlimit(RLIMIT_CORE, &cds) < 0) syslog(LOG_ERR, "couldn't set core dump size to 0: %m"); if (pledge("stdio rpath wpath cpath fattr flock getpw", NULL) == -1) err(1, "pledge"); if (token_init(argv[0]) < 0) { syslog(LOG_ERR, "unknown token type"); errx(1, "unknown token type"); } while ((c = getopt(argc, argv, "BDERT1dem:r")) != -1) switch (c) { case 'B': if (what != LIST) goto usage; how |= NOBANNER; break; case 'T': if (what != LIST) goto usage; how |= TERSE; break; case '1': if (what != LIST) goto usage; how |= ONECOL; break; case 'D': if (what != LIST) goto usage; how |= DISONLY; break; case 'E': if (what != LIST) goto usage; how |= ENONLY; break; case 'R': if (what != LIST) goto usage; how |= REVERSE; break; case 'd': if (what != LIST || how) goto usage; what = DISABLE; break; case 'e': if (what != LIST || how) goto usage; what = ENABLE; break; case 'r': if (what != LIST || emode || dmode || how) goto usage; what = REMOVE; break; case 'm': if (what == REMOVE || how) goto usage; if (*optarg == '-') { if ((c = token_mode(optarg+1)) == 0) errx(1, "%s: unknown mode", optarg+1); dmode |= c; } else { if ((c = token_mode(optarg)) == 0) errx(1, "%s: unknown mode", optarg); emode |= c; } break; default: goto usage; } if (what == LIST && (dmode || emode)) what = MODECH; if (what == LIST) { if ((how & (ENONLY|DISONLY)) == 0) how |= ENONLY|DISONLY; if (!(how & NOBANNER)) { if ((how & (TERSE|ONECOL)) == (TERSE|ONECOL)) { printf("User\n"); printf("----------------\n"); } else if (how & (TERSE)) { printf("User "); printf("User "); printf("User "); printf("User\n"); printf("---------------- "); printf("---------------- "); printf("---------------- "); printf("----------------\n"); } else { printf("User Status Modes\n"); printf("---------------- -------- -----\n"); } } if (optind >= argc) { if (tokendb_firstrec(how & REVERSE, &tokenrec)) exit(0); do print_record(&tokenrec, how); while (tokendb_nextrec(how & REVERSE, &tokenrec) == 0); print_record(NULL, how); exit(0); } } if (optind >= argc) { usage: fprintf(stderr, "usage: %sadm [-1BDdEeRrT] [-m [-]mode] [user ...]\n", tt->name); exit(1); } argv += optind - 1; while (*++argv) switch (what) { case LIST: if (tokendb_getrec(*argv, &tokenrec)) { printf("%s: no such user\n", *argv); break; } print_record(&tokenrec, how); break; case REMOVE: if (tokendb_delrec(*argv)) { warnx("%s: could not remove", *argv); errors++; } break; case DISABLE: if (process_record(*argv, ~TOKEN_ENABLED, 0)) { warnx("%s: could not disable", *argv); ++errors; } if (emode || dmode) goto modech; break; case ENABLE: if (process_record(*argv, ~TOKEN_ENABLED, TOKEN_ENABLED)) { warnx("%s: could not enable", *argv); ++errors; } if (emode || dmode) goto modech; break; modech: case MODECH: if (process_modes(*argv, ~dmode, emode)) { warnx("%s: could not change modes", *argv); ++errors; } break; } if (what == LIST) print_record(NULL, how); exit(errors); } /* * Process a user record */ static int process_record(char *username, unsigned and_mask, unsigned or_mask) { int count = 0; TOKENDB_Rec tokenrec; retry: switch (tokendb_lockrec(username, &tokenrec, TOKEN_LOCKED)) { case 0: tokenrec.flags &= and_mask; tokenrec.flags |= or_mask; tokenrec.flags &= ~TOKEN_LOCKED; if (!tokendb_putrec(username, &tokenrec)) return (0); else return (-1); case 1: sleep(1); if (count++ < 60) goto retry; if (force_unlock(username)) return (1); goto retry; case ENOENT: warnx("%s: nonexistent user", username); return (1); default: return (-1); } } static int process_modes(char *username, unsigned and_mask, unsigned or_mask) { int count = 0; TOKENDB_Rec tokenrec; retry: switch (tokendb_lockrec(username, &tokenrec, TOKEN_LOCKED)) { case 0: tokenrec.mode &= and_mask; tokenrec.mode |= or_mask; /* * When ever we set up for rim mode (even if we are * already set up for it) reset the rim key */ if (or_mask & TOKEN_RIM) memset(tokenrec.rim, 0, sizeof(tokenrec.rim)); tokenrec.flags &= ~TOKEN_LOCKED; if (!tokendb_putrec(username, &tokenrec)) return (0); else return (-1); case 1: sleep(1); if (count++ < 60) goto retry; if (force_unlock(username)) return (1); goto retry; case ENOENT: warnx("%s: nonexistent user", username); return (1); default: return (-1); } } /* * Force remove a user record-level lock. */ static int force_unlock(char *username) { TOKENDB_Rec tokenrec; if (tokendb_getrec(username, &tokenrec)) return (-1); tokenrec.flags &= ~TOKEN_LOCKED; tokenrec.flags &= ~TOKEN_LOGIN; if (tokendb_putrec(username, &tokenrec)) return (1); return (0); } /* * Print a database record according to user a specified format */ static void print_record(TOKENDB_Rec *rec, how_t how) { static int count = 0; int i; if (rec == NULL) { if ((count & 3) && (how & (TERSE|ONECOL)) == TERSE) printf("\n"); return; } if (rec->flags & TOKEN_ENABLED) { if ((how & ENONLY) == 0) return; } else { if ((how & DISONLY) == 0) return; } switch (how & (TERSE|ONECOL)) { case 0: case ONECOL: printf("%-16s %-8s", rec->uname, rec->flags & TOKEN_ENABLED ? "enabled" : "disabled"); for (i = 1; i; i <<= 1) if (rec->mode & i) printf(" %s", token_getmode(i)); printf("\n"); break; case TERSE: if ((count & 3) == 3) printf("%s\n", rec->uname); else printf("%-16s ", rec->uname); break; case TERSE|ONECOL: printf("%s\n", rec->uname); break; } ++count; }