92 static VSTREAM *safe_open_exist(
const char *path,
int flags,
95 struct stat local_statbuf;
103 if ((fp =
vstream_fopen(path, flags & ~(O_CREAT | O_EXCL), 0)) == 0) {
116 fstat_st = &local_statbuf;
118 msg_fatal(
"%s: bad open file status: %m", path);
119 }
else if (fstat_st->st_nlink != 1) {
121 (
int) fstat_st->st_nlink);
123 }
else if (S_ISDIR(fstat_st->st_mode)) {
149 else if (
lstat(path, &lstat_st) < 0) {
152 }
else if (S_ISLNK(lstat_st.st_mode)) {
153 if (lstat_st.st_uid == 0) {
155 const char *parent_path =
sane_dirname(parent_buf, path);
156 struct stat parent_st;
159 parent_ok = (
stat(parent_path, &parent_st) == 0
160 && parent_st.st_uid == 0
161 && (parent_st.st_mode & (S_IWGRP | S_IWOTH)) == 0);
168 }
else if (fstat_st->st_dev != lstat_st.st_dev
169 || fstat_st->st_ino != lstat_st.st_ino
171 || fstat_st->st_gen != lstat_st.st_gen
173 || fstat_st->st_nlink != lstat_st.st_nlink
174 || fstat_st->st_mode != lstat_st.st_mode) {
195 static VSTREAM *safe_open_create(
const char *path,
int flags, mode_t mode,
196 struct stat * st, uid_t user, gid_t group,
VSTRING *why)
204 if ((fp =
vstream_fopen(path, flags | (O_CREAT | O_EXCL), mode)) == 0) {
213 msg_fatal(
"%s: bad open file status: %m", path);
220 #define CHANGE_OWNER(user, group) (user != (uid_t) -1 || group != (gid_t) -1)
224 msg_warn(
"%s: cannot change file ownership: %m", path);
244 struct stat * st, uid_t user, gid_t group,
VSTRING *why)
248 switch (flags & (O_CREAT | O_EXCL)) {
254 return (safe_open_exist(path, flags, st, why));
259 case O_CREAT | O_EXCL:
260 return (safe_open_create(path, flags, mode, st, user, group, why));
269 fp = safe_open_exist(path, flags, st, why);
270 if (fp == 0 && errno == ENOENT) {
271 fp = safe_open_create(path, flags, mode, st, user, group, why);
272 if (fp == 0 && errno == EEXIST)
273 fp = safe_open_exist(path, flags, st, why);
281 msg_panic(
"safe_open: O_EXCL flag without O_CREAT flag");
NORETURN msg_panic(const char *fmt,...)
char * sane_dirname(VSTRING *bp, const char *path)
VSTREAM * vstream_fopen(const char *path, int flags, mode_t mode)
int vstream_fclose(VSTREAM *stream)
void msg_warn(const char *fmt,...)
VSTRING * vstring_alloc(ssize_t len)
#define CHANGE_OWNER(user, group)
VSTRING * vstring_sprintf(VSTRING *vp, const char *format,...)
NORETURN msg_fatal(const char *fmt,...)
VSTREAM * safe_open(const char *path, int flags, mode_t mode, struct stat *st, uid_t user, gid_t group, VSTRING *why)
VSTRING * vstring_free(VSTRING *vp)
#define vstream_fileno(vp)