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