diff options
author | Colin Walters <walters@verbum.org> | 2013-07-18 14:19:57 -0400 |
---|---|---|
committer | Colin Walters <walters@verbum.org> | 2013-07-18 14:19:57 -0400 |
commit | f56702ef40a5df056097d2e14ee0dac3614b744c (patch) | |
tree | da1baaef999c6a05203dea195fdf4bc4b9b2d873 | |
parent | 939cd18d39b1abf39543c83c406246b12dbfa03a (diff) | |
download | libgsystem-f56702ef40a5df056097d2e14ee0dac3614b744c.tar.gz |
fileutils: Add gs_file_create_with_uidgid()
If the provided mode includes S_ISUID or S_ISGID, we will successfully
invoke fchmod(), but then a subsequent chown() will undo any setuid
bits, even if we're just calling chown for the already extant uid.
This API can reliably create a file with the provided mode and owner.
-rw-r--r-- | gsystem-file-utils.c | 76 | ||||
-rw-r--r-- | gsystem-file-utils.h | 8 |
2 files changed, 84 insertions, 0 deletions
diff --git a/gsystem-file-utils.c b/gsystem-file-utils.c index 31e7331..5510948 100644 --- a/gsystem-file-utils.c +++ b/gsystem-file-utils.c @@ -252,6 +252,82 @@ gs_file_sync_data (GFile *file, } /** + * gs_file_create_with_uidgid: + * @file: Path of file to create + * @mode: Unix mode + * @uid: Unix uid + * @gid: Unix gid + * @out_stream: (out) (transfer full) (allow-none): Output stream connected to file descriptor + * @cancellable: a #GCancellable + * @error: a #GError + * + * Create @file exclusively; it must not exist already. Ensure the + * returned file has mode @mode and has Unix owners corresponding to + * the parameters @uid and @gid. + * + * The parameter @out_stream if provided, will be filled in with a + * #GOutputStream connected to the file. + * + * Returns: %TRUE on success, %FALSE on error. + */ +gboolean +gs_file_create_with_uidgid (GFile *file, + int mode, + uid_t uid, + gid_t gid, + GOutputStream **out_stream, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + int fd; + GOutputStream *ret_stream = NULL; + static gsize uidgid_cached; + static uid_t myuid; + static uid_t mygid; + + /* Ok yes this is lame, but calling these two over and over shows up + * in strace. I like my straces to be clean, shoot me. + */ + if (g_once_init_enter (&uidgid_cached)) + { + myuid = getuid (); + mygid = getgid (); + g_once_init_leave (&uidgid_cached, 1); + } + + fd = open_nointr (gs_file_get_path_cached (file), O_WRONLY | O_CREAT | O_EXCL, mode); + if (fd < 0) + { + _set_error_from_errno (error); + goto out; + } + + if (uid != myuid || gid != mygid) + { + if (fchown (fd, uid, gid) < 0) + { + _set_error_from_errno (error); + goto out; + } + } + + if (fchmod (fd, mode) < 0) + { + _set_error_from_errno (error); + goto out; + } + + ret_stream = g_unix_output_stream_new (fd, TRUE); + + ret = TRUE; + gs_transfer_out_value (out_stream, &ret_stream); + out: + g_clear_object (&ret_stream); + return ret; +} + +/** * gs_file_create: * @file: Path to non-existent file * @mode: Unix access permissions diff --git a/gsystem-file-utils.h b/gsystem-file-utils.h index 26ee878..d8cd73d 100644 --- a/gsystem-file-utils.h +++ b/gsystem-file-utils.h @@ -61,6 +61,14 @@ gboolean gs_file_create (GFile *file, GCancellable *cancellable, GError **error); +gboolean gs_file_create_with_uidgid (GFile *file, + int mode, + uid_t uid, + gid_t gid, + GOutputStream **out_stream, + GCancellable *cancellable, + GError **error); + gboolean gs_file_linkcopy (GFile *src, GFile *dest, GFileCopyFlags flags, |