int util_open_scoreboard(int flags) { int res; struct stat st; /* Prevent writing to a symlink while avoiding a race condition: open * the file name O_RDWR|O_CREAT first, then check to see if it's a symlink. * If so, close the file and error out. If not, truncate as necessary, * and continue. */ util_scoreboard_fd = open(util_scoreboard_file, flags); if (util_scoreboard_fd < 0) return -1; if (fstat(util_scoreboard_fd, &st) < 0) { close(util_scoreboard_fd); util_scoreboard_fd = -1; return -1; } if (S_ISLNK(st.st_mode)) { close(util_scoreboard_fd); util_scoreboard_fd = -1; errno = EPERM; return -1; } /* Check the header of this scoreboard file. */ res = read_scoreboard_header(&util_header); if (res < 0) return res; return 0; }
int pr_open_scoreboard(int flags) { int res; struct stat st; /* Try to prevent a file descriptor leak by only opening the scoreboard * file if the scoreboard file descriptor is not already positive, i.e. * if the scoreboard has not already been opened. */ if (scoreboard_fd >= 0 && scoreboard_opener == getpid()) { pr_log_debug(DEBUG7, "scoreboard already opened"); return 0; } pr_log_debug(DEBUG7, "opening scoreboard '%s'", scoreboard_file); /* Prevent writing to a symlink while avoiding a race condition: open * the file name O_RDWR|O_CREAT first, then check to see if it's a symlink. * If so, close the file and error out. If not, truncate as necessary, * and continue. */ while ((scoreboard_fd = open(scoreboard_file, flags|O_CREAT, PR_SCOREBOARD_MODE)) < 0) { if (errno == EINTR) { pr_signals_handle(); continue; } else return -1; } /* Make certain that the scoreboard mode will be read-only for everyone * except the user owner (this allows for non-root-running daemons to * still modify the scoreboard). */ while (fchmod(scoreboard_fd, 0644) < 0) { if (errno == EINTR) { pr_signals_handle(); continue; } else break; } while (fstat(scoreboard_fd, &st) < 0) { int st_errno = errno; if (errno == EINTR) { pr_signals_handle(); continue; } while (close(scoreboard_fd) < 0) { if (errno == EINTR) { pr_signals_handle(); continue; } else break; } /* Either way, the scoreboard fd should be marked as closed. */ scoreboard_fd = -1; errno = st_errno; return -1; } if (S_ISLNK(st.st_mode)) { while (close(scoreboard_fd) < 0) { if (errno == EINTR) { pr_signals_handle(); continue; } else break; } errno = EPERM; scoreboard_fd = -1; return -1; } scoreboard_opener = getpid(); /* Check the header of this scoreboard file. */ if ((res = read_scoreboard_header(&header)) == -1) { /* If this file is newly created, it needs to have the header * written. */ header.sch_magic = PR_SCOREBOARD_MAGIC; header.sch_version = PR_SCOREBOARD_VERSION; if (ServerType == SERVER_STANDALONE) { header.sch_pid = getpid(); header.sch_uptime = time(NULL); } else { header.sch_pid = 0; header.sch_uptime = 0; } /* Write-lock the scoreboard file. */ if (wlock_scoreboard() < 0) return -1; while (write(scoreboard_fd, &header, sizeof(header)) != sizeof(header)) { int wr_errno = errno; if (errno == EINTR) { pr_signals_handle(); continue; } unlock_scoreboard(); errno = wr_errno; return -1; } unlock_scoreboard(); return 0; } else return res; return 0; }