aboutsummaryrefslogtreecommitdiff
path: root/networking/telnetd.c
diff options
context:
space:
mode:
Diffstat (limited to 'networking/telnetd.c')
-rw-r--r--networking/telnetd.c805
1 files changed, 796 insertions, 9 deletions
diff --git a/networking/telnetd.c b/networking/telnetd.c
index 46dfb31..1855f1b 100644
--- a/networking/telnetd.c
+++ b/networking/telnetd.c
@@ -32,12 +32,65 @@
#endif
#include <arpa/telnet.h>
+#define ATLAS 1
+
+#ifdef ATLAS
+#include <string.h>
+#include <unistd.h>
+#include <linux/reboot.h>
+
+#define LOGIN_PREFIX "Atlas probe, see http://atlas.ripe.net/\r\n\r\n"
+#define LOGIN_PROMPT " login: "
+#define PASSWORD_PROMPT "\r\nPassword: "
+
+#define ATLAS_LOGIN "C_TO_P_TEST_V1"
+#define ATLAS_SESSION_FILE "/home/atlas/status/con_session_id.txt"
+#define SESSION_ID_PREFIX "SESSION_ID "
+
+#define CMD_CRONTAB "CRONTAB "
+#define CMD_CRONLINE "CRONLINE "
+#define CMD_ONEOFF "ONEOFF "
+#define CMD_REBOOT "REBOOT"
+
+#define CRLF "\r\n"
+#define RESULT_OK "OK" CRLF CRLF
+#define BAD_PASSWORD "BAD_PASSWORD" CRLF CRLF
+#define BAD_COMMAND "BAD_COMMAND" CRLF CRLF
+#define NAME_TOO_LONG "NAME_TOO_LONG" CRLF CRLF
+#define CRONTAB_BUSY "CRONTAB_BUSY" CRLF CRLF
+#define CREATE_FAILED "UNABLE_TO_CREATE_NEW_CRONTAB" CRLF CRLF
+#define IO_ERROR "IO_ERROR" CRLF CRLF
+#define BAD_PATH "BAD_PATH" CRLF CRLF
+
+#define CRONUSER "root"
+#define CRONTAB_NEW_SUF "/" CRONUSER ".new"
+#define CRONTAB_SUFFIX "/" CRONUSER
+#define CRONUPDATE "/cron.update"
+#define UPDATELINE CRONUSER "\n"
+#define ONEOFF_SUFFIX ".new"
+#define SAFE_PREFIX ATLAS_CRONS
+
+enum state
+{
+ DO_TRADITIONAL,
+ GET_LOGINNAME,
+ GET_PASSWORD,
+ GET_CMD,
+ DO_CRONTAB,
+ EOM_SEEN
+};
+#endif
+
/* Structure that describes a session */
struct tsession {
struct tsession *next;
int sockfd_read, sockfd_write, ptyfd;
int shell_pid;
+#ifdef ATLAS
+ enum state state;
+#endif
+
/* two circular buffers */
/*char *buf1, *buf2;*/
/*#define TS_BUF1 ts->buf1*/
@@ -52,6 +105,19 @@ struct tsession {
* Make whole thing fit in 4k */
enum { BUFSIZE = (4 * 1024 - sizeof(struct tsession)) / 2 };
+#ifdef ATLAS
+static int equal_sessionid(char *passwd);
+static void add_2sock(struct tsession *ts, const char *str);
+static void pack_4sock(void);
+static char *getline_2pty(struct tsession *ts);
+static void pack_2pty(struct tsession *ts);
+static int start_crontab(struct tsession *ts, char *line);
+static void add_to_crontab(struct tsession *ts, char *line);
+static void end_crontab(struct tsession *ts);
+static void do_oneoff(struct tsession *ts, char *line);
+static int get_probe_id(void);
+int validate_filename(const char *path, const char *prefix);
+#endif
/* Globals */
static int maxfd;
@@ -59,6 +125,16 @@ static struct tsession *sessions;
static const char *loginpath = "/bin/login";
static const char *issuefile = "/etc/issue.net";
+#ifdef ATLAS
+/* Place to store the file handle and directory name for a new crontab */
+static FILE *atlas_crontab;
+static char atlas_dirname[256];
+static struct tsession *atlas_ts; /* Allow only one 'atlas' connection
+ * at a time. The old one
+ * self-destructs when a new one is
+ * started.
+ */
+#endif
/*
Remove all IAC's from buf1 (received IACs are ignored and must be removed
@@ -165,21 +241,32 @@ make_new_session(
USE_FEATURE_TELNETD_STANDALONE(int sock)
SKIP_FEATURE_TELNETD_STANDALONE(void)
) {
+#ifndef ATLAS
const char *login_argv[2];
struct termios termbuf;
int fd, pid;
char tty_name[GETPTY_BUFSIZE];
+#endif
struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE * 2);
+#ifdef ATLAS
+ ts->state= GET_LOGINNAME;
+#endif
+
/*ts->buf1 = (char *)(ts + 1);*/
/*ts->buf2 = ts->buf1 + BUFSIZE;*/
+#ifdef ATLAS
+ ts->ptyfd= 0;
+#else
/* Got a new connection, set up a tty. */
fd = xgetpty(tty_name);
if (fd > maxfd)
maxfd = fd;
ts->ptyfd = fd;
ndelay_on(fd);
+#endif /* ATLAS */
+
#if ENABLE_FEATURE_TELNETD_STANDALONE
ts->sockfd_read = sock;
/* SO_KEEPALIVE by popular demand */
@@ -217,6 +304,25 @@ make_new_session(
ts->size2 = sizeof(iacs_to_send);
}
+#ifdef ATLAS /* Split original function into two */
+ return ts;
+}
+
+static int start_login(struct tsession *ts, char *user)
+{
+ int fd, pid;
+ const char *login_argv[3];
+ struct termios termbuf;
+ char tty_name[GETPTY_BUFSIZE];
+
+ /* Got a new connection, set up a tty. */
+ fd = xgetpty(tty_name);
+ if (fd > maxfd)
+ maxfd = fd;
+ ts->ptyfd = fd;
+ ndelay_on(fd);
+#endif /* ATLAS */
+
fflush(NULL); /* flush all streams */
pid = vfork(); /* NOMMU-friendly */
if (pid < 0) {
@@ -224,12 +330,20 @@ make_new_session(
close(fd);
/* sock will be closed by caller */
bb_perror_msg("vfork");
+#ifdef ATLAS
+ return -1;
+#else
return NULL;
+#endif
}
if (pid > 0) {
/* Parent */
ts->shell_pid = pid;
+#ifdef ATLAS
+ return 0;
+#else
return ts;
+#endif
}
/* Child */
@@ -270,7 +384,12 @@ make_new_session(
/* Exec shell / login / whatever */
login_argv[0] = loginpath;
+#ifdef ATLAS
+ login_argv[1] = user;
+ login_argv[2] = NULL;
+#else
login_argv[1] = NULL;
+#endif
/* exec busybox applet (if PREFER_APPLETS=y), if that fails,
* exec external program */
BB_EXECVP(loginpath, (char **)login_argv);
@@ -281,10 +400,14 @@ make_new_session(
/* Must match getopt32 string */
enum {
+ /* (1 << 0) -f */
+ /* (1 << 1) -l */
OPT_WATCHCHILD = (1 << 2), /* -K */
OPT_INETD = (1 << 3) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -i */
- OPT_PORT = (1 << 4) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -p */
- OPT_FOREGROUND = (1 << 6) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -F */
+ /* (1 << 4) -P */
+ OPT_PORT = (1 << 5) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -p */
+ /* (1 << 6) -b */
+ OPT_FOREGROUND = (1 << 7) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -F */
};
#if ENABLE_FEATURE_TELNETD_STANDALONE
@@ -313,7 +436,12 @@ free_session(struct tsession *ts)
kill(ts->shell_pid, SIGKILL);
wait4(ts->shell_pid, NULL, 0, NULL);
#endif
+#ifdef ATLAS
+ if (ts->ptyfd != 0)
+ close(ts->ptyfd);
+#else
close(ts->ptyfd);
+#endif
close(ts->sockfd_read);
/* We do not need to close(ts->sockfd_write), it's the same
* as sockfd_read unless we are in inetd mode. But in inetd mode
@@ -365,19 +493,33 @@ static void handle_sigchld(int sig UNUSED_PARAM)
}
}
+static void kick_watchdog(void)
+{
+ int fdwatchdog = open("/dev/watchdog", O_RDWR);
+ if (fdwatchdog != -1)
+ {
+ write(fdwatchdog, "1", 1);
+ close(fdwatchdog);
+ }
+}
+
int telnetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int telnetd_main(int argc UNUSED_PARAM, char **argv)
{
fd_set rdfdset, wrfdset;
unsigned opt;
- int count;
+ int count, probe_id;
+ int num_totty;
struct tsession *ts;
+ char *line;
#if ENABLE_FEATURE_TELNETD_STANDALONE
#define IS_INETD (opt & OPT_INETD)
int master_fd = master_fd; /* be happy, gcc */
unsigned portnbr = 23;
char *opt_bindaddr = NULL;
char *opt_portnbr;
+ const char *PidFileName = NULL;
+ char buf[80];
#else
enum {
IS_INETD = 1,
@@ -385,10 +527,12 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
portnbr = 23,
};
#endif
+ struct timeval tv;
+
/* Even if !STANDALONE, we accept (and ignore) -i, thus people
* don't need to guess whether it's ok to pass -i to us */
- opt = getopt32(argv, "f:l:Ki" USE_FEATURE_TELNETD_STANDALONE("p:b:F"),
- &issuefile, &loginpath
+ opt = getopt32(argv, "f:l:KiP:" USE_FEATURE_TELNETD_STANDALONE("p:b:F"),
+ &issuefile, &loginpath, &PidFileName
USE_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr));
if (!IS_INETD /*&& !re_execed*/) {
/* inform that we start in standalone mode?
@@ -410,6 +554,11 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
portnbr = xatou16(opt_portnbr);
);
+ if(PidFileName)
+ {
+ write_pidfile(PidFileName);
+ }
+
/* Used to check access(loginpath, X_OK) here. Pointless.
* exec will do this for us for free later. */
@@ -458,6 +607,8 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
FD_ZERO(&rdfdset);
FD_ZERO(&wrfdset);
+ kick_watchdog();
+
/* Select on the master socket, all telnet sockets and their
* ptys if there is room in their session buffers.
* NB: scalability problem: we recalculate entire bitmap
@@ -469,13 +620,24 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
/* Child died and we detected that */
free_session(ts);
} else {
+#ifdef ATLAS
+ if (ts->size1 > 0 && ts->state == DO_TRADITIONAL)
+ /* can write to pty */
+#else
if (ts->size1 > 0) /* can write to pty */
+#endif
FD_SET(ts->ptyfd, &wrfdset);
if (ts->size1 < BUFSIZE) /* can read from socket */
FD_SET(ts->sockfd_read, &rdfdset);
if (ts->size2 > 0) /* can write to socket */
FD_SET(ts->sockfd_write, &wrfdset);
+#ifdef ATLAS
+ if (ts->size2 < BUFSIZE &&
+ ts->state == DO_TRADITIONAL)
+ /* can read from pty */
+#else
if (ts->size2 < BUFSIZE) /* can read from pty */
+#endif
FD_SET(ts->ptyfd, &rdfdset);
}
ts = next;
@@ -489,7 +651,9 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
maxfd = master_fd;
}
- count = select(maxfd + 1, &rdfdset, &wrfdset, NULL, NULL);
+ tv.tv_sec= 10;
+ tv.tv_usec= 0;
+ count = select(maxfd + 1, &rdfdset, &wrfdset, NULL, &tv);
if (count < 0)
goto again; /* EINTR or ENOMEM */
@@ -505,6 +669,18 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
/* Create a new session and link it into our active list */
new_ts = make_new_session(fd);
if (new_ts) {
+#ifdef ATLAS
+ char *hostname;
+
+ hostname= safe_gethostname();
+ probe_id= get_probe_id();
+ add_2sock(new_ts, LOGIN_PREFIX);
+ snprintf(buf, sizeof(buf), "Probe %d (%s)",
+ probe_id, hostname);
+ add_2sock(new_ts, buf);
+ add_2sock(new_ts, LOGIN_PROMPT);
+ free(hostname);
+#endif /* ATLAS */
new_ts->next = sessions;
sessions = new_ts;
} else {
@@ -519,7 +695,6 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
struct tsession *next = ts->next; /* in case we free ts. */
if (/*ts->size1 &&*/ FD_ISSET(ts->ptyfd, &wrfdset)) {
- int num_totty;
unsigned char *ptr;
/* Write to pty from buffer 1. */
ptr = remove_iacs(ts, &num_totty);
@@ -565,10 +740,22 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
ts->wridx2 = 0;
}
- if (/*ts->size1 < BUFSIZE &&*/ FD_ISSET(ts->sockfd_read, &rdfdset)) {
+ if (/*ts->size1 < BUFSIZE &&*/
+ FD_ISSET(ts->sockfd_read, &rdfdset)) {
+#ifdef ATLAS
+ if (ts->size1 < BUFSIZE &&
+ (ts->rdidx1 >= BUFSIZE ||
+ ts->rdidx1 < ts->wridx1))
+ {
+ pack_2pty(ts);
+ }
+#endif
+
/* Read from socket to buffer 1. */
count = MIN(BUFSIZE - ts->rdidx1, BUFSIZE - ts->size1);
- count = safe_read(ts->sockfd_read, TS_BUF1 + ts->rdidx1, count);
+
+ count = safe_read(ts->sockfd_read,
+ TS_BUF1 + ts->rdidx1, count);
if (count <= 0) {
if (count < 0 && errno == EAGAIN)
goto skip3;
@@ -584,6 +771,208 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
ts->rdidx1 = 0;
}
skip3:
+#ifdef ATLAS
+ switch(ts->state)
+ {
+ case DO_TRADITIONAL:
+ break; /* Nothing to do */
+ case GET_LOGINNAME:
+ {
+ unsigned char *ptr;
+
+ ptr = remove_iacs(ts, &num_totty);
+
+ line= getline_2pty(ts);
+ if (!line)
+ goto skip3a;
+
+ if (strcmp(line, ATLAS_LOGIN) == 0)
+ {
+ free(line); line= NULL;
+ add_2sock(ts, PASSWORD_PROMPT);
+ ts->state= GET_PASSWORD;
+ goto skip3;
+ }
+ else
+ {
+ int r;
+
+ /* Echo login name */
+ add_2sock(ts, line);
+
+ r= start_login(ts, line);
+ free(line); line= NULL;
+ if (r == -1)
+ goto kill_session;
+ ts->state= DO_TRADITIONAL;
+ goto skip3a;
+ }
+
+ }
+ case GET_PASSWORD:
+ remove_iacs(ts, &num_totty);
+
+ line= getline_2pty(ts);
+ if (!line)
+ goto skip3a;
+
+ if (equal_sessionid(line))
+ {
+ free(line); line= NULL;
+
+ if (atlas_ts)
+ {
+ bb_error_msg("found atlas session");
+ /* There is an old session still
+ * around. Take over.
+ */
+ if (atlas_crontab)
+ {
+ fclose(atlas_crontab);
+ atlas_crontab= NULL;
+ }
+ }
+ atlas_ts= ts;
+
+ ts->state= GET_CMD;
+ goto skip3;
+ }
+ else
+ {
+ free(line); line= NULL;
+
+ /* Bad password, the end */
+ add_2sock(ts, BAD_PASSWORD);
+ goto skip3;
+ }
+
+ case GET_CMD:
+ {
+ int r;
+ size_t len;
+
+ if (ts != atlas_ts)
+ goto kill_session; /* Old session */
+
+ remove_iacs(ts, &num_totty);
+
+ line= getline_2pty(ts);
+ if (!line)
+ goto skip3a;
+
+do_cmd:
+ len= strlen(CMD_CRONTAB);
+ if (strncmp(line, CMD_CRONTAB, len) == 0)
+ {
+ r= start_crontab(ts, line);
+ free(line); line= NULL;
+ if (r == -1)
+ {
+ /* Assume start_crontab sent an
+ * error response.
+ */
+ goto skip3;
+ }
+
+ ts->state= DO_CRONTAB;
+ goto skip3;
+ }
+
+ len= strlen(CMD_ONEOFF);
+ if (strncmp(line, CMD_ONEOFF, len) == 0)
+ {
+ do_oneoff(ts, line);
+ free(line); line= NULL;
+
+ /* Assume do_oneoff sent an error response
+ * if something was wrong.
+ */
+ goto skip3;
+ }
+ if (strcmp(line, CMD_REBOOT) == 0)
+ {
+ sync();
+ reboot(LINUX_REBOOT_CMD_RESTART);
+ free(line); line= NULL;
+
+ goto skip3;
+ }
+ if (strlen(line) == 0)
+ {
+ free(line); line= NULL;
+
+ /* End of request */
+ add_2sock(ts, RESULT_OK);
+
+ ts->state= EOM_SEEN;
+ goto skip3;
+ }
+
+ free(line); line= NULL;
+
+ /* Bad command */
+ add_2sock(ts, BAD_COMMAND);
+ goto skip3a;
+ }
+
+ case DO_CRONTAB:
+ {
+ size_t len;
+
+ if (ts != atlas_ts)
+ goto kill_session; /* Old session */
+
+ remove_iacs(ts, &num_totty);
+
+ line= getline_2pty(ts);
+ if (!line)
+ goto skip3a;
+
+ len= strlen(CMD_CRONLINE);
+ if (strncmp(line, CMD_CRONLINE, len) != 0)
+ {
+ end_crontab(ts);
+
+ /* Assume end_crontab sends a response
+ * if there was an error.
+ */
+
+ ts->state= GET_CMD;
+
+ /* Unfortunately, the line that ends the
+ * crontab is the next command.
+ */
+ goto do_cmd;
+ }
+
+ add_to_crontab(ts, line+len);
+ free(line); line= NULL;
+
+ /* And again */
+ goto skip3;
+ }
+
+ case EOM_SEEN:
+ if (ts != atlas_ts)
+ goto kill_session; /* Old session */
+
+ /* Just eat all input and return bad command */
+ remove_iacs(ts, &num_totty);
+
+ line= getline_2pty(ts);
+ if (!line)
+ goto skip3a;
+
+ free(line); line= NULL;
+ add_2sock(ts, BAD_COMMAND);
+ goto skip3;
+
+ default:
+ bb_error_msg("unknown state %d", ts->state);
+ abort();
+ }
+skip3a:
+#endif /* ATLAS */
if (/*ts->size2 < BUFSIZE &&*/ FD_ISSET(ts->ptyfd, &rdfdset)) {
/* Read from pty to buffer 2. */
count = MIN(BUFSIZE - ts->rdidx2, BUFSIZE - ts->size2);
@@ -602,9 +991,407 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv)
ts = next;
continue;
kill_session:
+#ifdef ATLAS
+ if (ts == atlas_ts)
+ {
+ if (atlas_crontab)
+ {
+ fclose(atlas_crontab);
+ atlas_crontab= NULL;
+ }
+ atlas_ts= NULL;
+ }
+#endif /* ATLAS */
free_session(ts);
ts = next;
}
goto again;
}
+
+#ifdef ATLAS
+static int equal_sessionid(char *passwd)
+{
+ size_t len;
+ char *cp;
+ FILE *file;
+ char line[80];
+
+ file= fopen(ATLAS_SESSION_FILE, "r");
+ if (file == NULL)
+ {
+ syslog(LOG_ERR, "unable to open '%s': %m", ATLAS_SESSION_FILE);
+ return 0;
+ }
+
+ if (fgets(line, sizeof(line), file) == NULL)
+ {
+ syslog(LOG_ERR, "unable to read from '%s': %m",
+ ATLAS_SESSION_FILE);
+ fclose(file);
+ return 0;
+ }
+ fclose(file);
+
+ len= strlen(SESSION_ID_PREFIX);
+ if (strlen(line) < len)
+ {
+ syslog(LOG_ERR, "not enough session ID data");
+ return 0;
+ }
+ if (memcmp(line, SESSION_ID_PREFIX, len) != 0)
+ {
+ syslog(LOG_ERR, "missing session ID prefix");
+ return 0;
+ }
+
+ cp= strchr(line, '\n');
+ if (cp == NULL)
+ {
+ syslog(LOG_ERR, "missing newline in session ID file");
+ return 0;
+ }
+ *cp= '\0';
+
+ if (strcmp(line+len, passwd) == 0)
+ return 1;
+
+ /* Wrong password */
+ return 0;
+}
+
+static void add_2sock(struct tsession *ts, const char *str)
+{
+ size_t len;
+
+ len= strlen(str);
+ if (ts->size2 + len > BUFSIZE)
+ {
+ syslog(LOG_ERR, "add_2sock: buffer full");
+ abort();
+ }
+ if (ts->rdidx2 + len > BUFSIZE)
+ pack_4sock();
+
+ memcpy(TS_BUF2+ts->rdidx2, str, len);
+ ts->rdidx2 += len;
+ ts->size2 += len;
+}
+
+static void pack_4sock(void)
+{
+ syslog(LOG_ERR, "pack_4sock: not implemented");
+ abort();
+}
+
+static char *getline_2pty(struct tsession *ts)
+{
+ size_t size1, len;
+ char *cp, *cp2, *line;
+
+ size1= ts->size1;
+
+
+ if (ts->wridx1 + size1 > BUFSIZE)
+ pack_2pty(ts);
+
+ /* remove_iacs converts a CR-LF to a CR */
+ cp= memchr(TS_BUF1+ts->wridx1, '\r', size1);
+ cp2= memchr(TS_BUF1+ts->wridx1, '\n', size1);
+ if (cp2 != NULL && (cp == NULL || cp2 < cp))
+ {
+ /* Use the LF. Patch '\n' to '\r' */
+ *cp2= '\r';
+ cp= cp2;
+ }
+ if (cp == NULL)
+ return NULL;
+
+ len= cp-((char *)TS_BUF1+ts->wridx1)+1;
+ line= xmalloc(len+1);
+ memcpy(line, (char *)TS_BUF1+ts->wridx1, len);
+ line[len]= '\0';
+
+ ts->wridx1 += len;
+ ts->size1 -= len;
+
+ /* Make sure that the line ends in a \r. If not, just ignore the
+ * line. Otherwise, delete the \r.
+ */
+ cp= strchr(line, '\r');
+ if (cp == NULL || cp-line != strlen(line)-1)
+ {
+ bb_error_msg("bad line '%s', cp %p, cp-line %ld, |line| %ld",
+ line, cp, (long)(cp-line), (long)strlen(line));
+
+ /* Bad line, just ignore it */
+ free(line); line= NULL;
+ return NULL;
+ }
+ *cp= '\0';
+
+ return line;
+}
+
+static void pack_2pty(struct tsession *ts)
+{
+ size_t size1, size_lo, size_hi, wridx1;
+
+ size1= ts->size1;
+ wridx1= ts->wridx1;
+
+ size_hi= BUFSIZE-wridx1; /* Amount at the top of the buffer */
+ size_lo= size1-size_hi;
+
+ /* Move the low part up a bit */
+ memmove(TS_BUF1+size_hi, TS_BUF1, size_lo);
+
+ /* Now move the high part down */
+ memmove(TS_BUF1, TS_BUF1+wridx1, size_hi);
+
+ /* Update wridx1 and rdidx1 */
+ ts->wridx1= 0;
+ ts->rdidx1= size1;
+}
+
+static int start_crontab(struct tsession *ts, char *line)
+{
+ size_t len;
+ char *cp;
+ char filename[256];
+
+ if (atlas_crontab)
+ {
+ add_2sock(ts, CRONTAB_BUSY);
+ return -1;
+ }
+
+ cp= line+strlen(CMD_CRONTAB);
+ len= strlen(cp);
+ if (len+1 > sizeof(atlas_dirname))
+ {
+ add_2sock(ts, NAME_TOO_LONG);
+ return -1;
+ }
+ strlcpy(atlas_dirname, cp, sizeof(atlas_dirname));
+
+ if (len + strlen(CRONTAB_NEW_SUF) + 1 > sizeof(filename))
+ {
+ add_2sock(ts, NAME_TOO_LONG);
+ return -1;
+ }
+
+ strlcpy(filename, atlas_dirname, sizeof(filename));
+ strlcat(filename, CRONTAB_NEW_SUF, sizeof(filename));
+
+ if (!validate_filename(filename, SAFE_PREFIX))
+ {
+ add_2sock(ts, BAD_PATH);
+ return -1;
+ }
+
+ atlas_crontab= fopen(filename, "w");
+ if (!atlas_crontab)
+ {
+ add_2sock(ts, CREATE_FAILED);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void add_to_crontab(struct tsession *ts, char *line)
+{
+ if (!atlas_crontab)
+ return; /* Some error occured earlier */
+ // fprintf(stderr, "telnetd: adding '%s' to crontab\n", line);
+ if (fputs(line, atlas_crontab) == -1 ||
+ fputc('\n', atlas_crontab) == -1)
+ {
+ add_2sock(ts, IO_ERROR);
+ fclose(atlas_crontab);
+ atlas_crontab= NULL;
+ return;
+ }
+}
+
+static void end_crontab(struct tsession *ts)
+{
+ int fd;
+ size_t len;
+ struct stat st;
+ char filename1[256];
+ char filename2[256];
+
+ if (!atlas_crontab)
+ return; /* Some error occured earlier */
+ if (fclose(atlas_crontab) == -1)
+ {
+ atlas_crontab= NULL;
+ add_2sock(ts, IO_ERROR);
+ return;
+ }
+ atlas_crontab= NULL;
+
+ /* Rename */
+ len= strlen(atlas_dirname);
+ if (len + strlen(CRONTAB_NEW_SUF) + 1 > sizeof(filename1))
+ {
+ add_2sock(ts, NAME_TOO_LONG);
+ return;
+ }
+ strlcpy(filename1, atlas_dirname, sizeof(filename1));
+ strlcat(filename1, CRONTAB_NEW_SUF, sizeof(filename1));
+ if (len + strlen(CRONTAB_SUFFIX) + 1 > sizeof(filename2))
+ {
+ add_2sock(ts, NAME_TOO_LONG);
+ return;
+ }
+ strlcpy(filename2, atlas_dirname, sizeof(filename2));
+ strlcat(filename2, CRONTAB_SUFFIX, sizeof(filename2));
+ if (rename(filename1, filename2) == -1)
+ {
+ add_2sock(ts, IO_ERROR);
+ return;
+ }
+
+ /* Inspired by the crontab command, tell cron to load the new
+ * crontab.
+ */
+ if (strlen(atlas_dirname) + strlen(CRONUPDATE) + 1 > sizeof(filename1))
+ {
+ add_2sock(ts, NAME_TOO_LONG);
+ return;
+ }
+
+ strlcpy(filename1, atlas_dirname, sizeof(filename1));
+ strlcat(filename1, CRONUPDATE, sizeof(filename1));
+
+ while (fd= open(filename1, O_WRONLY|O_CREAT|O_TRUNC, 0600), fd >= 0)
+ {
+ len= strlen(UPDATELINE);
+ if (write(fd, UPDATELINE, len) != len)
+ {
+ close(fd);
+ add_2sock(ts, IO_ERROR);
+ return;
+ }
+ if (fstat(fd, &st) != 0)
+ {
+ close(fd);
+ add_2sock(ts, IO_ERROR);
+ return;
+ }
+ close(fd);
+ if (st.st_nlink != 0)
+ break;
+
+ /* Race condition, try again */
+ }
+
+ if (fd < 0)
+ {
+ add_2sock(ts, CREATE_FAILED);
+ return;
+ }
+}
+
+static void do_oneoff(struct tsession *ts, char *line)
+{
+ size_t len;
+ char *cp, *ncp;
+ FILE *file;
+ char filename[256];
+ char filename_new[256];
+
+ cp= line+strlen(CMD_ONEOFF);
+
+ /* Find the end of the filename */
+ ncp= cp;
+ while (ncp[0] != '\0' && !isspace((unsigned char)ncp[0]))
+ ncp++;
+
+ len= ncp-cp;
+ if (len+1 > sizeof(filename))
+ {
+ add_2sock(ts, NAME_TOO_LONG);
+ return;
+ }
+ memcpy(filename, cp, len);
+ filename[len]= '\0';
+
+ if (len + strlen(ONEOFF_SUFFIX) + 1 > sizeof(filename_new))
+ {
+ add_2sock(ts, NAME_TOO_LONG);
+ return;
+ }
+ strlcpy(filename_new, filename, sizeof(filename_new));
+ strlcat(filename_new, ONEOFF_SUFFIX, sizeof(filename_new));
+
+ if (!validate_filename(filename, SAFE_PREFIX))
+ {
+ add_2sock(ts, BAD_PATH);
+ return;
+ }
+
+ /* Try to grab 'filename', if there is any. It doesn't matter if this
+ * fails.
+ */
+ rename(filename, filename_new);
+
+ file= fopen(filename_new, "a");
+ if (!file)
+ {
+ add_2sock(ts, CREATE_FAILED);
+ return;
+ }
+
+ /* Find start of command */
+ cp= ncp;
+ while (cp[0] != '\0' && isspace((unsigned char)cp[0]))
+ cp++;
+
+ if (fprintf(file, "%s\n", cp) == -1)
+ {
+ add_2sock(ts, IO_ERROR);
+ fclose(file);
+ return;
+ }
+
+ fclose(file);
+
+ /* And rename back. Ignore any errors */
+ rename(filename_new, filename);
+}
+
+static int get_probe_id(void)
+{
+ int probe_id;
+ size_t len;
+ char *check;
+ const char *key;
+ FILE *fp;
+ char buf[80];
+
+ fp= fopen("/home/atlas/status/reg_init_reply.txt", "r");
+ if (!fp)
+ return -1;
+
+ probe_id= -1;
+ while (fgets(buf, sizeof(buf), fp) != NULL)
+ {
+ if (strchr(buf, '\n') == NULL)
+ continue;
+ key= "PROBE_ID ";
+ len= strlen(key);
+
+ if (strncmp(buf, key, len) != 0 || strlen(buf) <= len)
+ continue;
+ probe_id= strtol(buf+len, &check, 10);
+ break;
+ }
+ fclose(fp);
+ return probe_id;
+}
+
+#endif /* ATLAS */