Commit 773ffd0e authored by jan.koester's avatar jan.koester
Browse files

test

parent 191d7bb1
Loading
Loading
Loading
Loading
+61 −18
Changes for src/files.cpp: 61 added lines, 18 removed lines.
Original line number Diff line number Diff line
@@ -155,24 +155,70 @@ bool inheritOwner(int fd, int dir, const struct stat &st) {
    return fchown(fd, st.st_uid, st.st_gid) == 0;
}

bool parseId(const std::string &v, bool group, unsigned &out) {
// An owner or group to set: classic, or (systempp) a UUID or GUID one;
// unset leaves it unchanged.
#ifdef SHAREDD_UID_R
struct OwnerId {
    uid_r_t id = uid_r_none();
    bool set() const { return id.type != UID_R_NONE; }
};
#else
struct OwnerId {
    unsigned id = (unsigned)-1;
    bool set() const { return id != (unsigned)-1; }
};
#endif

// a name, a number or (systempp) an id's text form
bool parseId(const std::string &v, bool group, OwnerId &out) {
    if (!v.empty() && v.find_first_not_of("0123456789") == std::string::npos) {
        out = (unsigned)std::strtoul(v.c_str(), nullptr, 10);
        unsigned n = (unsigned)std::strtoul(v.c_str(), nullptr, 10);
#ifdef SHAREDD_UID_R
        out.id = uid_r_legacy(n);
#else
        out.id = n;
#endif
        return true;
    }
#ifdef SHAREDD_UID_R
    if (group) {
        if (struct group_id_r *gr = getgrnam_id_r(v.c_str())) {
            out.id = gr->gr_gid;
            return true;
        }
    } else if (struct passwd_id_r *pw = getpwnam_id_r(v.c_str())) {
        out.id = pw->pw_uid;
        return true;
    }
    return uid_r_from_str(v.c_str(), &out.id) == 0 && !uid_r_is_legacy(&out.id);
#else
    if (group) {
        struct group *gr = getgrnam(v.c_str());
        if (gr) out = gr->gr_gid;
        if (gr) out.id = gr->gr_gid;
        return gr != nullptr;
    }
    struct passwd *pw = getpwnam(v.c_str());
    if (pw) out = pw->pw_uid;
    if (pw) out.id = pw->pw_uid;
    return pw != nullptr;
#endif
}

bool chownFd(int fd, const OwnerId &uid, const OwnerId &gid) {
    if (!uid.set() && !gid.set()) return true;
#ifdef SHAREDD_UID_R
    if (fchown_r(fd, &uid.id, &gid.id) == 0) return true;
    if (errno != ENOSYS || (uid.set() && !uid_r_is_legacy(&uid.id)) || (gid.set() && !uid_r_is_legacy(&gid.id)))
        return false;
    // a kernel without the *_r calls: classic ids only
    return fchown(fd, uid.set() ? uid.id.legacy : (uid_t)-1, gid.set() ? gid.id.legacy : (gid_t)-1) == 0;
#else
    return fchown(fd, uid.id, gid.id) == 0;
#endif
}

// owner, group and mode on an open file descriptor
bool apply(int fd, bool isDir, uid_t uid, gid_t gid, int mode) {
    if ((uid != (uid_t)-1 || gid != (gid_t)-1) && fchown(fd, uid, gid) != 0) return false;
bool apply(int fd, bool isDir, const OwnerId &uid, const OwnerId &gid, int mode) {
    if (!chownFd(fd, uid, gid)) return false;
    if (mode >= 0) {
        unsigned m = (unsigned)mode & AllowedModes;
        if (!isDir) m &= 0666u;  // files: read/write only -- no execute, setgid or sticky
@@ -198,7 +244,7 @@ Fd openEntry(int dir, const char *name, bool &isDir) {
}

// everything below dir; failures are counted, the walk goes on
void applyTree(int dir, uid_t uid, gid_t gid, int mode, int &failed) {
void applyTree(int dir, const OwnerId &uid, const OwnerId &gid, int mode, int &failed) {
    DIR *d = fdopendir(dup(dir));
    if (!d) {
        ++failed;
@@ -287,19 +333,16 @@ std::string setPermissions(const Share &s, const std::string &rel, const std::st
                           const std::string &group, int mode, bool recursive, const std::string &lang) {
    std::vector<std::string> parts;
    if (!split(rel, parts)) return tr(lang, "invalid path", "ungültiger Pfad");
    uid_t uid = (uid_t)-1;
    gid_t gid = (gid_t)-1;
    unsigned id;
    if (!owner.empty()) {
        if (!parseId(owner, false, id)) return tr(lang, "no user %1", "kein Benutzer %1", {owner});
        uid = id;
    }
    if (!group.empty()) {
        if (!parseId(group, true, id)) return tr(lang, "no group %1", "keine Gruppe %1", {group});
        gid = id;
    }
    OwnerId uid, gid;
    if (!owner.empty() && !parseId(owner, false, uid)) return tr(lang, "no user %1", "kein Benutzer %1", {owner});
    if (!group.empty() && !parseId(group, true, gid)) return tr(lang, "no group %1", "keine Gruppe %1", {group});
#ifdef SHAREDD_UID_R
    endpwent_id_r();
    endgrent_id_r();
#else
    endpwent();
    endgrent();
#endif
    if (mode >= 0 && ((unsigned)mode & ~AllowedModes))
        return tr(lang, "invalid mode (setuid isn't allowed)", "ungültige Rechte (setuid ist nicht erlaubt)");