1/* 2 * Copyright (c) 2004,2006,2008 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/* 24 * krbtool.cpp - basic PKINIT tool 25 * 26 * Created 20 May 2004 by Doug Mitchell. 27 */ 28 29#include <stdio.h> 30#include <stdlib.h> 31#include <unistd.h> 32#include <sys/types.h> 33#include <pwd.h> 34#include "identPicker.h" 35#include "asnUtils.h" 36#include <Kerberos/KerberosLogin.h> 37#include <Kerberos/pkinit_cert_store.h> 38 39static void usage(char **argv) 40{ 41 printf("Usage: op [option..]\n"); 42 printf("Ops:\n"); 43 printf(" l login\n"); 44 printf(" s select PKINIT client cert\n"); 45 printf(" d display PKINIT client cert\n"); 46 printf(" D delete PKINIT client cert setting\n"); 47 printf("Options:\n"); 48 printf(" -p principal -- default is current user for login\n"); 49 printf(" -l -- loop (for malloc debug)\n"); 50 printf(" TBD\n"); 51 exit(1); 52} 53 54typedef enum { 55 KTO_Login = 0, 56 KTO_Select, 57 KTO_Display, 58 KTO_DeleteCert 59} KrbToolOp; 60 61typedef struct { 62 const char *principal; 63 /* I'm sure others */ 64} KrbToolArgs; 65 66static int pkinitLogin( 67 const KrbToolArgs *args) 68{ 69 /* Get a principal string one way or the other */ 70 const char *principalStr = args->principal; 71 bool freeStr = false; 72 int ourRtn = 0; 73 KLLoginOptions klOpts = NULL; 74 75 if(principalStr == NULL) { 76 struct passwd *pw = getpwuid(getuid ()); 77 if(pw == NULL) { 78 printf("***Sorry, can't find current user info. Aborting.\n"); 79 return -1; 80 } 81 principalStr = strdup(pw->pw_name); 82 freeStr = true; 83 } 84 85 KLPrincipal principal = NULL; 86 KLStatus klrtn; 87 88 klrtn = KLCreatePrincipalFromString(principalStr, kerberosVersion_V5, &principal); 89 if(klrtn) { 90 printf("***KLCreatePrincipalFromString returned %d. Aborting.\n", (int)klrtn); 91 ourRtn = -1; 92 goto errOut; 93 } 94 95 /* Options, later maybe */ 96 /* FIXME - don't know if the login options arg is optional */ 97 98 /* By convention we use a non-NULL string as password; this may change later */ 99 printf("...attempting TGT acquisition\n"); 100 klrtn = KLAcquireNewInitialTicketsWithPassword(principal, klOpts, " ", NULL); 101 if(klrtn) { 102 printf("***KLAcquireInitialTicketsWithPassword returned %d\n", (int)klrtn); 103 } 104 else { 105 printf("...TGT acquisition successful.\n"); 106 } 107errOut: 108 if(freeStr && (principalStr != NULL)) { 109 free((void *)principalStr); 110 } 111 if(klOpts != NULL) { 112 KLDisposeLoginOptions(klOpts); 113 } 114 if(principal != NULL) { 115 KLDisposePrincipal(principal); 116 } 117 return ourRtn; 118} 119 120static int pkinitSelect( 121 const KrbToolArgs *args) 122{ 123 OSStatus ortn; 124 SecIdentityRef idRef = NULL; 125 126 if(args->principal == NULL) { 127 printf("***You must supply a principal name for this operation.\n"); 128 return -1; 129 } 130 ortn = simpleIdentPicker(NULL, &idRef); 131 switch(ortn) { 132 case CSSMERR_CSSM_USER_CANCELED: 133 printf("...operation terminated with no change to your settings.\n"); 134 return 0; 135 case noErr: 136 break; 137 default: 138 printf("***Operation aborted.\n"); 139 return -1; 140 } 141 142 krb5_error_code krtn = krb5_pkinit_set_client_cert(args->principal, 143 (krb5_pkinit_signing_cert_t)idRef); 144 if(krtn) { 145 cssmPerror("krb5_pkinit_set_client_cert", krtn); 146 } 147 else { 148 printf("...PKINIT client cert selection successful.\n\n"); 149 } 150 if(idRef) { 151 CFRelease(idRef); 152 } 153 return 0; 154} 155 156static int pkinitDisplay( 157 const KrbToolArgs *args) 158{ 159 krb5_pkinit_signing_cert_t idRef = NULL; 160 krb5_error_code krtn; 161 162 if(args->principal == NULL) { 163 printf("***You must supply a principal name for this operation.\n"); 164 return -1; 165 } 166 krtn = krb5_pkinit_get_client_cert(args->principal, &idRef); 167 switch(krtn) { 168 case errSecItemNotFound: 169 printf("...No PKINIT client cert configured for %s.\n", 170 args->principal ? args->principal : "Default"); 171 break; 172 case noErr: 173 { 174 SecCertificateRef certRef = NULL; 175 OSStatus ortn; 176 CSSM_DATA cdata; 177 178 ortn = SecIdentityCopyCertificate((SecIdentityRef)idRef, &certRef); 179 if(ortn) { 180 cssmPerror("SecIdentityCopyCertificate", ortn); 181 break; 182 } 183 ortn = SecCertificateGetData(certRef, &cdata); 184 if(ortn) { 185 cssmPerror("SecCertificateGetData", ortn); 186 break; 187 } 188 printf("--------- PKINIT Client Certificate ---------\n"); 189 printCertName(cdata.Data, cdata.Length, NameBoth); 190 printf("---------------------------------------------\n\n"); 191 192 char *cert_hash = NULL; 193 krb5_data kcert = {0, cdata.Length, (char *)cdata.Data}; 194 cert_hash = krb5_pkinit_cert_hash_str(&kcert); 195 if(cert_hash == NULL) { 196 printf("***Error obtaining cert hash\n"); 197 } 198 else { 199 printf("Cert hash string : %s\n\n", cert_hash); 200 free(cert_hash); 201 } 202 CFRelease(certRef); 203 break; 204 } 205 default: 206 cssmPerror("krb5_pkinit_get_client_cert", krtn); 207 printf("***Error obtaining client cert\n"); 208 break; 209 } 210 if(idRef) { 211 krb5_pkinit_release_cert(idRef); 212 } 213 214 return 0; 215} 216 217static int pkinitDeleteCert( 218 const KrbToolArgs *args) 219{ 220 krb5_error_code krtn; 221 222 krtn = krb5_pkinit_set_client_cert(args->principal, NULL); 223 if(krtn) { 224 cssmPerror("krb5_pkinit_set_client_cert(NULL)", krtn); 225 printf("***Error deleting client cert entry\n"); 226 } 227 else { 228 printf("...client cert setting for %s deleted\n", args->principal ? 229 args->principal : "Default principal"); 230 } 231 return krtn; 232} 233 234int main(int argc, char **argv) 235{ 236 if(argc < 2) { 237 usage(argv); 238 } 239 240 KrbToolOp op = KTO_Login; 241 switch(argv[1][0]) { 242 case 'l': 243 op = KTO_Login; 244 break; 245 case 's': 246 op = KTO_Select; 247 break; 248 case 'd': 249 op = KTO_Display; 250 break; 251 case 'D': 252 op = KTO_DeleteCert; 253 break; 254 default: 255 usage(argv); 256 } 257 258 extern int optind; 259 extern char *optarg; 260 int arg; 261 int ourRtn = 0; 262 KrbToolArgs args; 263 bool doLoop = false; 264 265 memset(&args, 0, sizeof(args)); 266 optind = 2; 267 while ((arg = getopt(argc, argv, "p:lh")) != -1) { 268 switch (arg) { 269 case 'p': 270 args.principal = optarg; 271 break; 272 case 'l': 273 doLoop = true; 274 break; 275 case 'h': 276 default: 277 usage(argv); 278 } 279 } 280 281 do { 282 switch(op) { 283 case KTO_Login: 284 ourRtn = pkinitLogin(&args); 285 break; 286 case KTO_Select: 287 ourRtn = pkinitSelect(&args); 288 break; 289 case KTO_Display: 290 ourRtn = pkinitDisplay(&args); 291 break; 292 case KTO_DeleteCert: 293 ourRtn = pkinitDeleteCert(&args); 294 break; 295 default: 296 printf("***BRRZAP! Internal error.\n"); 297 exit(1); 298 } 299 if(doLoop) { 300 char resp; 301 302 fpurge(stdin); 303 printf("q to quit, anything else to loop: "); 304 resp = getchar(); 305 if(resp == 'q') { 306 break; 307 } 308 } 309 } while(doLoop); 310 /* cleanup */ 311 return ourRtn; 312 313} 314