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 28 #include <stdio.h> 29 #include <stdarg.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <sys/types.h> 33 #include <unistd.h> 34 #include <signal.h> 35 #include <locale.h> 36 #include <sys/param.h> 37 #include <openssl/bio.h> 38 39 #include <libinst.h> 40 #include <pkglib.h> 41 #include <pkgerr.h> 42 #include <keystore.h> 43 #include "pkgadm.h" 44 #include "pkgadm_msgs.h" 45 46 /* 47 * Name: listcert 48 * Desc: Lists one or more certificates from the keystore 49 * Syntax: listcert [-a app] [-f format] [-k keystore] \ 50 * [-n name] [-o outfile] [-P passarg] [-R altroot] 51 */ 52 int 53 listcert(int argc, char **argv) 54 { 55 int i; 56 char keystore_file[MAXPATHLEN] = ""; 57 char *keystore_base = NULL; 58 char *homedir; 59 char *passarg = NULL; 60 char *altroot = NULL; 61 char *prog = NULL; 62 char *format_str = NULL; 63 keystore_encoding_format_t format; 64 char *alias = NULL; 65 char *outfile_str = NULL; 66 FILE *outfile = NULL; 67 int ret = 1; 68 PKG_ERR *err = NULL; 69 keystore_handle_t keystore = NULL; 70 71 while ((i = getopt(argc, argv, ":a:f:k:n:o:P:R:")) != EOF) { 72 switch (i) { 73 case 'a': 74 prog = optarg; 75 break; 76 case 'f': 77 format_str = optarg; 78 break; 79 case 'k': 80 keystore_base = optarg; 81 break; 82 case 'n': 83 alias = optarg; 84 break; 85 case 'o': 86 outfile_str = optarg; 87 break; 88 case 'P': 89 passarg = optarg; 90 break; 91 case 'R': 92 altroot = optarg; 93 break; 94 case ':': 95 log_msg(LOG_MSG_ERR, MSG_MISSING_OPERAND, optopt); 96 /* fallthrough intentional */ 97 case '?': 98 default: 99 log_msg(LOG_MSG_ERR, MSG_USAGE); 100 goto cleanup; 101 } 102 } 103 104 /* should be no arguments left */ 105 if ((argc-optind) > 0) { 106 log_msg(LOG_MSG_ERR, MSG_USAGE); 107 goto cleanup; 108 } 109 110 /* figure out format */ 111 if (format_str == NULL) { 112 format = KEYSTORE_FORMAT_TEXT; 113 } else { 114 if (ci_streq(format_str, "text")) { 115 format = KEYSTORE_FORMAT_TEXT; 116 } else if (ci_streq(format_str, "pem")) { 117 format = KEYSTORE_FORMAT_PEM; 118 } else if (ci_streq(format_str, "der")) { 119 format = KEYSTORE_FORMAT_DER; 120 } else { 121 log_msg(LOG_MSG_ERR, MSG_BAD_FORMAT, format_str); 122 goto cleanup; 123 } 124 } 125 126 /* open output file */ 127 if (outfile_str == NULL) { 128 outfile = stdout; 129 outfile_str = "stdout"; 130 } else { 131 if ((outfile = fopen(outfile_str, "w+")) == NULL) { 132 log_msg(LOG_MSG_ERR, MSG_OPEN_WRITE, outfile_str); 133 goto cleanup; 134 } 135 } 136 137 /* set up proper keystore */ 138 if (altroot != NULL) { 139 if (strlcpy(keystore_file, altroot, MAXPATHLEN) >= MAXPATHLEN) { 140 log_msg(LOG_MSG_ERR, MSG_TOO_LONG, altroot); 141 goto cleanup; 142 } 143 144 if (strlcat(keystore_file, "/", MAXPATHLEN) >= MAXPATHLEN) { 145 log_msg(LOG_MSG_ERR, MSG_TOO_LONG, altroot); 146 goto cleanup; 147 } 148 } 149 150 if (keystore_base == NULL) { 151 if (geteuid() == 0 || altroot != NULL) { 152 /* 153 * If we have an alternate 154 * root, then we have no choice but to use 155 * root's keystore on that alternate root, 156 * since there is no way to resolve a 157 * user's home dir given an alternate root 158 */ 159 if (strlcat(keystore_file, PKGSEC, 160 MAXPATHLEN) >= MAXPATHLEN) { 161 log_msg(LOG_MSG_ERR, MSG_TOO_LONG, 162 keystore_file); 163 goto cleanup; 164 } 165 } else { 166 if ((homedir = getenv("HOME")) == NULL) { 167 /* 168 * not superuser, but no home dir, so 169 * use superuser's keystore 170 */ 171 if (strlcat(keystore_file, PKGSEC, 172 MAXPATHLEN) >= MAXPATHLEN) { 173 log_msg(LOG_MSG_ERR, MSG_TOO_LONG, 174 keystore_file); 175 goto cleanup; 176 } 177 } else { 178 if (strlcat(keystore_file, homedir, 179 MAXPATHLEN) >= MAXPATHLEN) { 180 log_msg(LOG_MSG_ERR, MSG_TOO_LONG, 181 homedir); 182 goto cleanup; 183 } 184 if (strlcat(keystore_file, "/.pkg/security", 185 MAXPATHLEN) >= MAXPATHLEN) { 186 log_msg(LOG_MSG_ERR, MSG_TOO_LONG, 187 keystore_file); 188 goto cleanup; 189 } 190 } 191 } 192 } else { 193 if (strlcat(keystore_file, keystore_base, 194 MAXPATHLEN) >= MAXPATHLEN) { 195 log_msg(LOG_MSG_ERR, MSG_TOO_LONG, 196 keystore_base); 197 goto cleanup; 198 } 199 } 200 err = pkgerr_new(); 201 202 /* now load the key store */ 203 log_msg(LOG_MSG_DEBUG, "Loading keystore <%s>", keystore_file); 204 205 set_passphrase_prompt(MSG_KEYSTORE_PASSPROMPT); 206 set_passphrase_passarg(passarg); 207 if (open_keystore(err, keystore_file, prog, 208 pkg_passphrase_cb, KEYSTORE_DFLT_FLAGS, 209 &keystore) != 0) { 210 log_pkgerr(LOG_MSG_ERR, err); 211 log_msg(LOG_MSG_ERR, MSG_PRINT, outfile_str); 212 goto cleanup; 213 } 214 215 /* list the certs */ 216 log_msg(LOG_MSG_DEBUG, "Listing certificates"); 217 if (print_certs(err, keystore, alias, format, outfile) != 0) { 218 log_pkgerr(LOG_MSG_ERR, err); 219 log_msg(LOG_MSG_ERR, MSG_PRINT, outfile_str); 220 goto cleanup; 221 } 222 223 /* now close it out */ 224 log_msg(LOG_MSG_DEBUG, "Closing keystore"); 225 set_passphrase_prompt(MSG_KEYSTORE_PASSOUTPROMPT); 226 set_passphrase_passarg(passarg); 227 if (close_keystore(err, keystore, pkg_passphrase_cb) != 0) { 228 log_pkgerr(LOG_MSG_ERR, err); 229 log_msg(LOG_MSG_ERR, MSG_PRINT, outfile_str); 230 goto cleanup; 231 } 232 233 /* everything worked */ 234 ret = 0; 235 236 /* fallthrough intentional */ 237 cleanup: 238 if (outfile != NULL) 239 (void) fclose(outfile); 240 241 if (err != NULL) 242 pkgerr_free(err); 243 244 return (ret); 245 } 246