X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=libatalk%2Futil%2Funix.c;h=0ff282a0864c2e57442f266c6110f43191bd6e9c;hb=b362b6f7b22b6e4e9e74760989f389149677917b;hp=9e71fcb4b71a3b7fd53479c4cebc2cef7cb3bb30;hpb=6145c1c31a1a2494fe6ad7ca65f9c2a63a05b07d;p=netatalk.git diff --git a/libatalk/util/unix.c b/libatalk/util/unix.c index 9e71fcb4..0ff282a0 100644 --- a/libatalk/util/unix.c +++ b/libatalk/util/unix.c @@ -41,6 +41,75 @@ #include #include +/* close all FDs >= a specified value */ +static void closeall(int fd) +{ + int fdlimit = sysconf(_SC_OPEN_MAX); + + while (fd < fdlimit) + close(fd++); +} + +/*! + * Daemonize + * + * Fork, exit parent, setsid(), optionally chdir("/"), optionally close all fds + * + * returns -1 on failure, but you can't do much except exit in that case + * since we may already have forked + */ +int daemonize(int nochdir, int noclose) +{ + switch (fork()) { + case 0: + break; + case -1: + return -1; + default: + _exit(0); + } + + if (setsid() < 0) + return -1; + + switch (fork()) { + case 0: + break; + case -1: + return -1; + default: + _exit(0); + } + + if (!nochdir) + chdir("/"); + + if (!noclose) { + closeall(0); + open("/dev/null",O_RDWR); + dup(0); + dup(0); + } + + 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 * @@ -57,6 +126,28 @@ const char *getcwdpath(void) return strerror(errno); } +/*! + * @brief Request absolute path + * + * @returns Absolute filesystem path to object + */ +const char *fullpathname(const char *name) +{ + static char wd[MAXPATHLEN + 1]; + + if (name[0] == '/') + return name; + + if (getcwd(wd , MAXPATHLEN)) { + strlcat(wd, "/", MAXPATHLEN); + strlcat(wd, name, MAXPATHLEN); + } else { + strlcpy(wd, name, MAXPATHLEN); + } + + return wd; +} + /*! * Takes a buffer with a path, strips slashs, returns basename * @@ -77,20 +168,103 @@ char *stripped_slashes_basename(char *p) return (strrchr(p, '/') ? strrchr(p, '/') + 1 : p); } +/********************************************************************************* + * chdir(), chmod(), chown(), stat() wrappers taking an additional option. + * Currently the only used options are O_NOFOLLOW, used to switch between symlink + * behaviour, and O_NETATALK_ACL for ochmod() indicating chmod_acl() shall be + * called which does special ACL handling depending on the filesytem + *********************************************************************************/ + +int ostat(const char *path, struct stat *buf, int options) +{ + if (options & O_NOFOLLOW) + return lstat(path, buf); + else + return stat(path, buf); +} + +int ochown(const char *path, uid_t owner, gid_t group, int options) +{ + if (options & O_NOFOLLOW) + return lchown(path, owner, group); + else + return chown(path, owner, group); +} + +/*! + * chmod() wrapper for symlink and ACL handling + * + * @param path (r) path + * @param mode (r) requested mode + * @param sb (r) stat() of path or NULL + * @param option (r) O_NOFOLLOW | O_NETATALK_ACL + * + * Options description: + * O_NOFOLLOW: don't chmod() symlinks, do nothing, return 0 + * O_NETATALK_ACL: call chmod_acl() instead of chmod() + */ +int ochmod(const char *path, mode_t mode, const struct stat *st, int options) +{ + struct stat sb; + + if (!st) { + if (lstat(path, &sb) != 0) + return -1; + st = &sb; + } + + if (options & O_NOFOLLOW) + if (S_ISLNK(st->st_mode)) + return 0; + + if (options & O_NETATALK_ACL) { + return chmod_acl(path, mode); + } else { + return chmod(path, mode); + } +} + +/* + * @brief ostat/fsstatat multiplexer + * + * ostatat mulitplexes ostat and fstatat. If we dont HAVE_ATFUNCS, dirfd is ignored. + * + * @param dirfd (r) Only used if HAVE_ATFUNCS, ignored else, -1 gives AT_FDCWD + * @param path (r) pathname + * @param st (rw) pointer to struct stat + */ +int ostatat(int dirfd, const char *path, struct stat *st, int options) +{ +#ifdef HAVE_ATFUNCS + if (dirfd == -1) + dirfd = AT_FDCWD; + return fstatat(dirfd, path, st, (options & O_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0); +#else + return ostat(path, st, options); +#endif + + /* DEADC0DE */ + return -1; +} + /*! * @brief symlink safe chdir replacement * - * Only chdirs to dir if it doesn't contain symlinks. + * Only chdirs to dir if it doesn't contain symlinks or if symlink checking + * is disabled * * @returns 1 if a path element is a symlink, 0 otherwise, -1 on syserror */ -int lchdir(const char *dir) +int ochdir(const char *dir, int options) { char buf[MAXPATHLEN+1]; char cwd[MAXPATHLEN+1]; char *test; int i; + if (!(options & O_NOFOLLOW)) + return chdir(dir); + /* dir is a canonical path (without "../" "./" "//" ) but may end with a /