diff options
Diffstat (limited to 'networking/telnetd.c')
-rw-r--r-- | networking/telnetd.c | 805 |
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 */ |