/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* * Copyright (c) 1994 by the University of Southern California * * EXPORT OF THIS SOFTWARE from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to copy, modify, and distribute * this software and its documentation in source and binary forms is * hereby granted, provided that any documentation or other materials * related to such distribution or use acknowledge that the software * was developed by the University of Southern California. * * DISCLAIMER OF WARRANTY. THIS SOFTWARE IS PROVIDED "AS IS". The * University of Southern California MAKES NO REPRESENTATIONS OR * WARRANTIES, EXPRESS OR IMPLIED. By way of example, but not * limitation, the University of Southern California MAKES NO * REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY * PARTICULAR PURPOSE. The University of Southern * California shall not be held liable for any liability nor for any * direct, indirect, or consequential damages with respect to any * claim by the user or distributor of the ksu software. * * KSU was written by: Ari Medvinsky, ari@isi.edu */ #include "ksu.h" void plain_dump_principal (); krb5_boolean krb5_auth_check(context, client_pname, hostname, options, target_user, cc, path_passwd, target_uid) krb5_context context; krb5_principal client_pname; char *hostname; krb5_get_init_creds_opt *options; char *target_user; uid_t target_uid; krb5_ccache cc; int *path_passwd; { krb5_principal client; krb5_verify_init_creds_opt vfy_opts; krb5_creds tgt, tgtq; krb5_error_code retval =0; int got_it = 0; krb5_boolean zero_password; *path_passwd = 0; memset(&tgtq, 0, sizeof(tgtq)); memset(&tgt, 0, sizeof(tgt)); if ((retval= krb5_copy_principal(context, client_pname, &client))){ com_err(prog_name, retval, _("while copying client principal")); return (FALSE) ; } if ((retval= krb5_copy_principal(context, client, &tgtq.client))){ com_err(prog_name, retval, _("while copying client principal")); return (FALSE) ; } if ((retval = ksu_tgtname(context, krb5_princ_realm(context, client), krb5_princ_realm(context, client), &tgtq.server))){ com_err(prog_name, retval, _("while creating tgt for local realm")); krb5_free_principal(context, client); return (FALSE) ; } if (auth_debug){ dump_principal(context, "local tgt principal name", tgtq.server ); } retval = krb5_cc_retrieve_cred(context, cc, KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_SUPPORTED_KTYPES, &tgtq, &tgt); if (! retval) retval = krb5_check_exp(context, tgt.times); if (retval){ if ((retval != KRB5_CC_NOTFOUND) && (retval != KRB5KRB_AP_ERR_TKT_EXPIRED)){ com_err(prog_name, retval, _("while retrieving creds from cache")); return (FALSE) ; } } else{ got_it = 1; } if (! got_it){ #ifdef GET_TGT_VIA_PASSWD if (krb5_seteuid(0)||krb5_seteuid(target_uid)) { com_err("ksu", errno, _("while switching to target uid")); return FALSE; } fprintf(stderr, _("WARNING: Your password may be exposed if you enter " "it here and are logged \n")); fprintf(stderr, _(" in remotely using an unsecure " "(non-encrypted) channel. \n")); /*get the ticket granting ticket, via passwd(prompt for passwd)*/ if (ksu_get_tgt_via_passwd(context, client, options, &zero_password, &tgt) == FALSE) { krb5_seteuid(0); return FALSE; } *path_passwd = 1; if (krb5_seteuid(0)) { com_err("ksu", errno, _("while reclaiming root uid")); return FALSE; } #else plain_dump_principal (context, client); fprintf(stderr, _("does not have any appropriate tickets in the cache.\n")); return FALSE; #endif /* GET_TGT_VIA_PASSWD */ } krb5_verify_init_creds_opt_init(&vfy_opts); krb5_verify_init_creds_opt_set_ap_req_nofail( &vfy_opts, 1); retval = krb5_verify_init_creds(context, &tgt, NULL, NULL, NULL, &vfy_opts); if (retval) { com_err(prog_name, retval, _("while verifying ticket for server")); return (FALSE); } return (TRUE); } krb5_boolean ksu_get_tgt_via_passwd(context, client, options, zero_password, creds_out) krb5_context context; krb5_principal client; krb5_get_init_creds_opt *options; krb5_boolean *zero_password; krb5_creds *creds_out; { krb5_error_code code; krb5_creds creds; krb5_timestamp now; unsigned int pwsize; char password[255], *client_name, prompt[255]; int result; *zero_password = FALSE; if (creds_out != NULL) memset(creds_out, 0, sizeof(*creds_out)); if ((code = krb5_unparse_name(context, client, &client_name))) { com_err (prog_name, code, _("when unparsing name")); return (FALSE); } memset(&creds, 0, sizeof(creds)); if ((code = krb5_timeofday(context, &now))) { com_err(prog_name, code, _("while getting time of day")); return (FALSE); } result = snprintf(prompt, sizeof(prompt), _("Kerberos password for %s: "), client_name); if (SNPRINTF_OVERFLOW(result, sizeof(prompt))) { fprintf(stderr, _("principal name %s too long for internal buffer space\n"), client_name); return FALSE; } pwsize = sizeof(password); code = krb5_read_password(context, prompt, 0, password, &pwsize); if (code ) { com_err(prog_name, code, _("while reading password for '%s'\n"), client_name); return (FALSE); } if ( pwsize == 0) { fprintf(stderr, _("No password given\n")); *zero_password = TRUE; return (FALSE); } code = krb5_get_init_creds_password(context, &creds, client, password, krb5_prompter_posix, NULL, 0, NULL, options); zap(password, sizeof(password)); if (code) { if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) fprintf(stderr, _("%s: Password incorrect\n"), prog_name); else com_err(prog_name, code, _("while getting initial credentials")); return (FALSE); } if (creds_out != NULL) *creds_out = creds; else krb5_free_cred_contents(context, &creds); return (TRUE); } void dump_principal (context, str, p) krb5_context context; char *str; krb5_principal p; { char * stname; krb5_error_code retval; if ((retval = krb5_unparse_name(context, p, &stname))) { fprintf(stderr, _(" %s while unparsing name\n"), error_message(retval)); } fprintf(stderr, " %s: %s\n", str, stname); } void plain_dump_principal (context, p) krb5_context context; krb5_principal p; { char * stname; krb5_error_code retval; if ((retval = krb5_unparse_name(context, p, &stname))) { fprintf(stderr, _(" %s while unparsing name\n"), error_message(retval)); } fprintf(stderr, "%s ", stname); } /********************************************************************** returns the principal that is closest to client. plist contains a principal list obtained from .k5login and parhaps .k5users file. This routine gets called before getting the password for a tgt. A principal is picked that has the best chance of getting in. **********************************************************************/ krb5_error_code get_best_principal(context, plist, client) krb5_context context; char **plist; krb5_principal *client; { krb5_error_code retval =0; krb5_principal temp_client, best_client = NULL; int i = 0, nelem; if (! plist ) return 0; nelem = krb5_princ_size(context, *client); while(plist[i]){ if ((retval = krb5_parse_name(context, plist[i], &temp_client))){ return retval; } if (data_eq(*krb5_princ_realm(context, *client), *krb5_princ_realm(context, temp_client))) { if (nelem && krb5_princ_size(context, *client) > 0 && krb5_princ_size(context, temp_client) > 0) { krb5_data *p1 = krb5_princ_component(context, *client, 0); krb5_data *p2 = krb5_princ_component(context, temp_client, 0); if (data_eq(*p1, *p2)) { if (auth_debug){ fprintf(stderr, "get_best_principal: compare with %s\n", plist[i]); } if(best_client){ if(krb5_princ_size(context, best_client) > krb5_princ_size(context, temp_client)){ best_client = temp_client; } }else{ best_client = temp_client; } } } } i++; } if (best_client) *client = best_client; return 0; }