/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * wtmpfix - adjust wtmpx file and remove date changes. * wtmpfix wtmpx2 * * code are added to really fix wtmpx if it is corrupted .. */ #include #include #include #include "acctdef.h" #include #include #include #include #include #include #include #define MAXRUNTIME 3600 /* time out after 1 hour */ #define DAYEPOCH (60 * 60 * 24) #define wout(f, w) fwrite(w, sizeof (struct utmpx), 1, f); FILE *Wtmpx, *Opw; FILE *fp; char Ofile[] = "/tmp/wXXXXXX"; static char time_buf[50]; struct dtab { off_t d_off1; /* file offset start */ off_t d_off2; /* file offset stop */ time_t d_adj; /* time adjustment */ struct dtab *d_ndp; /* next record */ }; struct dtab *Fdp; /* list header */ struct dtab *Ldp; /* list trailer */ time_t lastmonth, nextmonth; off_t recno; struct utmpx Ut, Ut2; int year, month; int ch; int n; int multimode; /* multi user mode WHCC */ static int winp(FILE *, struct utmpx *); static void mkdtab(off_t); static void setdtab(off_t, struct utmpx *, struct utmpx *); static void adjust(off_t, struct utmpx *); static int invalid(char *); static void intr(int) __NORETURN; static void scanfile(void); static int inrange(void); static void wabort(int); int main(int argc, char **argv) { time_t tloc; struct tm *tmp; int fd; (void) setlocale(LC_ALL, ""); setbuf(stdout, NULL); alarm(MAXRUNTIME); if (signal(SIGALRM, wabort) == SIG_ERR) { perror("signal"); return (1); } if (signal(SIGINT, intr) == SIG_ERR) { perror("signal"); return (1); } time(&tloc); tmp = localtime(&tloc); year = tmp->tm_year; month = tmp->tm_mon + 1; lastmonth = ((year + 1900 - 1970) * 365 + (month - 1) * 30) * DAYEPOCH; nextmonth = ((year + 1900 - 1970) * 365 + (month + 1) * 30) * DAYEPOCH; if (argc < 2) { argv[argc] = "-"; argc++; } if ((fd = mkstemp(Ofile)) == -1) { fprintf(stderr, "cannot make temporary: %s\n", Ofile); intr(0); } if ((Opw = fdopen(fd, "w")) == NULL) { fprintf(stderr, "cannot open temporary: %s\n", Ofile); intr(0); } while (--argc > 0) { argv++; if (strcmp(*argv, "-") == 0) Wtmpx = stdin; else if ((Wtmpx = fopen(*argv, "r")) == NULL) { fprintf(stderr, "Cannot open: %s\n", *argv); intr(0); } scanfile(); if (Wtmpx != stdin) fclose(Wtmpx); } fclose(Opw); if ((Opw = fopen(Ofile, "r")) == NULL) { fprintf(stderr, "Cannot read from temp: %s\n", Ofile); intr(0); } recno = 0; while (winp(Opw, &Ut)) { adjust(recno, &Ut); recno += sizeof (struct utmpx); wout(stdout, &Ut); } fclose(Opw); unlink(Ofile); return (0); } static int winp(FILE *f, struct utmpx *w) { if (fread(w, sizeof (struct utmpx), 1, f) != 1) return (0); if ((w->ut_type >= EMPTY) && (w->ut_type <= UTMAXTYPE)) return (1); else { fprintf(stderr, "Bad file at offset %ld\n", ftell(f) - sizeof (struct utmpx)); cftime(time_buf, DATE_FMT, &w->ut_xtime); fprintf(stderr, "%-12s %-8s %lu %s", w->ut_line, w->ut_user, w->ut_xtime, time_buf); intr(0); } /* NOTREACHED */ } static void mkdtab(off_t p) { struct dtab *dp; dp = Ldp; if (dp == NULL) { dp = calloc(sizeof (struct dtab), 1); if (dp == NULL) { fprintf(stderr, "out of core\n"); intr(0); } Fdp = Ldp = dp; } dp->d_off1 = p; } static void setdtab(off_t p, struct utmpx *w1, struct utmpx *w2) { struct dtab *dp; if ((dp = Ldp) == NULL) { fprintf(stderr, "no dtab\n"); intr(0); } dp->d_off2 = p; dp->d_adj = w2->ut_xtime - w1->ut_xtime; if ((Ldp = calloc(sizeof (struct dtab), 1)) == NULL) { fprintf(stderr, "out of core\n"); intr(0); } Ldp->d_off1 = dp->d_off1; dp->d_ndp = Ldp; } static void adjust(off_t p, struct utmpx *w) { off_t pp; struct dtab *dp; pp = p; for (dp = Fdp; dp != NULL; dp = dp->d_ndp) { if (dp->d_adj == 0) continue; if (pp >= dp->d_off1 && pp < dp->d_off2) w->ut_xtime += dp->d_adj; } } /* * invalid() determines whether the name field adheres to * the criteria set forth in acctcon1. If the name violates * conventions, it returns a truth value meaning the name is * invalid; if the name is okay, it returns false indicating * the name is not invalid. */ static int invalid(char *name) { int i; for (i = 0; i < NSZ; i++) { if (name[i] == '\0') return (VALID); if (! (isalnum(name[i]) || (name[i] == '$') || (name[i] == ' ') || (name[i] == '.') || (name[i] == '_') || (name[i] == '-'))) { return (INVALID); } } return (VALID); } static void intr(int sig) { signal(SIGINT, SIG_IGN); unlink(Ofile); exit(1); } /* * scanfile: * 1) reads the file, to see if the record is within reasonable * range; if not, then it will scan the file, delete foreign stuff. * 2) enter setdtab if in multiuser mode * 3) change bad login names to INVALID */ static void scanfile() { while ((n = fread(&Ut, sizeof (Ut), 1, Wtmpx)) > 0) { if (n == 0) { unlink(Ofile); exit(0); } if (!inrange()) { for (;;) { if (fseek(Wtmpx, -(off_t)sizeof (Ut), 1) != 0) { perror("seek error\n"); exit(1); } if ((ch = getc(Wtmpx)) == EOF) { perror("read\n"); exit(1); } fprintf(stderr, "checking offset %lo\n", ftell(Wtmpx)); if (fread(&Ut, sizeof (Ut), 1, Wtmpx) == 0) { exit(1); } if (inrange()) break; } } /* Now we have a good utmpx record, do more processing */ #define UTYPE Ut.ut_type #define ULINE Ut.ut_line if (recno == 0 || UTYPE == BOOT_TIME) mkdtab(recno); if (UTYPE == RUN_LVL) { if (strncmp(ULINE, "run-level S", 11) == 0) multimode = 0; if (strncmp(ULINE, "run-level 2", 11) == 0) multimode++; } if (invalid(Ut.ut_name)) { fprintf(stderr, "wtmpfix: logname \"%*.*s\" changed " "to \"INVALID\"\n", OUTPUT_NSZ, OUTPUT_NSZ, Ut.ut_name); (void) strncpy(Ut.ut_name, "INVALID", NSZ); } if (UTYPE == OLD_TIME) { if (!winp(Wtmpx, &Ut2)) { fprintf(stderr, "Input truncated at " "offset %ld\n", recno); intr(0); } if (Ut2.ut_type != NEW_TIME) { fprintf(stderr, "New date expected at " "offset %ld", recno); intr(0); } if (multimode) /* multiuser */ setdtab(recno, &Ut, &Ut2); recno += (2 * sizeof (struct utmpx)); wout(Opw, &Ut); wout(Opw, &Ut2); continue; } wout(Opw, &Ut); recno += sizeof (struct utmpx); } } static int inrange() { if ((strcmp(Ut.ut_line, RUNLVL_MSG) == 0) || (strcmp(Ut.ut_line, BOOT_MSG) == 0) || (strcmp(Ut.ut_line, "acctg on") == 0) || (strcmp(Ut.ut_line, OTIME_MSG) == 0) || (strcmp(Ut.ut_line, NTIME_MSG) == 0)) return (1); if (Ut.ut_id != 0 && Ut.ut_xtime > 0 && Ut.ut_xtime > lastmonth && Ut.ut_xtime < nextmonth && Ut.ut_type >= EMPTY && Ut.ut_type <= UTMAXTYPE && Ut.ut_pid >= 0) return (1); return (0); } static void wabort(int sig) { fprintf(stderr, "give up\n"); exit(1); }