From be13d9b759b7b9a1c200efa88d4c7067224d5ae6 Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Tue, 31 Jan 2012 11:58:10 +0100 Subject: [PATCH] Add become_root() capability to nfsv4_chmod() --- include/atalk/unix.h | 3 +++ libatalk/acl/unix.c | 30 ++++++++++++++++++++++++------ libatalk/util/unix.c | 16 ++++++++++++++++ 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/include/atalk/unix.h b/include/atalk/unix.h index f6d191ca..cc7bf5b0 100644 --- a/include/atalk/unix.h +++ b/include/atalk/unix.h @@ -39,4 +39,7 @@ extern int dir_rx_set(mode_t mode); extern int stickydirmode(const char *name, const mode_t mode, const int dropbox, const mode_t v_umask); extern int unix_rename(int sfd, const char *oldpath, int dfd, const char *newpath); extern int copy_file(int sfd, const char *src, const char *dst, mode_t mode); +extern void become_root(void); +extern void unbecome_root(void); + #endif /* ATALK_UNIX_H */ diff --git a/libatalk/acl/unix.c b/libatalk/acl/unix.c index 9bad9c94..8defd7d8 100644 --- a/libatalk/acl/unix.c +++ b/libatalk/acl/unix.c @@ -33,6 +33,7 @@ #include #include #include +#include #ifdef HAVE_SOLARIS_ACLS @@ -47,7 +48,7 @@ int get_nfsv4_acl(const char *name, ace_t **retAces) *retAces = NULL; /* Only call acl() for regular files and directories, otherwise just return 0 */ if (lstat(name, &st) != 0) { - LOG(log_warning, logtype_afpd, "get_nfsv4_acl(\"%s/%s\"): %s", getcwdpath(), name, strerror(errno)); + LOG(log_debug, logtype_afpd, "get_nfsv4_acl(\"%s/%s\"): %s", getcwdpath(), name, strerror(errno)); return -1; } @@ -234,8 +235,16 @@ int nfsv4_chmod(char *name, mode_t mode) if (chmod(name, mode) != 0) /* (3) */ goto exit; - if ((nnaces = get_nfsv4_acl(name, &nacl)) == -1) /* (4) */ - goto exit; + if ((nnaces = get_nfsv4_acl(name, &nacl)) == -1) {/* (4) */ + if (errno != EACCES) + goto exit; + become_root(); + nnaces = get_nfsv4_acl(name, &nacl); + unbecome_root(); + if (nnaces == -1) + goto exit; + } + if ((nnaces = strip_nontrivial_aces(&nacl, nnaces)) == -1) /* (5) */ goto exit; @@ -243,8 +252,17 @@ int nfsv4_chmod(char *name, mode_t mode) goto exit; if ((ret = acl(name, ACE_SETACL, noaces + nnaces, cacl)) != 0) { - LOG(log_error, logtype_afpd, "nfsv4_chmod: error setting acl: %s", strerror(errno)); - goto exit; + if (errno != EACCES) { + LOG(log_error, logtype_afpd, "nfsv4_chmod: error setting acl: %s", strerror(errno)); + goto exit; + } + become_root(); + ret = acl(name, ACE_SETACL, noaces + nnaces, cacl); + unbecome_root(); + if (ret != 0) { + LOG(log_error, logtype_afpd, "nfsv4_chmod: error setting acl: %s", strerror(errno)); + goto exit; + } } exit: @@ -252,7 +270,7 @@ exit: if (nacl) free(nacl); if (cacl) free(cacl); - LOG(log_debug, logtype_afpd, "nfsv4_chmod(\"%s/%s\", %04o): result: %u", + LOG(log_debug, logtype_afpd, "nfsv4_chmod(\"%s/%s\", %04o): result: %d", getcwdpath(), name, mode, ret); return ret; diff --git a/libatalk/util/unix.c b/libatalk/util/unix.c index 0e466307..e4cb21e8 100644 --- a/libatalk/util/unix.c +++ b/libatalk/util/unix.c @@ -94,6 +94,22 @@ int daemonize(int nochdir, int noclose) return 0; } +static uid_t saved_uid = -1; + +void become_root(void) +{ + saved_uid = geteuid(); + if (seteuid(0) != 0) + AFP_PANIC("Can't seteuid(0)"); +} + +void unbecome_root(void) +{ + if (saved_uid == -1 || seteuid(saved_uid) < 0) + AFP_PANIC("Can't seteuid back"); + saved_uid = -1; +} + /*! * @brief get cwd in static buffer * -- 2.39.2