806 lines
21 KiB
C
806 lines
21 KiB
C
/*
|
|
Copyright (C) 1989 by the Massachusetts Institute of Technology
|
|
|
|
Export of this software from the United States of America is assumed
|
|
to 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 use, copy, modify, and
|
|
distribute this software and its documentation for any purpose and
|
|
without fee is hereby granted, provided that the above copyright
|
|
notice appear in all copies and that both that copyright notice and
|
|
this permission notice appear in supporting documentation, and that
|
|
the name of M.I.T. not be used in advertising or publicity pertaining
|
|
to distribution of the software without specific, written prior
|
|
permission. M.I.T. makes no representations about the suitability of
|
|
this software for any purpose. It is provided "as is" without express
|
|
or implied warranty.
|
|
|
|
*/
|
|
|
|
#include "krb_locl.h"
|
|
|
|
RCSID("$Id: tf_util.c,v 1.39 1999/12/02 18:03:16 assar Exp $");
|
|
|
|
|
|
#define TOO_BIG -1
|
|
#define TF_LCK_RETRY ((unsigned)2) /* seconds to sleep before
|
|
* retry if ticket file is
|
|
* locked */
|
|
#define TF_LCK_RETRY_COUNT (50) /* number of retries */
|
|
|
|
#ifndef O_BINARY
|
|
#define O_BINARY 0
|
|
#endif
|
|
|
|
#define MAGIC_TICKET_NAME "magic"
|
|
#define MAGIC_TICKET_TIME_DIFF_INST "time-diff"
|
|
#define MAGIC_TICKET_ADDR_INST "our-address"
|
|
|
|
/*
|
|
* fd must be initialized to something that won't ever occur as a real
|
|
* file descriptor. Since open(2) returns only non-negative numbers as
|
|
* valid file descriptors, and tf_init always stuffs the return value
|
|
* from open in here even if it is an error flag, we must
|
|
* a. Initialize fd to a negative number, to indicate that it is
|
|
* not initially valid.
|
|
* b. When checking for a valid fd, assume that negative values
|
|
* are invalid (ie. when deciding whether tf_init has been
|
|
* called.)
|
|
* c. In tf_close, be sure it gets reinitialized to a negative
|
|
* number.
|
|
*/
|
|
static int fd = -1;
|
|
static int curpos; /* Position in tfbfr */
|
|
static int lastpos; /* End of tfbfr */
|
|
static char tfbfr[BUFSIZ]; /* Buffer for ticket data */
|
|
|
|
static int tf_gets(char *s, int n);
|
|
static int tf_read(void *s, int n);
|
|
|
|
/*
|
|
* This file contains routines for manipulating the ticket cache file.
|
|
*
|
|
* The ticket file is in the following format:
|
|
*
|
|
* principal's name (null-terminated string)
|
|
* principal's instance (null-terminated string)
|
|
* CREDENTIAL_1
|
|
* CREDENTIAL_2
|
|
* ...
|
|
* CREDENTIAL_n
|
|
* EOF
|
|
*
|
|
* Where "CREDENTIAL_x" consists of the following fixed-length
|
|
* fields from the CREDENTIALS structure (see "krb.h"):
|
|
*
|
|
* char service[ANAME_SZ]
|
|
* char instance[INST_SZ]
|
|
* char realm[REALM_SZ]
|
|
* C_Block session
|
|
* int lifetime
|
|
* int kvno
|
|
* KTEXT_ST ticket_st
|
|
* u_int32_t issue_date
|
|
*
|
|
* Short description of routines:
|
|
*
|
|
* tf_init() opens the ticket file and locks it.
|
|
*
|
|
* tf_get_pname() returns the principal's name.
|
|
*
|
|
* tf_put_pname() writes the principal's name to the ticket file.
|
|
*
|
|
* tf_get_pinst() returns the principal's instance (may be null).
|
|
*
|
|
* tf_put_pinst() writes the instance.
|
|
*
|
|
* tf_get_cred() returns the next CREDENTIALS record.
|
|
*
|
|
* tf_save_cred() appends a new CREDENTIAL record to the ticket file.
|
|
*
|
|
* tf_close() closes the ticket file and releases the lock.
|
|
*
|
|
* tf_gets() returns the next null-terminated string. It's an internal
|
|
* routine used by tf_get_pname(), tf_get_pinst(), and tf_get_cred().
|
|
*
|
|
* tf_read() reads a given number of bytes. It's an internal routine
|
|
* used by tf_get_cred().
|
|
*/
|
|
|
|
/*
|
|
* tf_init() should be called before the other ticket file routines.
|
|
* It takes the name of the ticket file to use, "tf_name", and a
|
|
* read/write flag "rw" as arguments.
|
|
*
|
|
* It tries to open the ticket file, checks the mode, and if everything
|
|
* is okay, locks the file. If it's opened for reading, the lock is
|
|
* shared. If it's opened for writing, the lock is exclusive.
|
|
*
|
|
* Returns KSUCCESS if all went well, otherwise one of the following:
|
|
*
|
|
* NO_TKT_FIL - file wasn't there
|
|
* TKT_FIL_ACC - file was in wrong mode, etc.
|
|
* TKT_FIL_LCK - couldn't lock the file, even after a retry
|
|
*/
|
|
|
|
#ifdef _NO_LOCKING
|
|
#undef flock
|
|
#define flock(F, M) 0
|
|
#endif
|
|
|
|
int
|
|
tf_init(char *tf_name, int rw)
|
|
{
|
|
/* Unix implementation */
|
|
int wflag;
|
|
struct stat stat_buf;
|
|
int i_retry;
|
|
|
|
switch (rw) {
|
|
case R_TKT_FIL:
|
|
wflag = 0;
|
|
break;
|
|
case W_TKT_FIL:
|
|
wflag = 1;
|
|
break;
|
|
default:
|
|
if (krb_debug)
|
|
krb_warning("tf_init: illegal parameter\n");
|
|
return TKT_FIL_ACC;
|
|
}
|
|
if (lstat(tf_name, &stat_buf) < 0)
|
|
switch (errno) {
|
|
case ENOENT:
|
|
return NO_TKT_FIL;
|
|
default:
|
|
return TKT_FIL_ACC;
|
|
}
|
|
if (!S_ISREG(stat_buf.st_mode))
|
|
return TKT_FIL_ACC;
|
|
|
|
/* The code tries to guess when the calling program is running
|
|
* set-uid and prevent unauthorized access.
|
|
*
|
|
* All library functions now assume that the right set of userids
|
|
* are set upon entry, therefore it's not strictly necessary to
|
|
* perform these test for programs adhering to these assumptions.
|
|
*
|
|
* This doesn't work on cygwin because getuid() returns a different
|
|
* uid than the owner of files that are created.
|
|
*/
|
|
#ifndef __CYGWIN__
|
|
{
|
|
uid_t me = getuid();
|
|
if (stat_buf.st_uid != me && me != 0)
|
|
return TKT_FIL_ACC;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* If "wflag" is set, open the ticket file in append-writeonly mode
|
|
* and lock the ticket file in exclusive mode. If unable to lock
|
|
* the file, sleep and try again. If we fail again, return with the
|
|
* proper error message.
|
|
*/
|
|
|
|
curpos = sizeof(tfbfr);
|
|
|
|
|
|
if (wflag) {
|
|
fd = open(tf_name, O_RDWR | O_BINARY, 0600);
|
|
if (fd < 0) {
|
|
return TKT_FIL_ACC;
|
|
}
|
|
for (i_retry = 0; i_retry < TF_LCK_RETRY_COUNT; i_retry++) {
|
|
if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
|
|
if (krb_debug)
|
|
krb_warning("tf_init: retry %d of write lock of `%s'.\n",
|
|
i_retry, tf_name);
|
|
sleep (TF_LCK_RETRY);
|
|
} else {
|
|
return KSUCCESS; /* all done */
|
|
}
|
|
}
|
|
close (fd);
|
|
fd = -1;
|
|
return TKT_FIL_LCK;
|
|
}
|
|
/*
|
|
* Otherwise "wflag" is not set and the ticket file should be opened
|
|
* for read-only operations and locked for shared access.
|
|
*/
|
|
|
|
fd = open(tf_name, O_RDONLY | O_BINARY, 0600);
|
|
if (fd < 0) {
|
|
return TKT_FIL_ACC;
|
|
}
|
|
|
|
for (i_retry = 0; i_retry < TF_LCK_RETRY_COUNT; i_retry++) {
|
|
if (flock(fd, LOCK_SH | LOCK_NB) < 0) {
|
|
if (krb_debug)
|
|
krb_warning("tf_init: retry %d of read lock of `%s'.\n",
|
|
i_retry, tf_name);
|
|
sleep (TF_LCK_RETRY);
|
|
} else {
|
|
return KSUCCESS; /* all done */
|
|
}
|
|
}
|
|
/* failure */
|
|
close(fd);
|
|
fd = -1;
|
|
return TKT_FIL_LCK;
|
|
}
|
|
|
|
/*
|
|
* tf_create() should be called when creating a new ticket file.
|
|
* The only argument is the name of the ticket file.
|
|
* After calling this, it should be possible to use other tf_* functions.
|
|
*
|
|
* New algoritm for creating ticket file:
|
|
* 1. try to erase contents of existing file.
|
|
* 2. try to remove old file.
|
|
* 3. try to open with O_CREAT and O_EXCL
|
|
* 4. if this fails, someone has created a file in between 1 and 2 and
|
|
* we should fail. Otherwise, all is wonderful.
|
|
*/
|
|
|
|
int
|
|
tf_create(char *tf_name)
|
|
{
|
|
struct stat statbuf;
|
|
char garbage[BUFSIZ];
|
|
|
|
fd = open(tf_name, O_RDWR | O_BINARY, 0);
|
|
if (fd >= 0) {
|
|
if (fstat (fd, &statbuf) == 0) {
|
|
int i;
|
|
|
|
for (i = 0; i < statbuf.st_size; i += sizeof(garbage))
|
|
write (fd, garbage, sizeof(garbage));
|
|
}
|
|
close (fd);
|
|
}
|
|
|
|
if (unlink (tf_name) && errno != ENOENT)
|
|
return TKT_FIL_ACC;
|
|
|
|
fd = open(tf_name, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
|
|
if (fd < 0)
|
|
return TKT_FIL_ACC;
|
|
if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
|
|
sleep(TF_LCK_RETRY);
|
|
if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
|
|
close(fd);
|
|
fd = -1;
|
|
return TKT_FIL_LCK;
|
|
}
|
|
}
|
|
return KSUCCESS;
|
|
}
|
|
|
|
/*
|
|
* tf_get_pname() reads the principal's name from the ticket file. It
|
|
* should only be called after tf_init() has been called. The
|
|
* principal's name is filled into the "p" parameter. If all goes well,
|
|
* KSUCCESS is returned. If tf_init() wasn't called, TKT_FIL_INI is
|
|
* returned. If the name was null, or EOF was encountered, or the name
|
|
* was longer than ANAME_SZ, TKT_FIL_FMT is returned.
|
|
*/
|
|
|
|
int
|
|
tf_get_pname(char *p)
|
|
{
|
|
if (fd < 0) {
|
|
if (krb_debug)
|
|
krb_warning("tf_get_pname called before tf_init.\n");
|
|
return TKT_FIL_INI;
|
|
}
|
|
if (tf_gets(p, ANAME_SZ) < 2) /* can't be just a null */
|
|
{
|
|
if (krb_debug)
|
|
krb_warning ("tf_get_pname: pname < 2.\n");
|
|
return TKT_FIL_FMT;
|
|
}
|
|
return KSUCCESS;
|
|
}
|
|
|
|
/*
|
|
* tf_put_pname() sets the principal's name in the ticket file. Call
|
|
* after tf_create().
|
|
*/
|
|
|
|
int
|
|
tf_put_pname(const char *p)
|
|
{
|
|
unsigned count;
|
|
|
|
if (fd < 0) {
|
|
if (krb_debug)
|
|
krb_warning("tf_put_pname called before tf_create.\n");
|
|
return TKT_FIL_INI;
|
|
}
|
|
count = strlen(p)+1;
|
|
if (write(fd,p,count) != count)
|
|
return(KFAILURE);
|
|
return KSUCCESS;
|
|
}
|
|
|
|
/*
|
|
* tf_get_pinst() reads the principal's instance from a ticket file.
|
|
* It should only be called after tf_init() and tf_get_pname() have been
|
|
* called. The instance is filled into the "inst" parameter. If all
|
|
* goes well, KSUCCESS is returned. If tf_init() wasn't called,
|
|
* TKT_FIL_INI is returned. If EOF was encountered, or the instance
|
|
* was longer than ANAME_SZ, TKT_FIL_FMT is returned. Note that the
|
|
* instance may be null.
|
|
*/
|
|
|
|
int
|
|
tf_get_pinst(char *inst)
|
|
{
|
|
if (fd < 0) {
|
|
if (krb_debug)
|
|
krb_warning("tf_get_pinst called before tf_init.\n");
|
|
return TKT_FIL_INI;
|
|
}
|
|
if (tf_gets(inst, INST_SZ) < 1)
|
|
{
|
|
if (krb_debug)
|
|
krb_warning("tf_get_pinst: inst_sz < 1.\n");
|
|
return TKT_FIL_FMT;
|
|
}
|
|
return KSUCCESS;
|
|
}
|
|
|
|
/*
|
|
* tf_put_pinst writes the principal's instance to the ticket file.
|
|
* Call after tf_create.
|
|
*/
|
|
|
|
int
|
|
tf_put_pinst(const char *inst)
|
|
{
|
|
unsigned count;
|
|
|
|
if (fd < 0) {
|
|
if (krb_debug)
|
|
krb_warning("tf_put_pinst called before tf_create.\n");
|
|
return TKT_FIL_INI;
|
|
}
|
|
count = strlen(inst)+1;
|
|
if (write(fd,inst,count) != count)
|
|
return(KFAILURE);
|
|
return KSUCCESS;
|
|
}
|
|
|
|
/*
|
|
* tf_get_cred() reads a CREDENTIALS record from a ticket file and fills
|
|
* in the given structure "c". It should only be called after tf_init(),
|
|
* tf_get_pname(), and tf_get_pinst() have been called. If all goes well,
|
|
* KSUCCESS is returned. Possible error codes are:
|
|
*
|
|
* TKT_FIL_INI - tf_init wasn't called first
|
|
* TKT_FIL_FMT - bad format
|
|
* EOF - end of file encountered
|
|
*/
|
|
|
|
static int
|
|
real_tf_get_cred(CREDENTIALS *c)
|
|
{
|
|
KTEXT ticket = &c->ticket_st; /* pointer to ticket */
|
|
int k_errno;
|
|
|
|
if (fd < 0) {
|
|
if (krb_debug)
|
|
krb_warning ("tf_get_cred called before tf_init.\n");
|
|
return TKT_FIL_INI;
|
|
}
|
|
if ((k_errno = tf_gets(c->service, SNAME_SZ)) < 2)
|
|
switch (k_errno) {
|
|
case TOO_BIG:
|
|
if (krb_debug)
|
|
krb_warning("tf_get_cred: too big service cred.\n");
|
|
case 1: /* can't be just a null */
|
|
tf_close();
|
|
if (krb_debug)
|
|
krb_warning("tf_get_cred: null service cred.\n");
|
|
return TKT_FIL_FMT;
|
|
case 0:
|
|
return EOF;
|
|
}
|
|
if ((k_errno = tf_gets(c->instance, INST_SZ)) < 1)
|
|
switch (k_errno) {
|
|
case TOO_BIG:
|
|
if (krb_debug)
|
|
krb_warning ("tf_get_cred: too big instance cred.\n");
|
|
return TKT_FIL_FMT;
|
|
case 0:
|
|
return EOF;
|
|
}
|
|
if ((k_errno = tf_gets(c->realm, REALM_SZ)) < 2)
|
|
switch (k_errno) {
|
|
case TOO_BIG:
|
|
if (krb_debug)
|
|
krb_warning ("tf_get_cred: too big realm cred.\n");
|
|
case 1: /* can't be just a null */
|
|
tf_close();
|
|
if (krb_debug)
|
|
krb_warning ("tf_get_cred: null realm cred.\n");
|
|
return TKT_FIL_FMT;
|
|
case 0:
|
|
return EOF;
|
|
}
|
|
if (
|
|
tf_read((c->session), DES_KEY_SZ) < 1 ||
|
|
tf_read(&(c->lifetime), sizeof(c->lifetime)) < 1 ||
|
|
tf_read(&(c->kvno), sizeof(c->kvno)) < 1 ||
|
|
tf_read(&(ticket->length), sizeof(ticket->length))
|
|
< 1 ||
|
|
/* don't try to read a silly amount into ticket->dat */
|
|
ticket->length > MAX_KTXT_LEN ||
|
|
tf_read((ticket->dat), ticket->length) < 1 ||
|
|
tf_read(&(c->issue_date), sizeof(c->issue_date)) < 1
|
|
) {
|
|
tf_close();
|
|
if (krb_debug)
|
|
krb_warning ("tf_get_cred: failed tf_read.\n");
|
|
return TKT_FIL_FMT;
|
|
}
|
|
return KSUCCESS;
|
|
}
|
|
|
|
int
|
|
tf_get_cred(CREDENTIALS *c)
|
|
{
|
|
int ret;
|
|
int fake;
|
|
|
|
do {
|
|
fake = 0;
|
|
|
|
ret = real_tf_get_cred (c);
|
|
if (ret)
|
|
return ret;
|
|
|
|
if(strcmp(c->service, MAGIC_TICKET_NAME) == 0) {
|
|
if(strcmp(c->instance, MAGIC_TICKET_TIME_DIFF_INST) == 0) {
|
|
/* we found the magic `time diff' ticket; update the kdc time
|
|
differential, and then get the next ticket */
|
|
u_int32_t d;
|
|
|
|
krb_get_int(c->ticket_st.dat, &d, 4, 0);
|
|
krb_set_kdc_time_diff(d);
|
|
fake = 1;
|
|
} else if (strcmp(c->instance, MAGIC_TICKET_ADDR_INST) == 0) {
|
|
fake = 1;
|
|
}
|
|
}
|
|
} while (fake);
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
tf_get_cred_addr(char *realm, size_t realm_sz, struct in_addr *addr)
|
|
{
|
|
int ret;
|
|
int fake;
|
|
CREDENTIALS cred;
|
|
|
|
do {
|
|
fake = 1;
|
|
|
|
ret = real_tf_get_cred (&cred);
|
|
if (ret)
|
|
return ret;
|
|
|
|
if(strcmp(cred.service, MAGIC_TICKET_NAME) == 0) {
|
|
if(strcmp(cred.instance, MAGIC_TICKET_TIME_DIFF_INST) == 0) {
|
|
/* we found the magic `time diff' ticket; update the kdc time
|
|
differential, and then get the next ticket */
|
|
u_int32_t d;
|
|
|
|
krb_get_int(cred.ticket_st.dat, &d, 4, 0);
|
|
krb_set_kdc_time_diff(d);
|
|
} else if (strcmp(cred.instance, MAGIC_TICKET_ADDR_INST) == 0) {
|
|
strlcpy(realm, cred.realm, realm_sz);
|
|
memcpy (addr, cred.ticket_st.dat, sizeof(*addr));
|
|
fake = 0;
|
|
}
|
|
}
|
|
} while (fake);
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* tf_close() closes the ticket file and sets "fd" to -1. If "fd" is
|
|
* not a valid file descriptor, it just returns. It also clears the
|
|
* buffer used to read tickets.
|
|
*
|
|
* The return value is not defined.
|
|
*/
|
|
|
|
void
|
|
tf_close(void)
|
|
{
|
|
if (!(fd < 0)) {
|
|
flock(fd, LOCK_UN);
|
|
close(fd);
|
|
fd = -1; /* see declaration of fd above */
|
|
}
|
|
memset(tfbfr, 0, sizeof(tfbfr));
|
|
}
|
|
|
|
/*
|
|
* tf_gets() is an internal routine. It takes a string "s" and a count
|
|
* "n", and reads from the file until either it has read "n" characters,
|
|
* or until it reads a null byte. When finished, what has been read exists
|
|
* in "s". If it encounters EOF or an error, it closes the ticket file.
|
|
*
|
|
* Possible return values are:
|
|
*
|
|
* n the number of bytes read (including null terminator)
|
|
* when all goes well
|
|
*
|
|
* 0 end of file or read error
|
|
*
|
|
* TOO_BIG if "count" characters are read and no null is
|
|
* encountered. This is an indication that the ticket
|
|
* file is seriously ill.
|
|
*/
|
|
|
|
static int
|
|
tf_gets(char *s, int n)
|
|
{
|
|
int count;
|
|
|
|
if (fd < 0) {
|
|
if (krb_debug)
|
|
krb_warning ("tf_gets called before tf_init.\n");
|
|
return TKT_FIL_INI;
|
|
}
|
|
for (count = n - 1; count > 0; --count) {
|
|
if (curpos >= sizeof(tfbfr)) {
|
|
lastpos = read(fd, tfbfr, sizeof(tfbfr));
|
|
curpos = 0;
|
|
}
|
|
if (curpos == lastpos) {
|
|
tf_close();
|
|
return 0;
|
|
}
|
|
*s = tfbfr[curpos++];
|
|
if (*s++ == '\0')
|
|
return (n - count);
|
|
}
|
|
tf_close();
|
|
return TOO_BIG;
|
|
}
|
|
|
|
/*
|
|
* tf_read() is an internal routine. It takes a string "s" and a count
|
|
* "n", and reads from the file until "n" bytes have been read. When
|
|
* finished, what has been read exists in "s". If it encounters EOF or
|
|
* an error, it closes the ticket file.
|
|
*
|
|
* Possible return values are:
|
|
*
|
|
* n the number of bytes read when all goes well
|
|
*
|
|
* 0 on end of file or read error
|
|
*/
|
|
|
|
static int
|
|
tf_read(void *v, int n)
|
|
{
|
|
char *s = (char *)v;
|
|
int count;
|
|
|
|
for (count = n; count > 0; --count) {
|
|
if (curpos >= sizeof(tfbfr)) {
|
|
lastpos = read(fd, tfbfr, sizeof(tfbfr));
|
|
curpos = 0;
|
|
}
|
|
if (curpos == lastpos) {
|
|
tf_close();
|
|
return 0;
|
|
}
|
|
*s++ = tfbfr[curpos++];
|
|
}
|
|
return n;
|
|
}
|
|
|
|
/*
|
|
* tf_save_cred() appends an incoming ticket to the end of the ticket
|
|
* file. You must call tf_init() before calling tf_save_cred().
|
|
*
|
|
* The "service", "instance", and "realm" arguments specify the
|
|
* server's name; "session" contains the session key to be used with
|
|
* the ticket; "kvno" is the server key version number in which the
|
|
* ticket is encrypted, "ticket" contains the actual ticket, and
|
|
* "issue_date" is the time the ticket was requested (local host's time).
|
|
*
|
|
* Returns KSUCCESS if all goes well, TKT_FIL_INI if tf_init() wasn't
|
|
* called previously, and KFAILURE for anything else that went wrong.
|
|
*/
|
|
|
|
int
|
|
tf_save_cred(char *service, /* Service name */
|
|
char *instance, /* Instance */
|
|
char *realm, /* Auth domain */
|
|
unsigned char *session, /* Session key */
|
|
int lifetime, /* Lifetime */
|
|
int kvno, /* Key version number */
|
|
KTEXT ticket, /* The ticket itself */
|
|
u_int32_t issue_date) /* The issue time */
|
|
{
|
|
int count; /* count for write */
|
|
|
|
if (fd < 0) { /* fd is ticket file as set by tf_init */
|
|
if (krb_debug)
|
|
krb_warning ("tf_save_cred called before tf_init.\n");
|
|
return TKT_FIL_INI;
|
|
}
|
|
/* Find the end of the ticket file */
|
|
lseek(fd, 0L, SEEK_END);
|
|
|
|
/* Write the ticket and associated data */
|
|
/* Service */
|
|
count = strlen(service) + 1;
|
|
if (write(fd, service, count) != count)
|
|
goto bad;
|
|
/* Instance */
|
|
count = strlen(instance) + 1;
|
|
if (write(fd, instance, count) != count)
|
|
goto bad;
|
|
/* Realm */
|
|
count = strlen(realm) + 1;
|
|
if (write(fd, realm, count) != count)
|
|
goto bad;
|
|
/* Session key */
|
|
if (write(fd, session, 8) != 8)
|
|
goto bad;
|
|
/* Lifetime */
|
|
if (write(fd, &lifetime, sizeof(int)) != sizeof(int))
|
|
goto bad;
|
|
/* Key vno */
|
|
if (write(fd, &kvno, sizeof(int)) != sizeof(int))
|
|
goto bad;
|
|
/* Tkt length */
|
|
if (write(fd, &(ticket->length), sizeof(int)) !=
|
|
sizeof(int))
|
|
goto bad;
|
|
/* Ticket */
|
|
count = ticket->length;
|
|
if (write(fd, ticket->dat, count) != count)
|
|
goto bad;
|
|
/* Issue date */
|
|
if (write(fd, &issue_date, sizeof(issue_date)) != sizeof(issue_date))
|
|
goto bad;
|
|
|
|
return (KSUCCESS);
|
|
bad:
|
|
return (KFAILURE);
|
|
}
|
|
|
|
int
|
|
tf_setup(CREDENTIALS *cred, const char *pname, const char *pinst)
|
|
{
|
|
int ret;
|
|
ret = tf_create(tkt_string());
|
|
if (ret != KSUCCESS)
|
|
return ret;
|
|
|
|
if (tf_put_pname(pname) != KSUCCESS ||
|
|
tf_put_pinst(pinst) != KSUCCESS) {
|
|
tf_close();
|
|
return INTK_ERR;
|
|
}
|
|
|
|
if(krb_get_kdc_time_diff() != 0) {
|
|
/* Add an extra magic ticket containing the time differential
|
|
to the kdc. The first ticket defines which realm we belong
|
|
to, but since this ticket gets the same realm as the tgt,
|
|
this shouldn't be a problem */
|
|
des_cblock s = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
KTEXT_ST t;
|
|
int d = krb_get_kdc_time_diff();
|
|
krb_put_int(d, t.dat, sizeof(t.dat), 4);
|
|
t.length = 4;
|
|
tf_save_cred(MAGIC_TICKET_NAME, MAGIC_TICKET_TIME_DIFF_INST,
|
|
cred->realm, s,
|
|
cred->lifetime, 0, &t, cred->issue_date);
|
|
}
|
|
ret = tf_save_cred(cred->service, cred->instance, cred->realm,
|
|
cred->session, cred->lifetime, cred->kvno,
|
|
&cred->ticket_st, cred->issue_date);
|
|
tf_close();
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
in_tkt(char *pname, char *pinst)
|
|
{
|
|
int ret;
|
|
|
|
ret = tf_create (tkt_string());
|
|
if (ret != KSUCCESS)
|
|
return ret;
|
|
|
|
if (tf_put_pname(pname) != KSUCCESS ||
|
|
tf_put_pinst(pinst) != KSUCCESS) {
|
|
tf_close();
|
|
return INTK_ERR;
|
|
}
|
|
|
|
tf_close();
|
|
return KSUCCESS;
|
|
}
|
|
|
|
/*
|
|
* If there's a magic ticket with an address for realm `realm' in
|
|
* ticket file, return it in `addr'.
|
|
* realm == NULL means any realm.
|
|
*/
|
|
|
|
int
|
|
tf_get_addr (const char *realm, struct in_addr *addr)
|
|
{
|
|
CREDENTIALS cred;
|
|
krb_principal princ;
|
|
int ret;
|
|
|
|
ret = tf_init (tkt_string (), R_TKT_FIL);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = tf_get_pname (princ.name);
|
|
if (ret)
|
|
goto out;
|
|
ret = tf_get_pinst (princ.name);
|
|
if (ret)
|
|
goto out;
|
|
while ((ret = real_tf_get_cred (&cred)) == KSUCCESS) {
|
|
if (strcmp (cred.service, MAGIC_TICKET_NAME) == 0
|
|
&& strcmp (cred.instance, MAGIC_TICKET_ADDR_INST) == 0
|
|
&& (realm == NULL
|
|
|| strcmp (cred.realm, realm) == 0)) {
|
|
memcpy (addr, cred.ticket_st.dat, sizeof(*addr));
|
|
goto out;
|
|
}
|
|
}
|
|
ret = KFAILURE;
|
|
|
|
out:
|
|
tf_close ();
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Store `realm, addr' as a magic ticket.
|
|
*/
|
|
|
|
int
|
|
tf_store_addr (const char *realm, struct in_addr *addr)
|
|
{
|
|
CREDENTIALS c;
|
|
krb_principal princ;
|
|
int ret;
|
|
des_cblock s = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
KTEXT_ST t;
|
|
|
|
ret = tf_init (tkt_string (), W_TKT_FIL);
|
|
if (ret)
|
|
return ret;
|
|
|
|
t.length = sizeof(*addr);
|
|
memcpy (t.dat, addr, sizeof(*addr));
|
|
|
|
ret = tf_save_cred (MAGIC_TICKET_NAME, MAGIC_TICKET_ADDR_INST,
|
|
(char *)realm, s, 0, /* lifetime */
|
|
0, /* kvno */
|
|
&t, time(NULL));
|
|
tf_close ();
|
|
return ret;
|
|
}
|