static krb5_error_code copy_creds_except(krb5_context context, krb5_ccache incc, krb5_ccache outcc, krb5_principal princ) { krb5_error_code ret, ret2; krb5_cc_cursor cur; krb5_creds creds; /* Turn off TC_OPENCLOSE on input ccache. */ ret = krb5_cc_set_flags(context, incc, 0); if (ret) return ret; ret = krb5_cc_start_seq_get(context, incc, &cur); if (ret) goto cleanup; while (!(ret = krb5_cc_next_cred(context, incc, &cur, &creds))) { if (krb5_principal_compare(context, princ, creds.server)) continue; ret = krb5_cc_store_cred(context, outcc, &creds); krb5_free_cred_contents(context, &creds); if (ret) goto cleanup; } if (ret != KRB5_CC_END) goto cleanup; ret = 0; cleanup: ret2 = krb5_cc_set_flags(context, incc, KRB5_TC_OPENCLOSE); return (ret == 0) ? ret2 : ret; }
static int query_krb5_ccache(const char* cred_cache, char **ret_princname, char **ret_realm) { krb5_error_code ret; krb5_context context; krb5_ccache ccache; krb5_principal principal; int found = 0; char *str = NULL; char *princstring; ret = krb5_init_context(&context); if (ret) return 0; if(!cred_cache || krb5_cc_resolve(context, cred_cache, &ccache)) goto err_cache; if (krb5_cc_set_flags(context, ccache, 0)) goto err_princ; ret = krb5_cc_get_principal(context, ccache, &principal); if (ret) goto err_princ; found = check_for_tgt(context, ccache, principal); if (found) { ret = krb5_unparse_name(context, principal, &princstring); if (ret == 0) { if ((str = strchr(princstring, '@')) != NULL) { *str = '\0'; *ret_princname = strdup(princstring); *ret_realm = strdup(str+1); } k5_free_unparsed_name(context, princstring); } else { found = 0; } } krb5_free_principal(context, principal); err_princ: krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE); krb5_cc_close(context, ccache); err_cache: krb5_free_context(context); return found; }
/* * Check if a ccache has any tickets. */ static krb5_error_code cc_has_tickets(krb5_context kcontext, krb5_ccache ccache, int *has_tickets) { krb5_error_code code; krb5_cc_cursor cursor; krb5_creds creds; krb5_timestamp now = time(0); *has_tickets = 0; code = krb5_cc_set_flags(kcontext, ccache, KRB5_TC_NOTICKET); if (code) return code; code = krb5_cc_start_seq_get(kcontext, ccache, &cursor); if (code) return code; while (!*has_tickets) { code = krb5_cc_next_cred(kcontext, ccache, &cursor, &creds); if (code) break; if (!krb5_is_config_principal(kcontext, creds.server) && creds.times.endtime > now) *has_tickets = 1; krb5_free_cred_contents(kcontext, &creds); } krb5_cc_end_seq_get(kcontext, ccache, &cursor); return 0; }
static krb5_error_code copy_creds_except(krb5_context context, krb5_ccache incc, krb5_ccache outcc, krb5_principal princ) { krb5_error_code code; krb5_flags flags; krb5_cc_cursor cur; krb5_creds creds; flags = 0; /* turns off OPENCLOSE mode */ if ((code = krb5_cc_set_flags(context, incc, flags))) return(code); if ((code = krb5_cc_start_seq_get(context, incc, &cur))) goto cleanup; while (!(code = krb5_cc_next_cred(context, incc, &cur, &creds))) { if (krb5_principal_compare(context, princ, creds.server)) continue; code = krb5_cc_store_cred(context, outcc, &creds); krb5_free_cred_contents(context, &creds); if (code) goto cleanup; } if (code != KRB5_CC_END) goto cleanup; code = 0; cleanup: flags = KRB5_TC_OPENCLOSE; if (code) krb5_cc_set_flags(context, incc, flags); else code = krb5_cc_set_flags(context, incc, flags); return(code); }
krb5_error_code KRB5_CALLCONV krb5_cc_copy_creds(krb5_context context, krb5_ccache incc, krb5_ccache outcc) { krb5_error_code code; krb5_flags flags; krb5_cc_cursor cur = 0; krb5_creds creds; flags = 0; /* turns off OPENCLOSE mode */ if ((code = krb5_cc_set_flags(context, incc, flags))) return(code); /* the code for this will open the file for reading only, which is not what I had in mind. So I won't turn off OPENCLOSE for the output ccache */ #if 0 if ((code = krb5_cc_set_flags(context, outcc, flags))) return(code); #endif if ((code = krb5_cc_start_seq_get(context, incc, &cur))) goto cleanup; while (!(code = krb5_cc_next_cred(context, incc, &cur, &creds))) { code = krb5_cc_store_cred(context, outcc, &creds); krb5_free_cred_contents(context, &creds); if (code) goto cleanup; } if (code != KRB5_CC_END) goto cleanup; code = krb5_cc_end_seq_get(context, incc, &cur); cur = 0; if (code) goto cleanup; code = 0; cleanup: flags = KRB5_TC_OPENCLOSE; /* If set then we are in an error pathway */ if (cur) krb5_cc_end_seq_get(context, incc, &cur); if (code) krb5_cc_set_flags(context, incc, flags); else code = krb5_cc_set_flags(context, incc, flags); #if 0 if (code) krb5_cc_set_flags(context, outcc, flags); else code = krb5_cc_set_flags(context, outcc, flags); #endif return(code); }
static void print_tickets (krb5_context context, krb5_ccache ccache, krb5_principal principal, int do_verbose, int do_flags, int do_hidden) { krb5_error_code ret; char *str, *name; krb5_cc_cursor cursor; krb5_creds creds; krb5_deltat sec; rtbl_t ct = NULL; ret = krb5_unparse_name (context, principal, &str); if (ret) krb5_err (context, 1, ret, "krb5_unparse_name"); printf ("%17s: %s:%s\n", N_("Credentials cache", ""), krb5_cc_get_type(context, ccache), krb5_cc_get_name(context, ccache)); printf ("%17s: %s\n", N_("Principal", ""), str); ret = krb5_cc_get_friendly_name(context, ccache, &name); if (ret == 0) { if (strcmp(name, str) != 0) printf ("%17s: %s\n", N_("Friendly name", ""), name); free(name); } free (str); if(do_verbose) { printf ("%17s: %d\n", N_("Cache version", ""), krb5_cc_get_version(context, ccache)); } else { krb5_cc_set_flags(context, ccache, KRB5_TC_NOTICKET); } ret = krb5_cc_get_kdc_offset(context, ccache, &sec); if (ret == 0 && do_verbose && sec != 0) { char buf[BUFSIZ]; int val; int sig; val = sec; sig = 1; if (val < 0) { sig = -1; val = -val; } unparse_time (val, buf, sizeof(buf)); printf ("%17s: %s%s\n", N_("KDC time offset", ""), sig == -1 ? "-" : "", buf); } printf("\n"); ret = krb5_cc_start_seq_get (context, ccache, &cursor); if (ret) krb5_err(context, 1, ret, "krb5_cc_start_seq_get"); if(!do_verbose) { ct = rtbl_create(); rtbl_add_column(ct, COL_ISSUED, 0); rtbl_add_column(ct, COL_EXPIRES, 0); if(do_flags) rtbl_add_column(ct, COL_FLAGS, 0); rtbl_add_column(ct, COL_PRINCIPAL, 0); rtbl_set_separator(ct, " "); } while ((ret = krb5_cc_next_cred (context, ccache, &cursor, &creds)) == 0) { if (!do_hidden && krb5_is_config_principal(context, creds.server)) { ; }else if(do_verbose){ print_cred_verbose(context, &creds); }else{ print_cred(context, &creds, ct, do_flags); } krb5_free_cred_contents (context, &creds); } if(ret != KRB5_CC_END) krb5_err(context, 1, ret, "krb5_cc_get_next"); ret = krb5_cc_end_seq_get (context, ccache, &cursor); if (ret) krb5_err (context, 1, ret, "krb5_cc_end_seq_get"); if(!do_verbose) { rtbl_format(ct, stdout); rtbl_destroy(ct); } }
/* * Class: sun_security_krb5_Credentials * Method: acquireDefaultNativeCreds * Signature: ([I])Lsun/security/krb5/Credentials; */ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativeCreds (JNIEnv *env, jclass krbcredsClass, jintArray jetypes) { jobject krbCreds = NULL; krb5_error_code err = 0; krb5_ccache ccache = NULL; krb5_cc_cursor cursor = NULL; krb5_creds creds; krb5_flags flags = 0; krb5_context kcontext = NULL; int netypes; jint *etypes = NULL; /* Initialize the Kerberos 5 context */ err = krb5_init_context (&kcontext); if (!err) { err = krb5_cc_default (kcontext, &ccache); } if (!err) { err = krb5_cc_set_flags (kcontext, ccache, flags); /* turn off OPENCLOSE */ } if (!err) { err = krb5_cc_start_seq_get (kcontext, ccache, &cursor); } netypes = (*env)->GetArrayLength(env, jetypes); etypes = (jint *) (*env)->GetIntArrayElements(env, jetypes, NULL); if (etypes != NULL && !err) { while ((err = krb5_cc_next_cred (kcontext, ccache, &cursor, &creds)) == 0) { char *serverName = NULL; if (!err) { err = krb5_unparse_name (kcontext, creds.server, &serverName); printiferr (err, "while unparsing server name"); } if (!err) { char* slash = strchr(serverName, '/'); char* at = strchr(serverName, '@'); // Make sure the server's name is krbtgt/REALM@REALM, the etype // is supported, and the ticket has not expired if (slash && at && strncmp (serverName, "krbtgt", slash-serverName) == 0 && // the ablove line shows at must be after slash strncmp (slash+1, at+1, at-slash-1) == 0 && isIn (creds.keyblock.enctype, netypes, etypes) && creds.times.endtime > time(0)) { jobject ticket, clientPrincipal, targetPrincipal, encryptionKey; jobject ticketFlags, startTime, endTime; jobject authTime, renewTillTime, hostAddresses; ticket = clientPrincipal = targetPrincipal = encryptionKey = NULL; ticketFlags = startTime = endTime = NULL; authTime = renewTillTime = hostAddresses = NULL; // For the default credentials we're only interested in the krbtgt server. clientPrincipal = BuildClientPrincipal(env, kcontext, creds.client); if (clientPrincipal == NULL) goto cleanup; targetPrincipal = BuildClientPrincipal(env, kcontext, creds.server); if (targetPrincipal == NULL) goto cleanup; // Build a sun/security/krb5/internal/Ticket ticket = BuildTicket(env, &creds.ticket); if (ticket == NULL) goto cleanup; // Get the encryption key encryptionKey = BuildEncryptionKey(env, &creds.keyblock); if (encryptionKey == NULL) goto cleanup; // and the ticket flags ticketFlags = BuildTicketFlags(env, creds.ticket_flags); if (ticketFlags == NULL) goto cleanup; // Get the timestamps out. startTime = BuildKerberosTime(env, creds.times.starttime); if (startTime == NULL) goto cleanup; authTime = BuildKerberosTime(env, creds.times.authtime); if (authTime == NULL) goto cleanup; endTime = BuildKerberosTime(env, creds.times.endtime); if (endTime == NULL) goto cleanup; renewTillTime = BuildKerberosTime(env, creds.times.renew_till); if (renewTillTime == NULL) goto cleanup; // Create the addresses object. hostAddresses = BuildAddressList(env, creds.addresses); if (krbcredsConstructor == 0) { krbcredsConstructor = (*env)->GetMethodID(env, krbcredsClass, "<init>", "(Lsun/security/krb5/internal/Ticket;Lsun/security/krb5/PrincipalName;Lsun/security/krb5/PrincipalName;Lsun/security/krb5/EncryptionKey;Lsun/security/krb5/internal/TicketFlags;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/HostAddresses;)V"); if (krbcredsConstructor == 0) { printf("Couldn't find sun.security.krb5.internal.Ticket constructor\n"); break; } } // and now go build a KrbCreds object krbCreds = (*env)->NewObject( env, krbcredsClass, krbcredsConstructor, ticket, clientPrincipal, targetPrincipal, encryptionKey, ticketFlags, authTime, startTime, endTime, renewTillTime, hostAddresses); cleanup: if (ticket) (*env)->DeleteLocalRef(env, ticket); if (clientPrincipal) (*env)->DeleteLocalRef(env, clientPrincipal); if (targetPrincipal) (*env)->DeleteLocalRef(env, targetPrincipal); if (encryptionKey) (*env)->DeleteLocalRef(env, encryptionKey); if (ticketFlags) (*env)->DeleteLocalRef(env, ticketFlags); if (authTime) (*env)->DeleteLocalRef(env, authTime); if (startTime) (*env)->DeleteLocalRef(env, startTime); if (endTime) (*env)->DeleteLocalRef(env, endTime); if (renewTillTime) (*env)->DeleteLocalRef(env, renewTillTime); if (hostAddresses) (*env)->DeleteLocalRef(env, hostAddresses); // Stop if there is an exception or we already found the initial TGT if ((*env)->ExceptionCheck(env) || krbCreds) { break; } } } if (serverName != NULL) { krb5_free_unparsed_name (kcontext, serverName); } krb5_free_cred_contents (kcontext, &creds); } if (err == KRB5_CC_END) { err = 0; } printiferr (err, "while retrieving a ticket"); } if (!err) { err = krb5_cc_end_seq_get (kcontext, ccache, &cursor); printiferr (err, "while finishing ticket retrieval"); } if (!err) { flags = KRB5_TC_OPENCLOSE; /* restore OPENCLOSE mode */ err = krb5_cc_set_flags (kcontext, ccache, flags); printiferr (err, "while finishing ticket retrieval"); } if (etypes != NULL) { (*env)->ReleaseIntArrayElements(env, jetypes, etypes, 0); } krb5_free_context (kcontext); return krbCreds; }
static void cc_test(krb5_context context, const char *name, krb5_flags flags) { krb5_ccache id, id2; krb5_creds creds; krb5_error_code kret; krb5_cc_cursor cursor; krb5_principal tmp; const char *c_name; char newcache[300]; char *save_type; kret = init_test_cred(context); CHECK(kret, "init_creds"); kret = krb5_cc_resolve(context, name, &id); CHECK(kret, "resolve"); kret = krb5_cc_initialize(context, id, test_creds.client); CHECK(kret, "initialize"); c_name = krb5_cc_get_name(context, id); CHECK_STR(c_name, "get_name"); c_name = krb5_cc_get_type(context, id); CHECK_STR(c_name, "get_type"); save_type=strdup(c_name); CHECK_STR(save_type, "copying type"); kret = krb5_cc_store_cred(context, id, &test_creds); CHECK(kret, "store"); kret = krb5_cc_get_principal(context, id, &tmp); CHECK(kret, "get_principal"); CHECK_BOOL(krb5_realm_compare(context, tmp, test_creds.client) != TRUE, "realms do not match", "realm_compare"); CHECK_BOOL(krb5_principal_compare(context, tmp, test_creds.client) != TRUE, "principals do not match", "principal_compare"); krb5_free_principal(context, tmp); kret = krb5_cc_set_flags (context, id, flags); CHECK(kret, "set_flags"); kret = krb5_cc_start_seq_get(context, id, &cursor); CHECK(kret, "start_seq_get"); kret = 0; while (kret != KRB5_CC_END) { if(debug) printf("Calling next_cred\n"); kret = krb5_cc_next_cred(context, id, &cursor, &creds); if(kret == KRB5_CC_END) { if(debug) printf("next_cred: ok at end\n"); } else { CHECK(kret, "next_cred"); krb5_free_cred_contents(context, &creds); } } kret = krb5_cc_end_seq_get(context, id, &cursor); CHECK(kret, "end_seq_get"); kret = krb5_cc_close(context, id); CHECK(kret, "close"); /* ------------------------------------------------- */ kret = krb5_cc_resolve(context, name, &id); CHECK(kret, "resolve2"); { /* Copy the cache test*/ snprintf(newcache, sizeof(newcache), "%s.new", name); kret = krb5_cc_resolve(context, newcache, &id2); CHECK(kret, "resolve of new cache"); /* This should fail as the new creds are not initialized */ kret = krb5_cc_copy_creds(context, id, id2); CHECK_FAIL(KRB5_FCC_NOFILE, kret, "copy_creds"); kret = krb5_cc_initialize(context, id2, test_creds.client); CHECK(kret, "initialize of id2"); kret = krb5_cc_copy_creds(context, id, id2); CHECK(kret, "copy_creds"); kret = krb5_cc_destroy(context, id2); CHECK(kret, "destroy new cache"); } /* Destroy the first cache */ kret = krb5_cc_destroy(context, id); CHECK(kret, "destroy"); /* ----------------------------------------------------- */ /* Tests the generate new code */ kret = krb5_cc_new_unique(context, save_type, NULL, &id2); CHECK(kret, "new_unique"); kret = krb5_cc_initialize(context, id2, test_creds.client); CHECK(kret, "initialize"); kret = krb5_cc_store_cred(context, id2, &test_creds); CHECK(kret, "store"); kret = krb5_cc_destroy(context, id2); CHECK(kret, "destroy id2"); free(save_type); free_test_cred(context); }
void main( int argc, char *argv[] ) { krb5_context kcontext; krb5_error_code code; krb5_ccache ccache=NULL; krb5_ccache mslsa_ccache=NULL; krb5_cc_cursor cursor; krb5_creds creds; krb5_principal princ; int initial_ticket = 0; int option; char * ccachestr = 0; prog = strrchr(argv[0], '/'); prog = prog ? (prog + 1) : argv[0]; while ((option = getopt(argc, argv, "c:h")) != -1) { switch (option) { case 'c': ccachestr = optarg; break; case 'h': default: xusage(); break; } } if (code = krb5_init_context(&kcontext)) { com_err(argv[0], code, "while initializing kerberos library"); exit(1); } if (code = krb5_cc_resolve(kcontext, "MSLSA:", &mslsa_ccache)) { com_err(argv[0], code, "while opening MS LSA ccache"); krb5_free_context(kcontext); exit(1); } if (code = krb5_cc_set_flags(kcontext, mslsa_ccache, KRB5_TC_NOTICKET)) { com_err(argv[0], code, "while setting KRB5_TC_NOTICKET flag"); krb5_cc_close(kcontext, mslsa_ccache); krb5_free_context(kcontext); exit(1); } /* Enumerate tickets from cache looking for an initial ticket */ if ((code = krb5_cc_start_seq_get(kcontext, mslsa_ccache, &cursor))) { com_err(argv[0], code, "while initiating the cred sequence of MS LSA ccache"); krb5_cc_close(kcontext, mslsa_ccache); krb5_free_context(kcontext); exit(1); } while (!(code = krb5_cc_next_cred(kcontext, mslsa_ccache, &cursor, &creds))) { if ( creds.ticket_flags & TKT_FLG_INITIAL ) { krb5_free_cred_contents(kcontext, &creds); initial_ticket = 1; break; } krb5_free_cred_contents(kcontext, &creds); } krb5_cc_end_seq_get(kcontext, mslsa_ccache, &cursor); if (code = krb5_cc_set_flags(kcontext, mslsa_ccache, 0)) { com_err(argv[0], code, "while clearing flags"); krb5_cc_close(kcontext, mslsa_ccache); krb5_free_context(kcontext); exit(1); } if ( !initial_ticket ) { fprintf(stderr, "%s: Initial Ticket Getting Tickets are not available from the MS LSA\n", argv[0]); krb5_cc_close(kcontext, mslsa_ccache); krb5_free_context(kcontext); exit(1); } if (code = krb5_cc_get_principal(kcontext, mslsa_ccache, &princ)) { com_err(argv[0], code, "while obtaining MS LSA principal"); krb5_cc_close(kcontext, mslsa_ccache); krb5_free_context(kcontext); exit(1); } if (ccachestr) code = krb5_cc_resolve(kcontext, ccachestr, &ccache); else code = krb5_cc_default(kcontext, &ccache); if (code) { com_err(argv[0], code, "while getting default ccache"); krb5_free_principal(kcontext, princ); krb5_cc_close(kcontext, mslsa_ccache); krb5_free_context(kcontext); exit(1); } if (code = krb5_cc_initialize(kcontext, ccache, princ)) { com_err (argv[0], code, "when initializing ccache"); krb5_free_principal(kcontext, princ); krb5_cc_close(kcontext, mslsa_ccache); krb5_cc_close(kcontext, ccache); krb5_free_context(kcontext); exit(1); } if (code = krb5_cc_copy_creds(kcontext, mslsa_ccache, ccache)) { com_err (argv[0], code, "while copying MS LSA ccache to default ccache"); krb5_free_principal(kcontext, princ); krb5_cc_close(kcontext, ccache); krb5_cc_close(kcontext, mslsa_ccache); krb5_free_context(kcontext); exit(1); } krb5_free_principal(kcontext, princ); krb5_cc_close(kcontext, ccache); krb5_cc_close(kcontext, mslsa_ccache); krb5_free_context(kcontext); return(0); }
/* * Class: sun_security_krb5_Credentials * Method: acquireDefaultNativeCreds * Signature: ()Lsun/security/krb5/Credentials; */ JNIEXPORT jobject JNICALL Java_sun_security_krb5_Credentials_acquireDefaultNativeCreds (JNIEnv *env, jclass krbcredsClass) { jobject krbCreds = NULL; krb5_error_code err = 0; krb5_ccache ccache = NULL; krb5_cc_cursor cursor = NULL; krb5_creds creds; krb5_flags flags = 0; krb5_context kcontext = NULL; /* Initialize the Kerberos 5 context */ err = krb5_init_context (&kcontext); if (!err) { err = krb5_cc_default (kcontext, &ccache); } if (!err) { err = krb5_cc_set_flags (kcontext, ccache, flags); /* turn off OPENCLOSE */ } if (!err) { err = krb5_cc_start_seq_get (kcontext, ccache, &cursor); } if (!err) { while ((err = krb5_cc_next_cred (kcontext, ccache, &cursor, &creds)) == 0) { char *serverName = NULL; if (!err) { err = krb5_unparse_name (kcontext, creds.server, &serverName); printiferr (err, "while unparsing server name"); } if (!err) { if (strncmp (serverName, "krbtgt", strlen("krbtgt")) == 0) { jobject ticket, clientPrincipal, targetPrincipal, encryptionKey; jobject ticketFlags, startTime, endTime; jobject authTime, renewTillTime, hostAddresses; ticket = clientPrincipal = targetPrincipal = encryptionKey = NULL; ticketFlags = startTime = endTime = NULL; authTime = renewTillTime = hostAddresses = NULL; // For the default credentials we're only interested in the krbtgt server. clientPrincipal = BuildClientPrincipal(env, kcontext, creds.client); if (clientPrincipal == NULL) goto cleanup; targetPrincipal = BuildClientPrincipal(env, kcontext, creds.server); if (targetPrincipal == NULL) goto cleanup; // Build a com.ibm.security.krb5.Ticket ticket = BuildTicket(env, &creds.ticket); if (ticket == NULL) goto cleanup; // Get the encryption key encryptionKey = BuildEncryptionKey(env, &creds.keyblock); if (encryptionKey == NULL) goto cleanup; // and the ticket flags ticketFlags = BuildTicketFlags(env, creds.ticket_flags); if (ticketFlags == NULL) goto cleanup; // Get the timestamps out. startTime = BuildKerberosTime(env, creds.times.starttime); if (startTime == NULL) goto cleanup; authTime = BuildKerberosTime(env, creds.times.authtime); if (authTime == NULL) goto cleanup; endTime = BuildKerberosTime(env, creds.times.endtime); if (endTime == NULL) goto cleanup; renewTillTime = BuildKerberosTime(env, creds.times.renew_till); if (renewTillTime == NULL) goto cleanup; // Create the addresses object. hostAddresses = BuildAddressList(env, creds.addresses); if (krbcredsConstructor == 0) { krbcredsConstructor = (*env)->GetMethodID(env, krbcredsClass, "<init>", "(Lsun/security/krb5/internal/Ticket;Lsun/security/krb5/PrincipalName;Lsun/security/krb5/PrincipalName;Lsun/security/krb5/EncryptionKey;Lsun/security/krb5/internal/TicketFlags;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/KerberosTime;Lsun/security/krb5/internal/HostAddresses;)V"); if (krbcredsConstructor == 0) { printf("Couldn't find com.ibm.security.krb5.Credentials constructor\n"); break; } } // and now go build a KrbCreds object krbCreds = (*env)->NewObject( env, krbcredsClass, krbcredsConstructor, ticket, clientPrincipal, targetPrincipal, encryptionKey, ticketFlags, authTime, startTime, endTime, renewTillTime, hostAddresses); cleanup: if (ticket) (*env)->DeleteLocalRef(env, ticket); if (clientPrincipal) (*env)->DeleteLocalRef(env, clientPrincipal); if (targetPrincipal) (*env)->DeleteLocalRef(env, targetPrincipal); if (encryptionKey) (*env)->DeleteLocalRef(env, encryptionKey); if (ticketFlags) (*env)->DeleteLocalRef(env, ticketFlags); if (authTime) (*env)->DeleteLocalRef(env, authTime); if (startTime) (*env)->DeleteLocalRef(env, startTime); if (endTime) (*env)->DeleteLocalRef(env, endTime); if (renewTillTime) (*env)->DeleteLocalRef(env, renewTillTime); if (hostAddresses) (*env)->DeleteLocalRef(env, hostAddresses); } } if (serverName != NULL) { krb5_free_unparsed_name (kcontext, serverName); } krb5_free_cred_contents (kcontext, &creds); } if (err == KRB5_CC_END) { err = 0; } printiferr (err, "while retrieving a ticket"); } if (!err) { err = krb5_cc_end_seq_get (kcontext, ccache, &cursor); printiferr (err, "while finishing ticket retrieval"); } if (!err) { flags = KRB5_TC_OPENCLOSE; /* restore OPENCLOSE mode */ err = krb5_cc_set_flags (kcontext, ccache, flags); printiferr (err, "while finishing ticket retrieval"); } krb5_free_context (kcontext); return krbCreds; }
static krb5_error_code krb5_cc_retrieve_cred_seq (krb5_context context, krb5_ccache id, krb5_flags whichfields, krb5_creds *mcreds, krb5_creds *creds, int nktypes, krb5_enctype *ktypes) { /* This function could be considerably faster if it kept indexing */ /* information.. sounds like a "next version" idea to me. :-) */ krb5_cc_cursor cursor; krb5_error_code kret; krb5_error_code nomatch_err = KRB5_CC_NOTFOUND; struct { krb5_creds creds; int pref; } fetched, best; int have_creds = 0; krb5_flags oflags = 0; #define fetchcreds (fetched.creds) /* Solaris Kerberos */ memset(&best, 0, sizeof (best)); memset(&fetched, 0, sizeof (fetched)); kret = krb5_cc_get_flags(context, id, &oflags); if (kret != KRB5_OK) return kret; if (oflags & KRB5_TC_OPENCLOSE) (void) krb5_cc_set_flags(context, id, oflags & ~KRB5_TC_OPENCLOSE); kret = krb5_cc_start_seq_get(context, id, &cursor); if (kret != KRB5_OK) { if (oflags & KRB5_TC_OPENCLOSE) krb5_cc_set_flags(context, id, oflags); return kret; } while ((kret = krb5_cc_next_cred(context, id, &cursor, &fetchcreds)) == KRB5_OK) { if (krb5int_cc_creds_match_request(context, whichfields, mcreds, &fetchcreds)) { if (ktypes) { fetched.pref = pref (fetchcreds.keyblock.enctype, nktypes, ktypes); if (fetched.pref < 0) nomatch_err = KRB5_CC_NOT_KTYPE; else if (!have_creds || fetched.pref < best.pref) { if (have_creds) krb5_free_cred_contents (context, &best.creds); else have_creds = 1; best = fetched; continue; } } else { krb5_cc_end_seq_get(context, id, &cursor); *creds = fetchcreds; /* Solaris Kerberos */ creds->keyblock.hKey = CK_INVALID_HANDLE; if (oflags & KRB5_TC_OPENCLOSE) krb5_cc_set_flags(context, id, oflags); return KRB5_OK; } } /* This one doesn't match */ krb5_free_cred_contents(context, &fetchcreds); } /* If we get here, a match wasn't found */ krb5_cc_end_seq_get(context, id, &cursor); if (oflags & KRB5_TC_OPENCLOSE) krb5_cc_set_flags(context, id, oflags); if (have_creds) { *creds = best.creds; /* Solaris Kerberos */ creds->keyblock.hKey = CK_INVALID_HANDLE; return KRB5_OK; } else return nomatch_err; }
/* * Output the ccache contents */ int do_ccache(krb5_ccache cache) { char *ccname = NULL; krb5_creds creds; krb5_cc_cursor cursor; krb5_principal princ = NULL; char *princname = NULL; krb5_flags flags = 0; krb5_error_code retval; int status = 1; asprintf(&ccname, "%s:%s", krb5_cc_get_type(ctx, cache), krb5_cc_get_name(ctx, cache)); if (!ccname) goto cleanup; if (show_ccname_only && !show_collection) { // With just -N, always show the name... printf("%s\n", ccname); status = 0; goto cleanup; } retval = krb5_cc_set_flags(ctx, cache, flags); if (retval) { if (quiet_errors) ; else if (retval == KRB5_FCC_NOFILE) com_err(progname, retval, "(ticket cache %s)", ccname); else com_err(progname, retval, "while setting cache flags (ticket cache %s)", ccname); goto cleanup; } retval = krb5_cc_get_principal(ctx, cache, &princ); if (retval) { if (quiet_errors) ; else if (retval == KRB5_FCC_NOFILE) com_err(progname, retval, "(ticket cache %s)", ccname); else com_err(progname, retval, "while obtaining default principal (ticket cache %s)", ccname); goto cleanup; } if (show_nothing) { status = 0; goto cleanup; } retval = krb5_unparse_name(ctx, princ, &princname); if (retval) goto cleanup; if (show_ccname_only && show_collection) { // ...with -l -N, only show names pointing to valid ccaches. printf("%s\n", ccname); status = 0; goto cleanup; } if (show_defname_only) { printf("%s\n", princname); status = 0; goto cleanup; } if (!show_names_only) { if (show_collection == 1) { // only show the header printf("cache\t%s\t%s\n", ccname, princname); status = 0; goto cleanup; } else { // TODO: should the format be merged into the one above? // separate cache/principal kept for now, for compat reasons printf("cache\t%s\n", ccname); printf("principal\t%s\n", princname); } printf("CREDENTIALS\tclient_name\tserver_name\tstart_time\texpiry_time\trenew_time\tflags\tticket_data\n"); } retval = krb5_cc_start_seq_get(ctx, cache, &cursor); if (retval) { com_err(progname, retval, "while starting to retrieve tickets"); goto cleanup; } for (;;) { retval = krb5_cc_next_cred(ctx, cache, &cursor, &creds); if (retval) break; show_cred(&creds); krb5_free_cred_contents(ctx, &creds); } if (retval == KRB5_CC_END) { krb5_cc_end_seq_get(ctx, cache, &cursor); status = 0; } else { com_err(progname, retval, "while retrieving a ticket"); } cleanup: if (princ) krb5_free_principal(ctx, princ); if (princname) krb5_free_unparsed_name(ctx, princname); if (ccname) free(ccname); return status; }
static int cifs_krb5_get_req(const char *host, const char *ccname, DATA_BLOB * mechtoken, DATA_BLOB * sess_key) { krb5_error_code ret; krb5_keyblock *tokb; krb5_context context; krb5_ccache ccache; krb5_creds in_creds, *out_creds; krb5_data apreq_pkt, in_data; krb5_auth_context auth_context = NULL; #if defined(HAVE_KRB5_AUTH_CON_SETADDRS) && defined(HAVE_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE) static const uint8_t gss_cksum[24] = { 0x10, 0x00, /* ... */}; #endif ret = krb5_init_context(&context); if (ret) { syslog(LOG_DEBUG, "%s: unable to init krb5 context", __func__); return ret; } ret = krb5_cc_resolve(context, ccname, &ccache); if (ret) { syslog(LOG_DEBUG, "%s: unable to resolve %s to ccache\n", __func__, ccname); goto out_free_context; } memset(&in_creds, 0, sizeof(in_creds)); ret = krb5_cc_get_principal(context, ccache, &in_creds.client); if (ret) { syslog(LOG_DEBUG, "%s: unable to get client principal name", __func__); goto out_free_ccache; } ret = krb5_sname_to_principal(context, host, "cifs", KRB5_NT_UNKNOWN, &in_creds.server); if (ret) { syslog(LOG_DEBUG, "%s: unable to convert sname to princ (%s).", __func__, host); goto out_free_principal; } ret = krb5_get_credentials(context, 0, ccache, &in_creds, &out_creds); krb5_free_principal(context, in_creds.server); if (ret) { syslog(LOG_DEBUG, "%s: unable to get credentials for %s", __func__, host); goto out_free_principal; } in_data.length = 0; in_data.data = NULL; ret = krb5_auth_con_init(context, &auth_context); if (ret) { syslog(LOG_DEBUG, "%s: unable to create auth_context: %d", __func__, ret); goto out_free_creds; } #if defined(HAVE_KRB5_AUTH_CON_SETADDRS) && defined(HAVE_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE) /* Ensure we will get an addressless ticket. */ ret = krb5_auth_con_setaddrs(context, auth_context, NULL, NULL); if (ret) { syslog(LOG_DEBUG, "%s: unable to set NULL addrs: %d", __func__, ret); goto out_free_auth; } /* * Create a GSSAPI checksum (0x8003), see RFC 4121. * * The current layout is * * 0x10, 0x00, 0x00, 0x00 - length = 16 * 0x00, 0x00, 0x00, 0x00 - channel binding info - 16 zero bytes * 0x00, 0x00, 0x00, 0x00 * 0x00, 0x00, 0x00, 0x00 * 0x00, 0x00, 0x00, 0x00 * 0x00, 0x00, 0x00, 0x00 - flags * * GSS_C_NO_CHANNEL_BINDINGS means 16 zero bytes, * this is needed to work against some closed source * SMB servers. * * See https://bugzilla.samba.org/show_bug.cgi?id=7890 */ in_data.data = discard_const_p(char, gss_cksum); in_data.length = 24; /* MIT krb5 < 1.7 is missing the prototype, but still has the symbol */ #if !HAVE_DECL_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE krb5_error_code krb5_auth_con_set_req_cksumtype( krb5_context context, krb5_auth_context auth_context, krb5_cksumtype cksumtype); #endif ret = krb5_auth_con_set_req_cksumtype(context, auth_context, 0x8003); if (ret) { syslog(LOG_DEBUG, "%s: unable to set 0x8003 checksum", __func__); goto out_free_auth; } #endif apreq_pkt.length = 0; apreq_pkt.data = NULL; ret = krb5_mk_req_extended(context, &auth_context, AP_OPTS_USE_SUBKEY, &in_data, out_creds, &apreq_pkt); if (ret) { syslog(LOG_DEBUG, "%s: unable to make AP-REQ for %s", __func__, host); goto out_free_auth; } ret = krb5_auth_con_getsendsubkey(context, auth_context, &tokb); if (ret) { syslog(LOG_DEBUG, "%s: unable to get session key for %s", __func__, host); goto out_free_auth; } *mechtoken = data_blob(apreq_pkt.data, apreq_pkt.length); *sess_key = data_blob(KRB5_KEY_DATA(tokb), KRB5_KEY_LENGTH(tokb)); krb5_free_keyblock(context, tokb); out_free_auth: krb5_auth_con_free(context, auth_context); out_free_creds: krb5_free_creds(context, out_creds); out_free_principal: krb5_free_principal(context, in_creds.client); out_free_ccache: #if defined(KRB5_TC_OPENCLOSE) krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE); #endif krb5_cc_close(context, ccache); out_free_context: krb5_free_context(context); return ret; }
/* does the ccache have a valid TGT? */ static time_t get_tgt_time(const char *ccname) { krb5_context context; krb5_ccache ccache; krb5_cc_cursor cur; krb5_creds creds; krb5_principal principal; time_t credtime = 0; char *realm = NULL; if (krb5_init_context(&context)) { syslog(LOG_DEBUG, "%s: unable to init krb5 context", __func__); return 0; } if (krb5_cc_resolve(context, ccname, &ccache)) { syslog(LOG_DEBUG, "%s: unable to resolve krb5 cache", __func__); goto err_cache; } if (krb5_cc_set_flags(context, ccache, 0)) { syslog(LOG_DEBUG, "%s: unable to set flags", __func__); goto err_cache; } if (krb5_cc_get_principal(context, ccache, &principal)) { syslog(LOG_DEBUG, "%s: unable to get principal", __func__); goto err_princ; } if (krb5_cc_start_seq_get(context, ccache, &cur)) { syslog(LOG_DEBUG, "%s: unable to seq start", __func__); goto err_ccstart; } if ((realm = cifs_krb5_principal_get_realm(context, principal)) == NULL) { syslog(LOG_DEBUG, "%s: unable to get realm", __func__); goto err_ccstart; } while (!credtime && !krb5_cc_next_cred(context, ccache, &cur, &creds)) { char *name; if (krb5_unparse_name(context, creds.server, &name)) { syslog(LOG_DEBUG, "%s: unable to unparse name", __func__); goto err_endseq; } if (krb5_realm_compare(context, creds.server, principal) && !strncasecmp(name, KRB5_TGS_NAME, KRB5_TGS_NAME_SIZE) && !strncasecmp(name + KRB5_TGS_NAME_SIZE + 1, realm, strlen(realm)) && creds.times.endtime > time(NULL)) credtime = creds.times.endtime; krb5_free_cred_contents(context, &creds); krb5_free_unparsed_name(context, name); } err_endseq: krb5_cc_end_seq_get(context, ccache, &cur); err_ccstart: krb5_free_principal(context, principal); err_princ: #if defined(KRB5_TC_OPENCLOSE) krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE); #endif krb5_cc_close(context, ccache); err_cache: krb5_free_context(context); return credtime; }
int main(int argc, const char **argv) { poptContext poptContext; int poptResult; uid_t uid; int kq; HANDLE lsaConnection = (HANDLE) NULL; PVOID pUserInfo = NULL; struct kevent event = { 0 }; int numChanges = 1; krb5_context krb5Context = NULL; char krb5FileCachePath[PATH_MAX]; krb5_ccache krb5FileCache = NULL; krb5_ccache krb5MemoryCache = NULL; krb5_cc_cursor krb5Cursor = NULL; krb5_creds krb5Credentials = { 0 }; krb5_principal krb5Principal = NULL; krb5_error_code krb5Error; int exitStatus = 0; DWORD dwError = LW_ERROR_SUCCESS; poptContext = poptGetContext(NULL, argc, argv, Options, 0); while ((poptResult = poptGetNextOpt(poptContext)) >= 0) { /* All options are processed automatically. */ } if (poptResult < -1) { fprintf(stderr, "%s: %s: %s\n", getprogname(), poptBadOption(poptContext, POPT_BADOPTION_NOALIAS), poptStrerror(poptResult)); exitStatus = 1; goto error; } uid = getuid(); /* Make sure we're running as an AD user. */ dwError = LsaOpenServer(&lsaConnection); BAIL_ON_LSA_ERROR(dwError); dwError = LsaFindUserById( lsaConnection, uid, 0, &pUserInfo); if (dwError == LW_ERROR_NO_SUCH_USER) { /* * Running as a non-AD user; exit 0 so launchd doesn't restart * the ticketcopy program (see com.beyondtrust.pbis.ticketcopy.plist). */ LSA_LOG_DEBUG( "uid %lu is not an AD user; exiting", (unsigned long) uid); dwError = LW_ERROR_SUCCESS; goto cleanup; } BAIL_ON_LSA_ERROR(dwError); kq = kqueue(); BAIL_ON_UNIX_ERROR(kq == -1); krb5Error = krb5_init_context(&krb5Context); BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError); krb5Error = krb5_cc_default(krb5Context, &krb5MemoryCache); BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError); snprintf( krb5FileCachePath, sizeof(krb5FileCachePath), "FILE:/tmp/krb5cc_%lu", (unsigned long) uid); while (1) /* Forever (or until an error occurs) */ { while ((event.ident = open(krb5FileCachePath + 5, O_RDONLY)) == -1) { sleep(5); } event.filter = EVFILT_VNODE; event.flags = EV_ADD | EV_ENABLE | EV_CLEAR; event.fflags = NOTE_DELETE | NOTE_WRITE; numChanges = 1; krb5Error = krb5_cc_resolve( krb5Context, krb5FileCachePath, &krb5FileCache); BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError); while (1) /* While the file continues to exist. */ { /* * Turn off KRB5_TC_OPENCLOSE so the file will be opened once * and kept open. This causes it to actually attempt to open * the file, so this is where we check for the file not * existing and retry after sleeping a bit. */ krb5Error = krb5_cc_set_flags(krb5Context, krb5FileCache, 0); if (krb5Error == KRB5_FCC_NOFILE) { break; } BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError); /* Copy all credentials from the file to the memory cache. */ krb5Error = krb5_cc_start_seq_get( krb5Context, krb5FileCache, &krb5Cursor); BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError); while ((krb5Error = krb5_cc_next_cred( krb5Context, krb5FileCache, &krb5Cursor, &krb5Credentials)) == 0) { krb5Error = krb5_cc_store_cred( krb5Context, krb5MemoryCache, &krb5Credentials); if (krb5Error == KRB5_FCC_NOFILE) { krb5Error = krb5_cc_get_principal( krb5Context, krb5FileCache, &krb5Principal); BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError); /* The memory cache was destroyed; re-create it. */ krb5Error = krb5_cc_initialize( krb5Context, krb5MemoryCache, krb5Principal); BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError); krb5_free_principal(krb5Context, krb5Principal); krb5Principal = NULL; krb5Error = krb5_cc_store_cred( krb5Context, krb5MemoryCache, &krb5Credentials); } BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError); krb5_free_cred_contents(krb5Context, &krb5Credentials); } if (krb5Error != KRB5_CC_END) { BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError); } krb5Error = krb5_cc_end_seq_get( krb5Context, krb5FileCache, &krb5Cursor); krb5Cursor = NULL; BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError); /* * Turn KRB5_TC_OPENCLOSE back on; this will cause * the file to be closed and any locks to be * released. */ krb5Error = krb5_cc_set_flags( krb5Context, krb5FileCache, KRB5_TC_OPENCLOSE); BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError); /* * Wait for the file to be modified or deleted. The first * time this is called after the file is opened, numChanges * will be 1, which will install the fd into the event * list. After that numChanges is changed to 0, so it will * just report events from the existing list. */ if (kevent(kq, &event, numChanges, &event, 1, NULL) != 1) { fprintf(stderr, "kevent failed\n"); exitStatus = 1; goto cleanup; } if (event.fflags & NOTE_DELETE) { break; } numChanges = 0; } krb5Error = krb5_cc_close(krb5Context, krb5FileCache); BAIL_ON_KRB5_ERROR(krb5Context, krb5Error, dwError); krb5FileCache = NULL; close(event.ident); event.ident = -1; /* * The cache file is usually removed as part of a * rename(2) system call, so only wait a short * time before the first attempt to re-open it. */ usleep(100000); } error: cleanup: krb5_free_cred_contents(krb5Context, &krb5Credentials); if (krb5Cursor) { krb5_cc_end_seq_get(krb5Context, krb5FileCache, &krb5Cursor); } if (krb5FileCache) { krb5_cc_close(krb5Context, krb5FileCache); } if (krb5Principal) { krb5_free_principal(krb5Context, krb5Principal); } if (krb5Context) { krb5_free_context(krb5Context); } if (event.ident != -1) { close(event.ident); } if (pUserInfo) { LsaFreeUserInfo(0, pUserInfo); } if (lsaConnection != (HANDLE) NULL) { LsaCloseServer(lsaConnection); } if (dwError) { exitStatus = 1; } return exitStatus; }