krb5_error_code krb5_rc_io_creat(krb5_context context, krb5_rc_iostuff *d, char **fn) { krb5_int16 rc_vno = htons(KRB5_RC_VNO); krb5_error_code retval = 0; int flags, do_not_unlink = 0; char *dir; size_t dirlen; GETDIR; if (fn && *fn) { if (asprintf(&d->fn, "%s%s%s", dir, PATH_SEPARATOR, *fn) < 0) return KRB5_RC_IO_MALLOC; d->fd = -1; do { if (unlink(d->fn) == -1 && errno != ENOENT) break; flags = O_WRONLY | O_CREAT | O_TRUNC | O_EXCL | O_BINARY; d->fd = THREEPARAMOPEN(d->fn, flags, 0600); } while (d->fd == -1 && errno == EEXIST); } else { retval = krb5_rc_io_mkstemp(context, d, dir); if (retval) goto cleanup; if (d->fd != -1 && fn) { *fn = strdup(d->fn + dirlen); if (*fn == NULL) { free(d->fn); return KRB5_RC_IO_MALLOC; } } } if (d->fd == -1) { retval = rc_map_errno(context, errno, d->fn, "create"); if (retval == KRB5_RC_IO_PERM) do_not_unlink = 1; goto cleanup; } set_cloexec_fd(d->fd); retval = krb5_rc_io_write(context, d, (krb5_pointer)&rc_vno, sizeof(rc_vno)); if (retval) goto cleanup; retval = krb5_rc_io_sync(context, d); cleanup: if (retval) { if (d->fn) { if (!do_not_unlink) (void) unlink(d->fn); free(d->fn); d->fn = NULL; } if (d->fd != -1) { (void) close(d->fd); } } return retval; }
static krb5_error_code krb5_rc_io_open_internal(krb5_context context, krb5_rc_iostuff *d, char *fn, char* full_pathname) { krb5_int16 rc_vno; krb5_error_code retval = 0; int do_not_unlink = 1; #ifndef NO_USERID struct stat sb1, sb2; #endif char *dir; dir = getdir(); if (full_pathname) { if (!(d->fn = strdup(full_pathname))) return KRB5_RC_IO_MALLOC; } else { if (asprintf(&d->fn, "%s%s%s", dir, PATH_SEPARATOR, fn) < 0) return KRB5_RC_IO_MALLOC; } #ifdef NO_USERID d->fd = THREEPARAMOPEN(d->fn, O_RDWR | O_BINARY, 0600); if (d->fd == -1) { retval = rc_map_errno(context, errno, d->fn, "open"); goto cleanup; } #else d->fd = -1; retval = lstat(d->fn, &sb1); if (retval != 0) { retval = rc_map_errno(context, errno, d->fn, "lstat"); goto cleanup; } d->fd = THREEPARAMOPEN(d->fn, O_RDWR | O_BINARY, 0600); if (d->fd < 0) { retval = rc_map_errno(context, errno, d->fn, "open"); goto cleanup; } retval = fstat(d->fd, &sb2); if (retval < 0) { retval = rc_map_errno(context, errno, d->fn, "fstat"); goto cleanup; } /* check if someone was playing with symlinks */ if ((sb1.st_dev != sb2.st_dev || sb1.st_ino != sb2.st_ino) || (sb1.st_mode & S_IFMT) != S_IFREG) { retval = KRB5_RC_IO_PERM; k5_setmsg(context, retval, "rcache not a file %s", d->fn); goto cleanup; } /* check that non other can read/write/execute the file */ if (sb1.st_mode & 077) { k5_setmsg(context, retval, _("Insecure file mode for replay cache file %s"), d->fn); return KRB5_RC_IO_UNKNOWN; } /* owned by me */ if (sb1.st_uid != geteuid()) { retval = KRB5_RC_IO_PERM; k5_setmsg(context, retval, _("rcache not owned by %d"), (int)geteuid()); goto cleanup; } #endif set_cloexec_fd(d->fd); do_not_unlink = 0; retval = krb5_rc_io_read(context, d, (krb5_pointer) &rc_vno, sizeof(rc_vno)); if (retval) goto cleanup; if (ntohs(rc_vno) != KRB5_RC_VNO) retval = KRB5_RCACHE_BADVNO; cleanup: if (retval) { if (!do_not_unlink) (void) unlink(d->fn); free(d->fn); d->fn = NULL; if (d->fd >= 0) (void) close(d->fd); } return retval; }