1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 1993-2002 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28*0Sstevel@tonic-gate /* All Rights Reserved */ 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 32*0Sstevel@tonic-gate /* 33*0Sstevel@tonic-gate * wtmpfix - adjust wtmpx file and remove date changes. 34*0Sstevel@tonic-gate * wtmpfix <wtmpx1 >wtmpx2 35*0Sstevel@tonic-gate * 36*0Sstevel@tonic-gate * code are added to really fix wtmpx if it is corrupted .. 37*0Sstevel@tonic-gate */ 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gate #include <stdio.h> 40*0Sstevel@tonic-gate #include <sys/types.h> 41*0Sstevel@tonic-gate #include <sys/param.h> 42*0Sstevel@tonic-gate #include "acctdef.h" 43*0Sstevel@tonic-gate #include <utmpx.h> 44*0Sstevel@tonic-gate #include <signal.h> 45*0Sstevel@tonic-gate #include <time.h> 46*0Sstevel@tonic-gate #include <ctype.h> 47*0Sstevel@tonic-gate #include <locale.h> 48*0Sstevel@tonic-gate #include <limits.h> 49*0Sstevel@tonic-gate #include <stdlib.h> 50*0Sstevel@tonic-gate 51*0Sstevel@tonic-gate #define MAXRUNTIME 3600 /* time out after 1 hour */ 52*0Sstevel@tonic-gate #define DAYEPOCH (60 * 60 * 24) 53*0Sstevel@tonic-gate #define wout(f, w) fwrite(w, sizeof (struct utmpx), 1, f); 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate FILE *Wtmpx, *Opw; 56*0Sstevel@tonic-gate FILE *fp; 57*0Sstevel@tonic-gate char Ofile[] = "/tmp/wXXXXXX"; 58*0Sstevel@tonic-gate static char time_buf[50]; 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate struct dtab 61*0Sstevel@tonic-gate { 62*0Sstevel@tonic-gate off_t d_off1; /* file offset start */ 63*0Sstevel@tonic-gate off_t d_off2; /* file offset stop */ 64*0Sstevel@tonic-gate time_t d_adj; /* time adjustment */ 65*0Sstevel@tonic-gate struct dtab *d_ndp; /* next record */ 66*0Sstevel@tonic-gate }; 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate struct dtab *Fdp; /* list header */ 69*0Sstevel@tonic-gate struct dtab *Ldp; /* list trailer */ 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate time_t lastmonth, nextmonth; 72*0Sstevel@tonic-gate off_t recno; 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate struct utmpx Ut, Ut2; 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate int year, month; 77*0Sstevel@tonic-gate int ch; 78*0Sstevel@tonic-gate int n; 79*0Sstevel@tonic-gate int multimode; /* multi user mode WHCC */ 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate static int winp(FILE *, struct utmpx *); 82*0Sstevel@tonic-gate static void mkdtab(off_t); 83*0Sstevel@tonic-gate static void setdtab(off_t, struct utmpx *, struct utmpx *); 84*0Sstevel@tonic-gate static void adjust(off_t, struct utmpx *); 85*0Sstevel@tonic-gate static int invalid(char *); 86*0Sstevel@tonic-gate static void intr(int); 87*0Sstevel@tonic-gate static void scanfile(void); 88*0Sstevel@tonic-gate static int inrange(void); 89*0Sstevel@tonic-gate static void wabort(int); 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate int 92*0Sstevel@tonic-gate main(int argc, char **argv) 93*0Sstevel@tonic-gate { 94*0Sstevel@tonic-gate time_t tloc; 95*0Sstevel@tonic-gate struct tm *tmp; 96*0Sstevel@tonic-gate int fd; 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 99*0Sstevel@tonic-gate setbuf(stdout, NULL); 100*0Sstevel@tonic-gate alarm(MAXRUNTIME); 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gate if (signal(SIGALRM, wabort) == SIG_ERR) { 103*0Sstevel@tonic-gate perror("signal"); 104*0Sstevel@tonic-gate return (1); 105*0Sstevel@tonic-gate } 106*0Sstevel@tonic-gate if (signal(SIGINT, intr) == SIG_ERR) { 107*0Sstevel@tonic-gate perror("signal"); 108*0Sstevel@tonic-gate return (1); 109*0Sstevel@tonic-gate } 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate time(&tloc); 112*0Sstevel@tonic-gate tmp = localtime(&tloc); 113*0Sstevel@tonic-gate year = tmp->tm_year; 114*0Sstevel@tonic-gate month = tmp->tm_mon + 1; 115*0Sstevel@tonic-gate lastmonth = ((year + 1900 - 1970) * 365 + 116*0Sstevel@tonic-gate (month - 1) * 30) * DAYEPOCH; 117*0Sstevel@tonic-gate nextmonth = ((year + 1900 - 1970) * 365 + 118*0Sstevel@tonic-gate (month + 1) * 30) * DAYEPOCH; 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate if (argc < 2) { 121*0Sstevel@tonic-gate argv[argc] = "-"; 122*0Sstevel@tonic-gate argc++; 123*0Sstevel@tonic-gate } 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate if ((fd = mkstemp(Ofile)) == -1) { 126*0Sstevel@tonic-gate fprintf(stderr, "cannot make temporary: %s\n", Ofile); 127*0Sstevel@tonic-gate intr(0); 128*0Sstevel@tonic-gate } 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate if ((Opw = fdopen(fd, "w")) == NULL) { 131*0Sstevel@tonic-gate fprintf(stderr, "cannot open temporary: %s\n", Ofile); 132*0Sstevel@tonic-gate intr(0); 133*0Sstevel@tonic-gate } 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate while (--argc > 0) { 136*0Sstevel@tonic-gate argv++; 137*0Sstevel@tonic-gate if (strcmp(*argv, "-") == 0) 138*0Sstevel@tonic-gate Wtmpx = stdin; 139*0Sstevel@tonic-gate else if ((Wtmpx = fopen(*argv, "r")) == NULL) { 140*0Sstevel@tonic-gate fprintf(stderr, "Cannot open: %s\n", *argv); 141*0Sstevel@tonic-gate intr(0); 142*0Sstevel@tonic-gate } 143*0Sstevel@tonic-gate scanfile(); 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gate if (Wtmpx != stdin) 146*0Sstevel@tonic-gate fclose(Wtmpx); 147*0Sstevel@tonic-gate } 148*0Sstevel@tonic-gate fclose(Opw); 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate if ((Opw = fopen(Ofile, "r")) == NULL) { 151*0Sstevel@tonic-gate fprintf(stderr, "Cannot read from temp: %s\n", Ofile); 152*0Sstevel@tonic-gate intr(0); 153*0Sstevel@tonic-gate } 154*0Sstevel@tonic-gate recno = 0; 155*0Sstevel@tonic-gate while (winp(Opw, &Ut)) { 156*0Sstevel@tonic-gate adjust(recno, &Ut); 157*0Sstevel@tonic-gate recno += sizeof (struct utmpx); 158*0Sstevel@tonic-gate wout(stdout, &Ut); 159*0Sstevel@tonic-gate } 160*0Sstevel@tonic-gate fclose(Opw); 161*0Sstevel@tonic-gate unlink(Ofile); 162*0Sstevel@tonic-gate return (0); 163*0Sstevel@tonic-gate } 164*0Sstevel@tonic-gate 165*0Sstevel@tonic-gate static int 166*0Sstevel@tonic-gate winp(FILE *f, struct utmpx *w) 167*0Sstevel@tonic-gate { 168*0Sstevel@tonic-gate if (fread(w, sizeof (struct utmpx), 1, f) != 1) 169*0Sstevel@tonic-gate return (0); 170*0Sstevel@tonic-gate if ((w->ut_type >= EMPTY) && (w->ut_type <= UTMAXTYPE)) 171*0Sstevel@tonic-gate return (1); 172*0Sstevel@tonic-gate else { 173*0Sstevel@tonic-gate fprintf(stderr, "Bad file at offset %ld\n", 174*0Sstevel@tonic-gate ftell(f) - sizeof (struct utmpx)); 175*0Sstevel@tonic-gate cftime(time_buf, DATE_FMT, &w->ut_xtime); 176*0Sstevel@tonic-gate fprintf(stderr, "%-12s %-8s %lu %s", 177*0Sstevel@tonic-gate w->ut_line, w->ut_user, w->ut_xtime, time_buf); 178*0Sstevel@tonic-gate intr(0); 179*0Sstevel@tonic-gate } 180*0Sstevel@tonic-gate /* NOTREACHED */ 181*0Sstevel@tonic-gate } 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate static void 184*0Sstevel@tonic-gate mkdtab(off_t p) 185*0Sstevel@tonic-gate { 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate struct dtab *dp; 188*0Sstevel@tonic-gate 189*0Sstevel@tonic-gate dp = Ldp; 190*0Sstevel@tonic-gate if (dp == NULL) { 191*0Sstevel@tonic-gate dp = calloc(sizeof (struct dtab), 1); 192*0Sstevel@tonic-gate if (dp == NULL) { 193*0Sstevel@tonic-gate fprintf(stderr, "out of core\n"); 194*0Sstevel@tonic-gate intr(0); 195*0Sstevel@tonic-gate } 196*0Sstevel@tonic-gate Fdp = Ldp = dp; 197*0Sstevel@tonic-gate } 198*0Sstevel@tonic-gate dp->d_off1 = p; 199*0Sstevel@tonic-gate } 200*0Sstevel@tonic-gate 201*0Sstevel@tonic-gate static void 202*0Sstevel@tonic-gate setdtab(off_t p, struct utmpx *w1, struct utmpx *w2) 203*0Sstevel@tonic-gate { 204*0Sstevel@tonic-gate struct dtab *dp; 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate if ((dp = Ldp) == NULL) { 207*0Sstevel@tonic-gate fprintf(stderr, "no dtab\n"); 208*0Sstevel@tonic-gate intr(0); 209*0Sstevel@tonic-gate } 210*0Sstevel@tonic-gate dp->d_off2 = p; 211*0Sstevel@tonic-gate dp->d_adj = w2->ut_xtime - w1->ut_xtime; 212*0Sstevel@tonic-gate if ((Ldp = calloc(sizeof (struct dtab), 1)) == NULL) { 213*0Sstevel@tonic-gate fprintf(stderr, "out of core\n"); 214*0Sstevel@tonic-gate intr(0); 215*0Sstevel@tonic-gate } 216*0Sstevel@tonic-gate Ldp->d_off1 = dp->d_off1; 217*0Sstevel@tonic-gate dp->d_ndp = Ldp; 218*0Sstevel@tonic-gate } 219*0Sstevel@tonic-gate 220*0Sstevel@tonic-gate static void 221*0Sstevel@tonic-gate adjust(off_t p, struct utmpx *w) 222*0Sstevel@tonic-gate { 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate off_t pp; 225*0Sstevel@tonic-gate struct dtab *dp; 226*0Sstevel@tonic-gate 227*0Sstevel@tonic-gate pp = p; 228*0Sstevel@tonic-gate 229*0Sstevel@tonic-gate for (dp = Fdp; dp != NULL; dp = dp->d_ndp) { 230*0Sstevel@tonic-gate if (dp->d_adj == 0) 231*0Sstevel@tonic-gate continue; 232*0Sstevel@tonic-gate if (pp >= dp->d_off1 && pp < dp->d_off2) 233*0Sstevel@tonic-gate w->ut_xtime += dp->d_adj; 234*0Sstevel@tonic-gate } 235*0Sstevel@tonic-gate } 236*0Sstevel@tonic-gate 237*0Sstevel@tonic-gate /* 238*0Sstevel@tonic-gate * invalid() determines whether the name field adheres to 239*0Sstevel@tonic-gate * the criteria set forth in acctcon1. If the name violates 240*0Sstevel@tonic-gate * conventions, it returns a truth value meaning the name is 241*0Sstevel@tonic-gate * invalid; if the name is okay, it returns false indicating 242*0Sstevel@tonic-gate * the name is not invalid. 243*0Sstevel@tonic-gate */ 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate static int 246*0Sstevel@tonic-gate invalid(char *name) 247*0Sstevel@tonic-gate { 248*0Sstevel@tonic-gate int i; 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate for (i = 0; i < NSZ; i++) { 251*0Sstevel@tonic-gate if (name[i] == '\0') 252*0Sstevel@tonic-gate return (VALID); 253*0Sstevel@tonic-gate if (! (isalnum(name[i]) || (name[i] == '$') || 254*0Sstevel@tonic-gate (name[i] == ' ') || (name[i] == '.') || 255*0Sstevel@tonic-gate (name[i] == '_') || (name[i] == '-'))) { 256*0Sstevel@tonic-gate return (INVALID); 257*0Sstevel@tonic-gate } 258*0Sstevel@tonic-gate } 259*0Sstevel@tonic-gate return (VALID); 260*0Sstevel@tonic-gate } 261*0Sstevel@tonic-gate 262*0Sstevel@tonic-gate static void 263*0Sstevel@tonic-gate intr(int sig) 264*0Sstevel@tonic-gate { 265*0Sstevel@tonic-gate signal(SIGINT, SIG_IGN); 266*0Sstevel@tonic-gate unlink(Ofile); 267*0Sstevel@tonic-gate exit(1); 268*0Sstevel@tonic-gate } 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate /* 271*0Sstevel@tonic-gate * scanfile: 272*0Sstevel@tonic-gate * 1) reads the file, to see if the record is within reasonable 273*0Sstevel@tonic-gate * range; if not, then it will scan the file, delete foreign stuff. 274*0Sstevel@tonic-gate * 2) enter setdtab if in multiuser mode 275*0Sstevel@tonic-gate * 3) change bad login names to INVALID 276*0Sstevel@tonic-gate */ 277*0Sstevel@tonic-gate 278*0Sstevel@tonic-gate static void 279*0Sstevel@tonic-gate scanfile() 280*0Sstevel@tonic-gate { 281*0Sstevel@tonic-gate while ((n = fread(&Ut, sizeof (Ut), 1, Wtmpx)) > 0) { 282*0Sstevel@tonic-gate if (n == 0) { 283*0Sstevel@tonic-gate unlink(Ofile); 284*0Sstevel@tonic-gate exit(0); 285*0Sstevel@tonic-gate } 286*0Sstevel@tonic-gate if (!inrange()) { 287*0Sstevel@tonic-gate for (;;) { 288*0Sstevel@tonic-gate if (fseek(Wtmpx, 289*0Sstevel@tonic-gate -(off_t)sizeof (Ut), 1) != 0) { 290*0Sstevel@tonic-gate perror("seek error\n"); 291*0Sstevel@tonic-gate exit(1); 292*0Sstevel@tonic-gate } 293*0Sstevel@tonic-gate if ((ch = getc(Wtmpx)) == EOF) { 294*0Sstevel@tonic-gate perror("read\n"); 295*0Sstevel@tonic-gate exit(1); 296*0Sstevel@tonic-gate } 297*0Sstevel@tonic-gate fprintf(stderr, "checking offset %lo\n", 298*0Sstevel@tonic-gate ftell(Wtmpx)); 299*0Sstevel@tonic-gate if (fread(&Ut, sizeof (Ut), 1, Wtmpx) == 0) { 300*0Sstevel@tonic-gate exit(1); 301*0Sstevel@tonic-gate } 302*0Sstevel@tonic-gate if (inrange()) 303*0Sstevel@tonic-gate break; 304*0Sstevel@tonic-gate } 305*0Sstevel@tonic-gate } 306*0Sstevel@tonic-gate /* Now we have a good utmpx record, do more processing */ 307*0Sstevel@tonic-gate 308*0Sstevel@tonic-gate #define UTYPE Ut.ut_type 309*0Sstevel@tonic-gate #define ULINE Ut.ut_line 310*0Sstevel@tonic-gate 311*0Sstevel@tonic-gate if (recno == 0 || UTYPE == BOOT_TIME) 312*0Sstevel@tonic-gate mkdtab(recno); 313*0Sstevel@tonic-gate if (UTYPE == RUN_LVL) { 314*0Sstevel@tonic-gate if (strncmp(ULINE, "run-level S", 11) == 0) 315*0Sstevel@tonic-gate multimode = 0; 316*0Sstevel@tonic-gate if (strncmp(ULINE, "run-level 2", 11) == 0) 317*0Sstevel@tonic-gate multimode++; 318*0Sstevel@tonic-gate } 319*0Sstevel@tonic-gate if (invalid(Ut.ut_name)) { 320*0Sstevel@tonic-gate fprintf(stderr, 321*0Sstevel@tonic-gate "wtmpfix: logname \"%*.*s\" changed " 322*0Sstevel@tonic-gate "to \"INVALID\"\n", OUTPUT_NSZ, 323*0Sstevel@tonic-gate OUTPUT_NSZ, Ut.ut_name); 324*0Sstevel@tonic-gate (void) strncpy(Ut.ut_name, "INVALID", NSZ); 325*0Sstevel@tonic-gate } 326*0Sstevel@tonic-gate if (UTYPE == OLD_TIME) { 327*0Sstevel@tonic-gate if (!winp(Wtmpx, &Ut2)) { 328*0Sstevel@tonic-gate fprintf(stderr, "Input truncated at " 329*0Sstevel@tonic-gate "offset %ld\n", recno); 330*0Sstevel@tonic-gate intr(0); 331*0Sstevel@tonic-gate } 332*0Sstevel@tonic-gate if (Ut2.ut_type != NEW_TIME) { 333*0Sstevel@tonic-gate fprintf(stderr, "New date expected at " 334*0Sstevel@tonic-gate "offset %ld", recno); 335*0Sstevel@tonic-gate intr(0); 336*0Sstevel@tonic-gate } 337*0Sstevel@tonic-gate if (multimode) /* multiuser */ 338*0Sstevel@tonic-gate setdtab(recno, &Ut, &Ut2); 339*0Sstevel@tonic-gate recno += (2 * sizeof (struct utmpx)); 340*0Sstevel@tonic-gate wout(Opw, &Ut); 341*0Sstevel@tonic-gate wout(Opw, &Ut2); 342*0Sstevel@tonic-gate continue; 343*0Sstevel@tonic-gate } 344*0Sstevel@tonic-gate wout(Opw, &Ut); 345*0Sstevel@tonic-gate recno += sizeof (struct utmpx); 346*0Sstevel@tonic-gate } 347*0Sstevel@tonic-gate } 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate static int 350*0Sstevel@tonic-gate inrange() 351*0Sstevel@tonic-gate { 352*0Sstevel@tonic-gate if ((strcmp(Ut.ut_line, RUNLVL_MSG) == 0) || 353*0Sstevel@tonic-gate (strcmp(Ut.ut_line, BOOT_MSG) == 0) || 354*0Sstevel@tonic-gate (strcmp(Ut.ut_line, "acctg on") == 0) || 355*0Sstevel@tonic-gate (strcmp(Ut.ut_line, OTIME_MSG) == 0) || 356*0Sstevel@tonic-gate (strcmp(Ut.ut_line, NTIME_MSG) == 0)) 357*0Sstevel@tonic-gate return (1); 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate if (Ut.ut_id != 0 && 360*0Sstevel@tonic-gate Ut.ut_xtime > 0 && 361*0Sstevel@tonic-gate Ut.ut_xtime > lastmonth && 362*0Sstevel@tonic-gate Ut.ut_xtime < nextmonth && 363*0Sstevel@tonic-gate Ut.ut_type >= EMPTY && 364*0Sstevel@tonic-gate Ut.ut_type <= UTMAXTYPE && 365*0Sstevel@tonic-gate Ut.ut_pid >= 0) 366*0Sstevel@tonic-gate return (1); 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate return (0); 369*0Sstevel@tonic-gate } 370*0Sstevel@tonic-gate 371*0Sstevel@tonic-gate static void 372*0Sstevel@tonic-gate wabort(int sig) 373*0Sstevel@tonic-gate { 374*0Sstevel@tonic-gate fprintf(stderr, "give up\n"); 375*0Sstevel@tonic-gate exit(1); 376*0Sstevel@tonic-gate } 377