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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 31 32 #include <stdio.h> 33 #include <limits.h> 34 #include <stdlib.h> 35 #include <unistd.h> 36 #include <utime.h> 37 #include <sys/types.h> 38 #include <sys/param.h> 39 #include <sys/stat.h> 40 #include <sys/statvfs.h> 41 #include <grp.h> 42 #include <pwd.h> 43 #include <errno.h> 44 #include <string.h> 45 #include <stdarg.h> 46 #include <fcntl.h> 47 #include <sys/mkdev.h> 48 #include "pkgstrct.h" 49 #include "pkglib.h" 50 #include "pkglibmsgs.h" 51 #include "pkglocale.h" 52 53 #define WDMSK 0xFFFF 54 #define DATEFMT "%D %r" 55 #define LONG_BOUNDARY ((sizeof (unsigned long))-1) 56 #define CHUNK 1024*1024 57 58 static char theErrBuf[PATH_MAX+512] = {'\0'}; 59 static char *theErrStr = NULL; 60 61 /* checksum disable switch */ 62 static int enable_checksum = 1; 63 64 /* attribute disable flag */ 65 static int disable_attributes = 0; 66 67 /* non-ABI symlinks supported */ 68 static int nonabi_symlinks; 69 70 /* 71 * forward declarations 72 */ 73 74 static int clear_target(char *path, char *ftype, int is_a_dir); 75 76 unsigned long compute_checksum(int *r_err, char *path); 77 78 /* union used to generate checksum */ 79 typedef union hilo { 80 struct part { 81 uint16_t hi; 82 uint16_t lo; 83 } hl; 84 uint32_t lg; 85 } CHECKSUM_T; 86 87 /*PRINTFLIKE1*/ 88 void 89 reperr(char *fmt, ...) 90 { 91 char *pt; 92 ssize_t ptln; 93 va_list ap; 94 int n; 95 96 if (fmt == (char *)NULL) { 97 theErrBuf[0] = '\0'; 98 } else { 99 if (n = strlen(theErrBuf)) { 100 pt = theErrBuf + n; 101 *pt++ = '\n'; 102 *pt = '\0'; 103 ptln = sizeof (theErrBuf)-n; 104 } else { 105 pt = theErrBuf; 106 ptln = sizeof (theErrBuf); 107 } 108 va_start(ap, fmt); 109 /* LINTED variable format specifier to vsnprintf() */ 110 (void) vsnprintf(pt, ptln, fmt, ap); 111 va_end(ap); 112 } 113 } 114 115 /* 116 * Name: cverify 117 * Description: This function verifies and (if fix > 0) fixes the contents 118 * of the file at the path provided 119 * Arguments: fix - 0 - do not fix entries, 1 - fix entries 120 * ftype - single character "type" the entry is supposed to be 121 * path - path to file 122 * cinfo - content info structure representing the contents 123 * the entry is supposed to contain 124 * allow_checksum - determine if checksumming should be disabled: 125 * == 0 - do not perform checksum ever - override enable_checksum. 126 * != 0 - use the default checksum flag "enable_checksum" to 127 * determine if checksumming should be done. 128 * NOTE: modification and creation times can be repaired; the contents 129 * of the file cannot be corrected if the checksum indicates that 130 * the contents are not correct - VE_CONT will be returned in this 131 * case. 132 * Possible return values: 133 * - 0 = successful 134 * - VE_EXIST = path name does not exist 135 * - VE_FTYPE = path file type is not recognized, is not supported, 136 * or is not what was expected 137 * - VE_ATTR = path mode/group/user is not what was expected 138 * - VE_CONT = mod time/link target/major/minor/size/file system type/current 139 * directory is not what was expected 140 * - VE_FAIL = utime/target directory/link/stat/symlink/mknod/chmod/statvfs/ 141 * chown failed 142 */ 143 144 int 145 cverify(int fix, char *ftype, char *path, struct cinfo *cinfo, 146 int allow_checksum) 147 { 148 struct stat status; /* file status buffer */ 149 struct utimbuf times; 150 unsigned long mycksum; 151 int setval, retcode; 152 char tbuf1[512]; 153 char tbuf2[512]; 154 int cksumerr; 155 156 setval = (*ftype == '?'); 157 retcode = 0; 158 reperr(NULL); 159 160 if (stat(path, &status) < 0) { 161 reperr(pkg_gt(ERR_EXIST)); 162 return (VE_EXIST); 163 } 164 165 /* -1 requires modtimes to be the same */ 166 /* 0 reports modtime failure */ 167 /* 1 fixes modtimes */ 168 169 if (setval || (cinfo->modtime == BADCONT)) { 170 cinfo->modtime = status.st_mtime; 171 } else if (status.st_mtime != cinfo->modtime) { 172 if (fix > 0) { 173 /* reset times on the file */ 174 times.actime = cinfo->modtime; 175 times.modtime = cinfo->modtime; 176 if (utime(path, ×)) { 177 reperr(pkg_gt(ERR_MODFAIL)); 178 retcode = VE_FAIL; 179 } 180 } else if (fix < 0) { 181 /* modtimes must be the same */ 182 if (strftime(tbuf1, sizeof (tbuf1), DATEFMT, 183 localtime(&cinfo->modtime)) == 0) { 184 reperr(pkg_gt(ERR_MEM)); 185 } 186 if (strftime(tbuf2, sizeof (tbuf2), DATEFMT, 187 localtime(&status.st_mtime)) == 0) { 188 reperr(pkg_gt(ERR_MEM)); 189 } 190 reperr(pkg_gt(ERR_MTIME), tbuf1, tbuf2); 191 retcode = VE_CONT; 192 } 193 } 194 195 if (setval || (cinfo->size == (fsblkcnt_t)BADCONT)) { 196 cinfo->size = status.st_size; 197 } else if (status.st_size != cinfo->size) { 198 if (!retcode) { 199 retcode = VE_CONT; 200 } 201 reperr(pkg_gt(ERR_SIZE), cinfo->size, status.st_size); 202 } 203 204 cksumerr = 0; 205 206 /* 207 * see if checksumming should be done: if checksumming is allowed, 208 * and checksumming is enabled, then checksum the file. 209 */ 210 211 /* return if no need to compute checksum */ 212 213 if ((allow_checksum == 0) || (enable_checksum == 0)) { 214 return (retcode); 215 } 216 217 /* compute checksum */ 218 219 mycksum = compute_checksum(&cksumerr, path); 220 221 /* set value if not set or if checksum cannot be computed */ 222 223 if (setval || (cinfo->cksum == BADCONT)) { 224 cinfo->cksum = mycksum; 225 return (retcode); 226 } 227 228 /* report / return error if checksums mismatch or there is an error */ 229 230 if ((mycksum != cinfo->cksum) || cksumerr) { 231 if (!retcode) { 232 retcode = VE_CONT; 233 } 234 if (!cksumerr) { 235 reperr(pkg_gt(ERR_CKSUM), cinfo->cksum, mycksum); 236 } 237 } 238 239 return (retcode); 240 } 241 242 /* 243 * Name: compute_checksum 244 * Description: generate checksum for specified file 245 * Arguments: r_cksumerr (int *) [RO, *RW] 246 * - pointer to integer that is set on return to: 247 * == 0 - no error occurred 248 * != 0 - error occurred 249 * a_path (char *) [RO, *RO] 250 * - pointer to string representing path to file to 251 * generate checksum of 252 * Returns: unsigned long - results: 253 * - If *r_cksumerr == 0, checksum of specified file 254 * - If *r_cksumerr != 0, undefined 255 */ 256 unsigned long 257 compute_checksum(int *r_cksumerr, char *a_path) 258 { 259 CHECKSUM_T suma; /* to split four-bytes into 2 two-byte values */ 260 CHECKSUM_T tempa; 261 int fd; 262 uint32_t lg; /* running checksum value */ 263 uint32_t buf[CHUNK/4]; /* to read CHUNK bytes */ 264 uint32_t lsavhi; /* high order two-bytes of four-byte checksum */ 265 uint32_t lsavlo; /* low order two-bytes of four-byte checksum */ 266 int leap = sizeof (uint32_t); 267 int notyet = 0; 268 int nread; 269 struct stat64 sbuf; 270 271 /* reset error flag */ 272 *r_cksumerr = 0; 273 274 /* open file and obtain -> where file is mapped/read */ 275 if ((fd = open(a_path, O_RDONLY)) < 0) { 276 *r_cksumerr = 1; 277 reperr(pkg_gt(ERR_NO_CKSUM)); 278 perror(ERR_NO_CKSUM); 279 return (0); 280 } 281 282 if (fstat64(fd, &sbuf) != 0) { 283 *r_cksumerr = 1; 284 reperr(pkg_gt(ERR_NO_CKSUM)); 285 perror(ERR_NO_CKSUM); 286 return (0); 287 } 288 289 /* initialize checksum value */ 290 lg = 0; 291 292 /* 293 * Read CHUNK bytes off the file at a time; Read size of long bytes 294 * from memory at a time and process them. 295 * If last read, then read remnant bytes and process individually. 296 */ 297 errno = 0; 298 while ((nread = read(fd, (void*)buf, 299 (sbuf.st_size < CHUNK) ? sbuf.st_size : CHUNK)) > 0) { 300 uchar_t *s; 301 uint32_t *p = buf; 302 303 notyet = nread % leap; 304 nread -= notyet; 305 306 for (; nread > 0; nread -= leap) { 307 lg += ((((*p)>>24)&0xFF) & WDMSK); 308 lg += ((((*p)>>16)&0xFF) & WDMSK); 309 lg += ((((*p)>>8)&0xFF) & WDMSK); 310 lg += (((*p)&0xFF) & WDMSK); 311 p++; 312 } 313 s = (uchar_t *)p; 314 /* leftover bytes less than four in number */ 315 while (notyet--) 316 lg += (((uint32_t)(*s++)) & WDMSK); 317 } 318 319 /* wind up */ 320 (void) close(fd); 321 322 /* compute checksum components */ 323 suma.lg = lg; 324 tempa.lg = (suma.hl.lo & WDMSK) + (suma.hl.hi & WDMSK); 325 lsavhi = (uint32_t)tempa.hl.hi; 326 lsavlo = (uint32_t)tempa.hl.lo; 327 328 /* return final checksum value */ 329 return (lsavhi+lsavlo); 330 } 331 332 static struct stat status; /* file status buffer */ 333 static struct statvfs vfsstatus; /* filesystem status buffer */ 334 335 /* 336 * Remove the thing that's currently in place so we can put down the package 337 * object. If we're replacing a directory with a directory, leave it alone. 338 * Returns 1 if all OK and 0 if failed. 339 */ 340 static int 341 clear_target(char *path, char *ftype, int is_a_dir) 342 { 343 int retcode = 1; 344 345 if (is_a_dir) { /* if there's a directory there already ... */ 346 /* ... and this isn't, ... */ 347 if ((*ftype != 'd') && (*ftype != 'x')) { 348 if (rmdir(path)) { /* try to remove it. */ 349 reperr(pkg_gt(ERR_RMDIR), path); 350 retcode = 0; 351 } 352 } 353 } else { 354 if (remove(path)) { 355 if (errno != ENOENT) { 356 retcode = 0; /* It didn't work. */ 357 } 358 } 359 } 360 361 return (retcode); 362 } 363 364 /* 365 * Name: averify 366 * Description: This function verifies and (if fix > 0) fixes the attributes 367 * of the file at the path provided. 368 * Arguments: fix - 0 - do not fix entries, 1 - fix entries 369 * ftype - single character "type" the entry is supposed to be 370 * path - path to file 371 * ainfo - attribute info structure representing the attributes 372 * the entry is supposed to be 373 * NOTE: attributes are links and permissions 374 * Possible return values: 375 * - 0 = successful 376 * - VE_EXIST = path name does not exist 377 * - VE_FTYPE = path file type is not recognized, is not supported, 378 * or is not what was expected 379 * - VE_ATTR = path mode/group/user is not what was expected 380 * - VE_CONT = mod time/link target/major/minor/size/file system type/current 381 * directory is not what was expected 382 * - VE_FAIL = utime/target directory/link/stat/symlink/mknod/chmod/statvfs/ 383 * chown failed 384 */ 385 int 386 averify(int fix, char *ftype, char *path, struct ainfo *ainfo) 387 { 388 struct group *grp; /* group entry buffer */ 389 struct passwd *pwd; 390 int n; 391 int setval; 392 int uid, gid; 393 int dochown; 394 int retcode; 395 int targ_is_dir = 0; /* replacing a directory */ 396 char myftype; 397 char buf[PATH_MAX]; 398 ino_t my_ino; 399 dev_t my_dev; 400 char cwd[MAXPATHLEN]; 401 char *cd; 402 char *c; 403 404 setval = (*ftype == '?'); 405 retcode = 0; 406 reperr(NULL); 407 408 if (get_disable_attribute_check()) { 409 return (0); 410 } 411 412 if (*ftype == 'l') { 413 if (stat(path, &status) < 0) { 414 retcode = VE_EXIST; 415 reperr(pkg_gt(ERR_EXIST)); 416 } 417 418 my_ino = status.st_ino; 419 my_dev = status.st_dev; 420 421 /* Get copy of the current working directory */ 422 if (getcwd(cwd, MAXPATHLEN) == NULL) { 423 reperr(pkg_gt(ERR_GETWD), ainfo->local); 424 return (VE_FAIL); 425 } 426 427 /* 428 * Change to the directory in which the hard 429 * link is to be created. 430 */ 431 cd = strdup(path); 432 c = strrchr(cd, '/'); 433 if (c) { 434 /* bugid 4247895 */ 435 if (strcmp(cd, c) == 0) 436 strcpy(cd, "/"); 437 else 438 *c = NULL; 439 440 if (chdir(cd) != 0) { 441 reperr(pkg_gt(ERR_CHDIR), cd); 442 return (VE_FAIL); 443 } 444 } 445 free(cd); 446 447 if (retcode || (status.st_nlink < 2) || 448 (stat(ainfo->local, &status) < 0) || 449 (my_dev != status.st_dev) || (my_ino != status.st_ino)) { 450 if (fix) { 451 /* 452 * Don't want to do a hard link to a 453 * directory. 454 */ 455 if (!isdir(ainfo->local)) { 456 chdir(cwd); 457 reperr(pkg_gt(ERR_LINKISDIR), 458 ainfo->local); 459 return (VE_FAIL); 460 } 461 /* Now do the link. */ 462 if (!clear_target(path, ftype, targ_is_dir)) 463 return (VE_FAIL); 464 465 if (link(ainfo->local, path)) { 466 chdir(cwd); 467 reperr(pkg_gt(ERR_LINKFAIL), 468 ainfo->local); 469 return (VE_FAIL); 470 } 471 retcode = 0; 472 } else { 473 /* Go back to previous working directory */ 474 if (chdir(cwd) != 0) 475 reperr(pkg_gt(ERR_CHDIR), cwd); 476 477 reperr(pkg_gt(ERR_LINK), ainfo->local); 478 return (VE_CONT); 479 } 480 } 481 482 /* Go back to previous working directory */ 483 if (chdir(cwd) != 0) { 484 reperr(pkg_gt(ERR_CHDIR), cwd); 485 return (VE_CONT); 486 } 487 488 return (retcode); 489 } 490 491 retcode = 0; 492 493 /* Evaluate the file type of existing object */ 494 retcode = eval_ftype(path, *ftype, &myftype); 495 496 /* 497 * If path file type is not recognized, is not supported or 498 * is not what is expected, return 499 */ 500 if (retcode == VE_FTYPE) 501 return (retcode); 502 503 /* If existing type is Directory, then set flag */ 504 if (myftype == 'd') 505 targ_is_dir = 1; 506 507 if (setval) { 508 /* 509 * Check to make sure that a package or an installf that uses 510 * wild cards '?' to assume the ftype of an object on the 511 * system is not assuming a door ftype. Doors are not supported 512 * but should be ignored. 513 */ 514 if (myftype == 'D') { 515 reperr(pkg_gt(ERR_FTYPED), path); 516 retcode = VE_FTYPE; 517 return (VE_FTYPE); 518 } else { 519 *ftype = myftype; 520 } 521 } else if (!retcode && (*ftype != myftype) && 522 ((myftype != 'f') || !strchr("ilev", *ftype)) && 523 ((myftype != 'd') || (*ftype != 'x'))) { 524 reperr(pkg_gt(ERR_FTYPE), *ftype, myftype); 525 retcode = VE_FTYPE; 526 } 527 528 if (!retcode && (*ftype == 's')) { 529 /* make sure that symbolic link is correct */ 530 n = readlink(path, buf, PATH_MAX); 531 if (n < 0) { 532 reperr(pkg_gt(ERR_SLINK), ainfo->local); 533 retcode = VE_CONT; 534 } else if (ainfo->local != NULL) { 535 buf[n] = '\0'; 536 if (strcmp(buf, ainfo->local)) { 537 reperr(pkg_gt(ERR_SLINK), ainfo->local); 538 retcode = VE_CONT; 539 } 540 } else if (ainfo->local == NULL) { 541 /* 542 * Since a sym link target exists, insert it 543 * into the ainfo structure 544 */ 545 buf[n] = '\0'; 546 ainfo->local = strdup(buf); 547 } 548 } 549 550 if (retcode) { 551 /* The path doesn't exist or is different than it should be. */ 552 if (fix) { 553 /* 554 * Clear the way for the write. If it won't clear, 555 * there's nothing we can do. 556 */ 557 if (!clear_target(path, ftype, targ_is_dir)) 558 return (VE_FAIL); 559 560 if ((*ftype == 'd') || (*ftype == 'x')) { 561 char *pt, *p; 562 563 /* Try to make it the easy way */ 564 if (mkdir(path, ainfo->mode)) { 565 /* 566 * Failing that, walk through the 567 * parent directories creating 568 * whatever is needed. 569 */ 570 p = strdup(path); 571 pt = (*p == '/') ? p+1 : p; 572 do { 573 if (pt = strchr(pt, '/')) 574 *pt = '\0'; 575 if (access(p, 0) && 576 mkdir(p, ainfo->mode)) 577 break; 578 if (pt) 579 *pt++ = '/'; 580 } while (pt); 581 free(p); 582 } 583 if (stat(path, &status) < 0) { 584 reperr(pkg_gt(ERR_DIRFAIL)); 585 return (VE_FAIL); 586 } 587 } else if (*ftype == 's') { 588 if (symlink(ainfo->local, path)) { 589 reperr(pkg_gt(ERR_SLINKFAIL), 590 ainfo->local); 591 return (VE_FAIL); 592 } 593 594 } else if (*ftype == 'c') { 595 int wilddevno = 0; 596 /* 597 * The next three if's support 2.4 and older 598 * packages that use "?" as device numbers. 599 * This should be considered for removal by 600 * release 2.7 or so. 601 */ 602 if (ainfo->major == BADMAJOR) { 603 ainfo->major = 0; 604 wilddevno = 1; 605 } 606 607 if (ainfo->minor == BADMINOR) { 608 ainfo->minor = 0; 609 wilddevno = 1; 610 } 611 612 if (wilddevno) { 613 wilddevno = 0; 614 logerr(MSG_WLDDEVNO, path, 615 ainfo->major, ainfo->minor); 616 } 617 618 if (mknod(path, ainfo->mode | S_IFCHR, 619 #ifdef SUNOS41 620 makedev(ainfo->xmajor, ainfo->xminor)) || 621 #else 622 makedev(ainfo->major, ainfo->minor)) || 623 #endif 624 (stat(path, &status) < 0)) { 625 reperr(pkg_gt(ERR_CDEVFAIL)); 626 return (VE_FAIL); 627 } 628 } else if (*ftype == 'b') { 629 int wilddevno = 0; 630 /* 631 * The next three if's support 2.4 and older 632 * packages that use "?" as device numbers. 633 * This should be considered for removal by 634 * release 2.7 or so. 635 */ 636 if (ainfo->major == BADMAJOR) { 637 ainfo->major = 0; 638 wilddevno = 1; 639 } 640 641 if (ainfo->minor == BADMINOR) { 642 ainfo->minor = 0; 643 wilddevno = 1; 644 } 645 646 if (wilddevno) { 647 wilddevno = 0; 648 logerr(MSG_WLDDEVNO, path, 649 ainfo->major, ainfo->minor); 650 } 651 652 if (mknod(path, ainfo->mode | S_IFBLK, 653 #ifdef SUNOS41 654 makedev(ainfo->xmajor, ainfo->xminor)) || 655 #else 656 makedev(ainfo->major, ainfo->minor)) || 657 #endif 658 (stat(path, &status) < 0)) { 659 reperr(pkg_gt(ERR_BDEVFAIL)); 660 return (VE_FAIL); 661 } 662 } else if (*ftype == 'p') { 663 if (mknod(path, ainfo->mode | S_IFIFO, NULL) || 664 (stat(path, &status) < 0)) { 665 reperr(pkg_gt(ERR_PIPEFAIL)); 666 return (VE_FAIL); 667 } 668 } else 669 return (retcode); 670 671 } else 672 return (retcode); 673 } 674 675 if (*ftype == 's') 676 return (0); /* don't check anything else */ 677 if (*ftype == 'i') 678 return (0); /* don't check anything else */ 679 680 retcode = 0; 681 if ((myftype == 'c') || (myftype == 'b')) { 682 #ifdef SUNOS41 683 if (setval || (ainfo->xmajor < 0)) 684 ainfo->xmajor = ((status.st_rdev>>8)&0377); 685 if (setval || (ainfo->xminor < 0)) 686 ainfo->xminor = (status.st_rdev&0377); 687 /* check major & minor */ 688 if (status.st_rdev != makedev(ainfo->xmajor, ainfo->xminor)) { 689 reperr(pkg_gt(ERR_MAJMIN), ainfo->xmajor, 690 ainfo->xminor, 691 (status.st_rdev>>8)&0377, status.st_rdev&0377); 692 retcode = VE_CONT; 693 } 694 #else 695 if (setval || (ainfo->major == BADMAJOR)) 696 ainfo->major = major(status.st_rdev); 697 if (setval || (ainfo->minor == BADMINOR)) 698 ainfo->minor = minor(status.st_rdev); 699 /* check major & minor */ 700 if (status.st_rdev != makedev(ainfo->major, ainfo->minor)) { 701 reperr(pkg_gt(ERR_MAJMIN), ainfo->major, ainfo->minor, 702 major(status.st_rdev), minor(status.st_rdev)); 703 retcode = VE_CONT; 704 } 705 #endif 706 } 707 708 /* compare specified mode w/ actual mode excluding sticky bit */ 709 if (setval || (ainfo->mode == BADMODE) || (ainfo->mode == WILDCARD)) 710 ainfo->mode = status.st_mode & 07777; 711 else if ((ainfo->mode & 06777) != (status.st_mode & 06777)) { 712 if (fix) { 713 if ((ainfo->mode == BADMODE) || 714 (chmod(path, ainfo->mode) < 0)) 715 retcode = VE_FAIL; 716 } else { 717 reperr(pkg_gt(ERR_PERM), ainfo->mode, 718 status.st_mode & 07777); 719 if (!retcode) 720 retcode = VE_ATTR; 721 } 722 } 723 724 dochown = 0; 725 726 /* get group entry for specified group */ 727 if (setval || strcmp(ainfo->group, BADGROUP) == 0) { 728 grp = cgrgid(status.st_gid); 729 if (grp) 730 (void) strcpy(ainfo->group, grp->gr_name); 731 else { 732 if (!retcode) 733 retcode = VE_ATTR; 734 reperr(pkg_gt(ERR_BADGRPID), status.st_gid); 735 } 736 gid = status.st_gid; 737 } else if ((grp = cgrnam(ainfo->group)) == NULL) { 738 reperr(pkg_gt(ERR_BADGRPNM), ainfo->group); 739 if (!retcode) 740 retcode = VE_ATTR; 741 } else if ((gid = grp->gr_gid) != status.st_gid) { 742 if (fix) { 743 /* save specified GID */ 744 gid = grp->gr_gid; 745 dochown++; 746 } else { 747 if ((grp = cgrgid((int)status.st_gid)) == 748 (struct group *)NULL) { 749 reperr(pkg_gt(ERR_GROUP), ainfo->group, 750 "(null)"); 751 } else { 752 reperr(pkg_gt(ERR_GROUP), ainfo->group, 753 grp->gr_name); 754 } 755 if (!retcode) 756 retcode = VE_ATTR; 757 } 758 } 759 760 /* get password entry for specified owner */ 761 if (setval || strcmp(ainfo->owner, BADOWNER) == 0) { 762 pwd = cpwuid((int)status.st_uid); 763 if (pwd) 764 (void) strcpy(ainfo->owner, pwd->pw_name); 765 else { 766 if (!retcode) 767 retcode = VE_ATTR; 768 reperr(pkg_gt(ERR_BADUSRID), status.st_uid); 769 } 770 uid = status.st_uid; 771 } else if ((pwd = cpwnam(ainfo->owner)) == NULL) { 772 /* UID does not exist in password file */ 773 reperr(pkg_gt(ERR_BADUSRNM), ainfo->owner); 774 if (!retcode) 775 retcode = VE_ATTR; 776 } else if ((uid = pwd->pw_uid) != status.st_uid) { 777 /* get owner name for actual UID */ 778 if (fix) { 779 uid = pwd->pw_uid; 780 dochown++; 781 } else { 782 pwd = cpwuid((int)status.st_uid); 783 if (pwd == NULL) 784 reperr(pkg_gt(ERR_BADUSRID), 785 (int)status.st_uid); 786 else 787 reperr(pkg_gt(ERR_OWNER), ainfo->owner, 788 pwd->pw_name); 789 790 if (!retcode) 791 retcode = VE_ATTR; 792 } 793 } 794 795 if (statvfs(path, &vfsstatus) < 0) { 796 reperr(pkg_gt(ERR_EXIST)); 797 retcode = VE_FAIL; 798 } else { 799 if (dochown) { 800 /* pcfs doesn't support file ownership */ 801 if (strcmp(vfsstatus.f_basetype, "pcfs") != 0 && 802 chown(path, uid, gid) < 0) { 803 retcode = VE_FAIL; /* chown failed */ 804 } 805 } 806 } 807 808 if (retcode == VE_FAIL) 809 reperr(pkg_gt(ERR_ATTRFAIL)); 810 return (retcode); 811 } 812 813 /* 814 * This is a special fast verify which basically checks the attributes 815 * and then, if all is OK, checks the size and mod time using the same 816 * stat and statvfs structures. 817 */ 818 int 819 fverify(int fix, char *ftype, char *path, struct ainfo *ainfo, 820 struct cinfo *cinfo) 821 { 822 int retval; 823 824 /* return success if attribute checks are disabled */ 825 826 if (get_disable_attribute_check()) { 827 return (0); 828 } 829 830 if ((retval = averify(fix, ftype, path, ainfo)) == 0) { 831 if (*ftype == 'f' || *ftype == 'i') { 832 if (cinfo->size != status.st_size) { 833 reperr(pkg_gt(WRN_QV_SIZE), path); 834 retval = VE_CONT; 835 } 836 /* pcfs doesn't support modification times */ 837 if (strcmp(vfsstatus.f_basetype, "pcfs") != 0) { 838 if (cinfo->modtime != status.st_mtime) { 839 reperr(pkg_gt(WRN_QV_MTIME), path); 840 retval = VE_CONT; 841 } 842 } 843 } 844 } 845 846 return (retval); 847 } 848 849 /* 850 * This function determines whether or not non-ABI symlinks are supported. 851 */ 852 853 int 854 nonABI_symlinks(void) 855 { 856 return (nonabi_symlinks); 857 } 858 859 void 860 set_nonABI_symlinks(void) 861 { 862 nonabi_symlinks = 1; 863 } 864 865 /* 866 * Disable attribute checking. Only disable attribute checking if files 867 * are guaranteed to exist in the FS. 868 */ 869 void 870 disable_attribute_check(void) 871 { 872 disable_attributes = 1; 873 } 874 875 /* 876 * This function determines whether or not to do attribute checking. 877 * Returns: 0 - Do attribute checking 878 * !0 - Don't do attribute checking 879 */ 880 int 881 get_disable_attribute_check(void) 882 { 883 return (disable_attributes); 884 } 885 886 /* 887 * This function returns the address of the "global" error buffer that 888 * is populated by the various functions in this module. 889 */ 890 891 char * 892 getErrbufAddr(void) 893 { 894 return (theErrBuf); 895 } 896 897 /* 898 * This function returns the size of the buffer returned by getErrbufAddr() 899 */ 900 901 int 902 getErrbufSize(void) 903 { 904 return (sizeof (theErrBuf)); 905 } 906 907 /* 908 * This function returns the current global "error string" 909 */ 910 911 char * 912 getErrstr(void) 913 { 914 return (theErrStr); 915 } 916 917 /* 918 * This function sets the global "error string" 919 */ 920 921 void 922 setErrstr(char *a_errstr) 923 { 924 theErrStr = a_errstr; 925 } 926 927 /* 928 * This function enables checksumming 929 */ 930 931 void 932 checksum_on(void) 933 { 934 enable_checksum = 1; 935 } 936 937 /* 938 * This function disables checksumming 939 */ 940 941 void 942 checksum_off(void) 943 { 944 enable_checksum = 0; 945 } 946