main.c revision 9781:ccf49524d5dc
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#include <locale.h>
32#include <libintl.h>
33#include <stdio.h>
34#include <signal.h>
35#include <stdlib.h>
36#include <unistd.h>
37#include <string.h>
38#include <pkgtrans.h>
39#include <pkglib.h>
40#include <pkglocs.h>
41#include <libadm.h>
42#include <libinst.h>
43
44static int	options;
45static keystore_handle_t	keystore = NULL;
46
47static void	usage(void);
48static void	trap(int signo);
49
50#define	PASSWD_CMDLINE \
51		"## WARNING: USING <%s> MAKES PASSWORD " \
52		"VISIBLE TO ALL USERS."
53
54#define	PASSPHRASE_PROMPT	"Enter keystore password:"
55#define	KEYSTORE_OPEN	"Retrieving signing certificates from keystore <%s>"
56#define	PARAM_LEN		"Parameter <%s> too long"
57
58int
59main(int argc, char *argv[])
60{
61	int	c;
62	void	(*func)();
63	extern char	*optarg;
64	extern int	optind;
65	char		*keystore_alias = NULL;
66	char		*keystore_file = NULL;
67	boolean_t	create_sig = B_FALSE;
68	char		*homedir = NULL;
69	PKG_ERR		*err;
70	int		ret, len, homelen;
71
72	(void) setlocale(LC_ALL, "");
73
74#if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
75#define	TEXT_DOMAIN "SYS_TEST"
76#endif
77	(void) textdomain(TEXT_DOMAIN);
78
79	(void) set_prog_name(argv[0]);
80
81	while ((c = getopt(argc, argv, "ga:P:k:snio?")) != EOF) {
82		switch (c) {
83		case 'n':
84			options |= PT_RENAME;
85			break;
86
87		case 'i':
88			options |= PT_INFO_ONLY;
89			break;
90
91		case 'o':
92			options |= PT_OVERWRITE;
93			break;
94
95		case 's':
96			options |= PT_ODTSTREAM;
97			break;
98
99		case 'g':
100			/* this should eventually be a PT_ option */
101			create_sig = B_TRUE;
102			break;
103
104		case 'k':
105			keystore_file = optarg;
106			break;
107
108		case 'a':
109			keystore_alias = optarg;
110			break;
111
112		case 'P':
113			set_passphrase_passarg(optarg);
114			if (ci_strneq(optarg, "pass:", 5)) {
115				/*
116				 * passwords on the command line are highly
117				 * insecure.  complain.
118				 */
119				logerr(gettext(PASSWD_CMDLINE), "pass:<pass>");
120			}
121			break;
122
123		default:
124			usage();
125			return (1);
126		}
127	}
128	func = signal(SIGINT, trap);
129	if (func != SIG_DFL)
130		(void) signal(SIGINT, func);
131	(void) signal(SIGHUP, trap);
132	(void) signal(SIGQUIT, trap);
133	(void) signal(SIGTERM, trap);
134	(void) signal(SIGPIPE, trap);
135#ifndef SUNOS41
136	(void) signal(SIGPWR, trap);
137#endif
138
139	if ((argc-optind) < 2) {
140		usage();
141		return (1);
142	}
143
144	if (create_sig) {
145		sec_init();
146		err = pkgerr_new();
147
148		/* figure out which keystore to use */
149		if (keystore_file == NULL) {
150			if (geteuid() == 0) {
151				/* we are superuser, so use their keystore */
152				keystore_file = PKGSEC;
153			} else {
154				if ((homedir = getenv("HOME")) == NULL) {
155				/*
156				 * not superuser, but no home dir, so
157				 * use superuser's keystore
158				 */
159					keystore_file = PKGSEC;
160				} else {
161				/* $HOME/.pkg/security\0 */
162					homelen = strlen(homedir) + 15;
163					keystore_file =
164					    malloc(strlen(homedir) + 15);
165					if (((len = snprintf(keystore_file,
166					    homelen, "%s/%s", homedir,
167					    ".pkg/security")) < 0) ||
168					    (len >= homelen)) {
169						logerr(gettext(PARAM_LEN),
170						    "$HOME");
171						quit(1);
172					}
173				}
174			}
175		}
176
177		logerr(gettext(KEYSTORE_OPEN), keystore_file);
178
179		set_passphrase_prompt(gettext(PASSPHRASE_PROMPT));
180
181		/* open keystore for reading */
182		if (open_keystore(err, keystore_file, get_prog_name(),
183		    pkg_passphrase_cb, KEYSTORE_DFLT_FLAGS, &keystore) != 0) {
184			pkgerr(err);
185			pkgerr_free(err);
186			quit(1);
187		}
188
189	} else {
190		/* no signature, so don't use a keystore */
191		keystore = NULL;
192	}
193
194	ret = pkgtrans(flex_device(argv[optind], 1),
195	    flex_device(argv[optind+1], 1), &argv[optind+2], options,
196	    keystore, keystore_alias);
197
198	if (create_sig) {
199		/* close keystore */
200		if (close_keystore(err, keystore, NULL) != 0) {
201			pkgerr(err);
202			pkgerr_free(err);
203			quit(1);
204		}
205		keystore = NULL;
206	}
207
208	quit(ret);
209	/*NOTREACHED*/
210}
211
212void
213quit(int retcode)
214{
215	PKG_ERR	*err;
216
217	err = pkgerr_new();
218	(void) signal(SIGINT, SIG_IGN);
219	(void) signal(SIGHUP, SIG_IGN);
220	(void) ds_close(1);
221	(void) pkghead(NULL);
222	if (keystore != NULL) {
223		(void) close_keystore(err, keystore, NULL);
224		pkgerr_free(err);
225	}
226	exit(retcode);
227}
228
229static void
230trap(int signo)
231{
232	(void) signal(SIGINT, SIG_IGN);
233	(void) signal(SIGHUP, SIG_IGN);
234
235	if (signo == SIGINT) {
236		progerr(gettext("aborted at user request.\n"));
237		quit(3);
238	}
239	progerr(gettext("aborted by signal %d\n"), signo);
240	quit(1);
241}
242
243static void
244usage(void)
245{
246	(void) fprintf(stderr,
247	    gettext("usage: %s [-ionsg] [-k keystore] " \
248	    "[-a alias] [-P password] srcdev dstdev [pkg [pkg...]]\n"),
249	    get_prog_name());
250}
251