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 static void
reperr(char * fmt,...)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 (void) vsnprintf(pt, ptln, fmt, ap);
110 va_end(ap);
111 }
112 }
113
114 /*
115 * Name: cverify
116 * Description: This function verifies and (if fix > 0) fixes the contents
117 * of the file at the path provided
118 * Arguments: fix - 0 - do not fix entries, 1 - fix entries
119 * ftype - single character "type" the entry is supposed to be
120 * path - path to file
121 * cinfo - content info structure representing the contents
122 * the entry is supposed to contain
123 * allow_checksum - determine if checksumming should be disabled:
124 * == 0 - do not perform checksum ever - override enable_checksum.
125 * != 0 - use the default checksum flag "enable_checksum" to
126 * determine if checksumming should be done.
127 * NOTE: modification and creation times can be repaired; the contents
128 * of the file cannot be corrected if the checksum indicates that
129 * the contents are not correct - VE_CONT will be returned in this
130 * case.
131 * Possible return values:
132 * - 0 = successful
133 * - VE_EXIST = path name does not exist
134 * - VE_FTYPE = path file type is not recognized, is not supported,
135 * or is not what was expected
136 * - VE_ATTR = path mode/group/user is not what was expected
137 * - VE_CONT = mod time/link target/major/minor/size/file system type/current
138 * directory is not what was expected
139 * - VE_FAIL = utime/target directory/link/stat/symlink/mknod/chmod/statvfs/
140 * chown failed
141 */
142
143 int
cverify(int fix,char * ftype,char * path,struct cinfo * cinfo,int allow_checksum)144 cverify(int fix, char *ftype, char *path, struct cinfo *cinfo,
145 int allow_checksum)
146 {
147 struct stat status; /* file status buffer */
148 struct utimbuf times;
149 unsigned long mycksum;
150 int setval, retcode;
151 char tbuf1[512];
152 char tbuf2[512];
153 int cksumerr;
154
155 setval = (*ftype == '?');
156 retcode = 0;
157 reperr(NULL);
158
159 if (stat(path, &status) < 0) {
160 reperr(pkg_gt(ERR_EXIST));
161 return (VE_EXIST);
162 }
163
164 /* -1 requires modtimes to be the same */
165 /* 0 reports modtime failure */
166 /* 1 fixes modtimes */
167
168 if (setval || (cinfo->modtime == BADCONT)) {
169 cinfo->modtime = status.st_mtime;
170 } else if (status.st_mtime != cinfo->modtime) {
171 if (fix > 0) {
172 /* reset times on the file */
173 times.actime = cinfo->modtime;
174 times.modtime = cinfo->modtime;
175 if (utime(path, ×)) {
176 reperr(pkg_gt(ERR_MODFAIL));
177 retcode = VE_FAIL;
178 }
179 } else if (fix < 0) {
180 /* modtimes must be the same */
181 if (strftime(tbuf1, sizeof (tbuf1), DATEFMT,
182 localtime(&cinfo->modtime)) == 0) {
183 reperr(pkg_gt(ERR_MEM));
184 }
185 if (strftime(tbuf2, sizeof (tbuf2), DATEFMT,
186 localtime(&status.st_mtime)) == 0) {
187 reperr(pkg_gt(ERR_MEM));
188 }
189 reperr(pkg_gt(ERR_MTIME), tbuf1, tbuf2);
190 retcode = VE_CONT;
191 }
192 }
193
194 if (setval || (cinfo->size == (fsblkcnt_t)BADCONT)) {
195 cinfo->size = status.st_size;
196 } else if (status.st_size != cinfo->size) {
197 if (!retcode) {
198 retcode = VE_CONT;
199 }
200 reperr(pkg_gt(ERR_SIZE), cinfo->size, status.st_size);
201 }
202
203 cksumerr = 0;
204
205 /*
206 * see if checksumming should be done: if checksumming is allowed,
207 * and checksumming is enabled, then checksum the file.
208 */
209
210 /* return if no need to compute checksum */
211
212 if ((allow_checksum == 0) || (enable_checksum == 0)) {
213 return (retcode);
214 }
215
216 /* compute checksum */
217
218 mycksum = compute_checksum(&cksumerr, path);
219
220 /* set value if not set or if checksum cannot be computed */
221
222 if (setval || (cinfo->cksum == BADCONT)) {
223 cinfo->cksum = mycksum;
224 return (retcode);
225 }
226
227 /* report / return error if checksums mismatch or there is an error */
228
229 if ((mycksum != cinfo->cksum) || cksumerr) {
230 if (!retcode) {
231 retcode = VE_CONT;
232 }
233 if (!cksumerr) {
234 reperr(pkg_gt(ERR_CKSUM), cinfo->cksum, mycksum);
235 }
236 }
237
238 return (retcode);
239 }
240
241 /*
242 * Name: compute_checksum
243 * Description: generate checksum for specified file
244 * Arguments: r_cksumerr (int *) [RO, *RW]
245 * - pointer to integer that is set on return to:
246 * == 0 - no error occurred
247 * != 0 - error occurred
248 * a_path (char *) [RO, *RO]
249 * - pointer to string representing path to file to
250 * generate checksum of
251 * Returns: unsigned long - results:
252 * - If *r_cksumerr == 0, checksum of specified file
253 * - If *r_cksumerr != 0, undefined
254 */
255 unsigned long
compute_checksum(int * r_cksumerr,char * a_path)256 compute_checksum(int *r_cksumerr, char *a_path)
257 {
258 CHECKSUM_T suma; /* to split four-bytes into 2 two-byte values */
259 CHECKSUM_T tempa;
260 int fd;
261 uint32_t lg; /* running checksum value */
262 uint32_t buf[CHUNK/4]; /* to read CHUNK bytes */
263 uint32_t lsavhi; /* high order two-bytes of four-byte checksum */
264 uint32_t lsavlo; /* low order two-bytes of four-byte checksum */
265 int leap = sizeof (uint32_t);
266 int notyet = 0;
267 int nread;
268 struct stat64 sbuf;
269
270 /* reset error flag */
271 *r_cksumerr = 0;
272
273 /* open file and obtain -> where file is mapped/read */
274 if ((fd = open(a_path, O_RDONLY)) < 0) {
275 *r_cksumerr = 1;
276 reperr(pkg_gt(ERR_NO_CKSUM));
277 perror(ERR_NO_CKSUM);
278 return (0);
279 }
280
281 if (fstat64(fd, &sbuf) != 0) {
282 *r_cksumerr = 1;
283 reperr(pkg_gt(ERR_NO_CKSUM));
284 perror(ERR_NO_CKSUM);
285 return (0);
286 }
287
288 /* initialize checksum value */
289 lg = 0;
290
291 /*
292 * Read CHUNK bytes off the file at a time; Read size of long bytes
293 * from memory at a time and process them.
294 * If last read, then read remnant bytes and process individually.
295 */
296 errno = 0;
297 while ((nread = read(fd, (void*)buf,
298 (sbuf.st_size < CHUNK) ? sbuf.st_size : CHUNK)) > 0) {
299 uchar_t *s;
300 uint32_t *p = buf;
301
302 notyet = nread % leap;
303 nread -= notyet;
304
305 for (; nread > 0; nread -= leap) {
306 lg += ((((*p)>>24)&0xFF) & WDMSK);
307 lg += ((((*p)>>16)&0xFF) & WDMSK);
308 lg += ((((*p)>>8)&0xFF) & WDMSK);
309 lg += (((*p)&0xFF) & WDMSK);
310 p++;
311 }
312 s = (uchar_t *)p;
313 /* leftover bytes less than four in number */
314 while (notyet--)
315 lg += (((uint32_t)(*s++)) & WDMSK);
316 }
317
318 /* wind up */
319 (void) close(fd);
320
321 /* compute checksum components */
322 suma.lg = lg;
323 tempa.lg = (suma.hl.lo & WDMSK) + (suma.hl.hi & WDMSK);
324 lsavhi = (uint32_t)tempa.hl.hi;
325 lsavlo = (uint32_t)tempa.hl.lo;
326
327 /* return final checksum value */
328 return (lsavhi+lsavlo);
329 }
330
331 static struct stat status; /* file status buffer */
332 static struct statvfs vfsstatus; /* filesystem status buffer */
333
334 /*
335 * Remove the thing that's currently in place so we can put down the package
336 * object. If we're replacing a directory with a directory, leave it alone.
337 * Returns 1 if all OK and 0 if failed.
338 */
339 static int
clear_target(char * path,char * ftype,int is_a_dir)340 clear_target(char *path, char *ftype, int is_a_dir)
341 {
342 int retcode = 1;
343
344 if (is_a_dir) { /* if there's a directory there already ... */
345 /* ... and this isn't, ... */
346 if ((*ftype != 'd') && (*ftype != 'x')) {
347 if (rmdir(path)) { /* try to remove it. */
348 reperr(pkg_gt(ERR_RMDIR), path);
349 retcode = 0;
350 }
351 }
352 } else {
353 if (remove(path)) {
354 if (errno != ENOENT) {
355 retcode = 0; /* It didn't work. */
356 }
357 }
358 }
359
360 return (retcode);
361 }
362
363 /*
364 * Name: averify
365 * Description: This function verifies and (if fix > 0) fixes the attributes
366 * of the file at the path provided.
367 * Arguments: fix - 0 - do not fix entries, 1 - fix entries
368 * ftype - single character "type" the entry is supposed to be
369 * path - path to file
370 * ainfo - attribute info structure representing the attributes
371 * the entry is supposed to be
372 * NOTE: attributes are links and permissions
373 * Possible return values:
374 * - 0 = successful
375 * - VE_EXIST = path name does not exist
376 * - VE_FTYPE = path file type is not recognized, is not supported,
377 * or is not what was expected
378 * - VE_ATTR = path mode/group/user is not what was expected
379 * - VE_CONT = mod time/link target/major/minor/size/file system type/current
380 * directory is not what was expected
381 * - VE_FAIL = utime/target directory/link/stat/symlink/mknod/chmod/statvfs/
382 * chown failed
383 */
384 int
averify(int fix,char * ftype,char * path,struct ainfo * ainfo)385 averify(int fix, char *ftype, char *path, struct ainfo *ainfo)
386 {
387 struct group *grp; /* group entry buffer */
388 struct passwd *pwd;
389 int n;
390 int setval;
391 int uid, gid;
392 int dochown;
393 int retcode;
394 int statError = 0;
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));
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 (void) 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 (void) 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 (void) 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 /* If we are to process symlinks the old way then we follow the link */
494 if (nonABI_symlinks()) {
495 if ((*ftype == 's') ? lstat(path, &status) :
496 stat(path, &status)) {
497 reperr(pkg_gt(ERR_EXIST));
498 retcode = VE_EXIST;
499 myftype = '?';
500 statError++;
501 }
502 /* If not then we inspect the target of the link */
503 } else {
504 if ((n = lstat(path, &status)) == -1) {
505 reperr(pkg_gt(ERR_EXIST));
506 retcode = VE_EXIST;
507 myftype = '?';
508 statError++;
509 }
510 }
511 if (!statError) {
512 /* determining actual type of existing object */
513 switch (status.st_mode & S_IFMT) {
514 case S_IFLNK:
515 myftype = 's';
516 break;
517
518 case S_IFIFO:
519 myftype = 'p';
520 break;
521
522 case S_IFCHR:
523 myftype = 'c';
524 break;
525
526 case S_IFDIR:
527 myftype = 'd';
528 targ_is_dir = 1;
529 break;
530
531 case S_IFBLK:
532 myftype = 'b';
533 break;
534
535 case S_IFREG:
536 case 0:
537 myftype = 'f';
538 break;
539
540 case S_IFDOOR:
541 myftype = 'D';
542 break;
543
544 default:
545 reperr(pkg_gt(ERR_UNKNOWN));
546 return (VE_FTYPE);
547 }
548 }
549
550 if (setval) {
551 /*
552 * Check to make sure that a package or an installf that uses
553 * wild cards '?' to assume the ftype of an object on the
554 * system is not assuming a door ftype. Doors are not supported
555 * but should be ignored.
556 */
557 if (myftype == 'D') {
558 reperr(pkg_gt(ERR_FTYPED), path);
559 retcode = VE_FTYPE;
560 return (VE_FTYPE);
561 } else {
562 *ftype = myftype;
563 }
564 } else if (!retcode && (*ftype != myftype) &&
565 ((myftype != 'f') || !strchr("ilev", *ftype)) &&
566 ((myftype != 'd') || (*ftype != 'x'))) {
567 reperr(pkg_gt(ERR_FTYPE), *ftype, myftype);
568 retcode = VE_FTYPE;
569 }
570
571 if (!retcode && (*ftype == 's')) {
572 /* make sure that symbolic link is correct */
573 n = readlink(path, buf, PATH_MAX);
574 if (n < 0) {
575 reperr(pkg_gt(ERR_SLINK), ainfo->local);
576 retcode = VE_CONT;
577 } else if (ainfo->local != NULL) {
578 buf[n] = '\0';
579 if (strcmp(buf, ainfo->local)) {
580 reperr(pkg_gt(ERR_SLINK), ainfo->local);
581 retcode = VE_CONT;
582 }
583 } else if (ainfo->local == NULL) {
584 /*
585 * Since a sym link target exists, insert it
586 * into the ainfo structure
587 */
588 buf[n] = '\0';
589 ainfo->local = strdup(buf);
590 }
591 }
592
593 if (retcode) {
594 /* The path doesn't exist or is different than it should be. */
595 if (fix) {
596 /*
597 * Clear the way for the write. If it won't clear,
598 * there's nothing we can do.
599 */
600 if (!clear_target(path, ftype, targ_is_dir))
601 return (VE_FAIL);
602
603 if ((*ftype == 'd') || (*ftype == 'x')) {
604 char *pt, *p;
605
606 /* Try to make it the easy way */
607 if (mkdir(path, ainfo->mode)) {
608 /*
609 * Failing that, walk through the
610 * parent directories creating
611 * whatever is needed.
612 */
613 p = strdup(path);
614 pt = (*p == '/') ? p+1 : p;
615 do {
616 if (pt = strchr(pt, '/'))
617 *pt = '\0';
618 if (access(p, 0) &&
619 mkdir(p, ainfo->mode))
620 break;
621 if (pt)
622 *pt++ = '/';
623 } while (pt);
624 free(p);
625 }
626 if (stat(path, &status) < 0) {
627 reperr(pkg_gt(ERR_DIRFAIL));
628 return (VE_FAIL);
629 }
630 } else if (*ftype == 's') {
631 if (symlink(ainfo->local, path)) {
632 reperr(pkg_gt(ERR_SLINKFAIL),
633 ainfo->local);
634 return (VE_FAIL);
635 }
636
637 } else if (*ftype == 'c') {
638 int wilddevno = 0;
639 /*
640 * The next three if's support 2.4 and older
641 * packages that use "?" as device numbers.
642 * This should be considered for removal by
643 * release 2.7 or so.
644 */
645 if (ainfo->major == BADMAJOR) {
646 ainfo->major = 0;
647 wilddevno = 1;
648 }
649
650 if (ainfo->minor == BADMINOR) {
651 ainfo->minor = 0;
652 wilddevno = 1;
653 }
654
655 if (wilddevno) {
656 wilddevno = 0;
657 logerr(MSG_WLDDEVNO, path,
658 ainfo->major, ainfo->minor);
659 }
660
661 if (mknod(path, ainfo->mode | S_IFCHR,
662 makedev(ainfo->major, ainfo->minor)) ||
663 (stat(path, &status) < 0)) {
664 reperr(pkg_gt(ERR_CDEVFAIL));
665 return (VE_FAIL);
666 }
667 } else if (*ftype == 'b') {
668 int wilddevno = 0;
669 /*
670 * The next three if's support 2.4 and older
671 * packages that use "?" as device numbers.
672 * This should be considered for removal by
673 * release 2.7 or so.
674 */
675 if (ainfo->major == BADMAJOR) {
676 ainfo->major = 0;
677 wilddevno = 1;
678 }
679
680 if (ainfo->minor == BADMINOR) {
681 ainfo->minor = 0;
682 wilddevno = 1;
683 }
684
685 if (wilddevno) {
686 wilddevno = 0;
687 logerr(MSG_WLDDEVNO, path,
688 ainfo->major, ainfo->minor);
689 }
690
691 if (mknod(path, ainfo->mode | S_IFBLK,
692 makedev(ainfo->major, ainfo->minor)) ||
693 (stat(path, &status) < 0)) {
694 reperr(pkg_gt(ERR_BDEVFAIL));
695 return (VE_FAIL);
696 }
697 } else if (*ftype == 'p') {
698 if (mknod(path, ainfo->mode | S_IFIFO, NULL) ||
699 (stat(path, &status) < 0)) {
700 reperr(pkg_gt(ERR_PIPEFAIL));
701 return (VE_FAIL);
702 }
703 } else
704 return (retcode);
705
706 } else
707 return (retcode);
708 }
709
710 if (*ftype == 's')
711 return (0); /* don't check anything else */
712 if (*ftype == 'i')
713 return (0); /* don't check anything else */
714
715 retcode = 0;
716 if ((myftype == 'c') || (myftype == 'b')) {
717 if (setval || (ainfo->major == BADMAJOR))
718 ainfo->major = major(status.st_rdev);
719 if (setval || (ainfo->minor == BADMINOR))
720 ainfo->minor = minor(status.st_rdev);
721 /* check major & minor */
722 if (status.st_rdev != makedev(ainfo->major, ainfo->minor)) {
723 reperr(pkg_gt(ERR_MAJMIN), ainfo->major, ainfo->minor,
724 major(status.st_rdev), minor(status.st_rdev));
725 retcode = VE_CONT;
726 }
727 }
728
729 /* compare specified mode w/ actual mode excluding sticky bit */
730 if (setval || (ainfo->mode == BADMODE) || (ainfo->mode == WILDCARD))
731 ainfo->mode = status.st_mode & 07777;
732 else if ((ainfo->mode & 06777) != (status.st_mode & 06777)) {
733 if (fix) {
734 if ((ainfo->mode == BADMODE) ||
735 (chmod(path, ainfo->mode) < 0))
736 retcode = VE_FAIL;
737 } else {
738 reperr(pkg_gt(ERR_PERM), ainfo->mode,
739 status.st_mode & 07777);
740 if (!retcode)
741 retcode = VE_ATTR;
742 }
743 }
744
745 dochown = 0;
746
747 /* get group entry for specified group */
748 if (setval || strcmp(ainfo->group, BADGROUP) == 0) {
749 grp = cgrgid(status.st_gid);
750 if (grp)
751 (void) strcpy(ainfo->group, grp->gr_name);
752 else {
753 if (!retcode)
754 retcode = VE_ATTR;
755 reperr(pkg_gt(ERR_BADGRPID), status.st_gid);
756 }
757 gid = status.st_gid;
758 } else if ((grp = cgrnam(ainfo->group)) == NULL) {
759 reperr(pkg_gt(ERR_BADGRPNM), ainfo->group);
760 if (!retcode)
761 retcode = VE_ATTR;
762 } else if ((gid = grp->gr_gid) != status.st_gid) {
763 if (fix) {
764 /* save specified GID */
765 gid = grp->gr_gid;
766 dochown++;
767 } else {
768 if ((grp = cgrgid((int)status.st_gid)) ==
769 (struct group *)NULL) {
770 reperr(pkg_gt(ERR_GROUP), ainfo->group,
771 "(null)");
772 } else {
773 reperr(pkg_gt(ERR_GROUP), ainfo->group,
774 grp->gr_name);
775 }
776 if (!retcode)
777 retcode = VE_ATTR;
778 }
779 }
780
781 /* get password entry for specified owner */
782 if (setval || strcmp(ainfo->owner, BADOWNER) == 0) {
783 pwd = cpwuid((int)status.st_uid);
784 if (pwd)
785 (void) strcpy(ainfo->owner, pwd->pw_name);
786 else {
787 if (!retcode)
788 retcode = VE_ATTR;
789 reperr(pkg_gt(ERR_BADUSRID), status.st_uid);
790 }
791 uid = status.st_uid;
792 } else if ((pwd = cpwnam(ainfo->owner)) == NULL) {
793 /* UID does not exist in password file */
794 reperr(pkg_gt(ERR_BADUSRNM), ainfo->owner);
795 if (!retcode)
796 retcode = VE_ATTR;
797 } else if ((uid = pwd->pw_uid) != status.st_uid) {
798 /* get owner name for actual UID */
799 if (fix) {
800 uid = pwd->pw_uid;
801 dochown++;
802 } else {
803 pwd = cpwuid((int)status.st_uid);
804 if (pwd == NULL)
805 reperr(pkg_gt(ERR_BADUSRID),
806 (int)status.st_uid);
807 else
808 reperr(pkg_gt(ERR_OWNER), ainfo->owner,
809 pwd->pw_name);
810
811 if (!retcode)
812 retcode = VE_ATTR;
813 }
814 }
815
816 if (statvfs(path, &vfsstatus) < 0) {
817 reperr(pkg_gt(ERR_EXIST));
818 retcode = VE_FAIL;
819 } else {
820 if (dochown) {
821 /* pcfs doesn't support file ownership */
822 if (strcmp(vfsstatus.f_basetype, "pcfs") != 0 &&
823 chown(path, uid, gid) < 0) {
824 retcode = VE_FAIL; /* chown failed */
825 }
826 }
827 }
828
829 if (retcode == VE_FAIL)
830 reperr(pkg_gt(ERR_ATTRFAIL));
831 return (retcode);
832 }
833
834 /*
835 * This is a special fast verify which basically checks the attributes
836 * and then, if all is OK, checks the size and mod time using the same
837 * stat and statvfs structures.
838 */
839 int
fverify(int fix,char * ftype,char * path,struct ainfo * ainfo,struct cinfo * cinfo)840 fverify(int fix, char *ftype, char *path, struct ainfo *ainfo,
841 struct cinfo *cinfo)
842 {
843 int retval;
844
845 /* return success if attribute checks are disabled */
846
847 if (get_disable_attribute_check()) {
848 return (0);
849 }
850
851 if ((retval = averify(fix, ftype, path, ainfo)) == 0) {
852 if (*ftype == 'f' || *ftype == 'i') {
853 if (cinfo->size != status.st_size) {
854 reperr(pkg_gt(WRN_QV_SIZE), path);
855 retval = VE_CONT;
856 }
857 /* pcfs doesn't support modification times */
858 if (strcmp(vfsstatus.f_basetype, "pcfs") != 0) {
859 if (cinfo->modtime != status.st_mtime) {
860 reperr(pkg_gt(WRN_QV_MTIME), path);
861 retval = VE_CONT;
862 }
863 }
864 }
865 }
866
867 return (retval);
868 }
869
870 /*
871 * This function determines whether or not non-ABI symlinks are supported.
872 */
873
874 int
nonABI_symlinks(void)875 nonABI_symlinks(void)
876 {
877 return (nonabi_symlinks);
878 }
879
880 void
set_nonABI_symlinks(void)881 set_nonABI_symlinks(void)
882 {
883 nonabi_symlinks = 1;
884 }
885
886 /*
887 * Disable attribute checking. Only disable attribute checking if files
888 * are guaranteed to exist in the FS.
889 */
890 void
disable_attribute_check(void)891 disable_attribute_check(void)
892 {
893 disable_attributes = 1;
894 }
895
896 /*
897 * This function determines whether or not to do attribute checking.
898 * Returns: 0 - Do attribute checking
899 * !0 - Don't do attribute checking
900 */
901 int
get_disable_attribute_check(void)902 get_disable_attribute_check(void)
903 {
904 return (disable_attributes);
905 }
906
907 /*
908 * This function returns the address of the "global" error buffer that
909 * is populated by the various functions in this module.
910 */
911
912 char *
getErrbufAddr(void)913 getErrbufAddr(void)
914 {
915 return (theErrBuf);
916 }
917
918 /*
919 * This function returns the size of the buffer returned by getErrbufAddr()
920 */
921
922 int
getErrbufSize(void)923 getErrbufSize(void)
924 {
925 return (sizeof (theErrBuf));
926 }
927
928 /*
929 * This function returns the current global "error string"
930 */
931
932 char *
getErrstr(void)933 getErrstr(void)
934 {
935 return (theErrStr);
936 }
937
938 /*
939 * This function sets the global "error string"
940 */
941
942 void
setErrstr(char * a_errstr)943 setErrstr(char *a_errstr)
944 {
945 theErrStr = a_errstr;
946 }
947
948 /*
949 * This function enables checksumming
950 */
951
952 void
checksum_on(void)953 checksum_on(void)
954 {
955 enable_checksum = 1;
956 }
957
958 /*
959 * This function disables checksumming
960 */
961
962 void
checksum_off(void)963 checksum_off(void)
964 {
965 enable_checksum = 0;
966 }
967