Skip to content

Instantly share code, notes, and snippets.

@mclarkson
Created January 31, 2017 15:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mclarkson/200a3ce77a308f294947de0ee290c1f8 to your computer and use it in GitHub Desktop.
Save mclarkson/200a3ce77a308f294947de0ee290c1f8 to your computer and use it in GitHub Desktop.
The mailsender binary used in nagrestconf
/* 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