static int pkgxfer(char *srcinst, int options) { int r; struct pkginfo info; FILE *fp, *pp; char *pt, *src, *dst; char dstdir[PATH_MAX], temp[PATH_MAX], srcdir[PATH_MAX], cmd[CMDSIZE], pkgname[NON_ABI_NAMELNGTH]; int i, n, part, nparts, maxpartsize, curpartcnt, iscomp; char volnos[128], tmpvol[128]; struct statvfs64 svfsb; longlong_t free_blocks; struct stat srcstat; info.pkginst = NULL; /* required initialization */ /* * when this routine is entered, the first part of * the package to transfer is already available in * the directory indicated by 'src' --- unless the * source device is a datstream, in which case only * the pkginfo and pkgmap files are available in 'src' */ src = srcdev.dirname; dst = dstdev.dirname; if (!(options & PT_SILENT)) (void) fprintf(stderr, pkg_gt(MSG_TRANSFER), srcinst); (void) strlcpy(dstinst, srcinst, sizeof (dstinst)); if (!(options & PT_ODTSTREAM)) { /* destination is a (possibly mounted) directory */ (void) snprintf(dstdir, sizeof (dstdir), "%s/%s", dst, dstinst); /* * need to check destination directory to assure * that we will not be duplicating a package which * already resides there (though we are allowed to * overwrite the same version) */ pkgdir = src; if (fpkginfo(&info, srcinst)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOEXISTS), srcinst); (void) fpkginfo(&info, NULL); return (1); } pkgdir = dst; (void) strlcpy(temp, srcinst, sizeof (temp)); if (pt = strchr(temp, '.')) *pt = '\0'; (void) strlcat(temp, ".*", sizeof (temp)); if (pt = fpkginst(temp, info.arch, info.version)) { /* * the same instance already exists, although * its pkgid might be different */ if (options & PT_OVERWRITE) { (void) strlcpy(dstinst, pt, sizeof (dstinst)); (void) snprintf(dstdir, sizeof (dstdir), "%s/%s", dst, dstinst); } else { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_DUPVERS), srcinst); (void) fpkginfo(&info, NULL); (void) fpkginst(NULL); return (2); } } else if (options & PT_RENAME) { /* * find next available instance by appending numbers * to the package abbreviation until the instance * does not exist in the destination directory */ if (pt = strchr(temp, '.')) *pt = '\0'; for (i = 2; (access(dstdir, 0) == 0); i++) { (void) snprintf(dstinst, sizeof (dstinst), "%s.%d", temp, i); (void) snprintf(dstdir, sizeof (dstdir), "%s/%s", dst, dstinst); } } else if (options & PT_OVERWRITE) { /* * we're allowed to overwrite, but there seems * to be no valid package to overwrite, and we are * not allowed to rename the destination, so act * as if we weren't given permission to overwrite * --- this keeps us from removing a destination * instance which is named the same as the source * instance, but really reflects a different pkg! */ options &= (~PT_OVERWRITE); } (void) fpkginfo(&info, NULL); (void) fpkginst(NULL); if (ckoverwrite(dst, dstinst, options)) return (2); if (isdir(dstdir) && mkdir(dstdir, 0755)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_MKDIR), dstdir); return (1); } (void) snprintf(srcdir, sizeof (srcdir), "%s/%s", src, srcinst); if (stat(srcdir, &srcstat) != -1) { if (chmod(dstdir, (srcstat.st_mode & S_IAMB)) == -1) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_CHMODDIR), dstdir); return (1); } } else { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_STATDIR), srcdir); return (1); } } if (!(options & PT_SILENT) && strcmp(dstinst, srcinst)) (void) fprintf(stderr, pkg_gt(MSG_RENAME), dstinst); (void) snprintf(srcdir, sizeof (srcdir), "%s/%s", src, srcinst); if (chdir(srcdir)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_CHDIR), srcdir); return (1); } if (ids_name) { /* unpack the datatstream into a directory */ /* * transfer pkginfo & pkgmap first */ (void) snprintf(cmd, sizeof (cmd), "%s -pudm %s", CPIOPROC, dstdir); if ((pp = epopen(cmd, "w")) == NULL) { rpterr(); progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_POPEN), cmd, errno); return (1); } (void) fprintf(pp, "%s\n%s\n", PKGINFO, PKGMAP); (void) sighold(SIGINT); (void) sighold(SIGHUP); r = epclose(pp); (void) sigrelse(SIGINT); (void) sigrelse(SIGHUP); if (r != 0) { rpterr(); progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_PCLOSE), cmd, errno); return (1); } if (options & PT_INFO_ONLY) return (0); /* don't transfer objects */ if (chdir(dstdir)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_CHDIR), dstdir); return (1); } /* * for each part of the package, use cpio() to * unpack the archive into the destination directory */ nparts = ds_findpkg(srcdev.cdevice, srcinst); if (nparts < 0) { progerr(pkg_gt(ERR_TRANSFER)); return (1); } for (part = 1; part <= nparts; /* void */) { if (ds_getpkg(srcdev.cdevice, part, dstdir)) { progerr(pkg_gt(ERR_TRANSFER)); return (1); } part++; if (dstdev.mount) { (void) chdir("/"); if (pkgumount(&dstdev)) return (1); if (part <= nparts) { if (n = pkgmount(&dstdev, NULL, part+1, nparts, 1)) return (n); if (ckoverwrite(dst, dstinst, options)) return (1); if (isdir(dstdir) && mkdir(dstdir, 0755)) { progerr( pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_MKDIR), dstdir); return (1); } /* * since volume is removable, each part * must contain a duplicate of the * pkginfo file to properly identify the * volume */ if (chdir(srcdir)) { progerr( pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_CHDIR), srcdir); return (1); } if ((pp = epopen(cmd, "w")) == NULL) { rpterr(); progerr( pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_POPEN), cmd, errno); return (1); } (void) fprintf(pp, "pkginfo"); (void) sighold(SIGINT); (void) sighold(SIGHUP); r = epclose(pp); (void) sigrelse(SIGINT); (void) sigrelse(SIGHUP); if (r != 0) { rpterr(); progerr( pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_PCLOSE), cmd, errno); return (1); } if (chdir(dstdir)) { progerr( pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_CHDIR), dstdir); return (1); } } } } return (0); } if ((fp = fopen(PKGMAP, "r")) == NULL) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOPKGMAP), srcinst); return (1); } nparts = 1; if (!rd_map_size(fp, &nparts, &maxpartsize, &compressedsize)) return (1); else (void) fclose(fp); if (srcdev.mount) { if (ckvolseq(srcdir, 1, nparts)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_SEQUENCE)); return (1); } } /* write each part of this package */ if (options & PT_ODTSTREAM) { char line[128]; (void) mgets(line, 128); curpartcnt = -1; /* LINTED E_SEC_SCANF_UNBOUNDED_COPY */ if (sscanf(line, "%s %d %d %[ 0-9]", pkgname, &nparts, &maxpartsize, volnos) == 4) { (void) sscanf(volnos, "%d %[ 0-9]", &curpartcnt, tmpvol); (void) strlcpy(volnos, tmpvol, sizeof (volnos)); } } for (part = 1; part <= nparts; /* void */) { if (curpartcnt == 0 && (options & PT_ODTSTREAM)) { char prompt[128]; int index; ds_volno++; (void) ds_close(0); (void) sprintf(prompt, pkg_gt("Insert %%v %d of %d into %%p"), ds_volno, ds_volcnt); if (n = getvol(ods_name, NULL, DM_FORMAT, prompt)) return (n); if ((ds_fd = open(dstdev.cdevice, O_WRONLY)) < 0) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_OPEN), dstdev.cdevice, errno); return (1); } if (ds_ginit(dstdev.cdevice) < 0) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_OPEN), dstdev.cdevice, errno); (void) ds_close(0); return (1); } (void) sscanf(volnos, "%d %[ 0-9]", &index, tmpvol); (void) strlcpy(volnos, tmpvol, sizeof (volnos)); curpartcnt += index; } if (options & PT_INFO_ONLY) nparts = 0; if (part == 1) { (void) snprintf(cmd, sizeof (cmd), "find %s %s", PKGINFO, PKGMAP); if (nparts && (isdir(INSTALL) == 0)) { (void) strlcat(cmd, " ", sizeof (cmd)); (void) strlcat(cmd, INSTALL, sizeof (cmd)); } } else (void) snprintf(cmd, sizeof (cmd), "find %s", PKGINFO); if (nparts > 1) { (void) snprintf(temp, sizeof (temp), "%s.%d", RELOC, part); if (iscpio(temp, &iscomp) || isdir(temp) == 0) { (void) strlcat(cmd, " ", sizeof (cmd)); (void) strlcat(cmd, temp, sizeof (cmd)); } (void) snprintf(temp, sizeof (temp), "%s.%d", ROOT, part); if (iscpio(temp, &iscomp) || isdir(temp) == 0) { (void) strlcat(cmd, " ", sizeof (cmd)); (void) strlcat(cmd, temp, sizeof (cmd)); } (void) snprintf(temp, sizeof (temp), "%s.%d", ARCHIVE, part); if (isdir(temp) == 0) { (void) strlcat(cmd, " ", sizeof (cmd)); (void) strlcat(cmd, temp, sizeof (cmd)); } } else if (nparts) { for (i = 0; reloc_names[i] != NULL; i++) { if (iscpio(reloc_names[i], &iscomp) || isdir(reloc_names[i]) == 0) { (void) strlcat(cmd, " ", sizeof (cmd)); (void) strlcat(cmd, reloc_names[i], sizeof (cmd)); } } for (i = 0; root_names[i] != NULL; i++) { if (iscpio(root_names[i], &iscomp) || isdir(root_names[i]) == 0) { (void) strlcat(cmd, " ", sizeof (cmd)); (void) strlcat(cmd, root_names[i], sizeof (cmd)); } } if (isdir(ARCHIVE) == 0) { (void) strlcat(cmd, " ", sizeof (cmd)); (void) strlcat(cmd, ARCHIVE, sizeof (cmd)); } } if (options & PT_ODTSTREAM) { (void) snprintf(cmd + strlen(cmd), sizeof (cmd) - strlen(cmd), " -print | %s -ocD -C %d", CPIOPROC, (int)BLK_SIZE); } else { if (statvfs64(dstdir, &svfsb) == -1) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_STATVFS), dstdir, errno); return (1); } free_blocks = (((long)svfsb.f_frsize > 0) ? howmany(svfsb.f_frsize, DEV_BSIZE) : howmany(svfsb.f_bsize, DEV_BSIZE)) * svfsb.f_bavail; if ((has_comp_size ? compressedsize : maxpartsize) > free_blocks) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOSPACE), has_comp_size ? (long)compressedsize : (long)maxpartsize, free_blocks); return (1); } (void) snprintf(cmd + strlen(cmd), sizeof (cmd) - strlen(cmd), " -print | %s -pdum %s", CPIOPROC, dstdir); } n = esystem(cmd, -1, (options & PT_ODTSTREAM) ? ds_fd : -1); if (n) { rpterr(); progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_CMDFAIL), cmd, n); return (1); } part++; if (srcdev.mount && (nparts > 1)) { /* unmount current source volume */ (void) chdir("/"); if (pkgumount(&srcdev)) return (1); /* loop until volume is mounted successfully */ while (part <= nparts) { /* read only */ n = pkgmount(&srcdev, NULL, part, nparts, 1); if (n) return (n); if (chdir(srcdir)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_CORRUPT)); (void) chdir("/"); (void) pkgumount(&srcdev); continue; } if (ckvolseq(srcdir, part, nparts)) { (void) chdir("/"); (void) pkgumount(&srcdev); continue; } break; } } if (!(options & PT_ODTSTREAM) && dstdev.mount) { /* unmount current volume */ if (pkgumount(&dstdev)) return (1); /* loop until next volume is mounted successfully */ while (part <= nparts) { /* writable */ n = pkgmount(&dstdev, NULL, part, nparts, 1); if (n) return (n); if (ckoverwrite(dst, dstinst, options)) continue; if (isdir(dstdir) && mkdir(dstdir, 0755)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_MKDIR), dstdir); continue; } break; } } if ((options & PT_ODTSTREAM) && part <= nparts) { if (curpartcnt >= 0 && part > curpartcnt) { char prompt[128]; int index; ds_volno++; if (ds_close(0)) return (1); (void) sprintf(prompt, pkg_gt("Insert %%v %d of %d into %%p"), ds_volno, ds_volcnt); if (n = getvol(ods_name, NULL, DM_FORMAT, prompt)) return (n); if ((ds_fd = open(dstdev.cdevice, 1)) < 0) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_OPEN), dstdev.cdevice, errno); return (1); } if (ds_ginit(dstdev.cdevice) < 0) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_OPEN), dstdev.cdevice, errno); (void) ds_close(0); return (1); } (void) sscanf(volnos, "%d %[ 0-9]", &index, tmpvol); (void) strlcpy(volnos, tmpvol, sizeof (volnos)); curpartcnt += index; } } } return (0); }
/* * Name: compute_checksum * Description: generate checksum for specified file * Arguments: r_cksumerr (int *) [RO, *RW] * - pointer to integer that is set on return to: * == 0 - no error occurred * != 0 - error occurred * a_path (char *) [RO, *RO] * - pointer to string representing path to file to * generate checksum of * Returns: unsigned long - results: * - If *r_cksumerr == 0, checksum of specified file * - If *r_cksumerr != 0, undefined */ unsigned long compute_checksum(int *r_cksumerr, char *a_path) { CHECKSUM_T suma; /* to split four-bytes into 2 two-byte values */ CHECKSUM_T tempa; int fd; uint32_t lg; /* running checksum value */ uint32_t buf[CHUNK/4]; /* to read CHUNK bytes */ uint32_t lsavhi; /* high order two-bytes of four-byte checksum */ uint32_t lsavlo; /* low order two-bytes of four-byte checksum */ int leap = sizeof (uint32_t); int notyet = 0; int nread; struct stat64 sbuf; /* reset error flag */ *r_cksumerr = 0; /* open file and obtain -> where file is mapped/read */ if ((fd = open(a_path, O_RDONLY)) < 0) { *r_cksumerr = 1; reperr(pkg_gt(ERR_NO_CKSUM)); perror(ERR_NO_CKSUM); return (0); } if (fstat64(fd, &sbuf) != 0) { *r_cksumerr = 1; reperr(pkg_gt(ERR_NO_CKSUM)); perror(ERR_NO_CKSUM); return (0); } /* initialize checksum value */ lg = 0; /* * Read CHUNK bytes off the file at a time; Read size of long bytes * from memory at a time and process them. * If last read, then read remnant bytes and process individually. */ errno = 0; while ((nread = read(fd, (void*)buf, (sbuf.st_size < CHUNK) ? sbuf.st_size : CHUNK)) > 0) { uchar_t *s; uint32_t *p = buf; notyet = nread % leap; nread -= notyet; for (; nread > 0; nread -= leap) { lg += ((((*p)>>24)&0xFF) & WDMSK); lg += ((((*p)>>16)&0xFF) & WDMSK); lg += ((((*p)>>8)&0xFF) & WDMSK); lg += (((*p)&0xFF) & WDMSK); p++; } s = (uchar_t *)p; /* leftover bytes less than four in number */ while (notyet--) lg += (((uint32_t)(*s++)) & WDMSK); } /* wind up */ (void) close(fd); /* compute checksum components */ suma.lg = lg; tempa.lg = (suma.hl.lo & WDMSK) + (suma.hl.hi & WDMSK); lsavhi = (uint32_t)tempa.hl.hi; lsavlo = (uint32_t)tempa.hl.lo; /* return final checksum value */ return (lsavhi+lsavlo); }
/* * Name: averify * Description: This function verifies and (if fix > 0) fixes the attributes * of the file at the path provided. * Arguments: fix - 0 - do not fix entries, 1 - fix entries * ftype - single character "type" the entry is supposed to be * path - path to file * ainfo - attribute info structure representing the attributes * the entry is supposed to be * NOTE: attributes are links and permissions * Possible return values: * - 0 = successful * - VE_EXIST = path name does not exist * - VE_FTYPE = path file type is not recognized, is not supported, * or is not what was expected * - VE_ATTR = path mode/group/user is not what was expected * - VE_CONT = mod time/link target/major/minor/size/file system type/current * directory is not what was expected * - VE_FAIL = utime/target directory/link/stat/symlink/mknod/chmod/statvfs/ * chown failed */ int averify(int fix, char *ftype, char *path, struct ainfo *ainfo) { struct group *grp; /* group entry buffer */ struct passwd *pwd; int n; int setval; int uid, gid; int dochown; int retcode; int statError = 0; int targ_is_dir = 0; /* replacing a directory */ char myftype; char buf[PATH_MAX]; ino_t my_ino; dev_t my_dev; char cwd[MAXPATHLEN]; char *cd; char *c; setval = (*ftype == '?'); retcode = 0; reperr(NULL); if (get_disable_attribute_check()) { return (0); } if (*ftype == 'l') { if (stat(path, &status) < 0) { retcode = VE_EXIST; reperr(pkg_gt(ERR_EXIST)); } my_ino = status.st_ino; my_dev = status.st_dev; /* Get copy of the current working directory */ if (getcwd(cwd, MAXPATHLEN) == NULL) { reperr(pkg_gt(ERR_GETWD)); return (VE_FAIL); } /* * Change to the directory in which the hard * link is to be created. */ cd = strdup(path); c = strrchr(cd, '/'); if (c) { /* bugid 4247895 */ if (strcmp(cd, c) == 0) (void) strcpy(cd, "/"); else *c = NULL; if (chdir(cd) != 0) { reperr(pkg_gt(ERR_CHDIR), cd); return (VE_FAIL); } } free(cd); if (retcode || (status.st_nlink < 2) || (stat(ainfo->local, &status) < 0) || (my_dev != status.st_dev) || (my_ino != status.st_ino)) { if (fix) { /* * Don't want to do a hard link to a * directory. */ if (!isdir(ainfo->local)) { (void) chdir(cwd); reperr(pkg_gt(ERR_LINKISDIR), ainfo->local); return (VE_FAIL); } /* Now do the link. */ if (!clear_target(path, ftype, targ_is_dir)) return (VE_FAIL); if (link(ainfo->local, path)) { (void) chdir(cwd); reperr(pkg_gt(ERR_LINKFAIL), ainfo->local); return (VE_FAIL); } retcode = 0; } else { /* Go back to previous working directory */ if (chdir(cwd) != 0) reperr(pkg_gt(ERR_CHDIR), cwd); reperr(pkg_gt(ERR_LINK), ainfo->local); return (VE_CONT); } } /* Go back to previous working directory */ if (chdir(cwd) != 0) { reperr(pkg_gt(ERR_CHDIR), cwd); return (VE_CONT); } return (retcode); } retcode = 0; /* If we are to process symlinks the old way then we follow the link */ if (nonABI_symlinks()) { if ((*ftype == 's') ? lstat(path, &status) : stat(path, &status)) { reperr(pkg_gt(ERR_EXIST)); retcode = VE_EXIST; myftype = '?'; statError++; } /* If not then we inspect the target of the link */ } else { if ((n = lstat(path, &status)) == -1) { reperr(pkg_gt(ERR_EXIST)); retcode = VE_EXIST; myftype = '?'; statError++; } } if (!statError) { /* determining actual type of existing object */ switch (status.st_mode & S_IFMT) { case S_IFLNK: myftype = 's'; break; case S_IFIFO: myftype = 'p'; break; case S_IFCHR: myftype = 'c'; break; case S_IFDIR: myftype = 'd'; targ_is_dir = 1; break; case S_IFBLK: myftype = 'b'; break; case S_IFREG: case 0: myftype = 'f'; break; case S_IFDOOR: myftype = 'D'; break; default: reperr(pkg_gt(ERR_UNKNOWN)); return (VE_FTYPE); } } if (setval) { /* * Check to make sure that a package or an installf that uses * wild cards '?' to assume the ftype of an object on the * system is not assuming a door ftype. Doors are not supported * but should be ignored. */ if (myftype == 'D') { reperr(pkg_gt(ERR_FTYPED), path); retcode = VE_FTYPE; return (VE_FTYPE); } else { *ftype = myftype; } } else if (!retcode && (*ftype != myftype) && ((myftype != 'f') || !strchr("ilev", *ftype)) && ((myftype != 'd') || (*ftype != 'x'))) { reperr(pkg_gt(ERR_FTYPE), *ftype, myftype); retcode = VE_FTYPE; } if (!retcode && (*ftype == 's')) { /* make sure that symbolic link is correct */ n = readlink(path, buf, PATH_MAX); if (n < 0) { reperr(pkg_gt(ERR_SLINK), ainfo->local); retcode = VE_CONT; } else if (ainfo->local != NULL) { buf[n] = '\0'; if (strcmp(buf, ainfo->local)) { reperr(pkg_gt(ERR_SLINK), ainfo->local); retcode = VE_CONT; } } else if (ainfo->local == NULL) { /* * Since a sym link target exists, insert it * into the ainfo structure */ buf[n] = '\0'; ainfo->local = strdup(buf); } } if (retcode) { /* The path doesn't exist or is different than it should be. */ if (fix) { /* * Clear the way for the write. If it won't clear, * there's nothing we can do. */ if (!clear_target(path, ftype, targ_is_dir)) return (VE_FAIL); if ((*ftype == 'd') || (*ftype == 'x')) { char *pt, *p; /* Try to make it the easy way */ if (mkdir(path, ainfo->mode)) { /* * Failing that, walk through the * parent directories creating * whatever is needed. */ p = strdup(path); pt = (*p == '/') ? p+1 : p; do { if (pt = strchr(pt, '/')) *pt = '\0'; if (access(p, 0) && mkdir(p, ainfo->mode)) break; if (pt) *pt++ = '/'; } while (pt); free(p); } if (stat(path, &status) < 0) { reperr(pkg_gt(ERR_DIRFAIL)); return (VE_FAIL); } } else if (*ftype == 's') { if (symlink(ainfo->local, path)) { reperr(pkg_gt(ERR_SLINKFAIL), ainfo->local); return (VE_FAIL); } } else if (*ftype == 'c') { int wilddevno = 0; /* * The next three if's support 2.4 and older * packages that use "?" as device numbers. * This should be considered for removal by * release 2.7 or so. */ if (ainfo->major == BADMAJOR) { ainfo->major = 0; wilddevno = 1; } if (ainfo->minor == BADMINOR) { ainfo->minor = 0; wilddevno = 1; } if (wilddevno) { wilddevno = 0; logerr(MSG_WLDDEVNO, path, ainfo->major, ainfo->minor); } if (mknod(path, ainfo->mode | S_IFCHR, makedev(ainfo->major, ainfo->minor)) || (stat(path, &status) < 0)) { reperr(pkg_gt(ERR_CDEVFAIL)); return (VE_FAIL); } } else if (*ftype == 'b') { int wilddevno = 0; /* * The next three if's support 2.4 and older * packages that use "?" as device numbers. * This should be considered for removal by * release 2.7 or so. */ if (ainfo->major == BADMAJOR) { ainfo->major = 0; wilddevno = 1; } if (ainfo->minor == BADMINOR) { ainfo->minor = 0; wilddevno = 1; } if (wilddevno) { wilddevno = 0; logerr(MSG_WLDDEVNO, path, ainfo->major, ainfo->minor); } if (mknod(path, ainfo->mode | S_IFBLK, makedev(ainfo->major, ainfo->minor)) || (stat(path, &status) < 0)) { reperr(pkg_gt(ERR_BDEVFAIL)); return (VE_FAIL); } } else if (*ftype == 'p') { if (mknod(path, ainfo->mode | S_IFIFO, NULL) || (stat(path, &status) < 0)) { reperr(pkg_gt(ERR_PIPEFAIL)); return (VE_FAIL); } } else return (retcode); } else return (retcode); } if (*ftype == 's') return (0); /* don't check anything else */ if (*ftype == 'i') return (0); /* don't check anything else */ retcode = 0; if ((myftype == 'c') || (myftype == 'b')) { if (setval || (ainfo->major == BADMAJOR)) ainfo->major = major(status.st_rdev); if (setval || (ainfo->minor == BADMINOR)) ainfo->minor = minor(status.st_rdev); /* check major & minor */ if (status.st_rdev != makedev(ainfo->major, ainfo->minor)) { reperr(pkg_gt(ERR_MAJMIN), ainfo->major, ainfo->minor, major(status.st_rdev), minor(status.st_rdev)); retcode = VE_CONT; } } /* compare specified mode w/ actual mode excluding sticky bit */ if (setval || (ainfo->mode == BADMODE) || (ainfo->mode == WILDCARD)) ainfo->mode = status.st_mode & 07777; else if ((ainfo->mode & 06777) != (status.st_mode & 06777)) { if (fix) { if ((ainfo->mode == BADMODE) || (chmod(path, ainfo->mode) < 0)) retcode = VE_FAIL; } else { reperr(pkg_gt(ERR_PERM), ainfo->mode, status.st_mode & 07777); if (!retcode) retcode = VE_ATTR; } } dochown = 0; /* get group entry for specified group */ if (setval || strcmp(ainfo->group, BADGROUP) == 0) { grp = cgrgid(status.st_gid); if (grp) (void) strcpy(ainfo->group, grp->gr_name); else { if (!retcode) retcode = VE_ATTR; reperr(pkg_gt(ERR_BADGRPID), status.st_gid); } gid = status.st_gid; } else if ((grp = cgrnam(ainfo->group)) == NULL) { reperr(pkg_gt(ERR_BADGRPNM), ainfo->group); if (!retcode) retcode = VE_ATTR; } else if ((gid = grp->gr_gid) != status.st_gid) { if (fix) { /* save specified GID */ gid = grp->gr_gid; dochown++; } else { if ((grp = cgrgid((int)status.st_gid)) == (struct group *)NULL) { reperr(pkg_gt(ERR_GROUP), ainfo->group, "(null)"); } else { reperr(pkg_gt(ERR_GROUP), ainfo->group, grp->gr_name); } if (!retcode) retcode = VE_ATTR; } } /* get password entry for specified owner */ if (setval || strcmp(ainfo->owner, BADOWNER) == 0) { pwd = cpwuid((int)status.st_uid); if (pwd) (void) strcpy(ainfo->owner, pwd->pw_name); else { if (!retcode) retcode = VE_ATTR; reperr(pkg_gt(ERR_BADUSRID), status.st_uid); } uid = status.st_uid; } else if ((pwd = cpwnam(ainfo->owner)) == NULL) { /* UID does not exist in password file */ reperr(pkg_gt(ERR_BADUSRNM), ainfo->owner); if (!retcode) retcode = VE_ATTR; } else if ((uid = pwd->pw_uid) != status.st_uid) { /* get owner name for actual UID */ if (fix) { uid = pwd->pw_uid; dochown++; } else { pwd = cpwuid((int)status.st_uid); if (pwd == NULL) reperr(pkg_gt(ERR_BADUSRID), (int)status.st_uid); else reperr(pkg_gt(ERR_OWNER), ainfo->owner, pwd->pw_name); if (!retcode) retcode = VE_ATTR; } } if (statvfs(path, &vfsstatus) < 0) { reperr(pkg_gt(ERR_EXIST)); retcode = VE_FAIL; } else { if (dochown) { /* pcfs doesn't support file ownership */ if (strcmp(vfsstatus.f_basetype, "pcfs") != 0 && chown(path, uid, gid) < 0) { retcode = VE_FAIL; /* chown failed */ } } } if (retcode == VE_FAIL) reperr(pkg_gt(ERR_ATTRFAIL)); return (retcode); }
int cverify(int fix, char *ftype, char *path, struct cinfo *cinfo, int allow_checksum) { struct stat status; /* file status buffer */ struct utimbuf times; unsigned long mycksum; int setval, retcode; char tbuf1[512]; char tbuf2[512]; int cksumerr; setval = (*ftype == '?'); retcode = 0; reperr(NULL); if (stat(path, &status) < 0) { reperr(pkg_gt(ERR_EXIST)); return (VE_EXIST); } /* -1 requires modtimes to be the same */ /* 0 reports modtime failure */ /* 1 fixes modtimes */ if (setval || (cinfo->modtime == BADCONT)) { cinfo->modtime = status.st_mtime; } else if (status.st_mtime != cinfo->modtime) { if (fix > 0) { /* reset times on the file */ times.actime = cinfo->modtime; times.modtime = cinfo->modtime; if (utime(path, ×)) { reperr(pkg_gt(ERR_MODFAIL)); retcode = VE_FAIL; } } else if (fix < 0) { /* modtimes must be the same */ if (strftime(tbuf1, sizeof (tbuf1), DATEFMT, localtime(&cinfo->modtime)) == 0) { reperr(pkg_gt(ERR_MEM)); } if (strftime(tbuf2, sizeof (tbuf2), DATEFMT, localtime(&status.st_mtime)) == 0) { reperr(pkg_gt(ERR_MEM)); } reperr(pkg_gt(ERR_MTIME), tbuf1, tbuf2); retcode = VE_CONT; } } if (setval || (cinfo->size == (fsblkcnt_t)BADCONT)) { cinfo->size = status.st_size; } else if (status.st_size != cinfo->size) { if (!retcode) { retcode = VE_CONT; } reperr(pkg_gt(ERR_SIZE), cinfo->size, status.st_size); } cksumerr = 0; /* * see if checksumming should be done: if checksumming is allowed, * and checksumming is enabled, then checksum the file. */ /* return if no need to compute checksum */ if ((allow_checksum == 0) || (enable_checksum == 0)) { return (retcode); } /* compute checksum */ mycksum = compute_checksum(&cksumerr, path); /* set value if not set or if checksum cannot be computed */ if (setval || (cinfo->cksum == BADCONT)) { cinfo->cksum = mycksum; return (retcode); } /* report / return error if checksums mismatch or there is an error */ if ((mycksum != cinfo->cksum) || cksumerr) { if (!retcode) { retcode = VE_CONT; } if (!cksumerr) { reperr(pkg_gt(ERR_CKSUM), cinfo->cksum, mycksum); } } return (retcode); }
int pkgmount(struct pkgdev *devp, char *pkg, int part, int nparts, int getvolflg) { int n; char *pt, prompt[64], cmd[CMDSIZ]; FILE *pp; if (getuid()) { progerr(pkg_gt(ERR_NOTROOT)); return (99); } if (part && nparts) { if (pkg) { (void) snprintf(prompt, sizeof (prompt), pkg_gt(LABEL0), part, nparts, pkg); } else { (void) snprintf(prompt, sizeof (prompt), pkg_gt(LABEL1), part, nparts); } } else if (pkg) (void) snprintf(prompt, sizeof (prompt), pkg_gt(LABEL2), pkg); else (void) snprintf(prompt, sizeof (prompt), pkg_gt(LABEL3)); n = 0; for (;;) { if (!getvolflg && n) /* * Return to caller if not prompting * and error was encountered. */ return (-1); if (getvolflg && (n = getvol(devp->bdevice, NULL, (devp->rdonly ? 0 : DM_FORMFS|DM_WLABEL), prompt))) { if (n == 3) return (3); if (n == 2) progerr(pkg_gt("unknown device <%s>"), devp->bdevice); else progerr( pkg_gt("unable to obtain package volume")); return (99); } if (devp->fstyp == NULL) { (void) snprintf(cmd, sizeof (cmd), "%s %s", FSTYP, devp->bdevice); if ((pp = epopen(cmd, "r")) == NULL) { rpterr(); logerr(pkg_gt(ERR_FSTYP), devp->bdevice); n = -1; continue; } cmd[0] = '\0'; if (fgets(cmd, CMDSIZ, pp) == NULL) { logerr(pkg_gt(ERR_FSTYP), devp->bdevice); (void) pclose(pp); n = -1; continue; } if (epclose(pp)) { rpterr(); logerr(pkg_gt(ERR_FSTYP), devp->bdevice); n = -1; continue; } if (pt = strpbrk(cmd, " \t\n")) *pt = '\0'; if (cmd[0] == '\0') { logerr(pkg_gt(ERR_FSTYP), devp->bdevice); n = -1; continue; } devp->fstyp = strdup(cmd); } if (devp->rdonly) { n = pkgexecl(NULL, NULL, NULL, NULL, MOUNT, "-r", "-F", devp->fstyp, devp->bdevice, devp->mount, NULL); } else { n = pkgexecl(NULL, NULL, NULL, NULL, MOUNT, "-F", devp->fstyp, devp->bdevice, devp->mount, NULL); } if (n) { progerr(pkg_gt("mount of %s failed"), devp->bdevice); continue; } devp->mntflg++; break; } return (0); }
int pkgexecv(char *filein, char *fileout, char *uname, char *gname, char *arg[]) { int exit_no; int n; int status; pid_t pid; pid_t waitstat; struct group *grp; struct passwd *pwp; struct sigaction nact; struct sigaction oact; void (*funcSighup)(int); void (*funcSigint)(int); /* flush standard i/o before creating new process */ (void) fflush(stdout); (void) fflush(stderr); /* * hold SIGINT/SIGHUP signals and reset signal received counter; * after the vfork() the parent and child need to setup their respective * interrupt handling and release the hold on the signals */ (void) sighold(SIGINT); (void) sighold(SIGHUP); sig_received = 0; /* * create new process to execute command in; * vfork() is being used to avoid duplicating the parents * memory space - this means that the child process may * not modify any of the parents memory including the * standard i/o descriptors - all the child can do is * adjust interrupts and open files as a prelude to a * call to exec(). */ pid = vfork(); if (pid < 0) { /* * ************************************************************* * fork failed! * ************************************************************* */ progerr(pkg_gt(ERR_FORK_FAILED), errno, strerror(errno)); /* release hold on signals */ (void) sigrelse(SIGHUP); (void) sigrelse(SIGINT); return (-1); } if (pid > 0) { /* * ************************************************************* * This is the forking (parent) process * ************************************************************* */ /* close datastream if any portion read */ if (ds_curpartcnt >= 0) { if (ds_close(0) != 0) { /* kill child process */ (void) sigsend(P_PID, pid, SIGKILL); /* release hold on signals */ (void) sigrelse(SIGHUP); (void) sigrelse(SIGINT); return (-1); } } /* * setup signal handlers for SIGINT and SIGHUP and release hold */ /* hook SIGINT to sig_trap() */ nact.sa_handler = sig_trap; nact.sa_flags = SA_RESTART; (void) sigemptyset(&nact.sa_mask); if (sigaction(SIGINT, &nact, &oact) < 0) { funcSigint = SIG_DFL; } else { funcSigint = oact.sa_handler; } /* hook SIGHUP to sig_trap() */ nact.sa_handler = sig_trap; nact.sa_flags = SA_RESTART; (void) sigemptyset(&nact.sa_mask); if (sigaction(SIGHUP, &nact, &oact) < 0) { funcSighup = SIG_DFL; } else { funcSighup = oact.sa_handler; } /* release hold on signals */ (void) sigrelse(SIGHUP); (void) sigrelse(SIGINT); /* * wait for the process to exit, reap child exit status */ for (;;) { status = 0; waitstat = waitpid(pid, (int *)&status, 0); if (waitstat < 0) { /* waitpid returned error */ if (errno == EAGAIN) { /* try again */ continue; } if (errno == EINTR) { continue; } /* error from waitpid: bail */ break; } else if (waitstat == pid) { /* child exit status available */ break; } } /* * reset signal handlers */ /* reset SIGINT */ nact.sa_handler = funcSigint; nact.sa_flags = SA_RESTART; (void) sigemptyset(&nact.sa_mask); (void) sigaction(SIGINT, &nact, (struct sigaction *)NULL); /* reset SIGHUP */ nact.sa_handler = funcSighup; nact.sa_flags = SA_RESTART; (void) sigemptyset(&nact.sa_mask); (void) sigaction(SIGHUP, &nact, (struct sigaction *)NULL); /* error if child process does not match */ if (waitstat != pid) { progerr(pkg_gt(ERR_WAIT_FAILED), pid, waitstat, status, errno, strerror(errno)); return (-1); } /* * determine final exit code: * - if signal received, then return interrupted (3) * - if child exit status is available, return exit child status * - otherwise return error (-1) */ if (sig_received != 0) { exit_no = 3; /* interrupted */ } else if (WIFEXITED(status)) { exit_no = WEXITSTATUS(status); } else { exit_no = -1; /* exec() or other process error */ } return (exit_no); } /* * ********************************************************************* * This is the forked (child) process * ********************************************************************* */ /* reset all signals to default */ for (n = 0; n < NSIG; n++) { (void) sigset(n, SIG_DFL); } /* release hold on signals held by parent before fork() */ (void) sigrelse(SIGHUP); (void) sigrelse(SIGINT); /* * The caller wants to have stdin connected to filein. */ if (filein && *filein) { /* * If input is supposed to be connected to /dev/tty */ if (strncmp(filein, "/dev/tty", 8) == 0) { /* * If stdin is connected to a tty device. */ if (isatty(STDIN_FILENO)) { /* * Reopen it to /dev/tty. */ n = open(filein, O_RDONLY); if (n >= 0) { (void) dup2(n, STDIN_FILENO); } } } else { /* * If we did not want to be connected to /dev/tty, we * connect input to the requested file no questions. */ n = open(filein, O_RDONLY); if (n >= 0) { (void) dup2(n, STDIN_FILENO); } } } /* * The caller wants to have stdout and stderr connected to fileout. * If "fileout" is "/dev/tty" then reconnect stdout to "/dev/tty" * only if /dev/tty is not already associated with "a tty". */ if (fileout && *fileout) { /* * If output is supposed to be connected to /dev/tty */ if (strncmp(fileout, "/dev/tty", 8) == 0) { /* * If stdout is connected to a tty device. */ if (isatty(STDOUT_FILENO)) { /* * Reopen it to /dev/tty if /dev/tty available. */ n = open(fileout, O_WRONLY); if (n >= 0) { /* * /dev/tty is available - close the * current standard output stream, and * reopen it on /dev/tty */ (void) dup2(n, STDOUT_FILENO); } } /* * not connected to tty device - probably redirect to * file - preserve existing output device */ } else { /* * If we did not want to be connected to /dev/tty, we * connect output to the requested file no questions. */ /* LINTED O_CREAT without O_EXCL specified in call to */ n = open(fileout, O_WRONLY|O_CREAT|O_APPEND, 0666); if (n >= 0) { (void) dup2(n, STDOUT_FILENO); } } /* * Dup stderr from stdout. */ (void) dup2(STDOUT_FILENO, STDERR_FILENO); } /* * do NOT close all file descriptors except stdio * file descriptors are passed in to some subcommands * (see dstream:ds_getinfo() and dstream:ds_putinfo()) */ /* set group/user i.d. if requested */ if (gname && *gname && (grp = cgrnam(gname)) != NULL) { if (setgid(grp->gr_gid) == -1) { progerr(pkg_gt(ERR_SETGID), grp->gr_gid); } } if (uname && *uname && (pwp = cpwnam(uname)) != NULL) { if (setuid(pwp->pw_uid) == -1) { progerr(pkg_gt(ERR_SETUID), pwp->pw_uid); } } /* execute target executable */ (void) execve(arg[0], arg, environ); progerr(pkg_gt(ERR_EX_FAIL), arg[0], errno); _exit(99); /*NOTREACHED*/ }
int esystem(char *cmd, int ifd, int ofd) { char *perrfile; int status = 0; pid_t pid; perrfile = tmpnam(NULL); if (perrfile == NULL) { progerr( pkg_gt("unable to create temp error file, errno=%d"), errno); return (-1); } (void) strlcpy(errfile, perrfile, sizeof (errfile)); /* flush standard i/o before creating new process */ (void) fflush(stderr); (void) fflush(stdout); /* * create new process to execute command in; * vfork() is being used to avoid duplicating the parents * memory space - this means that the child process may * not modify any of the parents memory including the * standard i/o descriptors - all the child can do is * adjust interrupts and open files as a prelude to a * call to exec(). */ pid = vfork(); if (pid == 0) { /* * this is the child process */ int i; /* reset any signals to default */ for (i = 0; i < NSIG; i++) { (void) sigset(i, SIG_DFL); } if (ifd > 0) { (void) dup2(ifd, STDIN_FILENO); } if (ofd >= 0 && ofd != STDOUT_FILENO) { (void) dup2(ofd, STDOUT_FILENO); } i = open(errfile, O_WRONLY|O_CREAT|O_TRUNC, 0666); if (i >= 0) { dup2(i, STDERR_FILENO); } /* Close all open files except standard i/o */ closefrom(3); /* execute target executable */ execl("/sbin/sh", "/sbin/sh", "-c", cmd, NULL); progerr(pkg_gt("exec of <%s> failed, errno=%d"), cmd, errno); _exit(99); } else if (pid < 0) { /* fork failed! */ logerr(pkg_gt("bad vfork(), errno=%d"), errno); return (-1); } /* * this is the parent process */ sighold(SIGINT); pid = waitpid(pid, &status, 0); sigrelse(SIGINT); if (pid < 0) { return (-1); /* probably interrupted */ } switch (status & 0177) { case 0: case 0177: status = status >> 8; /*FALLTHROUGH*/ default: /* terminated by a signal */ status = status & 0177; } if (status == 0) { ecleanup(); } return (status); }
/* will return 0, 1, 3, or 99 */ static int _pkgtrans(char *device1, char *device2, char **pkg, int options, keystore_handle_t keystore, char *keystore_alias) { #ifdef USE_KEYSTORE BIO *p7_bio = NULL; EVP_PKEY *privkey = NULL; #endif PKCS7 *sec_pkcs7 = NULL; #ifdef USE_KEYSTORE PKCS7_SIGNER_INFO *sec_signerinfo = NULL; PKG_ERR *err; STACK_OF(X509) *cacerts = NULL; STACK_OF(X509) *clcerts = NULL; STACK_OF(X509) *sec_chain = NULL; X509 *pubcert = NULL; #endif boolean_t making_sig = B_FALSE; char *src, *dst; int errflg, i, n; struct dm_buf *hdr; making_sig = (keystore != NULL) ? B_TRUE : B_FALSE; #ifdef USE_KEYSTORE if (making_sig) { /* new error object */ err = pkgerr_new(); /* find matching cert and key */ if (find_key_cert_pair(err, keystore, keystore_alias, &privkey, &pubcert) != 0) { pkgerr(err); pkgerr_free(err); return (1); } /* get CA certificates */ if (find_ca_certs(err, keystore, &cacerts) != 0) { pkgerr(err); pkgerr_free(err); return (1); } /* get CL (aka "chain") certificates */ if (find_cl_certs(err, keystore, &clcerts) != 0) { pkgerr(err); pkgerr_free(err); return (1); } /* initialize PKCS7 object to be filled in later */ sec_pkcs7 = PKCS7_new(); PKCS7_set_type(sec_pkcs7, NID_pkcs7_signed); sec_signerinfo = PKCS7_add_signature(sec_pkcs7, pubcert, privkey, EVP_sha1()); if (sec_signerinfo == NULL) { progerr(gettext(ERR_SEC), keystore_alias); ERR_print_errors_fp(stderr); pkgerr_free(err); return (1); } /* add signer cert into signature */ PKCS7_add_certificate(sec_pkcs7, pubcert); /* attempt to resolve cert chain starting at the signer cert */ if (get_cert_chain(err, pubcert, clcerts, cacerts, &sec_chain) != 0) { pkgerr(err); pkgerr_free(err); return (1); } /* * add the verification chain of certs into the signature. * The first cert is the user cert, which we don't need, * since it's baked in already, so skip it */ for (i = 1; i < sk_X509_num(sec_chain); i++) { PKCS7_add_certificate(sec_pkcs7, sk_X509_value(sec_chain, i)); } pkgerr_free(err); err = NULL; } #endif /* USE_KEYSTORE */ if (signal_received > 0) { return (1); } /* transfer spool to appropriate device */ if (devtype(device1, &srcdev)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_BADDEV), device1); return (1); } srcdev.rdonly++; /* check for datastream */ ids_name = NULL; if (srcdev.bdevice) { if (ds_readbuf(srcdev.cdevice)) ids_name = srcdev.cdevice; } if (srcdev.cdevice && !srcdev.bdevice) ids_name = srcdev.cdevice; else if (srcdev.pathname) { ids_name = srcdev.pathname; if (access(ids_name, 0) == -1) { progerr(ERR_TRANSFER); logerr(pkg_gt(MSG_GETVOL)); return (1); } } if (!ids_name && device2 == (char *)0) { if (n = pkgmount(&srcdev, NULL, 1, 0, 0)) { cleanup(); return (n); } if (srcdev.mount && *srcdev.mount) pkgdir = strdup(srcdev.mount); return (0); } if (ids_name && device2 == (char *)0) { char template[] = "/var/tmp/ptXXXXXX";