#include "ksu.h"
#include "adm_proto.h"
#include <sys/types.h>
#include <sys/stat.h>
void show_credential();
krb5_error_code krb5_ccache_copy (context, cc_def, cc_other_tag,
primary_principal, cc_out, stored, target_uid)
krb5_context context;
krb5_ccache cc_def;
char *cc_other_tag;
krb5_principal primary_principal;
uid_t target_uid;
krb5_ccache *cc_out;
krb5_boolean *stored;
{
int i=0;
krb5_ccache * cc_other;
const char * cc_def_name;
const char * cc_other_name;
krb5_error_code retval=0;
krb5_creds ** cc_def_creds_arr = NULL;
krb5_creds ** cc_other_creds_arr = NULL;
struct stat st_temp;
cc_other = (krb5_ccache *) xcalloc(1, sizeof (krb5_ccache));
if ((retval = krb5_cc_resolve(context, cc_other_tag, cc_other))){
com_err (prog_name, retval, "resolving ccache %s",
cc_other_tag);
return retval;
}
cc_def_name = krb5_cc_get_name(context, cc_def);
cc_other_name = krb5_cc_get_name(context, *cc_other);
if ( ! stat(cc_def_name, &st_temp)){
if((retval = krb5_get_nonexp_tkts(context,cc_def,&cc_def_creds_arr))){
return retval;
}
}
*stored = krb5_find_princ_in_cred_list(context, cc_def_creds_arr,
primary_principal);
#ifdef HAVE_LSTAT
if (!lstat( cc_other_name, &st_temp))
#else
if (!stat( cc_other_name, &st_temp))
#endif
return EINVAL;
if (krb5_seteuid(0)||krb5_seteuid(target_uid)) {
return errno;
}
if ((retval = krb5_cc_initialize(context, *cc_other, primary_principal))){
return retval;
}
retval = krb5_store_all_creds(context, * cc_other, cc_def_creds_arr,
cc_other_creds_arr);
if (cc_def_creds_arr){
while (cc_def_creds_arr[i]){
krb5_free_creds(context, cc_def_creds_arr[i]);
i++;
}
}
i=0;
if(cc_other_creds_arr){
while (cc_other_creds_arr[i]){
krb5_free_creds(context, cc_other_creds_arr[i]);
i++;
}
}
*cc_out = *cc_other;
return retval;
}
krb5_error_code krb5_store_all_creds(context, cc, creds_def, creds_other)
krb5_context context;
krb5_ccache cc;
krb5_creds **creds_def;
krb5_creds **creds_other;
{
int i = 0;
krb5_error_code retval = 0;
krb5_creds ** temp_creds= NULL;
if ((creds_def == NULL) && (creds_other == NULL))
return 0;
if ((creds_def == NULL) && (creds_other != NULL))
temp_creds = creds_other;
if ((creds_def != NULL) && (creds_other == NULL))
temp_creds = creds_def;
if (temp_creds){
while(temp_creds[i]){
if ((retval= krb5_cc_store_cred(context, cc,
temp_creds[i]))){
return retval;
}
i++;
}
}
else {
return KRB5KRB_ERR_GENERIC;
}
return 0;
}
krb5_boolean compare_creds(context, cred1, cred2)
krb5_context context;
krb5_creds *cred1;
krb5_creds *cred2;
{
krb5_boolean retval;
retval = krb5_principal_compare (context, cred1->client, cred2->client);
if (retval == TRUE)
retval = krb5_principal_compare (context, cred1->server, cred2->server);
return retval;
}
krb5_error_code krb5_get_nonexp_tkts(context, cc, creds_array)
krb5_context context;
krb5_ccache cc;
krb5_creds ***creds_array;
{
krb5_creds creds, temp_tktq, temp_tkt;
krb5_creds **temp_creds;
krb5_error_code retval=0;
krb5_cc_cursor cur;
int count = 0;
int chunk_count = 1;
if ( ! ( temp_creds = (krb5_creds **) malloc( CHUNK * sizeof(krb5_creds *)))){
return ENOMEM;
}
memset((char *) &temp_tktq, 0, sizeof(temp_tktq));
memset((char *) &temp_tkt, 0, sizeof(temp_tkt));
memset((char *) &creds, 0, sizeof(creds));
if ((retval = krb5_cc_start_seq_get(context, cc, &cur))) {
return retval;
}
while (!(retval = krb5_cc_next_cred(context, cc, &cur, &creds))){
if ((retval = krb5_check_exp(context, creds.times))){
if (retval != KRB5KRB_AP_ERR_TKT_EXPIRED){
return retval;
}
if (auth_debug){
fprintf(stderr,"krb5_ccache_copy: CREDS EXPIRED:\n");
fputs(" Valid starting Expires Service principal\n",stdout);
show_credential(context, &creds, cc);
fprintf(stderr,"\n");
}
}
else {
if ((retval = krb5_copy_creds(context, &creds,
&temp_creds[count]))){
return retval;
}
count ++;
if (count == (chunk_count * CHUNK -1)){
chunk_count ++;
if (!(temp_creds = (krb5_creds **) realloc(temp_creds,
chunk_count * CHUNK * sizeof(krb5_creds *)))){
return ENOMEM;
}
}
}
}
temp_creds[count] = NULL;
*creds_array = temp_creds;
if (retval == KRB5_CC_END) {
retval = krb5_cc_end_seq_get(context, cc, &cur);
}
return retval;
}
krb5_error_code krb5_check_exp(context, tkt_time)
krb5_context context;
krb5_ticket_times tkt_time;
{
krb5_error_code retval =0;
krb5_timestamp currenttime;
if ((retval = krb5_timeofday (context, ¤ttime))){
return retval;
}
if (auth_debug){
fprintf(stderr,"krb5_check_exp: the krb5_clockskew is %d \n",
context->clockskew);
fprintf(stderr,"krb5_check_exp: currenttime - endtime %d \n",
(currenttime - tkt_time.endtime ));
}
if (currenttime - tkt_time.endtime > context->clockskew){
retval = KRB5KRB_AP_ERR_TKT_EXPIRED ;
return retval;
}
return 0;
}
char *flags_string(cred)
krb5_creds *cred;
{
static char buf[32];
int i = 0;
if (cred->ticket_flags & TKT_FLG_FORWARDABLE)
buf[i++] = 'F';
if (cred->ticket_flags & TKT_FLG_FORWARDED)
buf[i++] = 'f';
if (cred->ticket_flags & TKT_FLG_PROXIABLE)
buf[i++] = 'P';
if (cred->ticket_flags & TKT_FLG_PROXY)
buf[i++] = 'p';
if (cred->ticket_flags & TKT_FLG_MAY_POSTDATE)
buf[i++] = 'D';
if (cred->ticket_flags & TKT_FLG_POSTDATED)
buf[i++] = 'd';
if (cred->ticket_flags & TKT_FLG_INVALID)
buf[i++] = 'i';
if (cred->ticket_flags & TKT_FLG_RENEWABLE)
buf[i++] = 'R';
if (cred->ticket_flags & TKT_FLG_INITIAL)
buf[i++] = 'I';
if (cred->ticket_flags & TKT_FLG_HW_AUTH)
buf[i++] = 'H';
if (cred->ticket_flags & TKT_FLG_PRE_AUTH)
buf[i++] = 'A';
buf[i] = '\0';
return(buf);
}
void printtime(tv)
time_t tv;
{
char fmtbuf[18];
char fill;
krb5_timestamp tstamp;
(void) localtime((time_t *)&tv);
tstamp = tv;
fill = ' ';
if (!krb5_timestamp_to_sfstring(tstamp,
fmtbuf,
sizeof(fmtbuf),
&fill))
printf(fmtbuf);
}
krb5_error_code
krb5_get_login_princ(luser, princ_list)
const char *luser;
char ***princ_list;
{
struct stat sbuf;
struct passwd *pwd;
char pbuf[MAXPATHLEN];
FILE *fp;
char * linebuf;
char *newline;
int gobble, result;
char ** buf_out;
struct stat st_temp;
int count = 0, chunk_count = 1;
if ((pwd = getpwnam(luser)) == NULL) {
return 0;
}
result = snprintf(pbuf, sizeof(pbuf), "%s/.k5login", pwd->pw_dir);
if (SNPRINTF_OVERFLOW(result, sizeof(pbuf))) {
fprintf (stderr, "home directory path for %s too long\n", luser);
exit (1);
}
if (stat(pbuf, &st_temp)) {
return 0;
}
if ((fp = fopen(pbuf, "r")) == NULL) {
return 0;
}
if (fstat(fileno(fp), &sbuf)) {
fclose(fp);
return 0;
}
if ((sbuf.st_uid != pwd->pw_uid) && sbuf.st_uid) {
fclose(fp);
return 0;
}
if( !(linebuf = (char *) calloc (BUFSIZ, sizeof(char)))) return ENOMEM;
if (!(buf_out = (char **) malloc( CHUNK * sizeof(char *)))) return ENOMEM;
while ( fgets(linebuf, BUFSIZ, fp) != NULL) {
linebuf[BUFSIZ-1] = '\0';
newline = NULL;
if ((newline = strchr(linebuf, '\n')))
*newline = '\0';
buf_out[count] = linebuf;
count ++;
if (count == (chunk_count * CHUNK -1)){
chunk_count ++;
if (!(buf_out = (char **) realloc(buf_out,
chunk_count * CHUNK * sizeof(char *)))){
return ENOMEM;
}
}
if (!newline)
while (((gobble = getc(fp)) != EOF) && gobble != '\n');
if( !(linebuf = (char *) calloc (BUFSIZ, sizeof(char)))) return ENOMEM;
}
buf_out[count] = NULL;
*princ_list = buf_out;
fclose(fp);
return 0;
}
void
show_credential(context, cred, cc)
krb5_context context;
krb5_creds *cred;
krb5_ccache cc;
{
krb5_error_code retval;
char *name, *sname, *flags;
int first = 1;
krb5_principal princ;
char * defname;
int show_flags =1;
retval = krb5_unparse_name(context, cred->client, &name);
if (retval) {
com_err(prog_name, retval, "while unparsing client name");
return;
}
retval = krb5_unparse_name(context, cred->server, &sname);
if (retval) {
com_err(prog_name, retval, "while unparsing server name");
free(name);
return;
}
if ((retval = krb5_cc_get_principal(context, cc, &princ))) {
com_err(prog_name, retval, "while retrieving principal name");
return;
}
if ((retval = krb5_unparse_name(context, princ, &defname))) {
com_err(prog_name, retval, "while unparsing principal name");
return;
}
if (!cred->times.starttime)
cred->times.starttime = cred->times.authtime;
printtime(cred->times.starttime);
putchar(' '); putchar(' ');
printtime(cred->times.endtime);
putchar(' '); putchar(' ');
printf("%s\n", sname);
if (strcmp(name, defname)) {
printf("\tfor client %s", name);
first = 0;
}
if (cred->times.renew_till) {
if (first)
fputs("\t",stdout);
else
fputs(", ",stdout);
fputs("renew until ", stdout);
printtime(cred->times.renew_till);
}
if (show_flags) {
flags = flags_string(cred);
if (flags && *flags) {
if (first)
fputs("\t",stdout);
else
fputs(", ",stdout);
printf("Flags: %s", flags);
first = 0;
}
}
putchar('\n');
free(name);
free(sname);
}
int gen_sym(){
static int i = 0;
i ++;
return i;
}
krb5_error_code krb5_ccache_overwrite(context, ccs, cct, primary_principal)
krb5_context context;
krb5_ccache ccs;
krb5_ccache cct;
krb5_principal primary_principal;
{
const char * cct_name;
const char * ccs_name;
krb5_error_code retval=0;
krb5_principal temp_principal;
krb5_creds ** ccs_creds_arr = NULL;
int i=0;
struct stat st_temp;
ccs_name = krb5_cc_get_name(context, ccs);
cct_name = krb5_cc_get_name(context, cct);
if ( ! stat(ccs_name, &st_temp)){
if ((retval = krb5_get_nonexp_tkts(context, ccs, &ccs_creds_arr))){
return retval;
}
}
if ( ! stat(cct_name, &st_temp)){
if ((retval = krb5_cc_get_principal(context, cct, &temp_principal))){
return retval;
}
}else{
temp_principal = primary_principal;
}
if ((retval = krb5_cc_initialize(context, cct, temp_principal))){
return retval;
}
retval = krb5_store_all_creds(context, cct, ccs_creds_arr, NULL);
if (ccs_creds_arr){
while (ccs_creds_arr[i]){
krb5_free_creds(context, ccs_creds_arr[i]);
i++;
}
}
return retval;
}
krb5_error_code krb5_store_some_creds(context, cc, creds_def, creds_other, prst,
stored)
krb5_context context;
krb5_ccache cc;
krb5_creds **creds_def;
krb5_creds **creds_other;
krb5_principal prst;
krb5_boolean *stored;
{
int i = 0;
krb5_error_code retval = 0;
krb5_creds ** temp_creds= NULL;
krb5_boolean temp_stored = FALSE;
if ((creds_def == NULL) && (creds_other == NULL))
return 0;
if ((creds_def == NULL) && (creds_other != NULL))
temp_creds = creds_other;
if ((creds_def != NULL) && (creds_other == NULL))
temp_creds = creds_def;
if (temp_creds){
while(temp_creds[i]){
if (krb5_principal_compare(context,
temp_creds[i]->client,
prst)== TRUE) {
if ((retval = krb5_cc_store_cred(context,
cc,temp_creds[i]))){
return retval;
}
temp_stored = TRUE;
}
i++;
}
}
else {
return KRB5KRB_ERR_GENERIC;
}
*stored = temp_stored;
return 0;
}
krb5_error_code krb5_ccache_copy_restricted (context, cc_def, cc_other_tag,
prst, cc_out, stored, target_uid)
krb5_context context;
krb5_ccache cc_def;
char *cc_other_tag;
krb5_principal prst;
uid_t target_uid;
krb5_ccache *cc_out;
krb5_boolean *stored;
{
int i=0;
krb5_ccache * cc_other;
const char * cc_def_name;
const char * cc_other_name;
krb5_error_code retval=0;
krb5_creds ** cc_def_creds_arr = NULL;
krb5_creds ** cc_other_creds_arr = NULL;
struct stat st_temp;
cc_other = (krb5_ccache *) xcalloc(1, sizeof (krb5_ccache));
if ((retval = krb5_cc_resolve(context, cc_other_tag, cc_other))){
com_err (prog_name, retval, "resolving ccache %s",
cc_other_tag);
return retval;
}
cc_def_name = krb5_cc_get_name(context, cc_def);
cc_other_name = krb5_cc_get_name(context, *cc_other);
if ( ! stat(cc_def_name, &st_temp)){
if((retval = krb5_get_nonexp_tkts(context,cc_def,&cc_def_creds_arr))){
return retval;
}
}
#ifdef HAVE_LSTAT
if (!lstat( cc_other_name, &st_temp)) {
#else
if (!stat( cc_other_name, &st_temp)) {
#endif
return EINVAL;
}
if (krb5_seteuid(0)||krb5_seteuid(target_uid)) {
return errno;
}
if ((retval = krb5_cc_initialize(context, *cc_other, prst))){
return retval;
}
retval = krb5_store_some_creds(context, * cc_other,
cc_def_creds_arr, cc_other_creds_arr, prst, stored);
if (cc_def_creds_arr){
while (cc_def_creds_arr[i]){
krb5_free_creds(context, cc_def_creds_arr[i]);
i++;
}
}
i=0;
if(cc_other_creds_arr){
while (cc_other_creds_arr[i]){
krb5_free_creds(context, cc_other_creds_arr[i]);
i++;
}
}
*cc_out = *cc_other;
return retval;
}
krb5_error_code krb5_ccache_filter (context, cc, prst)
krb5_context context;
krb5_ccache cc;
krb5_principal prst;
{
int i=0;
krb5_error_code retval=0;
krb5_principal temp_principal;
krb5_creds ** cc_creds_arr = NULL;
const char * cc_name;
krb5_boolean stored;
struct stat st_temp;
cc_name = krb5_cc_get_name(context, cc);
if ( ! stat(cc_name, &st_temp)){
if (auth_debug) {
fprintf(stderr,"putting cache %s through a filter for -z option\n", cc_name);
}
if ((retval = krb5_get_nonexp_tkts(context, cc, &cc_creds_arr))){
return retval;
}
if ((retval = krb5_cc_get_principal(context, cc, &temp_principal))){
return retval;
}
if ((retval = krb5_cc_initialize(context, cc, temp_principal))){
return retval;
}
if ((retval = krb5_store_some_creds(context, cc, cc_creds_arr,
NULL, prst, &stored))){
return retval;
}
if (cc_creds_arr){
while (cc_creds_arr[i]){
krb5_free_creds(context, cc_creds_arr[i]);
i++;
}
}
}
return 0;
}
krb5_boolean krb5_find_princ_in_cred_list (context, creds_list, princ)
krb5_context context;
krb5_creds **creds_list;
krb5_principal princ;
{
int i = 0;
krb5_boolean temp_stored = FALSE;
if (creds_list){
while(creds_list[i]){
if (krb5_principal_compare(context,
creds_list[i]->client,
princ)== TRUE){
temp_stored = TRUE;
break;
}
i++;
}
}
return temp_stored;
}
krb5_error_code krb5_find_princ_in_cache (context, cc, princ, found)
krb5_context context;
krb5_ccache cc;
krb5_principal princ;
krb5_boolean *found;
{
krb5_error_code retval;
krb5_creds ** creds_list = NULL;
const char * cc_name;
struct stat st_temp;
cc_name = krb5_cc_get_name(context, cc);
if ( ! stat(cc_name, &st_temp)){
if ((retval = krb5_get_nonexp_tkts(context, cc, &creds_list))){
return retval;
}
}
*found = krb5_find_princ_in_cred_list(context, creds_list, princ);
return 0;
}