Subversion Repositories public

Compare Revisions

Ignore whitespace Rev 101 → Rev 102

/incron/trunk/ict-main.cpp
2,18 → 2,21
/// inotify cron table manipulator main file
/**
* \file ict-main.cpp
*
*
* inotify cron system
*
*
* Copyright (C) 2006, 2007, 2008 Lukas Jelinek, <lukas@aiken.cz>
*
*
* This program is free software; you can use it, redistribute
* it and/or modify it under the terms of the GNU General Public
* License, version 2 (see LICENSE-GPL).
*
*
* Credits:
* kolter (fix for segfaulting on --user)
*
*/
 
 
#include <argp.h>
#include <pwd.h>
#include <string>
66,10 → 69,10
" -u <USER>, --user=<USER> overrides current user (requires root privileges)\n" \
" -f <FILE>, --config=<FILE> overrides default configuration file (requires root privileges)\n\n" \
"For reporting bugs please use http://bts.aiken.cz\n"
 
 
 
 
/// Copies a file to an user table.
/**
* \param[in] rPath path to file
79,7 → 82,7
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 == "-")
88,13 → 91,13
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;
}
 
102,13 → 105,13
/**
* \param[in] rUser user name
* \return true = success, false = failure
*/
*/
bool remove_table(const std::string& rUser)
{
fprintf(stderr, "removing table for user '%s'\n", rUser.c_str());
 
std::string tp(IncronTab::GetUserTablePath(rUser));
 
if (unlink(tp.c_str()) != 0) {
if (errno == ENOENT) {
fprintf(stderr, "table for user '%s' does not exist\n", rUser.c_str());
120,7 → 123,7
}
}
 
fprintf(stderr, "table for user '%s' successfully removed\n", rUser.c_str());
fprintf(stderr, "table for user '%s' successfully removed\n", rUser.c_str());
return true;
}
 
132,7 → 135,7
bool list_table(const std::string& rUser)
{
std::string tp(IncronTab::GetUserTablePath(rUser));
 
FILE* f = fopen(tp.c_str(), "r");
if (f == NULL) {
if (errno == ENOENT) {
144,14 → 147,14
return false;
}
}
 
char s[1024];
while (fgets(s, 1024, f) != NULL) {
fputs(s, stdout);
}
 
fclose(f);
 
return true;
}
 
159,7 → 162,7
/**
* \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..
167,19 → 170,19
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();
 
187,13 → 190,13
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;
200,13 → 203,13
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));
213,7 → 216,7
close(fd);
goto end;
}
 
in = fopen(tp.c_str(), "r");
if (in == NULL) {
if (errno == ENOENT) {
230,7 → 233,7
goto end;
}
}
 
char buf[1024];
while (fgets(buf, 1024, in) != NULL) {
fputs(buf, out);
237,15 → 240,15
}
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
252,15 → 255,15
// 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();
}
272,7 → 275,7
}
}
}
 
// this block is explicite due to gotos' usage simplification
{
pid_t pid = fork();
280,8 → 283,8
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);
}
301,18 → 304,18
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)) {
324,14 → 327,14
fprintf(stderr, "cannot move temporary table: %s\n", strerror(errno));
goto end;
}
 
}
 
ok = true;
fprintf(stderr, "table updated\n");
end:
 
end:
 
unlink(s);
return ok;
}
344,7 → 347,7
"IN_CLOSE_NOWRITE,IN_OPEN,IN_MOVED_FROM,IN_MOVED_TO,"\
"IN_CREATE,IN_DELETE,IN_DELETE_SELF,IN_CLOSE,IN_MOVE,"\
"IN_ONESHOT,IN_ALL_EVENTS");
 
#ifdef IN_DONT_FOLLOW
printf(",IN_DONT_FOLLOW");
#endif // IN_DONT_FOLLOW
356,7 → 359,7
#ifdef IN_MOVE_SELF
printf(",IN_MOVE_SELF");
#endif // IN_MOVE_SELF
 
printf("\n");
}
 
368,9 → 371,9
bool reload_table(const std::string& rUser)
{
fprintf(stderr, "requesting table reload for user '%s'...\n", rUser.c_str());
 
std::string tp(IncronTab::GetUserTablePath(rUser));
 
int fd = open(tp.c_str(), O_WRONLY | O_APPEND);
if (fd == -1) {
if (errno == ENOENT) {
382,11 → 385,11
return false;
}
}
 
close(fd);
 
fprintf(stderr, "request done\n");
 
return true;
}
 
408,24 → 411,24
fprintf(stderr, "error while initializing application");
return 1;
}
 
AppArgs::Parse(argc, argv);
 
if (AppArgs::ExistsOption("help")) {
fprintf(stderr, "%s\n", INCRONTAB_HELP);
return 0;
}
 
if (AppArgs::ExistsOption("about")) {
fprintf(stderr, "%s\n", INCRONTAB_DESCRIPTION);
return 0;
}
 
if (AppArgs::ExistsOption("version")) {
fprintf(stderr, "%s\n", INCRONTAB_VERSION);
return 0;
}
 
bool oper = AppArgs::ExistsOption("list")
|| AppArgs::ExistsOption("remove")
|| AppArgs::ExistsOption("edit")
432,57 → 435,58
|| AppArgs::ExistsOption("types")
|| AppArgs::ExistsOption("reload");
 
size_t vals = AppArgs::GetValueCount();
size_t vals = AppArgs::GetValueCount();
 
if (!oper && vals == 0) {
fprintf(stderr, "invalid arguments - specify operation or source file\n");
return 1;
}
 
if (oper && vals > 0) {
fprintf(stderr, "invalid arguments - operation and source file cannot be combined\n");
return 1;
}
 
uid_t uid = getuid();
 
std::string user;
bool chuser = AppArgs::GetOption("user", user);
 
if (uid != 0 && chuser) {
fprintf(stderr, "cannot override user to '%s': insufficient privileges\n", user.c_str());
return 1;
}
struct passwd pwd;
if (!chuser) {
struct passwd* ppwd = getpwuid(uid);
 
struct passwd* ppwd = NULL;
 
if (chuser) {
if ((ppwd = getpwnam(user.c_str())) != NULL) {
if ( setenv("LOGNAME", ppwd->pw_name, 1) != 0
|| setenv("USER", ppwd->pw_name, 1) != 0
|| setenv("USERNAME", ppwd->pw_name, 1) != 0
|| setenv("HOME", ppwd->pw_dir, 1) != 0
|| setenv("SHELL", ppwd->pw_shell, 1) != 0)
{
perror("cannot set environment variables");
return 1;
}
} else {
fprintf(stderr, "user '%s' not found\n", user.c_str());
return 1;
}
} else {
ppwd = getpwuid(uid);
if (ppwd == NULL) {
fprintf(stderr, "cannot determine current user\n");
return 1;
}
memcpy(&pwd, ppwd, sizeof(pwd));
user = pwd.pw_name;
user = ppwd->pw_name;
}
else if (getpwnam(user.c_str()) == NULL) {
fprintf(stderr, "user '%s' not found\n", user.c_str());
return 1;
}
else if ( setenv("LOGNAME", pwd.pw_name, 1) != 0
|| setenv("USER", pwd.pw_name, 1) != 0
|| setenv("USERNAME", pwd.pw_name, 1) != 0
|| setenv("HOME", pwd.pw_dir, 1) != 0
|| setenv("SHELL", pwd.pw_shell, 1) != 0)
{
perror("cannot set environment variables");
return 1;
}
 
try {
 
IncronCfg::Init();
 
std::string cfg(INCRON_CONFIG);
if (AppArgs::GetOption("config", cfg)) {
if (uid != 0) {
492,14 → 496,14
perror("cannot read configuration file (will use default)");
}
}
 
IncronCfg::Load(cfg);
 
if (!IncronTab::CheckUser(user)) {
fprintf(stderr, "user '%s' is not allowed to use incron\n", user.c_str());
return 1;
}
 
if (!oper) {
std::string file;
if (!AppArgs::GetValue(0, file)
533,14 → 537,14
return 1;
}
}
return 0;
 
return 0;
 
} catch (InotifyException e) {
fprintf(stderr, "*** unhandled exception occurred ***\n");
fprintf(stderr, "%s\n", e.GetMessage().c_str());
fprintf(stderr, "error: (%i) %s\n", e.GetErrorNumber(), strerror(e.GetErrorNumber()));
 
return 1;
}
}