Earlier use of MAXHOSTNAMELEN is not posix compliant, though it usually
results to be correct value. Using sysconf() is more correct, and avoids
rather nasty gethostname() catch. If a hostname length is exactly the
maximum a character buffer which has lenght of MAXHOSTNAMELEN will not be
null terminated. That will leave the later string operations vulnerable
to buffer overflow.
Reference:
http://refspecs.linuxfoundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-g...
Signed-off-by: Sami Kerola <kerolasa(a)iki.fi>
---
src/crontab.c | 26 ++++++++++++++++++--------
src/database.c | 10 +++++++---
src/do_command.c | 7 +++++--
src/funcs.h | 6 ++++--
src/misc.c | 30 +++++++++++++++++++++++++++++-
5 files changed, 63 insertions(+), 16 deletions(-)
diff --git a/src/crontab.c b/src/crontab.c
index 0e4c851..28e75a0 100644
--- a/src/crontab.c
+++ b/src/crontab.c
@@ -90,7 +90,7 @@ static char *selinux_context = 0;
static PID_T Pid;
static char User[MAX_UNAME], RealUser[MAX_UNAME];
static char Filename[MAX_FNAME], TempFilename[MAX_FNAME];
-static char Host[MAXHOSTNAMELEN];
+static char *Host;
static FILE *NewCrontab;
static int CheckErrorCount;
static int PromptOnDelete;
@@ -325,9 +325,13 @@ static void parse_args(int argc, char *argv[]) {
if (Option == opt_hostset && argv[optind] != NULL) {
HostSpecified = 1;
- if (strlen(argv[optind]) >= sizeof Host)
+ if (strlen(argv[optind]) >= get_hostname_max())
usage("hostname too long");
- (void) strcpy(Host, argv[optind]);
+ Host = strdup(argv[optind]);
+ if (Host == NULL) {
+ fprintf(stderr, "host argument strdup failed\n");
+ exit(ERROR_EXIT);
+ }
optind++;
}
@@ -453,9 +457,9 @@ static char *host_specific_filename(const char *filename, int prefix)
*/
static char safename[MAX_FNAME];
- char hostname[MAXHOSTNAMELEN];
+ char *hostname = xgethostname();
- if (gethostname(hostname, sizeof hostname) != 0)
+ if (hostname == NULL)
return NULL;
if (prefix) {
@@ -907,7 +911,7 @@ static int hostset_cmd(void) {
char *safename;
if (!HostSpecified)
- gethostname(Host, sizeof Host);
+ Host = xgethostname();
safename = host_specific_filename("tmp.XXXXXXXXXX", 1);
if (!safename || !glue_strings(TempFilename, sizeof TempFilename, SPOOL_DIR,
@@ -965,6 +969,7 @@ static int hostset_cmd(void) {
(void) unlink(TempFilename);
TempFilename[0] = '\0';
}
+ free(Host);
return (error);
}
@@ -972,8 +977,10 @@ static int hostget_cmd(void) {
char n[MAX_FNAME];
FILE *f;
+ Host = xgethostname();
if (!glue_strings(n, sizeof n, SPOOL_DIR, CRON_HOSTNAME, '/')) {
fprintf(stderr, "path too long\n");
+ free(Host);
return (-2);
}
@@ -982,12 +989,14 @@ static int hostget_cmd(void) {
fprintf(stderr, "File %s not found\n", n);
else
perror(n);
- return (-2);
+ free(Host);
+ return (-2);
}
- if (get_string(Host, sizeof Host, f, "\n") == EOF) {
+ if (get_string(Host, get_hostname_max(), f, "\n") == EOF) {
fprintf(stderr, "Error reading from %s\n", n);
fclose(f);
+ free(Host);
return (-2);
}
@@ -997,6 +1006,7 @@ static int hostget_cmd(void) {
fflush(stdout);
log_it(RealUser, Pid, "GET HOST", Host, 0);
+ free(Host);
return (0);
}
diff --git a/src/database.c b/src/database.c
index 61764d7..50bfd1b 100644
--- a/src/database.c
+++ b/src/database.c
@@ -255,7 +255,7 @@ cluster_host_is_local(void)
char filename[MAXNAMLEN+1];
int is_local;
FILE *f;
- char hostname[MAXHOSTNAMELEN], myhostname[MAXHOSTNAMELEN];
+ char *hostname, *myhostname;
if (!EnableClustering)
return (1);
@@ -275,14 +275,18 @@ cluster_host_is_local(void)
is_local = 0;
if (glue_strings(filename, sizeof filename, SPOOL_DIR, CRON_HOSTNAME, '/')) {
if ((f = fopen(filename, "r"))) {
+ hostname = xgethostname();
+ myhostname = xgethostname();
- if (EOF != get_string(hostname, MAXHOSTNAMELEN, f, "\n") &&
- gethostname(myhostname, MAXHOSTNAMELEN) == 0) {
+ if (!hostname && !myhostname &&
+ EOF != get_string(hostname, MAXHOSTNAMELEN, f, "\n")) {
is_local = (strcmp(myhostname, hostname) == 0);
} else {
Debug(DLOAD, ("cluster: hostname comparison error\n"));
}
+ free(hostname);
+ free(myhostname);
fclose(f);
} else {
Debug(DLOAD, ("cluster: file %s not found\n", filename));
diff --git a/src/do_command.c b/src/do_command.c
index cf2b7ab..f4ed647 100644
--- a/src/do_command.c
+++ b/src/do_command.c
@@ -413,12 +413,14 @@ static int child_process(entry * e, char **jobenv) {
&& strncmp(MailCmd,"off",4) && !SyslogOutput) {
char **env;
char mailcmd[MAX_COMMAND];
- char hostname[MAXHOSTNAMELEN];
+ char *hostname;
char *content_type = env_get("CONTENT_TYPE", jobenv),
*content_transfer_encoding =
env_get("CONTENT_TRANSFER_ENCODING", jobenv);
- gethostname(hostname, MAXHOSTNAMELEN);
+ do
+ hostname = xgethostname();
+ while (hostname == NULL && usleep(1000));
if (MailCmd[0] == '\0') {
if (snprintf(mailcmd, sizeof mailcmd, MAILFMT, MAILARG, mailfrom)
@@ -439,6 +441,7 @@ static int child_process(entry * e, char **jobenv) {
fprintf(mail, "To: %s\n", mailto);
fprintf(mail, "Subject: Cron <%s@%s> %s\n",
usernm, first_word(hostname, "."), e->cmd);
+ free(hostname);
#ifdef MAIL_DATE
fprintf(mail, "Date: %s\n", arpadate(&StartTime));
diff --git a/src/funcs.h b/src/funcs.h
index 4d95d22..d9afd48 100644
--- a/src/funcs.h
+++ b/src/funcs.h
@@ -73,7 +73,8 @@ int load_database(cron_db *),
allowed(const char * ,const char * ,const char *),
strdtb(char *);
-size_t strlens(const char *, ...);
+size_t strlens(const char *, ...),
+ get_hostname_max(void);
char *env_get(const char *, char **),
*arpadate(time_t *),
@@ -81,7 +82,8 @@ char *env_get(const char *, char **),
*first_word(const char *, const char *),
**env_init(void),
**env_copy(char **),
- **env_set(char **, char *);
+ **env_set(char **, char *),
+ *xgethostname(void);
user *load_user(int, struct passwd *, const char *, const char *, const char *),
*find_user(cron_db *, const char *, const char *);
diff --git a/src/misc.c b/src/misc.c
index 106f10e..e696171 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -391,7 +391,8 @@ int get_string(char *string, int size, FILE * file, const char *terms)
{
while (EOF != (ch = get_char(file)) && !strchr(terms, ch)) {
if (size > 1) {
- *string++ = (char) ch;
+ *string = (char) ch;
+ string++;
size--;
}
}
@@ -738,6 +739,33 @@ size_t strlens(const char *last, ...) {
return (ret);
}
+size_t get_hostname_max(void) {
+ long len = sysconf(_SC_HOST_NAME_MAX);
+
+ if (0 < len)
+ return len;
+#ifdef MAXHOSTNAMELEN
+ return MAXHOSTNAMELEN;
+#elif HOST_NAME_MAX
+ return HOST_NAME_MAX;
+#endif
+ return 64;
+}
+
+char *xgethostname(void) {
+ char *name;
+ size_t sz = get_hostname_max() + 1;
+
+ name = malloc(sizeof (char) * sz);
+ if (!name)
+ return NULL;
+ if (gethostname(name, sz) != 0)
+ return NULL;
+
+ name[sz - 1] = '\0';
+ return name;
+}
+
/* Return the offset from GMT in seconds (algorithm taken from sendmail).
*
* warning:
--
1.8.0.1