/* Store the error state for code from context into errsave, but only if code * indicates an error and errsave is empty. */ static void save_first_error(krb5_context context, krb5_error_code code, struct errinfo *errsave) { if (code && code != KRB5_CC_END && !errsave->code) k5_save_ctx_error(context, code, errsave); }
krb5_error_code KRB5_CALLCONV krb5_get_init_creds_keytab(krb5_context context, krb5_creds *creds, krb5_principal client, krb5_keytab arg_keytab, krb5_deltat start_time, const char *in_tkt_service, krb5_get_init_creds_opt *options) { krb5_error_code ret; int use_master; krb5_keytab keytab; struct errinfo errsave = EMPTY_ERRINFO; if (arg_keytab == NULL) { if ((ret = krb5_kt_default(context, &keytab))) return ret; } else { keytab = arg_keytab; } use_master = 0; /* first try: get the requested tkt from any kdc */ ret = get_init_creds_keytab(context, creds, client, keytab, start_time, in_tkt_service, options, &use_master); /* check for success */ if (ret == 0) goto cleanup; /* If all the kdc's are unavailable fail */ if ((ret == KRB5_KDC_UNREACH) || (ret == KRB5_REALM_CANT_RESOLVE)) goto cleanup; /* if the reply did not come from the master kdc, try again with the master kdc */ if (!use_master) { use_master = 1; k5_save_ctx_error(context, ret, &errsave); ret = get_init_creds_keytab(context, creds, client, keytab, start_time, in_tkt_service, options, &use_master); if (ret == 0) goto cleanup; /* If the master is unreachable, return the error from the slave we * were able to contact. */ if (ret == KRB5_KDC_UNREACH || ret == KRB5_REALM_CANT_RESOLVE || ret == KRB5_REALM_UNKNOWN) ret = k5_restore_ctx_error(context, &errsave); } /* at this point, we have a response from the master. Since we don't do any prompting or changing for keytabs, that's it. */ cleanup: if (arg_keytab == NULL) krb5_kt_close(context, keytab); k5_clear_error(&errsave); return(ret); }