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
44 static int options;
45 static keystore_handle_t keystore = NULL;
46
47 static void usage(void);
48 static 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
58 int
main(int argc,char * argv[])59 main(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
212 void
quit(int retcode)213 quit(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
229 static void
trap(int signo)230 trap(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
243 static void
usage(void)244 usage(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