#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include "identPicker.h"
#include "asnUtils.h"
#include <Kerberos/KerberosLogin.h>
#include <Kerberos/pkinit_cert_store.h>
static void usage(char **argv)
{
printf("Usage: op [option..]\n");
printf("Ops:\n");
printf(" l login\n");
printf(" s select PKINIT client cert\n");
printf(" d display PKINIT client cert\n");
printf(" D delete PKINIT client cert setting\n");
printf("Options:\n");
printf(" -p principal -- default is current user for login\n");
printf(" -l -- loop (for malloc debug)\n");
printf(" TBD\n");
exit(1);
}
typedef enum {
KTO_Login = 0,
KTO_Select,
KTO_Display,
KTO_DeleteCert
} KrbToolOp;
typedef struct {
const char *principal;
} KrbToolArgs;
static int pkinitLogin(
const KrbToolArgs *args)
{
const char *principalStr = args->principal;
bool freeStr = false;
int ourRtn = 0;
KLLoginOptions klOpts = NULL;
if(principalStr == NULL) {
struct passwd *pw = getpwuid(getuid ());
if(pw == NULL) {
printf("***Sorry, can't find current user info. Aborting.\n");
return -1;
}
principalStr = strdup(pw->pw_name);
freeStr = true;
}
KLPrincipal principal = NULL;
KLStatus klrtn;
klrtn = KLCreatePrincipalFromString(principalStr, kerberosVersion_V5, &principal);
if(klrtn) {
printf("***KLCreatePrincipalFromString returned %d. Aborting.\n", (int)klrtn);
ourRtn = -1;
goto errOut;
}
printf("...attempting TGT acquisition\n");
klrtn = KLAcquireNewInitialTicketsWithPassword(principal, klOpts, " ", NULL);
if(klrtn) {
printf("***KLAcquireInitialTicketsWithPassword returned %d\n", (int)klrtn);
}
else {
printf("...TGT acquisition successful.\n");
}
errOut:
if(freeStr && (principalStr != NULL)) {
free((void *)principalStr);
}
if(klOpts != NULL) {
KLDisposeLoginOptions(klOpts);
}
if(principal != NULL) {
KLDisposePrincipal(principal);
}
return ourRtn;
}
static int pkinitSelect(
const KrbToolArgs *args)
{
OSStatus ortn;
SecIdentityRef idRef = NULL;
if(args->principal == NULL) {
printf("***You must supply a principal name for this operation.\n");
return -1;
}
ortn = simpleIdentPicker(NULL, &idRef);
switch(ortn) {
case CSSMERR_CSSM_USER_CANCELED:
printf("...operation terminated with no change to your settings.\n");
return 0;
case noErr:
break;
default:
printf("***Operation aborted.\n");
return -1;
}
krb5_error_code krtn = krb5_pkinit_set_client_cert(args->principal,
(krb5_pkinit_signing_cert_t)idRef);
if(krtn) {
cssmPerror("krb5_pkinit_set_client_cert", krtn);
}
else {
printf("...PKINIT client cert selection successful.\n\n");
}
if(idRef) {
CFRelease(idRef);
}
return 0;
}
static int pkinitDisplay(
const KrbToolArgs *args)
{
krb5_pkinit_signing_cert_t idRef = NULL;
krb5_error_code krtn;
if(args->principal == NULL) {
printf("***You must supply a principal name for this operation.\n");
return -1;
}
krtn = krb5_pkinit_get_client_cert(args->principal, &idRef);
switch(krtn) {
case errSecItemNotFound:
printf("...No PKINIT client cert configured for %s.\n",
args->principal ? args->principal : "Default");
break;
case noErr:
{
SecCertificateRef certRef = NULL;
OSStatus ortn;
CSSM_DATA cdata;
ortn = SecIdentityCopyCertificate((SecIdentityRef)idRef, &certRef);
if(ortn) {
cssmPerror("SecIdentityCopyCertificate", ortn);
break;
}
ortn = SecCertificateGetData(certRef, &cdata);
if(ortn) {
cssmPerror("SecCertificateGetData", ortn);
break;
}
printf("--------- PKINIT Client Certificate ---------\n");
printCertName(cdata.Data, cdata.Length, NameBoth);
printf("---------------------------------------------\n\n");
char *cert_hash = NULL;
krb5_data kcert = {0, cdata.Length, (char *)cdata.Data};
cert_hash = krb5_pkinit_cert_hash_str(&kcert);
if(cert_hash == NULL) {
printf("***Error obtaining cert hash\n");
}
else {
printf("Cert hash string : %s\n\n", cert_hash);
free(cert_hash);
}
CFRelease(certRef);
break;
}
default:
cssmPerror("krb5_pkinit_get_client_cert", krtn);
printf("***Error obtaining client cert\n");
break;
}
if(idRef) {
krb5_pkinit_release_cert(idRef);
}
return 0;
}
static int pkinitDeleteCert(
const KrbToolArgs *args)
{
krb5_error_code krtn;
krtn = krb5_pkinit_set_client_cert(args->principal, NULL);
if(krtn) {
cssmPerror("krb5_pkinit_set_client_cert(NULL)", krtn);
printf("***Error deleting client cert entry\n");
}
else {
printf("...client cert setting for %s deleted\n", args->principal ?
args->principal : "Default principal");
}
return krtn;
}
int main(int argc, char **argv)
{
if(argc < 2) {
usage(argv);
}
KrbToolOp op = KTO_Login;
switch(argv[1][0]) {
case 'l':
op = KTO_Login;
break;
case 's':
op = KTO_Select;
break;
case 'd':
op = KTO_Display;
break;
case 'D':
op = KTO_DeleteCert;
break;
default:
usage(argv);
}
extern int optind;
extern char *optarg;
int arg;
int ourRtn = 0;
KrbToolArgs args;
bool doLoop = false;
memset(&args, 0, sizeof(args));
optind = 2;
while ((arg = getopt(argc, argv, "p:lh")) != -1) {
switch (arg) {
case 'p':
args.principal = optarg;
break;
case 'l':
doLoop = true;
break;
case 'h':
default:
usage(argv);
}
}
do {
switch(op) {
case KTO_Login:
ourRtn = pkinitLogin(&args);
break;
case KTO_Select:
ourRtn = pkinitSelect(&args);
break;
case KTO_Display:
ourRtn = pkinitDisplay(&args);
break;
case KTO_DeleteCert:
ourRtn = pkinitDeleteCert(&args);
break;
default:
printf("***BRRZAP! Internal error.\n");
exit(1);
}
if(doLoop) {
char resp;
fpurge(stdin);
printf("q to quit, anything else to loop: ");
resp = getchar();
if(resp == 'q') {
break;
}
}
} while(doLoop);
return ourRtn;
}