/* * lib/krb4/in_tkt.c * * Copyright 1985, 1986, 1987, 1988, 2000, 2001 by the Massachusetts * Institute of Technology. All Rights Reserved. * * 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 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. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * 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 #include #include "krb.h" #include #include #ifdef TKT_SHMEM #include #endif #ifdef HAVE_UNISTD_H #include #endif extern int krb_debug; /* * in_tkt() is used to initialize the ticket store. It creates the * file to contain the tickets and writes the given user's name "pname" * and instance "pinst" in the file. in_tkt() returns KSUCCESS on * success, or KFAILURE if something goes wrong. */ #ifdef HAVE_SETEUID #define do_seteuid(e) seteuid((e)) #else #ifdef HAVE_SETRESUID #define do_seteuid(e) setresuid(-1, (e), -1) #else #ifdef HAVE_SETREUID #define do_seteuid(e) setreuid(geteuid(), (e)) #else #define do_seteuid(e) (errno = EPERM, -1) #endif #endif #endif #ifndef O_SYNC #define O_SYNC 0 #endif KRB5_DLLIMP int KRB5_CALLCONV in_tkt(pname,pinst) char *pname; char *pinst; { int tktfile; uid_t me, metoo, getuid(), geteuid(); struct stat statpre, statpost; int count; char *file = TKT_FILE; int fd; register int i; char charbuf[BUFSIZ]; mode_t mask; #ifdef TKT_SHMEM char shmidname[MAXPATHLEN]; #endif /* TKT_SHMEM */ /* If ticket cache selector is null, use default cache. */ if (file == 0) file = tkt_string(); me = getuid (); metoo = geteuid(); if (lstat(file, &statpre) == 0) { if (statpre.st_uid != me || !(statpre.st_mode & S_IFREG) || statpre.st_nlink != 1 || statpre.st_mode & 077) { if (krb_debug) fprintf(stderr,"Error initializing %s",file); return(KFAILURE); } /* * Yes, we do uid twiddling here. It's not optimal, but some * applications may expect that the ruid is what should really * own the ticket file, e.g. setuid applications. */ if (me != metoo && do_seteuid(me) < 0) return KFAILURE; /* file already exists, and permissions appear ok, so nuke it */ fd = open(file, O_RDWR|O_SYNC, 0); (void)unlink(file); if (me != metoo && do_seteuid(metoo) < 0) return KFAILURE; if (fd < 0) { goto out; /* can't zero it, but we can still try truncating it */ } /* * Do some additional paranoid things. The worst-case * situation is that a user may be fooled into opening a * non-regular file briefly if the file is in a directory with * improper permissions. */ if (fstat(fd, &statpost) < 0) { (void)close(fd); goto out; } if (statpre.st_dev != statpost.st_dev || statpre.st_ino != statpost.st_ino) { (void)close(fd); errno = 0; goto out; } memset(charbuf, 0, sizeof(charbuf)); for (i = 0; i < statpost.st_size; i += sizeof(charbuf)) if (write(fd, charbuf, sizeof(charbuf)) != sizeof(charbuf)) { #ifndef NO_FSYNC (void) fsync(fd); #endif (void) close(fd); goto out; } #ifndef NO_FSYNC (void) fsync(fd); #endif (void) close(fd); } out: /* arrange so the file is owned by the ruid (swap real & effective uid if necessary). This isn't a security problem, since the ticket file, if it already exists, has the right uid (== ruid) and mode. */ if (me != metoo) { if (do_seteuid(me) < 0) { /* can't switch??? barf! */ if (krb_debug) perror("in_tkt: seteuid"); return(KFAILURE); } else if (krb_debug) printf("swapped UID's %d and %d\n",(int) metoo, (int) me); } /* Set umask to ensure that we have write access on the created ticket file. */ mask = umask(077); tktfile = open(file, O_RDWR|O_SYNC|O_CREAT|O_EXCL, 0600); umask(mask); if (me != metoo) { if (do_seteuid(metoo) < 0) { /* can't switch??? barf! */ if (krb_debug) perror("in_tkt: seteuid2"); return(KFAILURE); } else if (krb_debug) printf("swapped UID's %d and %d\n", (int) me, (int) metoo); } if (tktfile < 0) { if (krb_debug) fprintf(stderr,"Error initializing %s",TKT_FILE); return(KFAILURE); } count = strlen(pname)+1; if (write(tktfile,pname,count) != count) { (void) close(tktfile); return(KFAILURE); } count = strlen(pinst)+1; if (write(tktfile,pinst,count) != count) { (void) close(tktfile); return(KFAILURE); } (void) close(tktfile); #ifdef TKT_SHMEM (void) strncpy(shmidname, file, sizeof(shmidname) - 1); shmidname[sizeof(shmidname) - 1] = '\0'; (void) strncat(shmidname, ".shm", sizeof(shmidname) - 1 - strlen(shmidname)); return(krb_shm_create(shmidname)); #else /* !TKT_SHMEM */ return(KSUCCESS); #endif /* TKT_SHMEM */ } KRB5_DLLIMP int KRB5_CALLCONV krb_in_tkt(pname, pinst, prealm) char *pname; char *pinst; char *prealm; { return in_tkt(pname, pinst); }