/** * \param[in] rPath path to file * \param[in] rUser user name * \return true = success, false = failure */ bool copy_from_file(const std::string& rPath, const std::string& rUser) { fprintf(stderr, "copying table from file '%s'\n", rPath.c_str()); IncronTab tab; std::string s(rPath); if (s == "-") s = "/dev/stdin"; if (!tab.Load(s)) { fprintf(stderr, "cannot load table from file '%s'\n", rPath.c_str()); return false; } std::string out(IncronTab::GetUserTablePath(rUser)); if (!tab.Save(out)) { fprintf(stderr, "cannot create table for user '%s'\n", rUser.c_str()); return false; } struct passwd* ppwd = getpwnam(rUser.c_str()); if (ppwd == NULL) { fprintf(stderr, "cannot find user '%s': %s\n", rUser.c_str(), strerror(errno)); return false; } if (chown(out.c_str(), ppwd->pw_uid, -1) != 0) { fprintf(stderr, "cannot set owner '%s' to table '%s': %s\n", rUser.c_str(), out.c_str(), strerror(errno)); return false; } return true; }
/** * \param[in] rPath path to file * \param[in] rUser user name * \return true = success, false = failure */ bool copy_from_file(const std::string& rPath, const std::string& rUser) { fprintf(stderr, "copying table from file '%s'\n", rPath.c_str()); IncronTab tab; std::string s(rPath); if (s == "-") s = "/dev/stdin"; if (!tab.Load(s)) { fprintf(stderr, "cannot load table from file '%s'\n", rPath.c_str()); return false; } std::string out(IncronTab::GetUserTablePath(rUser)); if (!tab.Save(out)) { fprintf(stderr, "cannot create table for user '%s'\n", rUser.c_str()); return false; } return true; }
/** * \param[in] rUser user name * \return true = success, false = failure * * \attention This function is very complex and may contain * various bugs including security ones. Please keep * it in mind.. */ bool edit_table(const std::string& rUser) { std::string tp(IncronTab::GetUserTablePath(rUser)); struct passwd* ppwd = getpwnam(rUser.c_str()); if (ppwd == NULL) { fprintf(stderr, "cannot find user '%s': %s\n", rUser.c_str(), strerror(errno)); return false; } uid_t uid = ppwd->pw_uid; uid_t gid = ppwd->pw_gid; char s[NAME_MAX]; strcpy(s, "/tmp/incron.table-XXXXXX"); uid_t iu = geteuid(); uid_t ig = getegid(); if (setegid(gid) != 0 || seteuid(uid) != 0) { fprintf(stderr, "cannot change effective UID/GID for user '%s': %s\n", rUser.c_str(), strerror(errno)); return false; } int fd = mkstemp(s); if (fd == -1) { fprintf(stderr, "cannot create temporary file: %s\n", strerror(errno)); return false; } bool ok = false; FILE* out = NULL; FILE* in = NULL; time_t mt = (time_t) 0; const char* e = NULL; std::string ed; if (setegid(ig) != 0 || seteuid(iu) != 0) { fprintf(stderr, "cannot change effective UID/GID: %s\n", strerror(errno)); close(fd); goto end; } out = fdopen(fd, "w"); if (out == NULL) { fprintf(stderr, "cannot write to temporary file: %s\n", strerror(errno)); close(fd); goto end; } in = fopen(tp.c_str(), "r"); if (in == NULL) { if (errno == ENOENT) { in = fopen("/dev/null", "r"); if (in == NULL) { fprintf(stderr, "cannot get empty table for '%s': %s\n", rUser.c_str(), strerror(errno)); fclose(out); goto end; } } else { fprintf(stderr, "cannot read old table for '%s': %s\n", rUser.c_str(), strerror(errno)); fclose(out); goto end; } } char buf[1024]; while (fgets(buf, 1024, in) != NULL) { fputs(buf, out); } fclose(in); fclose(out); struct stat st; if (stat(s, &st) != 0) { fprintf(stderr, "cannot stat temporary file: %s\n", strerror(errno)); goto end; } mt = st.st_mtime; // save modification time for detecting its change // Editor selecting algorithm: // 1. Check EDITOR environment variable // 2. Check VISUAL environment variable // 3. Try to get from configuration // 4. Check presence of /etc/alternatives/editor // 5. Use hard-wired editor e = getenv("EDITOR"); if (e == NULL) { e = getenv("VISUAL"); if (e == NULL) { if (!IncronCfg::GetValue("editor", ed)) throw InotifyException("configuration is corrupted", EINVAL); if (!ed.empty()) { e = ed.c_str(); } else { if (access(INCRON_ALT_EDITOR, X_OK) == 0) e = INCRON_ALT_EDITOR; else e = INCRON_DEFAULT_EDITOR; } } } // this block is explicite due to gotos' usage simplification { pid_t pid = fork(); if (pid == 0) { if (setgid(gid) != 0 || setuid(uid) != 0) { fprintf(stderr, "cannot set user '%s': %s\n", rUser.c_str(), strerror(errno)); goto end; } execlp(e, e, s, (const char*) NULL); _exit(1); } else if (pid > 0) { int status; if (wait(&status) != pid) { perror("error while waiting for editor"); goto end; } if (!(WIFEXITED(status)) || WEXITSTATUS(status) != 0) { perror("editor finished with error"); goto end; } } else { perror("cannot start editor"); goto end; } } if (stat(s, &st) != 0) { fprintf(stderr, "cannot stat temporary file: %s\n", strerror(errno)); goto end; } if (st.st_mtime == mt) { fprintf(stderr, "table unchanged\n"); ok = true; goto end; } { IncronTab ict; if (ict.Load(s) && ict.Save(tp)) { if (chmod(tp.c_str(), S_IRUSR | S_IWUSR) != 0) { fprintf(stderr, "cannot change mode of temporary file: %s\n", strerror(errno)); } } else { fprintf(stderr, "cannot move temporary table: %s\n", strerror(errno)); goto end; } } ok = true; fprintf(stderr, "table updated\n"); end: unlink(s); return ok; }