#include <Security/SecKeychainItem.h>
#include <Security/SecKeychain.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/param.h>
#define KC_DB_PATH "Library/Keychains"
static void usage(char **argv)
{
printf("usage: %s keychainName command [options]\n", argv[0]);
printf("Commands:\n");
printf(" c create\n");
printf(" s get status\n");
printf(" l lock\n");
printf(" u unlock\n");
printf(" a add genericPassword\n");
printf(" g get (lookup) genericPassword\n");
printf(" d delete genericPassword\n");
printf("Options:\n");
printf(" p=keychainPassword\n");
printf(" g=genericPassword\n");
printf("Options (for create only):\n");
printf(" l=lockIntervalInSeconds\n");
printf(" L (no lockOnSleep)\n");
printf(" n(o user prompt)\n");
printf(" h(elp)\n");
exit(1);
}
#define GP_SERVICE_NAME "kctool"
#define GP_SERVICE_NAME_LEN ((UInt32)strlen(GP_SERVICE_NAME))
#define GP_ACCOUNT_NAME "John Galt"
#define GP_ACCOUNT_NAME_LEN ((UInt32)strlen(GP_ACCOUNT_NAME))
typedef enum {
KC_Nop,
KC_CreateKC,
KC_GetStatus,
KC_LockKC,
KC_UnlockKC,
KC_AddPasswd,
KC_LookupPasswd,
KC_DeletePasswd
} KcOp;
static void showError(
OSStatus ortn,
const char *msg)
{
printf("***Error %d on %s.\n", (int)ortn, msg);
}
static void safePrint(
char *buf,
UInt32 len)
{
UInt32 i;
char c;
for(i=0; i<len; i++) {
c = *buf++;
if(c == '\0') {
break;
}
putchar(c);
}
}
int main(int argc, char **argv)
{
SecKeychainRef kcRef = nil;
char kcPath[MAXPATHLEN + 1];
OSStatus ortn;
int arg;
char *argp;
KcOp op = KC_Nop;
char *kcPwd = NULL;
UInt32 kcPwdLen = 0;
char *genericPwd = NULL;
UInt32 genericPwdLen = 0;
int lockInterval = 0;
Boolean noLockOnSleep = false;
Boolean userPrompt = true;
if(argc < 3) {
usage(argv);
}
switch(argv[2][0]) {
case 'c':
op = KC_CreateKC;
break;
case 's':
op = KC_GetStatus;
break;
case 'l':
op = KC_LockKC;
break;
case 'u':
op = KC_UnlockKC;
break;
case 'a':
op = KC_AddPasswd;
break;
case 'g':
op = KC_LookupPasswd;
break;
case 'd':
op = KC_DeletePasswd;
break;
default:
usage(argv);
}
for(arg=3; arg<argc; arg++) {
argp = argv[arg];
switch(argp[0]) {
case 'p':
kcPwd = &argp[2];
kcPwdLen = strlen(kcPwd);
break;
case 'g':
genericPwd = &argp[2];
genericPwdLen = strlen(genericPwd);
break;
case 'l':
lockInterval = atoi(&argp[2]);
break;
case 'L':
noLockOnSleep = true;
break;
case 'n':
userPrompt = false;
break;
default:
usage(argv);
}
}
if(argv[1][0] == '/') {
strcpy(kcPath, argv[1]);
}
else {
char *userHome = getenv("HOME");
if(userHome == NULL) {
userHome = (char *)"";
}
sprintf(kcPath, "%s/%s/%s", userHome, KC_DB_PATH, argv[1]);
}
if(op != KC_CreateKC) {
ortn = SecKeychainOpen(kcPath, &kcRef);
if(ortn) {
showError(ortn, "SecKeychainOpen");
printf("Cannot open keychain at %s. Aborting.\n", kcPath);
exit(1);
}
}
switch(op) {
case KC_CreateKC:
{
ortn = SecKeychainCreate(kcPath,
kcPwdLen, kcPwd, userPrompt,
nil, &kcRef);
if(ortn) {
showError(ortn, "SecKeychainCreateNew");
exit(1);
}
else {
printf("...keychain %s created.\n", argv[1]);
}
break;
}
case KC_GetStatus:
{
SecKeychainStatus kcStat;
ortn = SecKeychainGetStatus(kcRef, &kcStat);
if(ortn) {
showError(ortn, "SecKeychainGetStatus");
exit(1);
}
printf("...SecKeychainStatus = %u ( ", (unsigned)kcStat);
if(kcStat & kSecUnlockStateStatus) {
printf("UnlockState ");
}
if(kcStat & kSecReadPermStatus) {
printf("RdPerm ");
}
if(kcStat & kSecWritePermStatus) {
printf("WrPerm ");
}
printf(")\n");
break;
}
case KC_LockKC:
{
ortn = SecKeychainLock(kcRef);
if(ortn) {
showError(ortn, "SecKeychainLock");
exit(1);
}
else {
printf("...keychain %s locked.\n", argv[1]);
}
break;
}
case KC_UnlockKC:
{
ortn = SecKeychainUnlock(kcRef,
kcPwdLen,
kcPwd,
kcPwd ? true : false);
if(ortn) {
showError(ortn, "SecKeychainUnlock");
exit(1);
}
else {
printf("...keychain %s unlocked.\n", argv[1]);
}
break;
}
case KC_AddPasswd:
{
SecKeychainItemRef itemRef = nil;
if(genericPwd == NULL) {
printf("***Must supply a genericPassword argument.\n");
exit(1);
}
ortn = SecKeychainAddGenericPassword(kcRef,
GP_SERVICE_NAME_LEN, GP_SERVICE_NAME,
GP_ACCOUNT_NAME_LEN, GP_ACCOUNT_NAME,
genericPwdLen, genericPwd,
&itemRef);
if(ortn) {
showError(ortn, "SecKeychainAddGenericPassword");
exit(1);
}
else {
printf("...password added to keychain %s.\n", argv[1]);
}
break;
}
case KC_LookupPasswd:
case KC_DeletePasswd:
{
char *foundPassword;
UInt32 pwdLen;
SecKeychainItemRef itemRef = nil;
ortn = SecKeychainFindGenericPassword(kcRef,
GP_SERVICE_NAME_LEN, GP_SERVICE_NAME,
GP_ACCOUNT_NAME_LEN, GP_ACCOUNT_NAME,
&pwdLen, (void **)&foundPassword,
&itemRef);
if(ortn) {
showError(ortn, "SecKeychainFindGenericPassword");
exit(1);
}
else if(op == KC_DeletePasswd) {
ortn = SecKeychainItemDelete(itemRef);
if(ortn) {
showError(ortn, "SecKeychainItemDelete");
exit(1);
}
else {
printf("...generic password deleted.\n");
}
}
else {
printf("...password found: ");
safePrint(foundPassword, pwdLen);
printf("\n");
}
break;
}
default:
usage(argv);
}
return 0;
}