krb5_error_code osa_adb_release_lock(osa_adb_db_t db) { int ret, fd; if (!db->lock->lockcnt) /* lock already unlocked */ return OSA_ADB_NOTLOCKED; if (--db->lock->lockcnt == 0) { if (db->lock->lockmode == KRB5_DB_LOCKMODE_PERMANENT) { /* now we need to create the file since it does not exist */ fd = THREEPARAMOPEN(db->lock->filename,O_RDWR | O_CREAT | O_EXCL, 0600); if (fd < 0) return OSA_ADB_NOLOCKFILE; set_cloexec_fd(fd); if ((db->lock->lockfile = fdopen(fd, "w+")) == NULL) return OSA_ADB_NOLOCKFILE; } else if ((ret = krb5_lock_file(db->lock->context, fileno(db->lock->lockfile), KRB5_LOCKMODE_UNLOCK))) return ret; db->lock->lockmode = 0; } return OSA_ADB_OK; }
krb5_error_code osa_adb_create_db(char *filename, char *lockfilename, int magic) { int lf; DB *db; BTREEINFO btinfo; memset(&btinfo, 0, sizeof(btinfo)); btinfo.flags = 0; btinfo.cachesize = 0; btinfo.psize = 4096; btinfo.lorder = 0; btinfo.minkeypage = 0; btinfo.compare = NULL; btinfo.prefix = NULL; db = dbopen(filename, O_RDWR | O_CREAT | O_EXCL, 0600, DB_BTREE, &btinfo); if (db == NULL) return errno; if (db->close(db) < 0) return errno; /* only create the lock file if we successfully created the db */ lf = THREEPARAMOPEN(lockfilename, O_RDWR | O_CREAT | O_EXCL, 0600); if (lf == -1) return errno; (void) close(lf); return OSA_ADB_OK; }
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 void update_last_prop_file(char *hostname, char *file_name) { char *file_last_prop; int fd; static char last_prop[] = ".last_prop"; if (asprintf(&file_last_prop, "%s.%s%s", file_name, hostname, last_prop) < 0) { com_err(progname, ENOMEM, _("while allocating filename for update_last_prop_file")); return; } fd = THREEPARAMOPEN(file_last_prop, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (fd < 0) { com_err(progname, errno, _("while creating 'last_prop' file, '%s'"), file_last_prop); free(file_last_prop); return; } write(fd, "", 1); free(file_last_prop); close(fd); }
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; }
/* Destroy the cache file and release the handle. */ static krb5_error_code KRB5_CALLCONV fcc_destroy(krb5_context context, krb5_ccache id) { krb5_error_code ret = 0; fcc_data *data = id->data; int st, fd; struct stat buf; unsigned long i, size; unsigned int wlen; char zeros[BUFSIZ]; k5_cc_mutex_lock(context, &data->lock); if (OPENCLOSE(id)) { invalidate_cache(data); fd = THREEPARAMOPEN(data->filename, O_RDWR | O_BINARY, 0); if (fd < 0) { ret = interpret_errno(context, errno); goto cleanup; } set_cloexec_fd(fd); data->fd = fd; } else { fcc_lseek(data, 0, SEEK_SET); } #ifdef MSDOS_FILESYSTEM /* * "Disgusting bit of UNIX trivia" - that's how the writers of NFS describe * the ability of UNIX to still write to a file which has been unlinked. * Naturally, the PC can't do this. As a result, we have to delete the * file after we wipe it clean, but that throws off all the error handling * code. So we have do the work ourselves. */ st = fstat(data->fd, &buf); if (st == -1) { ret = interpret_errno(context, errno); size = 0; /* Nothing to wipe clean */ } else { size = (unsigned long)buf.st_size; } memset(zeros, 0, BUFSIZ); while (size > 0) { wlen = (int)((size > BUFSIZ) ? BUFSIZ : size); /* How much to write */ i = write(data->fd, zeros, wlen); if (i < 0) { ret = interpret_errno(context, errno); /* Don't jump to cleanup--we still want to delete the file. */ break; } size -= i; } if (OPENCLOSE(id)) { (void)close(((fcc_data *)id->data)->fd); data->fd = -1; } st = unlink(data->filename); if (st < 0) { ret = interpret_errno(context, errno); goto cleanup; } #else /* MSDOS_FILESYSTEM */ st = unlink(data->filename); if (st < 0) { ret = interpret_errno(context, errno); if (OPENCLOSE(id)) { (void)close(data->fd); data->fd = -1; } goto cleanup; } st = fstat(data->fd, &buf); if (st < 0) { ret = interpret_errno(context, errno); if (OPENCLOSE(id)) { (void)close(data->fd); data->fd = -1; } goto cleanup; } /* XXX This may not be legal XXX */ size = (unsigned long)buf.st_size; memset(zeros, 0, BUFSIZ); for (i = 0; i < size / BUFSIZ; i++) { if (write(data->fd, zeros, BUFSIZ) < 0) { ret = interpret_errno(context, errno); if (OPENCLOSE(id)) { (void)close(data->fd); data->fd = -1; } goto cleanup; } } wlen = size % BUFSIZ; if (write(data->fd, zeros, wlen) < 0) { ret = interpret_errno(context, errno); if (OPENCLOSE(id)) { (void)close(data->fd); data->fd = -1; } goto cleanup; } st = close(data->fd); data->fd = -1; if (st) ret = interpret_errno(context, errno); #endif /* MSDOS_FILESYSTEM */ cleanup: k5_cc_mutex_unlock(context, &data->lock); dereference(context, data); free(id); krb5_change_cache(); return ret; }
/* Open and lock the cache file. If mode is FCC_OPEN_AND_ERASE, initialize it * with a header. Call with the mutex locked. */ static krb5_error_code open_cache_file(krb5_context context, krb5_ccache id, int mode) { krb5_os_context os_ctx = &context->os_context; krb5_error_code ret; fcc_data *data = id->data; char fcc_fvno[2]; uint16_t fcc_flen, fcc_tag, fcc_taglen; uint32_t time_offset, usec_offset; int f, open_flag, lock_flag, cnt; char buf[1024]; k5_cc_mutex_assert_locked(context, &data->lock); invalidate_cache(data); if (data->fd != NO_FILE) { /* Don't know what state it's in; shut down and start anew. */ (void)krb5_unlock_file(context, data->fd); (void)close(data->fd); data->fd = NO_FILE; } switch (mode) { case FCC_OPEN_AND_ERASE: unlink(data->filename); open_flag = O_CREAT | O_EXCL | O_TRUNC | O_RDWR; break; case FCC_OPEN_RDWR: open_flag = O_RDWR; break; case FCC_OPEN_RDONLY: default: open_flag = O_RDONLY; break; } f = THREEPARAMOPEN(data->filename, open_flag | O_BINARY, 0600); if (f == NO_FILE) { if (errno == ENOENT) { ret = KRB5_FCC_NOFILE; k5_setmsg(context, ret, _("Credentials cache file '%s' not found"), data->filename); return ret; } else { return interpret_errno(context, errno); } } set_cloexec_fd(f); data->mode = mode; if (data->mode == FCC_OPEN_RDONLY) lock_flag = KRB5_LOCKMODE_SHARED; else lock_flag = KRB5_LOCKMODE_EXCLUSIVE; ret = krb5_lock_file(context, f, lock_flag); if (ret) { (void)close(f); return ret; } if (mode == FCC_OPEN_AND_ERASE) { /* write the version number */ store_16_be(context->fcc_default_format, fcc_fvno); data->version = context->fcc_default_format; cnt = write(f, fcc_fvno, 2); if (cnt != 2) { ret = (cnt == -1) ? interpret_errno(context, errno) : KRB5_CC_IO; goto done; } data->fd = f; if (data->version == FVNO_4) { /* V4 of the credentials cache format allows for header tags */ fcc_flen = 0; if (os_ctx->os_flags & KRB5_OS_TOFFSET_VALID) fcc_flen += 2 + 2 + 4 + 4; /* Write header length. */ ret = store16(context, id, fcc_flen); if (ret) goto done; if (os_ctx->os_flags & KRB5_OS_TOFFSET_VALID) { /* Write time offset tag. */ fcc_tag = FCC_TAG_DELTATIME; fcc_taglen = 2 * 4; ret = store16(context, id, fcc_tag); if (ret) goto done; ret = store16(context, id, fcc_taglen); if (ret) goto done; ret = store32(context, id, os_ctx->time_offset); if (ret) goto done; ret = store32(context, id, os_ctx->usec_offset); if (ret) goto done; } } invalidate_cache(data); goto done; } /* Verify a valid version number is there. */ invalidate_cache(data); if (read(f, fcc_fvno, 2) != 2) { ret = KRB5_CC_FORMAT; goto done; } data->version = load_16_be(fcc_fvno); if (data->version != FVNO_4 && data->version != FVNO_3 && data->version != FVNO_2 && data->version != FVNO_1) { ret = KRB5_CCACHE_BADVNO; goto done; } data->fd = f; if (data->version == FVNO_4) { if (read16(context, id, &fcc_flen) || fcc_flen > sizeof(buf)) { ret = KRB5_CC_FORMAT; goto done; } while (fcc_flen) { if (fcc_flen < 2 * 2 || read16(context, id, &fcc_tag) || read16(context, id, &fcc_taglen) || fcc_taglen > fcc_flen - 2 * 2) { ret = KRB5_CC_FORMAT; goto done; } switch (fcc_tag) { case FCC_TAG_DELTATIME: if (fcc_taglen != 2 * 4) { ret = KRB5_CC_FORMAT; goto done; } if (!(context->library_options & KRB5_LIBOPT_SYNC_KDCTIME) || (os_ctx->os_flags & KRB5_OS_TOFFSET_VALID)) { if (read_bytes(context, id, buf, fcc_taglen)) { ret = KRB5_CC_FORMAT; goto done; } break; } if (read32(context, id, NULL, &time_offset) || read32(context, id, NULL, &usec_offset)) { ret = KRB5_CC_FORMAT; goto done; } os_ctx->time_offset = time_offset; os_ctx->usec_offset = usec_offset; os_ctx->os_flags = ((os_ctx->os_flags & ~KRB5_OS_TOFFSET_TIME) | KRB5_OS_TOFFSET_VALID); break; default: if (fcc_taglen && read_bytes(context, id, buf, fcc_taglen)) { ret = KRB5_CC_FORMAT; goto done; } break; } fcc_flen -= (2 * 2 + fcc_taglen); } } done: if (ret) { data->fd = -1; (void)krb5_unlock_file(context, f); (void)close(f); } return ret; }