Created
January 31, 2017 15:15
-
-
Save mclarkson/200a3ce77a308f294947de0ee290c1f8 to your computer and use it in GitHub Desktop.
The mailsender binary used in nagrestconf
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* gcc -static -o ~/mailsender mailsender.c | |
sudo dnf install glibc-static.i686 | |
# 32 bit build | |
gcc -m32 -static -o mailsender mailsender.c | |
*/ | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <sys/socket.h> | |
#include <arpa/inet.h> | |
#include <netdb.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <stdarg.h> | |
#include <time.h> | |
#include <ctype.h> | |
#include <fcntl.h> | |
#include <syslog.h> | |
#include <errno.h> | |
#include <signal.h> | |
#define MAXLINE 4092 | |
#define TRUE 1 | |
#define FALSE 0 | |
#define SA struct sockaddr | |
#define LISTENQ 128 | |
int daemon_proc = FALSE; | |
int nofile = 0; | |
/////////////////////////////////////////////////////////////////////////////////// | |
/* | |
* Print a message and return to caller. | |
* Caller specifies 'errnoflag' and 'level'. | |
*/ | |
static void err_doit(int errnoflag, int level, const char* fmt, va_list ap) | |
{ | |
int errno_save, n; | |
char buf[MAXLINE + 1]; | |
errno_save = errno; | |
vsnprintf(buf, MAXLINE, fmt, ap); | |
n = strlen(buf); | |
if (errnoflag) | |
snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save)); | |
strcat(buf, "\n"); | |
if(daemon_proc) | |
{ | |
syslog(level, buf); | |
} | |
else | |
{ | |
fflush(stdout); | |
fputs(buf, stderr); | |
fflush(stderr); | |
} | |
return; | |
} | |
/* | |
* Fatal error related to a system call. | |
* Print a message then terminate. | |
*/ | |
void err_sys(const char* fmt, ...) | |
{ | |
va_list ap; | |
va_start(ap,fmt); | |
err_doit(1, LOG_ERR, fmt, ap); | |
va_end(ap); | |
exit(1); | |
} | |
/////////////////////////////////////////////////////////////////////////////////// | |
int Socket(int family, int type, int protocol) | |
{ | |
int retval; | |
if ( (retval=socket(family, type, protocol)) < 0 ) | |
err_sys("socket error. Family:%d,Type:%d,Protocol:%d",family,type,protocol); | |
return (retval); | |
} | |
void Connect(int fd, struct sockaddr *sockaddr, socklen_t struct_size) | |
{ | |
if ( (connect(fd, sockaddr, struct_size) < 0 ) ) | |
err_sys("connect error"); | |
} | |
void Bind(int fd, struct sockaddr *sockaddr, socklen_t struct_size) | |
{ | |
if ( (bind(fd, sockaddr, struct_size) < 0 ) ) | |
err_sys("bind error"); | |
} | |
void Listen(int fd, int backlog) | |
{ | |
if ( (listen(fd, backlog) < 0 ) ) | |
err_sys("listen error"); | |
} | |
int Accept(int fd, struct sockaddr *sockaddr, socklen_t *struct_size) | |
{ | |
int retval; | |
if ( (retval=accept(fd, sockaddr, struct_size)) < 0 ) | |
err_sys("accept error"); | |
return (retval); | |
} | |
void Close(int fd) | |
{ | |
if ( close(fd) < 0 ) | |
err_sys("close error"); | |
} | |
/////////////////////////////////////////////////////////////////////////////////// | |
ssize_t readn(int fd, void *vptr, size_t n) | |
{ | |
size_t nleft; | |
ssize_t nread; | |
char *ptr; | |
ptr = vptr; | |
nleft = n; | |
while (nleft > 0) { | |
if ( (nread = read(fd, ptr, nleft)) < 0) { | |
if (errno == EINTR) | |
nread = 0; /* and call read again */ | |
else | |
return (-1); | |
} else if (nread == 0) | |
break; /* end of file */ | |
nleft -= nread; | |
ptr += nread; | |
} | |
return (n - nleft); | |
} | |
/* | |
static ssize_t my_read(int fd, char *ptr) | |
{ | |
static int read_cnt = 0; | |
static char *read_ptr; | |
static char read_buf[MAXLINE]; | |
if (read_cnt <= 0) { | |
again: | |
if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) { | |
if (errno == EINTR) | |
goto again; | |
return (-1); | |
} else if (read_cnt == 0) | |
return (0); | |
read_ptr = read_buf; | |
} | |
read_cnt--; | |
*ptr = *read_ptr++; | |
return (1); | |
}*/ | |
ssize_t readline(int fd, void *vptr, size_t maxlen) | |
{ | |
ssize_t n, rc; | |
char c, *ptr; | |
ptr = vptr; | |
for (n=1; n < maxlen; n++) { | |
if ( (rc = read(fd, &c, 1)) == 1) { | |
if (c == '\n') | |
break; /* newline is not stored, unlike fgets() */ | |
*ptr++ = c; | |
} else if (rc == 0) { | |
if (n == 1) | |
return (0); /* EOF, no data read */ | |
else | |
break; /* EOF, some data was read */ | |
} else | |
return (-1); /* error, errno set by read */ | |
} | |
/* Add crnl */ | |
*ptr = '\n'; | |
*(++ptr) = 0; /* null terminate like fgets() */ | |
return (n); | |
} | |
/////////////////////////////////////////////////////////////////////////////////// | |
int Write(int fd, char *buf, int buf_size) | |
{ | |
int n; | |
if ( (n = write(fd, buf, buf_size)) < 0) | |
err_sys("write error"); | |
return (n); | |
} | |
ssize_t writen(int fd, const void *vptr, size_t n) | |
{ | |
size_t nleft; | |
ssize_t nwritten; | |
const char *ptr; | |
ptr = vptr; | |
nleft = n; | |
while (nleft > 0) { | |
if ( (nwritten = write(fd, ptr, nleft)) < 0 ) { | |
if (errno == EINTR) | |
nwritten = 0; | |
else | |
return (-1); | |
} | |
nleft -= nwritten; | |
ptr += nwritten; | |
} | |
return (n); | |
} | |
/////////////////////////////////////////////////////////////////////////////////// | |
#define DATA 1 | |
#define COMMAND 2 | |
#define COMMANDTRANS 3 | |
#define DATATRANS 4 | |
struct _commands { | |
char *command; | |
int type; | |
} commands[] = { | |
{"DATA\r", DATATRANS}, | |
{".\r" , COMMANDTRANS}, | |
}; | |
#define NUM_COMMANDS sizeof(commands)/sizeof(command) | |
int write_file_to_network( int sockfd, char* filename ) | |
{ | |
int fd; | |
int nc; | |
int STATE=COMMAND; | |
char buf[MAXLINE+1]; | |
char wbuf[MAXLINE+1]; | |
int waiting_for_dot = 0; | |
if ( nofile ) | |
fd = 0; | |
else | |
fd = open (filename, O_RDONLY); | |
while ( (nc = readline (fd, wbuf, sizeof (buf))) ) | |
{ | |
int res; | |
wbuf[nc] = 0; | |
buf[nc] = 0; | |
printf( "SEND > %s", wbuf ); fflush(stdout); | |
if (writen (sockfd, (void *) wbuf, nc) < 0) | |
err_sys ("writen"); | |
res = strncmp( ".\r\n", wbuf, 3 ); | |
if( res == 0 ) { | |
close (fd); | |
return 0; | |
} | |
res = strncmp( ".\n", wbuf, 3 ); | |
if( res == 0 ) { | |
close (fd); | |
return 0; | |
} | |
if ( ! waiting_for_dot ) | |
{ | |
int res; | |
res = strncasecmp( "DATA\r", wbuf, 5 ); | |
if( res == 0 ) | |
{ | |
STATE=DATATRANS; | |
waiting_for_dot = 1; | |
} | |
} else | |
{ | |
int res; | |
res = strncmp( ".\r", wbuf, 2 ); | |
if( res == 0 ) | |
{ | |
STATE=COMMANDTRANS; | |
waiting_for_dot = 0; | |
} | |
} | |
switch( STATE ) | |
{ | |
int res; | |
case COMMANDTRANS: | |
again1: | |
nc = readline( sockfd, buf, sizeof(buf) ); | |
printf( "RECV > %s", buf ); fflush(stdout); | |
res = strncmp( "5", buf, 1 ); | |
if( res == 0 ) return 1; | |
if( buf[3] == '-' ) goto again1; | |
STATE = COMMAND; | |
break; | |
case DATATRANS: | |
again2: | |
nc = readline( sockfd, buf, sizeof(buf) ); | |
printf( "RECV > %s", buf ); fflush(stdout); | |
res = strncmp( "4", buf, 1 ); | |
if( res == 0 ) return 1; | |
res = strncmp( "5", buf, 1 ); | |
if( res == 0 ) return 1; | |
if( buf[3] == '-' ) goto again2; | |
STATE = DATA; | |
break; | |
case COMMAND: | |
again3: | |
nc = readline( sockfd, buf, sizeof(buf) ); | |
printf( "RECV > %s", buf ); fflush(stdout); | |
res = strncmp( "5", buf, 1 ); | |
if( buf[3] == '-' ) goto again3; | |
if( res == 0 ) return 1; | |
break; | |
case DATA: | |
break; | |
default: | |
break; | |
} | |
} | |
close (fd); | |
return 0; | |
} | |
void usage() | |
{ | |
printf("mailsender <host | ipaddr> <file name>\n"); | |
} | |
int main (int argc, char **argv) | |
{ | |
int sockfd, n; | |
char recvline[MAXLINE + 1]; | |
struct sockaddr_in servaddr; | |
int res; | |
char filename[MAXLINE]; | |
struct hostent *he; | |
if( argc != 3 ){ | |
usage(); | |
exit(0); | |
} | |
sockfd = Socket (AF_INET, SOCK_STREAM, 0); | |
bzero (&servaddr, sizeof (servaddr)); | |
servaddr.sin_family = AF_INET; | |
servaddr.sin_port = htons (25); | |
he = gethostbyname( argv[1] ); | |
if(he == 0) { | |
printf("Name not found.\n"); | |
exit (2); | |
} | |
memcpy(&servaddr.sin_addr, he->h_addr, 4); | |
printf("Connecting to %s (%s)\n" | |
,he->h_name | |
,inet_ntoa( servaddr.sin_addr )); | |
//if (inet_aton ( he->h_addr, &servaddr.sin_addr) <= 0) | |
//{ | |
// fprintf (stderr, "inet_aton error for %s\n", argv[1]); | |
// exit (1); | |
//} | |
if ( *argv[2] == '-' ) | |
nofile = 1; | |
else | |
nofile = 0; | |
strcpy( filename, argv[2]); | |
Connect (sockfd, (SA *) & servaddr, sizeof (servaddr)); | |
/* SOCKET CONNECTED */ | |
/* READ WELCOME BANNER */ | |
n = readline (sockfd, recvline, MAXLINE); | |
printf( "RECV > %s", recvline ); | |
/* Send the file using state machine */ | |
res = write_file_to_network( sockfd, filename ); | |
/*Write (sockfd, helo, strlen (helo)); | |
bzero (buf, sizeof (buf)); | |
if ((ret = readline (sockfd, buf, MAXLINE)) == 0) | |
printf ("read returned no data"); | |
else if (ret == -1)*/ | |
Close (sockfd); | |
exit (res); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment