/* -*- 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 writen 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;
}