Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added some hardening to CFLAGS #38

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
*.swp
protos.h
*.o
config
crond
crontab

11 changes: 11 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@ git

* Documentation and error message updates.

v4.6 09-March-2024
* Took over ownership of project, since last version was over a decade ago. Changed associated URLs.

* Fixed several bugs, both performance and output issues

* Added pid file when run in daemon mode.

* Documentation updates

* Added hardened CFLAGS and changed linking process. No idea when last eyes were on this with security in mind.

v4.5 1-May-2011
* Some cron jobs were running multiple times. Now we make sure not to
ArmJobs that are already running; and not to resynchronize while jobs are
Expand Down
8 changes: 5 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ INSTALL_PROGRAM = $(INSTALL) -D
INSTALL_DATA = $(INSTALL) -D -m0644 -g root
INSTALL_DIR = $(INSTALL) -d -m0755 -g root
CFLAGS ?= -O2
CFLAGS += -Wall -Wstrict-prototypes -Wno-missing-field-initializers
CFLAGS += -Wall -Wextra -Wstrict-prototypes -Wno-missing-field-initializers -Wfloat-equal -fstack-protector-all -Wformat-security -Wformat=2 -fPIE
CFLAGS += -Wl,-z,nodump -Wl,-z,noexecstack -Wl,-z,noexecheap -Wl,-z,relro -Wl,-z,now -Wl,-z,nodlopen -Wl,-z,-pie
CFLAGS += -Wno-format-nonliteral -Wno-sign-compare
SRCS = main.c subs.c database.c job.c concat.c chuser.c
OBJS = main.o subs.o database.o job.o concat.o chuser.o
TABSRCS = crontab.c chuser.c
Expand Down Expand Up @@ -54,10 +56,10 @@ protos.h: $(SRCS) $(TABSRCS)
fgrep -h Prototype $(SRCS) $(TABSRCS) > protos.h

crond: $(OBJS)
$(CC) $(LDFLAGS) $^ $(LIBS) -o crond
$(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) -o crond

crontab: $(TABOBJS)
$(CC) $(LDFLAGS) $^ -o crontab
$(CC) $(CLFAGS) $(LDFLAGS) $^ -o crontab

%.o: %.c defs.h $(PROTOS)
$(CC) $(CFLAGS) $(CPPFLAGS) -c $(DEFS) $< -o $@
Expand Down
8 changes: 3 additions & 5 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,10 @@ crond and close attention to preventing crond from running away.
DOWNLOADING
-----------

The project is hosted at: <http://www.jimpryor.net/linux/dcron.html>.
The project is hosted at: <https://github.com/ptchinster/dcron>.

The latest version is 4.5, which can be downloaded here:
<http://www.jimpryor.net/linux/releases/dcron-4.5.tar.gz>.

A public git repo is available at: <https://github.com/dubiousjim/dcron>.
The latest version is 4.6, which can be downloaded here:
<https://github.com/ptchinster/dcron/archive/refs/tags/v4.6.tar.gz>.


COMPILING
Expand Down
12 changes: 11 additions & 1 deletion crond.8
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
crond - dillon's lightweight cron daemon
.SH SYNOPSIS
.PP
\f[B]crond [-s dir] [-c dir] [-t dir] [-m user\@host] [-M mailhandler] [-S|-L file] [-l loglevel] [-b|-f|-d]\f[]
\f[B]crond [-s dir] [-c dir] [-t dir] [-m user\@host] [-M mailhandler] [-S|-L file] [-P|-p file] [-l loglevel] [-b|-f|-d]\f[]
.SH OPTIONS
.PP
\f[B]crond\f[] is a background daemon that parses individual
Expand Down Expand Up @@ -69,6 +69,16 @@ log to specified file instead of syslog.
.RS
.RE
.TP
.B -P
do not create a process-id file.
.RS
.RE
.TP
.B -L file
Write process-id to specified file instead of /var/run/crond.pi
.RS
.RE
.TP
.B -l loglevel
log events at the specified, or more important, loglevels.
The default is `notice'.
Expand Down
16 changes: 9 additions & 7 deletions crontab.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,11 @@ main(int ac, char **av)
exit(1);
}
} else {
printlogf(0, "user '%s' unknown", optarg);
printlogf(0, "user '%s' unknown\n", optarg);
exit(1);
}
} else {
printlogf(0, "-u option: superuser only");
printlogf(0, "-u option: superuser only\n");
exit(1);
}
break;
Expand All @@ -91,7 +91,7 @@ main(int ac, char **av)
if (*optarg != 0 && getuid() == geteuid()) {
CDir = optarg;
} else {
printlogf(0, "-c option: superuser only");
printlogf(0, "-c option: superuser only\n");
exit(1);
}
break;
Expand Down Expand Up @@ -122,7 +122,7 @@ main(int ac, char **av)
if (repFile) {
repFd = GetReplaceStream(caller, repFile);
if (repFd < 0) {
printlogf(0, "unable to read replacement file %s", repFile);
printlogf(0, "unable to read replacement file %s\n", repFile);
exit(1);
}
}
Expand All @@ -132,7 +132,7 @@ main(int ac, char **av)
*/

if (chdir(CDir) < 0) {
printlogf(0, "cannot change dir to %s: %s", CDir, strerror(errno));
printlogf(0, "cannot change dir to %s: %s\n", CDir, strerror(errno));
exit(1);
}

Expand Down Expand Up @@ -171,7 +171,7 @@ main(int ac, char **av)
* Then we delete the temp file, keeping its fd as repFd
*/
if ((fd = mkstemp(tmp)) >= 0) {
chown(tmp, getuid(), getgid());
fchown(fd, getuid(), getgid());
if ((fi = fopen(pas->pw_name, "r"))) {
while ((n = fread(buf, 1, sizeof(buf), fi)) > 0)
write(fd, buf, n);
Expand All @@ -181,7 +181,7 @@ main(int ac, char **av)
lseek(fd, 0L, 0);
repFd = fd;
} else {
printlogf(0, "unable to create %s: %s", tmp, strerror(errno));
printlogf(0, "unable to create %s: %s\n", tmp, strerror(errno));
exit(1);
}

Expand Down Expand Up @@ -253,6 +253,8 @@ main(int ac, char **av)
void
printlogf(int level, const char *ctl, ...)
{
UNUSED(level);

va_list va;
char buf[LOG_BUFFER];

Expand Down
2 changes: 2 additions & 0 deletions database.c
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,8 @@ SynchronizeFile(const char *dpath, const char *fileName, const char *userName)
line.cl_Days[j] = 1;
for (j=0; j<12; ++j)
line.cl_Mons[j] = 1;
for (j=0; j<12; ++j)
line.cl_Dow[j] = ALL_DOW;
}

while (*ptr == ' ' || *ptr == '\t')
Expand Down
6 changes: 6 additions & 0 deletions defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@
#ifndef CRONTABS
#define CRONTABS "/var/spool/cron/crontabs"
#endif
#ifndef PIDFILE
#define PIDFILE "/var/run/crond.pid"
#endif
#ifndef CRONSTAMPS
#define CRONSTAMPS "/var/spool/cron/cronstamps"
#endif
Expand Down Expand Up @@ -116,6 +119,9 @@
#define LOGHEADER TIMESTAMP_FMT " %%s " LOG_IDENT ": "
#define LOCALE_LOGHEADER "%c %%s " LOG_IDENT ": "

//For removing warnings from -Wunused-parameter
#define UNUSED(X) ((void)(X))

/* Limits */
#define MAXOPEN 256 /* close fds < this limit */
#define MAXLINES 256 /* max lines in non-root crontabs */
Expand Down
1 change: 1 addition & 0 deletions job.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Prototype void EndJob(CronFile *file, CronLine *line, int exit_status);

Prototype const char *SendMail;

//__attribute__((__format__ (__printf__, 1, 0)))
void
RunJob(CronFile *file, CronLine *line)
{
Expand Down
66 changes: 57 additions & 9 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@ short DebugOpt = 0;
short LogLevel = LOG_LEVEL;
short ForegroundOpt = 0;
short SyslogOpt = 1;
short PidFileOpt = 1;
const char *CDir = CRONTABS;
const char *SCDir = SCRONTABS;
const char *TSDir = CRONSTAMPS;
const char *LogFile = NULL; /* opened with mode 0600 */
const char *LogHeader = LOGHEADER;
const char *PidFile = PIDFILE;
const char *SendMail = NULL;
const char *Mailto = NULL;
char *TempDir;
Expand Down Expand Up @@ -72,7 +74,7 @@ main(int ac, char **av)

opterr = 0;

while ((i = getopt(ac,av,"dl:L:fbSc:s:m:M:t:")) != -1) {
while ((i = getopt(ac,av,"dl:L:fbSc:s:m:M:t:Pp:")) != -1) {
switch (i) {
case 'l':
{
Expand Down Expand Up @@ -128,7 +130,7 @@ main(int ac, char **av)
case 'd':
DebugOpt = 1;
LogLevel = LOG_DEBUG;
/* fall through to include f too */
[[fallthrough]]; //fall through to include f too
case 'f':
ForegroundOpt = 1;
break;
Expand Down Expand Up @@ -161,19 +163,28 @@ main(int ac, char **av)
case 'm':
if (*optarg != 0) Mailto = optarg;
break;
case 'P':
PidFileOpt = 0;
break;
case 'p':
PidFileOpt = 1;
PidFile = optarg;
break;
default:
/*
* check for parse error
*/
printf("dillon's cron daemon " VERSION "\n");
printf("crond [-s dir] [-c dir] [-t dir] [-m user@host] [-M mailer] [-S|-L [file]] [-l level] [-b|-f|-d]\n");
printf("crond [-s dir] [-c dir] [-t dir] [-m user@host] [-M mailer] [-S|-L [file]] [-P|-p [file]] [-l level] [-b|-f|-d]\n");
printf("-s directory of system crontabs (defaults to %s)\n", SCRONTABS);
printf("-c directory of per-user crontabs (defaults to %s)\n", CRONTABS);
printf("-t directory of timestamps (defaults to %s)\n", CRONSTAMPS);
printf("-m user@host where should cron output be directed? (defaults to local user)\n");
printf("-M mailer (defaults to %s)\n", SENDMAIL);
printf("-S log to syslog using identity '%s' (default)\n", LOG_IDENT);
printf("-L file log to specified file instead of syslog\n");
printf("-P do not create process-id file\n");
printf("-p file write pid to specified file instead of %s\n", PIDFILE);
printf("-l loglevel log events <= this level (defaults to %s (level %d))\n", LevelAry[LOG_LEVEL], LOG_LEVEL);
printf("-b run in background (default)\n");
printf("-f run in foreground\n");
Expand Down Expand Up @@ -219,16 +230,48 @@ main(int ac, char **av)

int fd;
int pid;
int pipe_fd[2];
int status;

if (pipe(pipe_fd) < 0) {
//pipe failed
perror("pipe");
exit(1);
}

if ((pid = fork()) < 0) {
/* fork failed */
perror("fork");
exit(1);
} else if (pid > 0) {
/* parent */
exit(0);
}
/* parent, reads from pipe */
close(pipe_fd[1]);
if (read(pipe_fd[0], &status, sizeof(status)) > 0) {
exit(status);
}
/* error: got zero bytes, so child just closed the write end */
exit(1);
}

/* child continues */
close(pipe_fd[0]);
status = 0;

/* write pid file or exit */

if (PidFileOpt) {
if ((fd = open(PidFile, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) {
status = errno;
fprintf(stderr, "failed to open PID file '%s', reason: %s\n", PidFile, strerror(status));
goto daemon_error;
}
if (fdprintf(fd, "%d\n", getpid()) < 0) {
status = errno;
fprintf(stderr, "failed to write PID file '%s', reason: %s\n", PidFile, strerror(status));
goto daemon_error;
}
close(fd);
}

/* become session leader, detach from terminal */

Expand Down Expand Up @@ -260,11 +303,16 @@ main(int ac, char **av)
fclose(stderr);
dup2(fd, 2);
} else {
int n = errno;
fdprintf(2, "failed to open logfile '%s', reason: %s", LogFile, strerror(n));
exit(n);
status = errno;
fdprintf(2, "failed to open logfile '%s', reason: %s\n", LogFile, strerror(errno));
goto daemon_error;
}
}
daemon_error:
write(pipe_fd[1], &status, sizeof(status));
if (status != 0) {
exit(status);
}
} else {
/* daemon in foreground */

Expand Down
11 changes: 8 additions & 3 deletions subs.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

Prototype void printlogf(int level, const char *ctl, ...);
Prototype void fdprintlogf(int level, int fd, const char *ctl, ...);
Prototype void fdprintf(int fd, const char *ctl, ...);
Prototype int fdprintf(int fd, const char *ctl, ...);
Prototype void initsignals(void);
Prototype char Hostname[SMALL_BUFFER];

Expand Down Expand Up @@ -40,16 +40,19 @@ fdprintlogf(int level, int fd, const char *ctl, ...)
va_end(va);
}

void
int
fdprintf(int fd, const char *ctl, ...)
{
va_list va;
char buf[LOG_BUFFER];
int n;

va_start(va, ctl);
vsnprintf(buf, sizeof(buf), ctl, va);
write(fd, buf, strlen(buf));
n = write(fd, buf, strlen(buf));
va_end(va);

return n;
}

void
Expand Down Expand Up @@ -111,6 +114,7 @@ vlog(int level, int fd, const char *ctl, va_list va)
}

void reopenlogger(int sig) {
UNUSED(sig);
int fd;
if (getpid() == DaemonPid) {
/* only daemon handles, children should ignore */
Expand All @@ -124,6 +128,7 @@ void reopenlogger(int sig) {
}

void waitmailjob(int sig) {
UNUSED(sig);
/*
* Wait for any children in our process group.
* These will all be mailjobs.
Expand Down