[226] in Kerberos-V5-bugs
Re: Can't start V5 server (krb5kdc)
daemon@ATHENA.MIT.EDU (sommerfeld@apollo.hp.com)
Thu May 7 13:27:23 1992
Date: Thu, 7 May 92 13:26:36 -0400
From: sommerfeld@apollo.hp.com
To: lunt@ctt.bellcore.com
Cc: krb5-bugs@MIT.EDU, kerberos@Athena.MIT.EDU
In-Reply-To: Steve Lunt's message of Thu, 7 May 92 12:29:57 EDT
Funny you should ask.. I just tripped over and fixed this one myself
yesterday..
The problem is that the replay cache code is, well, not the most
robust. The "recover" routine tosses its cookies, and fails; the
"initialize" routine then fails because the cache still exists.
To top it all off. In addition, the code in kdc/main.c which calls
these two routines tosses the first status code and only gives you the
second one.
- Bill
Context diffs. As always, your line numbers may vary.
These changes are bigger than necessary because I'm attempting to
correct some stylistic problems in the code as well..
RCS file: ./security/krb5/kdc/main.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.2
diff -cw -r1.1.1.1 -r1.1.1.2
*** 1.1.1.1 1992/05/05 01:33:12
--- 1.1.1.2 1992/05/05 02:42:05
***************
*** 232,238 ****
char *mkey_name = 0;
char *rcname = 0;
char *lrealm;
! krb5_error_code retval;
krb5_enctype etype;
extern krb5_deltat krb5_clockskew;
--- 232,238 ----
char *mkey_name = 0;
char *rcname = 0;
char *lrealm;
! krb5_error_code retval, retval2;
krb5_enctype etype;
extern krb5_deltat krb5_clockskew;
***************
*** 288,295 ****
exit(1);
}
if ((retval = krb5_rc_recover(kdc_rcache)) &&
! (retval = krb5_rc_initialize(kdc_rcache, krb5_clockskew))) {
! com_err(argv[0], retval, "while initializing replay cache '%s:%s'",
kdc_rcache->ops->type,
krb5_rc_get_name(kdc_rcache));
exit(1);
--- 288,298 ----
exit(1);
}
if ((retval = krb5_rc_recover(kdc_rcache)) &&
! (retval2 = krb5_rc_initialize(kdc_rcache, krb5_clockskew))) {
! com_err(argv[0], retval, "while recovering replay cache '%s:%s'",
! kdc_rcache->ops->type,
! krb5_rc_get_name(kdc_rcache));
! com_err(argv[0], retval2, "while initializing replay cache '%s:%s'",
kdc_rcache->ops->type,
krb5_rc_get_name(kdc_rcache));
exit(1);
RCS file: ./security/krb5/lib/rcache/rc_dfl.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.2
diff -cw -r1.1.1.1 -r1.1.1.2
*** 1.1.1.1 1992/05/04 19:57:10
--- 1.1.1.2 1992/05/05 02:44:03
***************
*** 216,222 ****
#ifndef NOIOSTUFF
if (retval = krb5_rc_io_creat(&t->d,&t->name))
return retval;
! if (krb5_rc_io_write(&t->d,(krb5_pointer) &t->lifespan,sizeof(t->lifespan)))
return KRB5_RC_IO;
#endif
return 0;
--- 216,223 ----
#ifndef NOIOSTUFF
if (retval = krb5_rc_io_creat(&t->d,&t->name))
return retval;
! if (krb5_rc_io_write(&t->d,(krb5_pointer) &t->lifespan,sizeof(t->lifespan))
! || krb5_rc_io_sync(&t->d))
return KRB5_RC_IO;
#endif
return 0;
***************
*** 279,284 ****
--- 280,352 ----
return 0;
}
+ void krb5_rc_free_entry (rep)
+ krb5_donot_replay **rep;
+ {
+ krb5_donot_replay *rp = *rep;
+
+ *rep = NULL;
+ if (rp)
+ {
+ if (rp->client)
+ free(rp->client);
+
+ if (rp->server)
+ free(rp->server);
+ rp->client = NULL;
+ rp->server = NULL;
+ free(rp);
+ }
+ }
+
+ krb5_error_code krb5_rc_io_fetch(t, rep, maxlen)
+ struct dfl_data *t;
+ krb5_donot_replay *rep;
+ int maxlen;
+ {
+ int len;
+ krb5_error_code retval;
+
+ retval = krb5_rc_io_read (&t->d, (krb5_pointer) &len, sizeof(len));
+ if (retval)
+ return retval;
+
+ if ((len <= 0) || (len >= maxlen))
+ return KRB5_RC_IO_EOF;
+
+ rep->client = malloc (len);
+ if (!rep->client)
+ return KRB5_RC_MALLOC;
+
+ retval = krb5_rc_io_read (&t->d, (krb5_pointer) rep->client, len);
+ if (retval)
+ return retval;
+
+ retval = krb5_rc_io_read (&t->d, (krb5_pointer) &len, sizeof(len));
+ if (retval)
+ return retval;
+
+ if ((len <= 0) || (len >= maxlen))
+ return KRB5_RC_IO_EOF;
+
+ rep->server = malloc (len);
+ if (!rep->server)
+ return KRB5_RC_MALLOC;
+
+ retval = krb5_rc_io_read (&t->d, (krb5_pointer) rep->server, len);
+ if (retval)
+ return retval;
+
+ retval = krb5_rc_io_read (&t->d, (krb5_pointer) &rep->cusec, sizeof(rep->cusec));
+ if (retval)
+ return retval;
+
+ retval = krb5_rc_io_read (&t->d, (krb5_pointer) &rep->ctime, sizeof(rep->ctime));
+ return retval;
+ }
+
+
+
krb5_error_code krb5_rc_dfl_recover(id)
krb5_rcache id;
{
***************
*** 290,375 ****
int i;
krb5_donot_replay *rep;
krb5_error_code retval;
if (retval = krb5_rc_io_open(&t->d,t->name))
return retval;
if (krb5_rc_io_read(&t->d,(krb5_pointer) &t->lifespan,sizeof(t->lifespan))) {
! krb5_rc_io_close(&t->d);
! return KRB5_RC_IO;
}
/* now read in each auth_replay and insert into table */
for (;;)
{
! #define FREE1 FREE(rep);
! #define FREE2 {FREE(rep->client); FREE(rep);}
! #define FREE3 {FREE(rep->server); FREE(rep->client); FREE(rep);}
! #define CLOSE krb5_rc_io_close(&t->d);
!
if (krb5_rc_io_mark(&t->d)) {
! krb5_rc_io_close(&t->d);
! return KRB5_RC_IO;
}
if (!(rep = (krb5_donot_replay *) malloc(sizeof(krb5_donot_replay)))) {
! CLOSE;
! return KRB5_RC_MALLOC;
! }
! switch(krb5_rc_io_read(&t->d,(krb5_pointer) &i,sizeof(i)))
! {
! case KRB5_RC_IO_EOF: FREE1; goto end_loop;
! case 0: break; default: FREE1; CLOSE; return KRB5_RC_IO; break;
! }
! if (!(rep->client = malloc(i)))
! { FREE1; CLOSE; return KRB5_RC_MALLOC; }
! switch(krb5_rc_io_read(&t->d,(krb5_pointer) rep->client,i))
! {
! case KRB5_RC_IO_EOF: FREE2; goto end_loop;
! case 0: break; default: FREE2; CLOSE; return KRB5_RC_IO; break;
! }
! switch(krb5_rc_io_read(&t->d,(krb5_pointer) &i,sizeof(i)))
! {
! case KRB5_RC_IO_EOF: FREE2; goto end_loop;
! case 0: break; default: FREE2; CLOSE; return KRB5_RC_IO; break;
! }
! if (!(rep->server = malloc(i)))
! { FREE2; CLOSE; return KRB5_RC_MALLOC; }
! switch(krb5_rc_io_read(&t->d,(krb5_pointer) rep->server,i))
! {
! case KRB5_RC_IO_EOF: FREE3; goto end_loop;
! case 0: break; default: FREE3; CLOSE; return KRB5_RC_IO; break;
! }
! switch(krb5_rc_io_read(&t->d,(krb5_pointer) &rep->cusec,sizeof(rep->cusec)))
! {
! case KRB5_RC_IO_EOF: FREE3; goto end_loop;
! case 0: break; default: FREE3; CLOSE; return KRB5_RC_IO; break;
}
! switch(krb5_rc_io_read(&t->d,(krb5_pointer) &rep->ctime,sizeof(rep->ctime)))
{
! case KRB5_RC_IO_EOF: FREE3; goto end_loop;
! case 0: break; default: FREE3; CLOSE; return KRB5_RC_IO; break;
}
! if (alive(rep,t->lifespan) != CMP_EXPIRED) {
if (store(id,rep) == CMP_MALLOC) {/* can't be a replay */
! CLOSE;
! return KRB5_RC_MALLOC;
}
/* store() copies the server & client fields to make sure they don't get
! stomped on by other callers, so we need to free them */
FREE(rep->server);
FREE(rep->client);
! } else FREE3; /* don't need it anymore, punt! */
}
! end_loop: krb5_rc_io_unmark(&t->d);
/* An automatic expunge here could remove the need for mark/unmark but
! would be inefficient. */
! return 0;
#endif
}
krb5_error_code krb5_rc_dfl_store(id, rep)
krb5_rcache id;
krb5_donot_replay *rep;
{
struct dfl_data *t = (struct dfl_data *)id->data;
int i;
--- 358,462 ----
int i;
krb5_donot_replay *rep;
krb5_error_code retval;
+ int max_size;
if (retval = krb5_rc_io_open(&t->d,t->name))
return retval;
+
+ max_size = krb5_rc_io_size(t);
+
+ rep = NULL;
if (krb5_rc_io_read(&t->d,(krb5_pointer) &t->lifespan,sizeof(t->lifespan))) {
! retval = KRB5_RC_IO;
! goto io_fail;
}
/* now read in each auth_replay and insert into table */
for (;;)
{
! rep = NULL;
if (krb5_rc_io_mark(&t->d)) {
! retval = KRB5_RC_IO;
! goto io_fail;
}
+
if (!(rep = (krb5_donot_replay *) malloc(sizeof(krb5_donot_replay)))) {
! retval = KRB5_RC_MALLOC;
! goto io_fail;
}
! rep->client = NULL;
! rep->server = NULL;
!
! retval = krb5_rc_io_fetch (t, rep, max_size);
!
! if (retval == KRB5_RC_IO_EOF)
! break;
! else if (retval != 0)
! goto io_fail;
!
!
! if (alive(rep,t->lifespan) == CMP_EXPIRED)
{
! krb5_rc_free_entry(&rep);
! continue;
}
!
if (store(id,rep) == CMP_MALLOC) { /* can't be a replay */
! retval = KRB5_RC_MALLOC; goto io_fail;
}
/* store() copies the server & client fields to make sure they don't get
! * stomped on by other callers, so we need to free them */
FREE(rep->server);
FREE(rep->client);
! rep = NULL;
}
! end_loop:
! retval = 0;
! krb5_rc_io_unmark(&t->d);
/* An automatic expunge here could remove the need for mark/unmark but
! * would be inefficient. */
! io_fail:
! krb5_rc_free_entry(&rep);
! if (retval)
! krb5_rc_io_close(&t->d);
! return retval;
!
#endif
}
+ krb5_error_code krb5_rc_io_store (t, rep)
+ struct dfl_data *t;
+ krb5_donot_replay *rep;
+ {
+ int clientlen, serverlen, len;
+ char *buf, *ptr;
+ unsigned long ret;
+
+ clientlen = strlen (rep->client) + 1;
+ serverlen = strlen (rep->server) + 1;
+ len = sizeof(clientlen) + clientlen + sizeof(serverlen) + serverlen +
+ sizeof(rep->cusec) + sizeof(rep->ctime);
+ buf = malloc (len);
+ if (buf == 0)
+ return KRB5_RC_MALLOC;
+ ptr = buf;
+ memcpy(ptr, &clientlen, sizeof(clientlen)); ptr += sizeof(clientlen);
+ memcpy(ptr, rep->client, clientlen); ptr += clientlen;
+ memcpy(ptr, &serverlen, sizeof(serverlen)); ptr += sizeof(serverlen);
+ memcpy(ptr, rep->server, serverlen); ptr += serverlen;
+ memcpy(ptr, &rep->cusec, sizeof(rep->cusec)); ptr += sizeof(rep->cusec);
+ memcpy(ptr, &rep->ctime, sizeof(rep->ctime)); ptr += sizeof(rep->ctime);
+
+ ret = krb5_rc_io_write(&t->d, buf, len);
+ free(buf);
+ return ret;
+ }
+
krb5_error_code krb5_rc_dfl_store(id, rep)
krb5_rcache id;
krb5_donot_replay *rep;
{
+ unsigned long ret;
struct dfl_data *t = (struct dfl_data *)id->data;
int i;
***************
*** 383,406 ****
default: /* wtf? */ ;
}
#ifndef NOIOSTUFF
! i = strlen(rep->client) + 1;
! if (krb5_rc_io_write(&t->d,(krb5_pointer) &i,sizeof(i)))
! return KRB5_RC_IO;
! if (krb5_rc_io_write(&t->d,(krb5_pointer) rep->client,i))
! return KRB5_RC_IO;
! i = strlen(rep->server) + 1;
! if (krb5_rc_io_write(&t->d,(krb5_pointer) &i,sizeof(i)))
! return KRB5_RC_IO;
! if (krb5_rc_io_write(&t->d,(krb5_pointer) rep->server,i))
! return KRB5_RC_IO;
! if (krb5_rc_io_write(&t->d,(krb5_pointer) &rep->cusec,sizeof(rep->cusec)))
! return KRB5_RC_IO;
! if (krb5_rc_io_write(&t->d,(krb5_pointer) &rep->ctime,sizeof(rep->ctime)))
! return KRB5_RC_IO;
#endif
/* Shall we automatically expunge? */
if (t->nummisses > t->numhits + EXCESSREPS)
return krb5_rc_dfl_expunge(id);
return 0;
}
--- 470,491 ----
default: /* wtf? */ ;
}
#ifndef NOIOSTUFF
! ret = krb5_rc_io_store (t, rep);
! if (ret)
! return ret;
#endif
/* Shall we automatically expunge? */
if (t->nummisses > t->numhits + EXCESSREPS)
+ {
return krb5_rc_dfl_expunge(id);
+ }
+ #ifndef NOIOSTUFF
+ else
+ {
+ if (krb5_rc_io_sync(&t->d))
+ return KRB5_RC_IO;
+ }
+ #endif
return 0;
}
***************
*** 460,480 ****
return KRB5_RC_IO;
for (q = t->a;q;q = q->na)
{
! i = strlen(q->rep.client) + 1;
! if (krb5_rc_io_write(&tmp,(krb5_pointer) &i,sizeof(i)))
! return KRB5_RC_IO;
! if (krb5_rc_io_write(&tmp,(krb5_pointer) q->rep.client,i))
return KRB5_RC_IO;
- i = strlen(q->rep.server) + 1;
- if (krb5_rc_io_write(&tmp,(krb5_pointer) &i,sizeof(i)))
- return KRB5_RC_IO;
- if (krb5_rc_io_write(&tmp,(krb5_pointer) q->rep.server,i))
- return KRB5_RC_IO;
- if (krb5_rc_io_write(&tmp,(krb5_pointer) &q->rep.cusec,sizeof(q->rep.cusec)))
- return KRB5_RC_IO;
- if (krb5_rc_io_write(&tmp,(krb5_pointer) &q->rep.ctime,sizeof(q->rep.ctime)))
- return KRB5_RC_IO;
}
if (krb5_rc_io_move(&t->d,&tmp))
return KRB5_RC_IO;
#endif
--- 545,555 ----
return KRB5_RC_IO;
for (q = t->a;q;q = q->na)
{
! if (krb5_rc_io_store (&tmp, &q->rep))
return KRB5_RC_IO;
}
+ if (krb5_rc_io_sync(&t->d))
+ return KRB5_RC_IO;
if (krb5_rc_io_move(&t->d,&tmp))
return KRB5_RC_IO;
#endif
RCS file: ./security/krb5/lib/rcache/rc_io.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.2
diff -cw -r1.1.1.1 -r1.1.1.2
***************
*** 49,54 ****
--- 49,55 ----
#include "rc_dfl.h"
#include "rc_io.h"
#include <krb5/osconf.h>
+ #include <sys/stat.h>
#ifdef KRB5_USE_INET
#include <netinet/in.h>
***************
*** 106,112 ****
else
{
/* %d is max 11 digits (-, 10 digits of 32-bit number)
! 11 + /krb5_RC + aaa = 24, +6 for slop */
if (!(d->fn = malloc(30 + dirlen)))
return KRB5_RC_IO_MALLOC;
if (fn)
--- 107,113 ----
else
{
/* %d is max 11 digits (-, 10 digits of 32-bit number)
! * 11 + /krb5_RC + aaa = 24, +6 for slop */
if (!(d->fn = malloc(30 + dirlen)))
return KRB5_RC_IO_MALLOC;
if (fn)
***************
*** 132,155 ****
(void) strcpy(*fn,d->fn + dirlen);
}
if (d->fd == -1)
switch(errno)
{
! case EBADF: FREE(d->fn); return KRB5_RC_IO_UNKNOWN; break;
! case EFBIG: FREE(d->fn); return KRB5_RC_IO_SPACE; break;
#ifdef EDQUOT
! case EDQUOT: FREE(d->fn); return KRB5_RC_IO_SPACE; break;
#endif
! case ENOSPC: FREE(d->fn); return KRB5_RC_IO_SPACE; break;
! case EIO: FREE(d->fn); return KRB5_RC_IO_IO; break;
! case EPERM: FREE(d->fn); return KRB5_RC_IO_PERM; break;
! case EACCES: FREE(d->fn); return KRB5_RC_IO_PERM; break;
! case EROFS: FREE(d->fn); return KRB5_RC_IO_PERM; break;
! case EEXIST: FREE(d->fn); return KRB5_RC_IO_PERM; break;
! default: FREE(d->fn); return KRB5_RC_IO_UNKNOWN; break;
}
! if (retval = krb5_rc_io_write(d, (krb5_pointer)&rc_vno, sizeof(rc_vno))) {
(void) unlink(d->fn);
FREE(d->fn);
(void) close(d->fd);
return retval;
}
--- 133,168 ----
(void) strcpy(*fn,d->fn + dirlen);
}
if (d->fd == -1)
+ {
switch(errno)
{
! case EFBIG:
#ifdef EDQUOT
! case EDQUOT:
#endif
! case ENOSPC:
! retval = KRB5_RC_IO_SPACE;
! goto fail;
! case EIO:
! retval = KRB5_RC_IO_IO; goto fail;
!
! case EPERM:
! case EACCES:
! case EROFS:
! case EEXIST:
! retval = KRB5_RC_IO_PERM; goto fail;
!
! default:
! retval = KRB5_RC_IO_UNKNOWN; goto fail;
}
! }
! if ((retval = krb5_rc_io_write(d, (krb5_pointer)&rc_vno, sizeof(rc_vno))) ||
! (retval = krb5_rc_io_sync(d)))
! {
! fail:
(void) unlink(d->fn);
FREE(d->fn);
+ d->fn = NULL;
(void) close(d->fd);
return retval;
}
***************
*** 175,181 ****
me = getuid();
/* must be owned by this user, to prevent some security problems with
! other users modifying replay cache stufff */
if ((statb.st_uid != me) || ((statb.st_mode & S_IFMT) != S_IFREG)) {
FREE(d->fn);
return KRB5_RC_IO_PERM;
--- 188,194 ----
me = getuid();
/* must be owned by this user, to prevent some security problems with
! * other users modifying replay cache stufff */
if ((statb.st_uid != me) || ((statb.st_mode & S_IFMT) != S_IFREG)) {
FREE(d->fn);
return KRB5_RC_IO_PERM;
***************
*** 185,214 ****
if (d->fd == -1) {
switch(errno)
{
! case EBADF: FREE(d->fn); return KRB5_RC_IO_UNKNOWN; break;
! case EFBIG: FREE(d->fn); return KRB5_RC_IO_SPACE; break;
#ifdef EDQUOT
! case EDQUOT: FREE(d->fn); return KRB5_RC_IO_SPACE; break;
#endif
! case ENOSPC: FREE(d->fn); return KRB5_RC_IO_SPACE; break;
! case EIO: FREE(d->fn); return KRB5_RC_IO_IO; break;
! case EPERM: FREE(d->fn); return KRB5_RC_IO_PERM; break;
! case EACCES: FREE(d->fn); return KRB5_RC_IO_PERM; break;
! case EROFS: FREE(d->fn); return KRB5_RC_IO_PERM; break;
! default: FREE(d->fn); return KRB5_RC_IO_UNKNOWN; break;
}
}
! if (retval = krb5_rc_io_read(d, (krb5_pointer) &rc_vno, sizeof(rc_vno))) {
(void) close(d->fd);
FREE(d->fn);
return retval;
}
- if (ntohs(rc_vno) != KRB5_RC_VNO) {
- (void) close(d->fd);
- FREE(d->fn);
- return KRB5_RCACHE_BADVNO;
- }
-
return 0;
}
--- 198,241 ----
if (d->fd == -1) {
switch(errno)
{
! case EFBIG:
#ifdef EDQUOT
! case EDQUOT:
#endif
! case ENOSPC:
! retval = KRB5_RC_IO_SPACE;
! goto fail;
!
! case EIO:
! retval = KRB5_RC_IO_IO;
! goto fail;
!
! case EPERM:
! case EACCES:
! case EROFS:
! retval = KRB5_RC_IO_PERM;
! goto fail;
!
! default:
! retval = KRB5_RC_IO_UNKNOWN;
! goto fail;
}
}
! if (retval = krb5_rc_io_read(d, (krb5_pointer) &rc_vno, sizeof(rc_vno)))
! goto unlk;
!
!
! if (ntohs(rc_vno) != KRB5_RC_VNO)
! {
! retval = KRB5_RCACHE_BADVNO;
! unlk:
! unlink(d->fn);
! fail:
(void) close(d->fd);
FREE(d->fn);
+ d->fn = NULL;
return retval;
}
return 0;
}
***************
*** 241,247 ****
--- 268,282 ----
case EIO: return KRB5_RC_IO_IO; break;
default: return KRB5_RC_IO_UNKNOWN; break;
}
+ return 0;
+ }
+
+ krb5_error_code krb5_rc_io_sync (d)
+ krb5_rc_iostuff *d;
+ {
+
if (fsync(d->fd) == -1)
+ {
switch(errno)
{
case EBADF: return KRB5_RC_IO_UNKNOWN; break;
***************
*** 248,253 ****
--- 283,289 ----
case EIO: return KRB5_RC_IO_IO; break;
default: return KRB5_RC_IO_UNKNOWN; break;
}
+ }
return 0;
}
***************
*** 273,278 ****
--- 309,315 ----
krb5_rc_iostuff *d;
{
FREE(d->fn);
+ d->fn = NULL;
if (close(d->fd) == -1) /* can't happen */
return KRB5_RC_IO_UNKNOWN;
return 0;
***************
*** 307,309 ****
--- 344,358 ----
(void) lseek(d->fd,d->mark,L_SET); /* if it fails, tough luck */
return 0;
}
+
+ int krb5_rc_io_size (d)
+ krb5_rc_iostuff *d;
+ {
+ struct stat statb;
+
+ if (fstat (d->fd, &statb) == 0)
+ return statb.st_size;
+ else
+ return 0;
+ }
+