예제 #1
0
/* 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)
{
	BIO			*p7_bio = NULL;
	EVP_PKEY		*privkey = NULL;
	PKCS7			*sec_pkcs7 = NULL;
	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;
	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;

	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();
		(void) 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 */
		(void) 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++) {
			(void) PKCS7_add_certificate(sec_pkcs7,
			    sk_X509_value(sec_chain, i));
		}

		pkgerr_free(err);
		err = NULL;
	}

	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 (n = _getvol(srcdev.bdevice, NULL, NULL,
		    pkg_gt("Insert %v into %p."), srcdev.norewind)) {
			cleanup();
			if (n == 3)
				return (3);
			progerr(pkg_gt(ERR_TRANSFER));
			logerr(pkg_gt(MSG_GETVOL));
			return (1);
		}
		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) {
		tmppath = tmpnam(NULL);
		tmppath = strdup(tmppath);
		if (tmppath == NULL) {
			progerr(pkg_gt(ERR_TRANSFER));
			logerr(pkg_gt(MSG_MEM));
			return (1);
		}
		if (mkdir(tmppath, 0755)) {
			progerr(pkg_gt(ERR_TRANSFER));
			logerr(pkg_gt(MSG_MKDIR), tmppath);
			return (1);
		}
		device2 = tmppath;
	}

	if (devtype(device2, &dstdev)) {
		progerr(pkg_gt(ERR_TRANSFER));
		logerr(pkg_gt(MSG_BADDEV), device2);
		return (1);
	}

	if ((srcdev.cdevice && dstdev.cdevice) &&
	    strcmp(srcdev.cdevice, dstdev.cdevice) == 0) {
		progerr(pkg_gt(ERR_TRANSFER));
		logerr(pkg_gt(MSG_SAMEDEV));
		return (1);
	}

	ods_name = NULL;
	if (dstdev.cdevice && !dstdev.bdevice || dstdev.pathname)
		options |= PT_ODTSTREAM;

	if (options & PT_ODTSTREAM) {
		if (!((ods_name = dstdev.cdevice) != NULL ||
		    (ods_name = dstdev.pathname) != NULL)) {
			progerr(pkg_gt(ERR_TRANSFER));
			logerr(pkg_gt(MSG_BADDEV), device2);
			return (1);
		}
		if (ids_name) {
			progerr(pkg_gt(ERR_TRANSFER));
			logerr(pkg_gt(MSG_TWODSTREAM));
			return (1);
		}
	} else {
		/*
		 * output device isn't a stream.  If we're making a signed
		 * package, then fail, since we can't make signed,
		 * non-stream pkgs
		 */
		if (making_sig) {
			progerr(pkg_gt(ERR_TRANSFER));
			logerr(pkg_gt(ERR_CANTSIGN));
			return (1);
		}
	}

	if ((srcdev.dirname && dstdev.dirname) &&
	    strcmp(srcdev.dirname, dstdev.dirname) == 0) {
		progerr(pkg_gt(ERR_TRANSFER));
		logerr(pkg_gt(MSG_SAMEDEV));
		return (1);
	}

	if ((srcdev.pathname && dstdev.pathname) &&
	    strcmp(srcdev.pathname, dstdev.pathname) == 0) {
		progerr(pkg_gt(ERR_TRANSFER));
		logerr(pkg_gt(MSG_SAMEDEV));
		return (1);
	}

	if (signal_received > 0) {
		return (1);
	}

	if (ids_name) {
		if (srcdev.cdevice && !srcdev.bdevice &&
		(n = _getvol(srcdev.cdevice, NULL, NULL, NULL,
		    srcdev.norewind))) {
			cleanup();
			if (n == 3)
				return (3);
			progerr(pkg_gt(ERR_TRANSFER));
			logerr(pkg_gt(MSG_GETVOL));
			return (1);
		}
		if (srcdev.dirname = tmpnam(NULL))
			tmpdir = srcdev.dirname = strdup(srcdev.dirname);

		if ((srcdev.dirname == NULL) || mkdir(srcdev.dirname, 0755) ||
		    chdir(srcdev.dirname)) {
			progerr(pkg_gt(ERR_TRANSFER));
			logerr(pkg_gt(MSG_NOTEMP), srcdev.dirname);
			cleanup();
			return (1);
		}
		if (ds_init(ids_name, pkg, srcdev.norewind)) {
			cleanup();
			return (1);
		}
	} else if (srcdev.mount) {
		if (n = pkgmount(&srcdev, NULL, 1, 0, 0)) {
			cleanup();
			return (n);
		}
	}

	src = srcdev.dirname;
	dst = dstdev.dirname;

	if (chdir(src)) {
		progerr(pkg_gt(ERR_TRANSFER));
		logerr(pkg_gt(MSG_CHDIR), src);
		cleanup();
		return (1);
	}

	if (signal_received > 0) {
		return (1);
	}

	xpkg = pkg = gpkglist(src, pkg, NULL);
	if (!pkg) {
		progerr(pkg_gt(ERR_TRANSFER));
		logerr(pkg_gt(MSG_NOPKGS), src);
		cleanup();
		return (1);
	}

	for (nxpkg = 0; pkg[nxpkg]; /* void */) {
		nxpkg++; /* count */
	}

	if (ids_name) {
		ds_order(pkg); /* order requests */
	}

	if (signal_received > 0) {
		return (1);
	}

	if (options & PT_ODTSTREAM) {
		char line[128];

		if (!dstdev.pathname &&
		    (n = _getvol(ods_name, NULL, DM_FORMAT, NULL,
		    dstdev.norewind))) {
			cleanup();
			if (n == 3)
				return (3);
			progerr(pkg_gt(ERR_TRANSFER));
			logerr(pkg_gt(MSG_GETVOL));
			return (1);
		}
		if ((hdr = genheader(src, pkg)) == NULL) {
			cleanup();
			return (1);
		}
		if (making_sig) {
			/* start up signature data stream */
			(void) PKCS7_content_new(sec_pkcs7, NID_pkcs7_data);
			(void) PKCS7_set_detached(sec_pkcs7, 1);
			p7_bio = PKCS7_dataInit(sec_pkcs7, NULL);

			/*
			 * Here we generate all the data that will go into
			 * the package, and send it through the signature
			 * generator, essentially calculating the signature
			 * of the entire package so we can place it in the
			 * header.  Otherwise we'd have to place it at the end
			 * of the pkg, which would break the ABI
			 */
			if (!(options & PT_SILENT)) {
				(void) fprintf(stderr, pkg_gt(MSG_SIGNING),
				    get_subject_display_name(pubcert));
			}
			if (dump_hdr_and_pkgs(p7_bio, hdr, pkg) != 0) {
			    progerr(gettext(ERR_NOGEN));
			    logerr(pkg_gt(MSG_GETVOL));
			    cleanup();
			    return (1);

			}

			BIO_flush(p7_bio);

			/*
			 * now generate PKCS7 signature
			 */
			if (!PKCS7_dataFinal(sec_pkcs7, p7_bio)) {
			    progerr(gettext(ERR_NOGEN));
			    logerr(pkg_gt(MSG_GETVOL));
			    cleanup();
			    return (1);
			}

			(void) BIO_free(p7_bio);
		}

		/* write out header to stream, which includes signature */
		if (wdsheader(hdr, src, ods_name, pkg, sec_pkcs7)) {
			cleanup();
			return (1);
		}

		if (sec_pkcs7 != NULL) {
			/* nuke in-memory signature for safety */
			PKCS7_free(sec_pkcs7);
			sec_pkcs7 = NULL;
		}

		ds_volno = 1; /* number of volumes in datastream */
		pinput = hdrbuf.text_buffer;
		/* skip past first line in header */
		(void) mgets(line, 128);
	}

	if (signal_received > 0) {
		return (1);
	}

	errflg = 0;

	for (i = 0; pkg[i]; i++) {

		if (signal_received > 0) {
			return (1);
		}

		if (!(options & PT_ODTSTREAM) && dstdev.mount) {
			if (n = pkgmount(&dstdev, NULL, 0, 0, 1)) {
				cleanup();
				return (n);
			}
		}
		if (errflg = pkgxfer(pkg[i], options)) {
			pkg[i] = NULL;
			if ((options & PT_ODTSTREAM) || (errflg != 2))
				break;
		} else if (strcmp(dstinst, pkg[i]))
			pkg[i] = strdup(dstinst);
	}

	if (!(options & PT_ODTSTREAM) && dst) {
		pkgdir = strdup(dst);
	}

	/*
	 * No cleanup of temporary directories created in this
	 * function is done here. The calling function must do
	 * the cleanup.
	 */

	return (signal_received > 0 ? 1 : errflg);
}
예제 #2
0
파일: main.c 프로젝트: aksr/heirloom
int
main(int argc, char *argv[])
{
	int	pkgfmt = 0;	/* Makes more sense as a pointer, but */
				/*	18N is compromised. */
	char	file[PATH_MAX+1],
		*abi_sym_ptr,
		*vfstab_file = NULL;
	char *all_pkgs[4] = {"all", NULL};
	char **category = NULL;
	char *catg_arg = NULL;
	int	c;
	int	n = 0;
	char	*prog,
		*Rvalue = NULL,
		*dvalue = NULL;
	int dbcreate = 0;
	int pathtype;

	/* initialize locale mechanism */

#if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
#define	TEXT_DOMAIN "SYS_TEST"
#endif
	(void) textdomain(TEXT_DOMAIN);

	/* determine program name */

	prog = set_prog_name(argv[0]);

	/* establish installation root directory */

	if (!set_inst_root(getenv("PKG_INSTALL_ROOT"))) {
		progerr(gettext(ERR_ROOT_SET));
		quit(1);
	}

	/* check if not ABI compliant mode */
	abi_sym_ptr = getenv("PKG_NONABI_SYMLINKS");
	if (abi_sym_ptr && strncasecmp(abi_sym_ptr, "TRUE", 4) == 0) {
		set_nonABI_symlinks();
	}

	/* bugId 4012147 */
	if ((uniTmp = getenv("PKG_NO_UNIFIED")) != NULL)
		map_client = 0;

	while ((c = getopt(argc, argv, "Y:R:e:p:d:nLli:vaV:Mm:cqxfQP:?"))
			!= EOF) {
		switch (c) {
		case 'p':
			pathlist[npaths] = strtok(optarg, " , ");
			if (pathlist[npaths++] == NULL) {
				progerr(gettext(ERR_POPTION));
				quit(1);
			}
			while (pathlist[npaths] = strtok(NULL, " , ")) {
				if (npaths++ >= MAXPATHS) {
					progerr(gettext(ERR_MAXPATHS),
						MAXPATHS);
					quit(1);
				}
			}
			break;

		case 'd':
			dvalue = optarg;
			dflag = 1;
			break;

		case 'n':
			nflag++;
			break;

		case 'M':
			map_client = 0;
			break;

		/*
		 * Allow admin to establish the client filesystem using a
		 * vfstab-like file of stable format.
		 */
		case 'V':
			vfstab_file = flex_device(optarg, 2);
			map_client = 1;
			break;

		case 'f':
#if 0
			if (getuid()) {
				progerr(gettext(ERR_NOTROOT), prog);
				quit(1);
			}
#endif
			fflag++;
			break;

		case 'i':
			setpathlist(optarg);
			break;

		case 'v':
			vflag++;
			break;

		case 'l':
			lflag++;
			break;

		case 'L':
			Lflag++;
			break;

		case 'x':
			if (aflag < 0)
				aflag = 0;
			if (cflag < 0)
				cflag = 0;
			xflag++;
			break;

		case 'q':
			qflag++;
			break;

		case 'a':
			if (cflag < 0)
				cflag = 0;
			aflag = 1;
			break;

		case 'c':
			if (aflag < 0)
				aflag = 0;
			cflag = 1;
			break;

		case 'e':
			envfile = optarg;
			break;

		case 'm':
			mapfile = optarg;
			break;

		case 'R':
			Rvalue = optarg;
			Rflag = 1;
			break;

		case 'Y':
			catg_arg = strdup(optarg);

			if ((category = get_categories(catg_arg)) == NULL) {
				progerr(gettext(ERR_CAT_INV), catg_arg);
				quit(1);
			} else if (is_not_valid_length(category)) {
				progerr(gettext(ERR_CAT_LNGTH));
				quit(1);
			}
			break;

		case 'Q':
			dbcreate++;
			break;

		case 'P':
			ppathlist[npaths] = strtok(optarg, " , ");
			if ((ppathlist[npaths] == NULL) ||
			    (ppathlist[npaths][0] == '-')) {
				progerr(gettext(ERR_PARTIAL_POPTION));
				quit(1);
			}
			npaths++;
			while (ppathlist[npaths] = strtok(NULL, " , ")) {
				if (npaths++ >= MAXPATHS) {
					progerr(gettext(ERR_MAXPATHS),
						MAXPATHS);
					quit(1);
				}
			}
			break;

		default:
			usage();
		}
	}

	/* Check for incompatible options */
	if (dflag && Rflag)
		usage();

	/* Check for root dir and device dir if set */
	if (Rflag) {
		if (!set_inst_root(Rvalue)) {
			progerr(gettext(ERR_ROOT_CMD));
			quit(1);
		}
	}

	if (dflag)
		device = flex_device(dvalue, 1);

	if (lflag || Lflag) {
		/* we're only supposed to list information */
		if ((cflag >= 0) || (aflag >= 0) ||
		qflag || xflag || fflag || nflag || vflag)
			usage();
	}

	set_PKGpaths(get_inst_root());

	if (catg_arg != NULL && device == NULL) {
		if (argc - optind) {
			usage();
		}
		pkg = gpkglist(pkgdir, all_pkgs, category);
		if (pkg == NULL) {
			progerr(gettext(ERR_CAT_FND), catg_arg);
			quit(1);
		} else {
			for (pkgcnt = 0; pkg[pkgcnt] != NULL; pkgcnt++);
		}
	} else if (catg_arg != NULL && optind < argc) {
		usage();
	} else {
		pkg = &argv[optind];
		pkgcnt = (argc - optind);
	}

	environ = NULL;		/* Sever the parent environment. */

	if (vcfile() == 0) {
		quit(99);
	}

	errflg = 0;
	if (mapfile) {
		/* check for incompatible options */
		if (device || pkgcnt)
			usage();
		put_path_params();	/* Restore what's needed. */

		/* send pathtype if partial path */
		pathtype = (ppathlist[0] != NULL) ? 1 : 0;
		if (checkmap(0, (device != NULL), mapfile, envfile, NULL,
		    NULL, pathtype))
			errflg++;
	} else if (device) {
		/* check for incompatible options */
		if ((cflag >= 0) || (aflag >= 0))
			usage();
		if (qflag || xflag || nflag || envfile)
			usage();
		tmpdir = NULL;
		if ((spooldir = devattr(device, "pathname")) == NULL)
			spooldir = device;
		if (isdir(spooldir)) {
			char	template[] = "/var/tmp/spoolXXXXXX";
			close(mkstemp(template));