KRB5_LIB_FUNCTION void KRB5_LIB_CALL krb5_get_init_creds_opt_set_default_flags(krb5_context context, const char *appname, krb5_const_realm realm, krb5_get_init_creds_opt *opt) { krb5_boolean b; time_t t; b = get_config_bool (context, KRB5_FORWARDABLE_DEFAULT, realm, "forwardable"); krb5_appdefault_boolean(context, appname, realm, "forwardable", b, &b); krb5_get_init_creds_opt_set_forwardable(opt, b); b = get_config_bool (context, FALSE, realm, "proxiable"); krb5_appdefault_boolean(context, appname, realm, "proxiable", b, &b); krb5_get_init_creds_opt_set_proxiable (opt, b); krb5_appdefault_time(context, appname, realm, "ticket_lifetime", 0, &t); if (t == 0) t = get_config_time (context, realm, "ticket_lifetime", 0); if(t != 0) krb5_get_init_creds_opt_set_tkt_life(opt, t); krb5_appdefault_time(context, appname, realm, "renew_lifetime", 0, &t); if (t == 0) t = get_config_time (context, realm, "renew_lifetime", 0); if(t != 0) krb5_get_init_creds_opt_set_renew_life(opt, t); krb5_appdefault_boolean(context, appname, realm, "no-addresses", KRB5_ADDRESSLESS_DEFAULT, &b); krb5_get_init_creds_opt_set_addressless (context, opt, b); #if 0 krb5_appdefault_boolean(context, appname, realm, "anonymous", FALSE, &b); krb5_get_init_creds_opt_set_anonymous (opt, b); krb5_get_init_creds_opt_set_etype_list(opt, enctype, etype_str.num_strings); krb5_get_init_creds_opt_set_salt(krb5_get_init_creds_opt *opt, krb5_data *salt); krb5_get_init_creds_opt_set_preauth_list(krb5_get_init_creds_opt *opt, krb5_preauthtype *preauth_list, int preauth_list_length); #endif }
static void krb5_init(void) { krb5_context context; krb5_error_code ret; krb5_boolean ret_val; ret = krb5_init_context(&context); if (ret) return; #if defined(AUTHENTICATION) && defined(FORWARD) krb5_appdefault_boolean(context, NULL, NULL, "forward", 0, &ret_val); if (ret_val) kerberos5_set_forward(1); krb5_appdefault_boolean(context, NULL, NULL, "forwardable", 0, &ret_val); if (ret_val) kerberos5_set_forwardable(1); #endif #ifdef ENCRYPTION krb5_appdefault_boolean(context, NULL, NULL, "encrypt", 0, &ret_val); if (ret_val) { encrypt_auto(1); decrypt_auto(1); wantencryption = 1; EncryptVerbose(1); } #endif krb5_free_context(context); }
/* * Load a boolean option from Kerberos appdefaults. Takes the Kerberos * context, the option, and the result location. */ void sync_config_boolean(krb5_context ctx, const char *opt, bool *result) { realm_type realm; int tmp; /* * The MIT version of krb5_appdefault_boolean takes an int * and the * Heimdal version takes a krb5_boolean *, so hope that Heimdal always * defines krb5_boolean to int or this will require more portability work. */ realm = default_realm(ctx); krb5_appdefault_boolean(ctx, "krb5-sync", realm, opt, *result, &tmp); *result = tmp; free_default_realm(ctx, realm); }
static krb5_error_code get_cred_kdc_address(krb5_context context, krb5_ccache id, krb5_kdc_flags flags, krb5_addresses *addrs, krb5_creds *in_creds, krb5_creds *krbtgt, krb5_principal impersonate_principal, Ticket *second_ticket, krb5_creds *out_creds) { krb5_error_code ret; krb5_addresses addresses = { 0, NULL }; /* * Inherit the address-ness of the krbtgt if the address is not * specified. */ if (addrs == NULL && krbtgt->addresses.len != 0) { krb5_boolean noaddr; krb5_appdefault_boolean(context, NULL, krbtgt->server->realm, "no-addresses", FALSE, &noaddr); if (!noaddr) { krb5_get_all_client_addrs(context, &addresses); /* XXX this sucks. */ addrs = &addresses; if(addresses.len == 0) addrs = NULL; } } ret = get_cred_kdc(context, id, flags, addrs, in_creds, krbtgt, impersonate_principal, second_ticket, out_creds); krb5_free_addresses(context, &addresses); return ret; }
int main(int argc, char **argv) { krb5_error_code ret; krb5_context context; krb5_ccache ccache; krb5_principal principal = NULL; int optidx = 0; krb5_deltat ticket_life = 0; #ifdef HAVE_SIGACTION struct sigaction sa; #endif setprogname(argv[0]); setlocale(LC_ALL, ""); bindtextdomain("heimdal_kuser", HEIMDAL_LOCALEDIR); textdomain("heimdal_kuser"); ret = krb5_init_context(&context); if (ret == KRB5_CONFIG_BADFORMAT) errx(1, "krb5_init_context failed to parse configuration file"); else if (ret) errx(1, "krb5_init_context failed: %d", ret); if (getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) usage(1); if (help_flag) usage(0); if (version_flag) { print_version(NULL); exit(0); } argc -= optidx; argv += optidx; /* * Open the keytab now, we use the keytab to determine the principal's * realm when the requested principal has no realm. */ if (use_keytab || keytab_str) { if (keytab_str) ret = krb5_kt_resolve(context, keytab_str, &kt); else ret = krb5_kt_default(context, &kt); if (ret) krb5_err(context, 1, ret, "resolving keytab"); } if (pk_enterprise_flag) { ret = krb5_pk_enterprise_cert(context, pk_user_id, argv[0], &principal, &ent_user_id); if (ret) krb5_err(context, 1, ret, "krb5_pk_enterprise_certs"); pk_user_id = NULL; } else if (anonymous_flag) { ret = krb5_make_principal(context, &principal, argv[0], KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME, NULL); if (ret) krb5_err(context, 1, ret, "krb5_make_principal"); krb5_principal_set_type(context, principal, KRB5_NT_WELLKNOWN); } else if (use_keytab || keytab_str) { get_princ_kt(context, &principal, argv[0]); } else { get_princ(context, &principal, argv[0]); } if (fcache_version) krb5_set_fcache_version(context, fcache_version); if (renewable_flag == -1) /* this seems somewhat pointless, but whatever */ krb5_appdefault_boolean(context, "kinit", krb5_principal_get_realm(context, principal), "renewable", FALSE, &renewable_flag); if (do_afslog == -1) krb5_appdefault_boolean(context, "kinit", krb5_principal_get_realm(context, principal), "afslog", TRUE, &do_afslog); if (cred_cache) ret = krb5_cc_resolve(context, cred_cache, &ccache); else { if (argc > 1) { char s[1024]; ret = krb5_cc_new_unique(context, NULL, NULL, &ccache); if (ret) krb5_err(context, 1, ret, "creating cred cache"); snprintf(s, sizeof(s), "%s:%s", krb5_cc_get_type(context, ccache), krb5_cc_get_name(context, ccache)); setenv("KRB5CCNAME", s, 1); } else { ret = krb5_cc_cache_match(context, principal, &ccache); if (ret) { const char *type; ret = krb5_cc_default(context, &ccache); if (ret) krb5_err(context, 1, ret, N_("resolving credentials cache", "")); /* * Check if the type support switching, and we do, * then do that instead over overwriting the current * default credential */ type = krb5_cc_get_type(context, ccache); if (krb5_cc_support_switch(context, type)) { krb5_cc_close(context, ccache); ret = get_switched_ccache(context, type, principal, &ccache); } } } } if (ret) krb5_err(context, 1, ret, N_("resolving credentials cache", "")); #ifndef NO_AFS if (argc > 1 && k_hasafs()) k_setpag(); #endif if (lifetime) { int tmp = parse_time(lifetime, "s"); if (tmp < 0) errx(1, N_("unparsable time: %s", ""), lifetime); ticket_life = tmp; } if (addrs_flag == 0 && extra_addresses.num_strings > 0) krb5_errx(context, 1, N_("specifying both extra addresses and " "no addresses makes no sense", "")); { int i; krb5_addresses addresses; memset(&addresses, 0, sizeof(addresses)); for(i = 0; i < extra_addresses.num_strings; i++) { ret = krb5_parse_address(context, extra_addresses.strings[i], &addresses); if (ret == 0) { krb5_add_extra_addresses(context, &addresses); krb5_free_addresses(context, &addresses); } } free_getarg_strings(&extra_addresses); } if (renew_flag || validate_flag) { ret = renew_validate(context, renew_flag, validate_flag, ccache, server_str, ticket_life); #ifndef NO_AFS if (ret == 0 && server_str == NULL && do_afslog && k_hasafs()) krb5_afslog(context, ccache, NULL, NULL); #endif exit(ret != 0); } ret = get_new_tickets(context, principal, ccache, ticket_life, 1); if (ret) exit(1); #ifndef NO_AFS if (ret == 0 && server_str == NULL && do_afslog && k_hasafs()) krb5_afslog(context, ccache, NULL, NULL); #endif if (argc > 1) { struct renew_ctx ctx; time_t timeout; timeout = ticket_lifetime(context, ccache, principal, server_str, NULL) / 2; ctx.context = context; ctx.ccache = ccache; ctx.principal = principal; ctx.ticket_life = ticket_life; ctx.timeout = timeout; #ifdef HAVE_SIGACTION memset(&sa, 0, sizeof(sa)); sigemptyset(&sa.sa_mask); sa.sa_handler = handle_siginfo; sigaction(SIGINFO, &sa, NULL); #endif ret = simple_execvp_timed(argv[1], argv+1, renew_func, &ctx, timeout); #define EX_NOEXEC 126 #define EX_NOTFOUND 127 if (ret == EX_NOEXEC) krb5_warnx(context, N_("permission denied: %s", ""), argv[1]); else if (ret == EX_NOTFOUND) krb5_warnx(context, N_("command not found: %s", ""), argv[1]); krb5_cc_destroy(context, ccache); #ifndef NO_AFS if (k_hasafs()) k_unlog(); #endif } else { krb5_cc_close(context, ccache); ret = 0; } krb5_free_principal(context, principal); if (kt) krb5_kt_close(context, kt); krb5_free_context(context); return ret; }
static OM_uint32 init_auth (OM_uint32 * minor_status, gsskrb5_cred initiator_cred_handle, gsskrb5_ctx ctx, krb5_const_principal name, const gss_OID mech_type, OM_uint32 req_flags, OM_uint32 time_req, const gss_channel_bindings_t input_chan_bindings, const gss_buffer_t input_token, gss_OID * actual_mech_type, gss_buffer_t output_token, OM_uint32 * ret_flags, OM_uint32 * time_rec ) { OM_uint32 ret = GSS_S_FAILURE; krb5_error_code kret; krb5_flags ap_options; krb5_creds *cred = NULL; krb5_data outbuf; krb5_ccache ccache = NULL; uint32_t flags; krb5_data authenticator; Checksum cksum; krb5_enctype enctype; krb5_data fwd_data; OM_uint32 lifetime_rec; krb5_data_zero(&outbuf); krb5_data_zero(&fwd_data); *minor_status = 0; if (actual_mech_type) *actual_mech_type = GSS_KRB5_MECHANISM; if (initiator_cred_handle == NULL) { kret = krb5_cc_default (_gsskrb5_context, &ccache); if (kret) { _gsskrb5_set_error_string (); *minor_status = kret; ret = GSS_S_FAILURE; goto failure; } } else ccache = initiator_cred_handle->ccache; kret = krb5_cc_get_principal (_gsskrb5_context, ccache, &ctx->source); if (kret) { _gsskrb5_set_error_string (); *minor_status = kret; ret = GSS_S_FAILURE; goto failure; } kret = krb5_copy_principal (_gsskrb5_context, name, &ctx->target); if (kret) { _gsskrb5_set_error_string (); *minor_status = kret; ret = GSS_S_FAILURE; goto failure; } ret = _gss_DES3_get_mic_compat(minor_status, ctx); if (ret) goto failure; ret = gsskrb5_get_creds(minor_status, ccache, ctx, ctx->target, time_req, time_rec, &cred); if (ret) goto failure; ctx->lifetime = cred->times.endtime; ret = _gsskrb5_lifetime_left(minor_status, ctx->lifetime, &lifetime_rec); if (ret) { goto failure; } if (lifetime_rec == 0) { *minor_status = 0; ret = GSS_S_CONTEXT_EXPIRED; goto failure; } krb5_auth_con_setkey(_gsskrb5_context, ctx->auth_context, &cred->session); kret = krb5_auth_con_generatelocalsubkey(_gsskrb5_context, ctx->auth_context, &cred->session); if(kret) { _gsskrb5_set_error_string (); *minor_status = kret; ret = GSS_S_FAILURE; goto failure; } /* * If the credential doesn't have ok-as-delegate, check what local * policy say about ok-as-delegate, default is FALSE that makes * code ignore the KDC setting and follow what the application * requested. If its TRUE, strip of the GSS_C_DELEG_FLAG if the * KDC doesn't set ok-as-delegate. */ if (!cred->flags.b.ok_as_delegate) { krb5_boolean delegate; krb5_appdefault_boolean(_gsskrb5_context, "gssapi", name->realm, "ok-as-delegate", FALSE, &delegate); if (delegate) req_flags &= ~GSS_C_DELEG_FLAG; } flags = 0; ap_options = 0; if (req_flags & GSS_C_DELEG_FLAG) do_delegation (ctx->auth_context, ccache, cred, name, &fwd_data, &flags); if (req_flags & GSS_C_MUTUAL_FLAG) { flags |= GSS_C_MUTUAL_FLAG; ap_options |= AP_OPTS_MUTUAL_REQUIRED; } if (req_flags & GSS_C_REPLAY_FLAG) flags |= GSS_C_REPLAY_FLAG; if (req_flags & GSS_C_SEQUENCE_FLAG) flags |= GSS_C_SEQUENCE_FLAG; if (req_flags & GSS_C_ANON_FLAG) ; /* XXX */ if (req_flags & GSS_C_DCE_STYLE) { /* GSS_C_DCE_STYLE implies GSS_C_MUTUAL_FLAG */ flags |= GSS_C_DCE_STYLE | GSS_C_MUTUAL_FLAG; ap_options |= AP_OPTS_MUTUAL_REQUIRED; } if (req_flags & GSS_C_IDENTIFY_FLAG) flags |= GSS_C_IDENTIFY_FLAG; if (req_flags & GSS_C_EXTENDED_ERROR_FLAG) flags |= GSS_C_EXTENDED_ERROR_FLAG; flags |= GSS_C_CONF_FLAG; flags |= GSS_C_INTEG_FLAG; flags |= GSS_C_TRANS_FLAG; if (ret_flags) *ret_flags = flags; ctx->flags = flags; ctx->more_flags |= LOCAL; ret = _gsskrb5_create_8003_checksum (minor_status, input_chan_bindings, flags, &fwd_data, &cksum); krb5_data_free (&fwd_data); if (ret) goto failure; enctype = ctx->auth_context->keyblock->keytype; kret = krb5_build_authenticator (_gsskrb5_context, ctx->auth_context, enctype, cred, &cksum, NULL, &authenticator, KRB5_KU_AP_REQ_AUTH); if (kret) { _gsskrb5_set_error_string (); *minor_status = kret; ret = GSS_S_FAILURE; goto failure; } kret = krb5_build_ap_req (_gsskrb5_context, enctype, cred, ap_options, authenticator, &outbuf); if (kret) { _gsskrb5_set_error_string (); *minor_status = kret; ret = GSS_S_FAILURE; goto failure; } ret = _gsskrb5_encapsulate (minor_status, &outbuf, output_token, (u_char *)"\x01\x00", GSS_KRB5_MECHANISM); if (ret) goto failure; krb5_data_free (&outbuf); krb5_free_creds(_gsskrb5_context, cred); free_Checksum(&cksum); if (initiator_cred_handle == NULL) krb5_cc_close(_gsskrb5_context, ccache); if (flags & GSS_C_MUTUAL_FLAG) { ctx->state = INITIATOR_WAIT_FOR_MUTAL; return GSS_S_CONTINUE_NEEDED; } return gsskrb5_initiator_ready(minor_status, ctx); failure: if(cred) krb5_free_creds(_gsskrb5_context, cred); if (ccache && initiator_cred_handle == NULL) krb5_cc_close(_gsskrb5_context, ccache); return ret; }
krb5_error_code KRB5_LIB_FUNCTION krb5_get_forwarded_creds (krb5_context context, krb5_auth_context auth_context, krb5_ccache ccache, krb5_flags flags, const char *hostname, krb5_creds *in_creds, krb5_data *out_data) { krb5_error_code ret; krb5_creds *out_creds; krb5_addresses addrs, *paddrs; KRB_CRED cred; KrbCredInfo *krb_cred_info; EncKrbCredPart enc_krb_cred_part; size_t len; unsigned char *buf; size_t buf_size; krb5_kdc_flags kdc_flags; krb5_crypto crypto; struct addrinfo *ai; int save_errno; krb5_creds *ticket; char *realm; if (in_creds->client && in_creds->client->realm) realm = in_creds->client->realm; else realm = in_creds->server->realm; addrs.len = 0; addrs.val = NULL; paddrs = &addrs; /* * If tickets are address-less, forward address-less tickets. */ ret = _krb5_get_krbtgt (context, ccache, realm, &ticket); if(ret == 0) { if (ticket->addresses.len == 0) paddrs = NULL; krb5_free_creds (context, ticket); } if (paddrs != NULL) { ret = getaddrinfo (hostname, NULL, NULL, &ai); if (ret) { save_errno = errno; krb5_set_error_string(context, "resolving %s: %s", hostname, gai_strerror(ret)); return krb5_eai_to_heim_errno(ret, save_errno); } ret = add_addrs (context, &addrs, ai); freeaddrinfo (ai); if (ret) return ret; } kdc_flags.b = int2KDCOptions(flags); ret = krb5_get_kdc_cred (context, ccache, kdc_flags, paddrs, NULL, in_creds, &out_creds); krb5_free_addresses (context, &addrs); if (ret) { return ret; } memset (&cred, 0, sizeof(cred)); cred.pvno = 5; cred.msg_type = krb_cred; ALLOC_SEQ(&cred.tickets, 1); if (cred.tickets.val == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto out2; } ret = decode_Ticket(out_creds->ticket.data, out_creds->ticket.length, cred.tickets.val, &len); if (ret) goto out3; memset (&enc_krb_cred_part, 0, sizeof(enc_krb_cred_part)); ALLOC_SEQ(&enc_krb_cred_part.ticket_info, 1); if (enc_krb_cred_part.ticket_info.val == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto out4; } if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) { krb5_timestamp sec; int32_t usec; krb5_us_timeofday (context, &sec, &usec); ALLOC(enc_krb_cred_part.timestamp, 1); if (enc_krb_cred_part.timestamp == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto out4; } *enc_krb_cred_part.timestamp = sec; ALLOC(enc_krb_cred_part.usec, 1); if (enc_krb_cred_part.usec == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto out4; } *enc_krb_cred_part.usec = usec; } else { enc_krb_cred_part.timestamp = NULL; enc_krb_cred_part.usec = NULL; } if (auth_context->local_address && auth_context->local_port) { krb5_boolean noaddr; krb5_const_realm realm; realm = krb5_principal_get_realm(context, out_creds->server); krb5_appdefault_boolean(context, NULL, realm, "no-addresses", paddrs == NULL, &noaddr); if (!noaddr) { ret = krb5_make_addrport (context, &enc_krb_cred_part.s_address, auth_context->local_address, auth_context->local_port); if (ret) goto out4; } } if (auth_context->remote_address) { if (auth_context->remote_port) { krb5_boolean noaddr; krb5_const_realm realm; realm = krb5_principal_get_realm(context, out_creds->server); /* Is this correct, and should we use the paddrs == NULL trick here as well? Having an address-less ticket may indicate that we don't know our own global address, but it does not necessary mean that we don't know the server's. */ krb5_appdefault_boolean(context, NULL, realm, "no-addresses", FALSE, &noaddr); if (!noaddr) { ret = krb5_make_addrport (context, &enc_krb_cred_part.r_address, auth_context->remote_address, auth_context->remote_port); if (ret) goto out4; } } else { ALLOC(enc_krb_cred_part.r_address, 1); if (enc_krb_cred_part.r_address == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto out4; } ret = krb5_copy_address (context, auth_context->remote_address, enc_krb_cred_part.r_address); if (ret) goto out4; } } /* fill ticket_info.val[0] */ enc_krb_cred_part.ticket_info.len = 1; krb_cred_info = enc_krb_cred_part.ticket_info.val; copy_EncryptionKey (&out_creds->session, &krb_cred_info->key); ALLOC(krb_cred_info->prealm, 1); copy_Realm (&out_creds->client->realm, krb_cred_info->prealm); ALLOC(krb_cred_info->pname, 1); copy_PrincipalName(&out_creds->client->name, krb_cred_info->pname); ALLOC(krb_cred_info->flags, 1); *krb_cred_info->flags = out_creds->flags.b; ALLOC(krb_cred_info->authtime, 1); *krb_cred_info->authtime = out_creds->times.authtime; ALLOC(krb_cred_info->starttime, 1); *krb_cred_info->starttime = out_creds->times.starttime; ALLOC(krb_cred_info->endtime, 1); *krb_cred_info->endtime = out_creds->times.endtime; ALLOC(krb_cred_info->renew_till, 1); *krb_cred_info->renew_till = out_creds->times.renew_till; ALLOC(krb_cred_info->srealm, 1); copy_Realm (&out_creds->server->realm, krb_cred_info->srealm); ALLOC(krb_cred_info->sname, 1); copy_PrincipalName (&out_creds->server->name, krb_cred_info->sname); ALLOC(krb_cred_info->caddr, 1); copy_HostAddresses (&out_creds->addresses, krb_cred_info->caddr); krb5_free_creds (context, out_creds); /* encode EncKrbCredPart */ ASN1_MALLOC_ENCODE(EncKrbCredPart, buf, buf_size, &enc_krb_cred_part, &len, ret); free_EncKrbCredPart (&enc_krb_cred_part); if (ret) { free_KRB_CRED(&cred); return ret; } if(buf_size != len) krb5_abortx(context, "internal error in ASN.1 encoder"); if (auth_context->flags & KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED) { cred.enc_part.etype = ENCTYPE_NULL; cred.enc_part.kvno = NULL; cred.enc_part.cipher.data = buf; cred.enc_part.cipher.length = buf_size; } else { krb5_keyblock *key; if (auth_context->local_subkey) key = auth_context->local_subkey; else if (auth_context->remote_subkey) key = auth_context->remote_subkey; else key = auth_context->keyblock; ret = krb5_crypto_init(context, key, 0, &crypto); if (ret) { free(buf); free_KRB_CRED(&cred); return ret; } ret = krb5_encrypt_EncryptedData (context, crypto, KRB5_KU_KRB_CRED, buf, len, 0, &cred.enc_part); free(buf); krb5_crypto_destroy(context, crypto); if (ret) { free_KRB_CRED(&cred); return ret; } } ASN1_MALLOC_ENCODE(KRB_CRED, buf, buf_size, &cred, &len, ret); free_KRB_CRED (&cred); if (ret) return ret; if(buf_size != len) krb5_abortx(context, "internal error in ASN.1 encoder"); out_data->length = len; out_data->data = buf; return 0; out4: free_EncKrbCredPart(&enc_krb_cred_part); out3: free_KRB_CRED(&cred); out2: krb5_free_creds (context, out_creds); return ret; }
static krb5_error_code get_cred_from_kdc_flags(krb5_context context, krb5_kdc_flags flags, krb5_ccache ccache, krb5_creds *in_creds, krb5_creds **out_creds, krb5_creds ***ret_tgts) { krb5_error_code ret; krb5_creds *tgt, tmp_creds; krb5_const_realm client_realm, server_realm, try_realm; *out_creds = NULL; client_realm = krb5_principal_get_realm(context, in_creds->client); server_realm = krb5_principal_get_realm(context, in_creds->server); memset(&tmp_creds, 0, sizeof(tmp_creds)); ret = krb5_copy_principal(context, in_creds->client, &tmp_creds.client); if(ret) return ret; try_realm = krb5_config_get_string(context, NULL, "capaths", client_realm, server_realm, NULL); #if 1 /* XXX remove in future release */ if(try_realm == NULL) try_realm = krb5_config_get_string(context, NULL, "libdefaults", "capath", server_realm, NULL); #endif if (try_realm == NULL) try_realm = client_realm; ret = krb5_make_principal(context, &tmp_creds.server, try_realm, KRB5_TGS_NAME, server_realm, NULL); if(ret){ krb5_free_principal(context, tmp_creds.client); return ret; } { krb5_creds tgts; /* XXX try krb5_cc_retrieve_cred first? */ ret = find_cred(context, ccache, tmp_creds.server, *ret_tgts, &tgts); if(ret == 0){ *out_creds = calloc(1, sizeof(**out_creds)); if(*out_creds == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; } else { krb5_boolean noaddr; krb5_appdefault_boolean(context, NULL, tgts.server->realm, "no-addresses", FALSE, &noaddr); if (noaddr) ret = get_cred_kdc(context, ccache, flags, NULL, in_creds, &tgts, *out_creds); else ret = get_cred_kdc_la(context, ccache, flags, in_creds, &tgts, *out_creds); if (ret) { free (*out_creds); *out_creds = NULL; } } krb5_free_cred_contents(context, &tgts); krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); return ret; } } if(krb5_realm_compare(context, in_creds->client, in_creds->server)) { krb5_clear_error_string (context); return KRB5_CC_NOTFOUND; } /* XXX this can loop forever */ while(1){ heim_general_string tgt_inst; ret = get_cred_from_kdc_flags(context, flags, ccache, &tmp_creds, &tgt, ret_tgts); if(ret) { krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); return ret; } ret = add_cred(context, ret_tgts, tgt); if(ret) { krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); return ret; } tgt_inst = tgt->server->name.name_string.val[1]; if(strcmp(tgt_inst, server_realm) == 0) break; krb5_free_principal(context, tmp_creds.server); ret = krb5_make_principal(context, &tmp_creds.server, tgt_inst, KRB5_TGS_NAME, server_realm, NULL); if(ret) { krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); return ret; } ret = krb5_free_creds(context, tgt); if(ret) { krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); return ret; } } krb5_free_principal(context, tmp_creds.server); krb5_free_principal(context, tmp_creds.client); *out_creds = calloc(1, sizeof(**out_creds)); if(*out_creds == NULL) { krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; } else { krb5_boolean noaddr; krb5_appdefault_boolean(context, NULL, tgt->server->realm, "no-addresses", FALSE, &noaddr); if (noaddr) ret = get_cred_kdc (context, ccache, flags, NULL, in_creds, tgt, *out_creds); else ret = get_cred_kdc_la(context, ccache, flags, in_creds, tgt, *out_creds); if (ret) { free (*out_creds); *out_creds = NULL; } } krb5_free_creds(context, tgt); return ret; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_get_forwarded_creds (krb5_context context, krb5_auth_context auth_context, krb5_ccache ccache, krb5_flags flags, const char *hostname, krb5_creds *in_creds, krb5_data *out_data) { krb5_error_code ret; krb5_creds *out_creds; krb5_addresses addrs, *paddrs; KRB_CRED cred; KrbCredInfo *krb_cred_info; EncKrbCredPart enc_krb_cred_part; size_t len; unsigned char *buf; size_t buf_size; krb5_kdc_flags kdc_flags; krb5_crypto crypto; struct addrinfo *ai; krb5_creds *ticket; paddrs = NULL; addrs.len = 0; addrs.val = NULL; ret = krb5_get_credentials(context, 0, ccache, in_creds, &ticket); if(ret == 0) { if (ticket->addresses.len) paddrs = &addrs; krb5_free_creds (context, ticket); } else { krb5_boolean noaddr; krb5_appdefault_boolean(context, NULL, krb5_principal_get_realm(context, in_creds->client), "no-addresses", KRB5_ADDRESSLESS_DEFAULT, &noaddr); if (!noaddr) paddrs = &addrs; } /* * If tickets have addresses, get the address of the remote host. */ if (paddrs != NULL) { ret = getaddrinfo (hostname, NULL, NULL, &ai); if (ret) { krb5_error_code ret2 = krb5_eai_to_heim_errno(ret, errno); krb5_set_error_message(context, ret2, N_("resolving host %s failed: %s", "hostname, error"), hostname, gai_strerror(ret)); return ret2; } ret = add_addrs (context, &addrs, ai); freeaddrinfo (ai); if (ret) return ret; } kdc_flags.b = int2KDCOptions(flags); ret = krb5_get_kdc_cred (context, ccache, kdc_flags, paddrs, NULL, in_creds, &out_creds); krb5_free_addresses (context, &addrs); if (ret) return ret; memset (&cred, 0, sizeof(cred)); cred.pvno = 5; cred.msg_type = krb_cred; ALLOC_SEQ(&cred.tickets, 1); if (cred.tickets.val == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto out2; } ret = decode_Ticket(out_creds->ticket.data, out_creds->ticket.length, cred.tickets.val, &len); if (ret) goto out3; memset (&enc_krb_cred_part, 0, sizeof(enc_krb_cred_part)); ALLOC_SEQ(&enc_krb_cred_part.ticket_info, 1); if (enc_krb_cred_part.ticket_info.val == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto out4; } if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) { krb5_timestamp sec; int32_t usec; krb5_us_timeofday (context, &sec, &usec); ALLOC(enc_krb_cred_part.timestamp, 1); if (enc_krb_cred_part.timestamp == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto out4; } *enc_krb_cred_part.timestamp = sec; ALLOC(enc_krb_cred_part.usec, 1); if (enc_krb_cred_part.usec == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto out4; } *enc_krb_cred_part.usec = usec; } else { enc_krb_cred_part.timestamp = NULL; enc_krb_cred_part.usec = NULL; } if (auth_context->local_address && auth_context->local_port && paddrs) { ret = krb5_make_addrport (context, &enc_krb_cred_part.s_address, auth_context->local_address, auth_context->local_port); if (ret) goto out4; } if (auth_context->remote_address) { if (auth_context->remote_port) { krb5_boolean noaddr; krb5_const_realm srealm; srealm = krb5_principal_get_realm(context, out_creds->server); /* Is this correct, and should we use the paddrs == NULL trick here as well? Having an address-less ticket may indicate that we don't know our own global address, but it does not necessary mean that we don't know the server's. */ krb5_appdefault_boolean(context, NULL, srealm, "no-addresses", FALSE, &noaddr); if (!noaddr) { ret = krb5_make_addrport (context, &enc_krb_cred_part.r_address, auth_context->remote_address, auth_context->remote_port); if (ret) goto out4; } } else { ALLOC(enc_krb_cred_part.r_address, 1); if (enc_krb_cred_part.r_address == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto out4; } ret = krb5_copy_address (context, auth_context->remote_address, enc_krb_cred_part.r_address); if (ret) goto out4; } } /* fill ticket_info.val[0] */ enc_krb_cred_part.ticket_info.len = 1; krb_cred_info = enc_krb_cred_part.ticket_info.val; copy_EncryptionKey (&out_creds->session, &krb_cred_info->key); ALLOC(krb_cred_info->prealm, 1); copy_Realm (&out_creds->client->realm, krb_cred_info->prealm); ALLOC(krb_cred_info->pname, 1); copy_PrincipalName(&out_creds->client->name, krb_cred_info->pname); ALLOC(krb_cred_info->flags, 1); *krb_cred_info->flags = out_creds->flags.b; ALLOC(krb_cred_info->authtime, 1); *krb_cred_info->authtime = out_creds->times.authtime; ALLOC(krb_cred_info->starttime, 1); *krb_cred_info->starttime = out_creds->times.starttime; ALLOC(krb_cred_info->endtime, 1); *krb_cred_info->endtime = out_creds->times.endtime; ALLOC(krb_cred_info->renew_till, 1); *krb_cred_info->renew_till = out_creds->times.renew_till; ALLOC(krb_cred_info->srealm, 1); copy_Realm (&out_creds->server->realm, krb_cred_info->srealm); ALLOC(krb_cred_info->sname, 1); copy_PrincipalName (&out_creds->server->name, krb_cred_info->sname); ALLOC(krb_cred_info->caddr, 1); copy_HostAddresses (&out_creds->addresses, krb_cred_info->caddr); krb5_free_creds (context, out_creds); /* encode EncKrbCredPart */ ASN1_MALLOC_ENCODE(EncKrbCredPart, buf, buf_size, &enc_krb_cred_part, &len, ret); free_EncKrbCredPart (&enc_krb_cred_part); if (ret) { free_KRB_CRED(&cred); return ret; } if(buf_size != len) krb5_abortx(context, "internal error in ASN.1 encoder"); /** * Some older of the MIT gssapi library used clear-text tickets * (warped inside AP-REQ encryption), use the krb5_auth_context * flag KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED to support those * tickets. The session key is used otherwise to encrypt the * forwarded ticket. */ if (auth_context->flags & KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED) { cred.enc_part.etype = KRB5_ENCTYPE_NULL; cred.enc_part.kvno = NULL; cred.enc_part.cipher.data = buf; cred.enc_part.cipher.length = buf_size; } else { /* * Here older versions then 0.7.2 of Heimdal used the local or * remote subkey. That is wrong, the session key should be * used. Heimdal 0.7.2 and newer have code to try both in the * receiving end. */ ret = krb5_crypto_init(context, auth_context->keyblock, 0, &crypto); if (ret) { free(buf); free_KRB_CRED(&cred); return ret; } ret = krb5_encrypt_EncryptedData (context, crypto, KRB5_KU_KRB_CRED, buf, len, 0, &cred.enc_part); free(buf); krb5_crypto_destroy(context, crypto); if (ret) { free_KRB_CRED(&cred); return ret; } } ASN1_MALLOC_ENCODE(KRB_CRED, buf, buf_size, &cred, &len, ret); free_KRB_CRED (&cred); if (ret) return ret; if(buf_size != len) krb5_abortx(context, "internal error in ASN.1 encoder"); out_data->length = len; out_data->data = buf; return 0; out4: free_EncKrbCredPart(&enc_krb_cred_part); out3: free_KRB_CRED(&cred); out2: krb5_free_creds (context, out_creds); return ret; }
static int send_krb5_auth(int s, struct sockaddr *thisaddr, struct sockaddr *thataddr, const char *hostname, const char *remote_user, const char *local_user, size_t cmd_len, const char *cmd) { krb5_principal server; krb5_data cksum_data; int status; size_t len; krb5_auth_context auth_context = NULL; const char *protocol_string = NULL; krb5_flags ap_opts; char *str; status = krb5_sname_to_principal(context, hostname, "host", KRB5_NT_SRV_HST, &server); if (status) { warnx ("%s: %s", hostname, krb5_get_err_text(context, status)); return 1; } if(do_encrypt == -1) { krb5_appdefault_boolean(context, NULL, krb5_principal_get_realm(context, server), "encrypt", FALSE, &do_encrypt); } cksum_data.length = asprintf (&str, "%u:%s%s%s", ntohs(socket_get_port(thataddr)), do_encrypt ? "-x " : "", cmd, remote_user); if (str == NULL) { warnx ("%s: failed to allocate command", hostname); return 1; } cksum_data.data = str; ap_opts = 0; if(do_encrypt) ap_opts |= AP_OPTS_MUTUAL_REQUIRED; switch(protocol_version) { case 2: ap_opts |= AP_OPTS_USE_SUBKEY; protocol_string = KCMD_NEW_VERSION; break; case 1: protocol_string = KCMD_OLD_VERSION; key_usage = KRB5_KU_OTHER_ENCRYPTED; break; default: abort(); } status = krb5_sendauth (context, &auth_context, &s, protocol_string, NULL, server, ap_opts, &cksum_data, NULL, NULL, NULL, NULL, NULL); /* do this while we have a principal */ if(do_forward == -1 || do_forwardable == -1) { krb5_const_realm realm = krb5_principal_get_realm(context, server); if (do_forwardable == -1) krb5_appdefault_boolean(context, NULL, realm, "forwardable", FALSE, &do_forwardable); if (do_forward == -1) krb5_appdefault_boolean(context, NULL, realm, "forward", FALSE, &do_forward); } krb5_free_principal(context, server); krb5_data_free(&cksum_data); if (status) { if(status == KRB5_SENDAUTH_REJECTED && protocol_version == 2 && protocol_version_str == NULL) sendauth_version_error = 1; else krb5_warn(context, status, "%s", hostname); return 1; } status = krb5_auth_con_getlocalsubkey (context, auth_context, &keyblock); if(keyblock == NULL) status = krb5_auth_con_getkey (context, auth_context, &keyblock); if (status) { warnx ("krb5_auth_con_getkey: %s", krb5_get_err_text(context, status)); return 1; } status = krb5_auth_con_setaddrs_from_fd (context, auth_context, &s); if (status) { warnx("krb5_auth_con_setaddrs_from_fd: %s", krb5_get_err_text(context, status)); return(1); } status = krb5_crypto_init(context, keyblock, 0, &crypto); if(status) { warnx ("krb5_crypto_init: %s", krb5_get_err_text(context, status)); return 1; } len = strlen(remote_user) + 1; if (net_write (s, remote_user, len) != len) { warn ("write"); return 1; } if (do_encrypt && net_write (s, "-x ", 3) != 3) { warn ("write"); return 1; } if (net_write (s, cmd, cmd_len) != cmd_len) { warn ("write"); return 1; } if (do_unique_tkfile) { if (net_write (s, tkfile, strlen(tkfile)) != strlen(tkfile)) { warn ("write"); return 1; } } len = strlen(local_user) + 1; if (net_write (s, local_user, len) != len) { warn ("write"); return 1; } if (!do_forward || krb5_forward_cred (auth_context, s, hostname, do_forwardable)) { /* Empty forwarding info */ u_char zero[4] = {0, 0, 0, 0}; write (s, &zero, 4); } krb5_auth_con_free (context, auth_context); return 0; }
static int verify_krb5(struct passwd *pwd, char *password, int32_t *exp, int quiet) { krb5_context context; krb5_error_code ret; krb5_ccache ccache; krb5_principal principal; ret = krb5_init_context(&context); if (ret) { syslog(LOG_AUTH|LOG_DEBUG, "krb5_init_context failed: %d", ret); goto out; } ret = krb5_parse_name (context, pwd->pw_name, &principal); if (ret) { syslog(LOG_AUTH|LOG_DEBUG, "krb5_parse_name: %s", krb5_get_err_text(context, ret)); goto out; } set_krb5ccname(pwd->pw_uid); ret = krb5_cc_resolve(context, krb5ccname, &ccache); if(ret) { syslog(LOG_AUTH|LOG_DEBUG, "krb5_cc_resolve: %s", krb5_get_err_text(context, ret)); goto out; } ret = krb5_verify_user_lrealm(context, principal, ccache, password, TRUE, NULL); if(ret) { syslog(LOG_AUTH|LOG_DEBUG, "krb5_verify_user: %s", krb5_get_err_text(context, ret)); goto out; } if(chown(krb5_cc_get_name(context, ccache), pwd->pw_uid, pwd->pw_gid)) { syslog(LOG_AUTH|LOG_DEBUG, "chown: %s", krb5_get_err_text(context, errno)); goto out; } #ifdef KRB4 { krb5_realm realm = NULL; krb5_boolean get_v4_tgt; krb5_get_default_realm(context, &realm); krb5_appdefault_boolean(context, "afskauthlib", realm, "krb4_get_tickets", FALSE, &get_v4_tgt); if (get_v4_tgt) { CREDENTIALS c; krb5_creds mcred, cred; krb5_cc_clear_mcred(&mcred); krb5_make_principal(context, &mcred.server, realm, "krbtgt", realm, NULL); ret = krb5_cc_retrieve_cred(context, ccache, 0, &mcred, &cred); if(ret == 0) { ret = krb524_convert_creds_kdc_ccache(context, ccache, &cred, &c); if(ret) krb5_warn(context, ret, "converting creds"); else { set_krbtkfile(pwd->pw_uid); tf_setup(&c, c.pname, c.pinst); } memset(&c, 0, sizeof(c)); krb5_free_cred_contents(context, &cred); } else syslog(LOG_AUTH|LOG_DEBUG, "krb5_cc_retrieve_cred: %s", krb5_get_err_text(context, ret)); krb5_free_principal(context, mcred.server); } free (realm); if (!pag_set && k_hasafs()) { k_setpag(); pag_set = 1; } if (pag_set) krb5_afslog_uid_home(context, ccache, NULL, NULL, pwd->pw_uid, pwd->pw_dir); } #endif out: if(ret && !quiet) printf ("%s\n", krb5_get_err_text (context, ret)); return ret; }
int main (int argc, char **argv) { krb5_error_code ret; krb5_context context; krb5_ccache ccache; krb5_principal principal; int optidx = 0; krb5_deltat ticket_life = 0; int parseflags = 0; setprogname (argv[0]); setlocale (LC_ALL, ""); #if defined(HEIMDAL_LOCALEDIR) bindtextdomain ("heimdal_kuser", HEIMDAL_LOCALEDIR); textdomain("heimdal_kuser"); #endif ret = krb5_init_context (&context); if (ret == KRB5_CONFIG_BADFORMAT) errx (1, "krb5_init_context failed to parse configuration file"); else if (ret) errx(1, "krb5_init_context failed: %d", ret); if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) usage(1); if (help_flag) usage (0); if(version_flag) { print_version(NULL); exit(0); } argc -= optidx; argv += optidx; if (canonicalize_flag) parseflags |= KRB5_PRINCIPAL_PARSE_ENTERPRISE; if (argv[0]) { ret = krb5_parse_name_flags (context, argv[0], parseflags, &principal); if (ret) krb5_err (context, 1, ret, "krb5_parse_name"); } else { ret = krb5_get_default_principal (context, &principal); if (ret) krb5_err (context, 1, ret, "krb5_get_default_principal"); } if(fcache_version) krb5_set_fcache_version(context, fcache_version); if(renewable_flag == -1) /* this seems somewhat pointless, but whatever */ krb5_appdefault_boolean(context, "kinit", krb5_principal_get_realm(context, principal), "renewable", FALSE, &renewable_flag); #ifndef HEIMDAL_SMALLER if(get_v4_tgt == -1) krb5_appdefault_boolean(context, "kinit", krb5_principal_get_realm(context, principal), "krb4_get_tickets", FALSE, &get_v4_tgt); #endif if(do_afslog == -1) krb5_appdefault_boolean(context, "kinit", krb5_principal_get_realm(context, principal), "afslog", TRUE, &do_afslog); if(cred_cache) ret = krb5_cc_resolve(context, cred_cache, &ccache); else { if(argc > 1) { char s[1024]; ret = krb5_cc_gen_new(context, &krb5_fcc_ops, &ccache); if(ret) krb5_err(context, 1, ret, "creating cred cache"); snprintf(s, sizeof(s), "%s:%s", krb5_cc_get_type(context, ccache), krb5_cc_get_name(context, ccache)); setenv("KRB5CCNAME", s, 1); #ifndef HEIMDAL_SMALLER if (get_v4_tgt) { int fd; if (asprintf(&krb4_cc_name, "%s_XXXXXX", TKT_ROOT) < 0) krb5_errx(context, 1, "out of memory"); if((fd = mkstemp(krb4_cc_name)) >= 0) { close(fd); setenv("KRBTKFILE", krb4_cc_name, 1); } else { free(krb4_cc_name); krb4_cc_name = NULL; } } #endif } else { ret = krb5_cc_cache_match(context, principal, &ccache); if (ret) ret = krb5_cc_default (context, &ccache); } } if (ret) krb5_err (context, 1, ret, N_("resolving credentials cache", "")); if(argc > 1 && k_hasafs ()) k_setpag(); if (lifetime) { int tmp = parse_time (lifetime, "s"); if (tmp < 0) errx (1, N_("unparsable time: %s", ""), lifetime); ticket_life = tmp; } if(addrs_flag == 0 && extra_addresses.num_strings > 0) krb5_errx(context, 1, N_("specifying both extra addresses and " "no addresses makes no sense", "")); { int i; krb5_addresses addresses; memset(&addresses, 0, sizeof(addresses)); for(i = 0; i < extra_addresses.num_strings; i++) { ret = krb5_parse_address(context, extra_addresses.strings[i], &addresses); if (ret == 0) { krb5_add_extra_addresses(context, &addresses); krb5_free_addresses(context, &addresses); } } free_getarg_strings(&extra_addresses); } if(renew_flag || validate_flag) { ret = renew_validate(context, renew_flag, validate_flag, ccache, server_str, ticket_life); exit(ret != 0); } #ifndef HEIMDAL_SMALLER if(!convert_524) #endif get_new_tickets(context, principal, ccache, ticket_life, 1); #ifndef HEIMDAL_SMALLER if(get_v4_tgt || convert_524) do_524init(context, ccache, NULL, server_str); #endif if(do_afslog && k_hasafs()) krb5_afslog(context, ccache, NULL, NULL); if(argc > 1) { struct renew_ctx ctx; time_t timeout; timeout = ticket_lifetime(context, ccache, principal, server_str) / 2; ctx.context = context; ctx.ccache = ccache; ctx.principal = principal; ctx.ticket_life = ticket_life; ret = simple_execvp_timed(argv[1], argv+1, renew_func, &ctx, timeout); #define EX_NOEXEC 126 #define EX_NOTFOUND 127 if(ret == EX_NOEXEC) krb5_warnx(context, N_("permission denied: %s", ""), argv[1]); else if(ret == EX_NOTFOUND) krb5_warnx(context, N_("command not found: %s", ""), argv[1]); krb5_cc_destroy(context, ccache); #ifndef HEIMDAL_SMALLER _krb5_krb_dest_tkt(context, krb4_cc_name); #endif if(k_hasafs()) k_unlog(); } else { krb5_cc_close (context, ccache); ret = 0; } krb5_free_principal(context, principal); krb5_free_context (context); return ret; }