mplisp

miniPicoLisp with FFI and modules for Buddy BDD library, OpenGL, Gtk and GMP
git clone https://logand.com/git/mplisp.git/
Log | Files | Refs

ssl.c (7024B)


      1 /* 06sep07abu
      2  * (c) Software Lab. Alexander Burger
      3  */
      4 
      5 #include <stdio.h>
      6 #include <stdlib.h>
      7 #include <unistd.h>
      8 #include <fcntl.h>
      9 #include <dirent.h>
     10 #include <errno.h>
     11 #include <string.h>
     12 #include <signal.h>
     13 #include <netdb.h>
     14 #include <sys/stat.h>
     15 #include <sys/socket.h>
     16 #include <arpa/inet.h>
     17 #include <netinet/tcp.h>
     18 #include <netinet/in.h>
     19 #include <syslog.h>
     20 
     21 #include <openssl/pem.h>
     22 #include <openssl/ssl.h>
     23 #include <openssl/err.h>
     24 
     25 typedef enum {NO,YES} bool;
     26 
     27 static char *File, *Dir, *Data;
     28 static off_t Size;
     29 static bool Log;
     30 
     31 static char Get[] =
     32    "GET /%s HTTP/1.0\r\n"
     33    "User-Agent: PicoLisp\r\n"
     34    "Host: %s:%s\r\n"
     35    "Accept-Charset: utf-8\r\n\r\n";
     36 
     37 static void logger(char *msg) {
     38    if (Log)
     39       syslog(LOG_ERR, "%s", msg);
     40    else
     41       fprintf(stderr, "ssl: %s\n", msg);
     42 }
     43 
     44 static void giveup(char *msg) {
     45    logger(msg);
     46    exit(1);
     47 }
     48 
     49 static void sslChk(int n) {
     50    if (n < 0) {
     51       ERR_print_errors_fp(stderr);
     52       exit(1);
     53    }
     54 }
     55 
     56 static int sslConnect(SSL *ssl, char *host, int port) {
     57    struct sockaddr_in addr;
     58    struct hostent *p;
     59    int sd;
     60 
     61    memset(&addr, 0, sizeof(addr));
     62    if ((long)(addr.sin_addr.s_addr = inet_addr(host)) == -1) {
     63       if (!(p = gethostbyname(host))  ||  p->h_length == 0)
     64          return -1;
     65       addr.sin_addr.s_addr = ((struct in_addr*)p->h_addr_list[0])->s_addr;
     66    }
     67 
     68    if ((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
     69       logger("No socket");
     70       return -1;
     71    }
     72    addr.sin_family = AF_INET;
     73    addr.sin_port = htons((unsigned short)port);
     74    if (connect(sd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
     75       close(sd);
     76       return -1;
     77    }
     78 
     79    SSL_set_fd(ssl,sd);
     80    if (SSL_connect(ssl) >= 0)
     81       return sd;
     82    close(sd);
     83    return -1;
     84 }
     85 
     86 static void sslClose(SSL *ssl, int sd) {
     87    SSL_shutdown(ssl);
     88    close(sd);
     89 }
     90 
     91 static bool sslFile(SSL *ssl, char *file) {
     92    int fd, n;
     93    char buf[BUFSIZ];
     94 
     95    if (file[0] == '-')
     96       return SSL_write(ssl, file+1, strlen(file)-1) >= 0;
     97    if ((fd = open(file, O_RDONLY)) < 0)
     98       return NO;
     99    while ((n = read(fd, buf, sizeof(buf))) > 0)
    100       if (SSL_write(ssl, buf, n) < 0) {
    101          close(fd);
    102          return NO;
    103       }
    104    close(fd);
    105    return n == 0;
    106 }
    107 
    108 static void doSigTerm(int n __attribute__((unused))) {
    109    int fd1, fd2, cnt;
    110    char buf[BUFSIZ];
    111 
    112    if (Data  &&  (fd1 = open(File, O_RDWR)) >= 0) {
    113       if (unlink(File) < 0)
    114          giveup("Can't unlink back");
    115       if ((fd2 = open(File, O_CREAT|O_WRONLY|O_TRUNC, 0666)) < 0)
    116          giveup("Can't create back");
    117       if (write(fd2, Data, Size) != Size)
    118          giveup("Can't write back");
    119       while ((cnt = read(fd1, buf, sizeof(buf))) > 0)
    120          write(fd2, buf, cnt);
    121    }
    122    exit(0);
    123 }
    124 
    125 // ssl host port url
    126 // ssl host port url file
    127 // ssl host port url key file
    128 // ssl host port url key file dir sec
    129 int main(int ac, char *av[]) {
    130    SSL_CTX *ctx;
    131    SSL *ssl;
    132    bool bin;
    133    int n, sec, getLen, lenLen, fd, sd;
    134    DIR *dp;
    135    struct dirent *p;
    136    struct stat st;
    137    struct flock fl;
    138    char get[1024], buf[4096], nm[4096], len[64];
    139 
    140    if (!(ac >= 4 && ac <= 6  ||  ac == 8))
    141       giveup("host port url [[key] file] | host port url key file dir sec");
    142    if (strlen(Get)+strlen(av[1])+strlen(av[2])+strlen(av[3]) >= sizeof(get))
    143       giveup("Names too long");
    144    if (strchr(av[3],'/'))
    145       bin = NO,  getLen = sprintf(get, Get, av[3], av[1], av[2]);
    146    else
    147       bin = YES,  getLen = sprintf(get, "@%s ", av[3]);
    148 
    149    SSL_library_init();
    150    SSL_load_error_strings();
    151    if (!(ctx = SSL_CTX_new(SSLv23_client_method()))) {
    152       ERR_print_errors_fp(stderr);
    153       giveup("SSL init");
    154    }
    155    ssl = SSL_new(ctx);
    156 
    157    if (ac <= 6) {
    158       if (sslConnect(ssl, av[1], atoi(av[2])) < 0) {
    159          logger("Can't connect");
    160          return 1;
    161       }
    162       sslChk(SSL_write(ssl, get, getLen));
    163       if (ac > 4) {
    164          if (*av[4]  &&  !sslFile(ssl,av[4]))
    165             giveup(av[4]);
    166          if (ac > 5  &&  *av[5]  &&  !sslFile(ssl,av[5]))
    167             giveup(av[5]);
    168       }
    169       while ((n = SSL_read(ssl, buf, sizeof(buf))) > 0)
    170          write(STDOUT_FILENO, buf, n);
    171       return 0;
    172    }
    173 
    174    signal(SIGCHLD,SIG_IGN);  /* Prevent zombies */
    175    if ((n = fork()) < 0)
    176       giveup("detach");
    177    if (n)
    178       return 0;
    179    setsid();
    180 
    181    openlog("ssl", LOG_CONS|LOG_PID, 0);
    182    Log = YES;
    183    File = av[5];
    184    Dir = av[6];
    185    sec = atoi(av[7]);
    186    signal(SIGINT, doSigTerm);
    187    signal(SIGTERM, doSigTerm);
    188    signal(SIGPIPE, SIG_IGN);
    189    for (;;) {
    190       if (*File && (fd = open(File, O_RDWR)) >= 0) {
    191          if (fstat(fd,&st) < 0  ||  st.st_size == 0)
    192             close(fd);
    193          else {
    194             fl.l_type = F_WRLCK;
    195             fl.l_whence = SEEK_SET;
    196             fl.l_start = 0;
    197             fl.l_len = 0;
    198             if (fcntl(fd, F_SETLKW, &fl) < 0)
    199                giveup("Can't lock");
    200             if (fstat(fd,&st) < 0  ||  (Size = st.st_size) == 0)
    201                giveup("Can't access");
    202             lenLen = sprintf(len, "%lld\n", Size);
    203             if ((Data = malloc(Size)) == NULL)
    204                giveup("Can't alloc");
    205             if (read(fd, Data, Size) != Size)
    206                giveup("Can't read");
    207             if (ftruncate(fd,0) < 0)
    208                logger("Can't truncate");
    209             close(fd);
    210             for (;;) {
    211                if ((sd = sslConnect(ssl, av[1], atoi(av[2]))) >= 0) {
    212                   if (SSL_write(ssl, get, getLen) == getLen  &&
    213                            (!*av[4] || sslFile(ssl,av[4]))  &&                   // key
    214                            (bin || SSL_write(ssl, len, lenLen) == lenLen)  &&    // length
    215                            SSL_write(ssl, Data, Size) == Size  &&                // data
    216                            SSL_write(ssl, bin? "\0" : "T", 1) == 1  &&           // ack
    217                            SSL_read(ssl, buf, 1) == 1  &&  buf[0] == 'T' ) {
    218                      sslClose(ssl,sd);
    219                      break;
    220                   }
    221                   sslClose(ssl,sd);
    222                   logger("Transmit failed");
    223                }
    224                sleep(sec);
    225                logger("Try to retransmit");
    226             }
    227             free(Data),  Data = NULL;
    228          }
    229       }
    230       if (*Dir && (dp = opendir(Dir))) {
    231          while (p = readdir(dp)) {
    232             if (p->d_name[0] != '.') {
    233                snprintf(nm, sizeof(nm), "%s%s", Dir, p->d_name);
    234                if ((n = readlink(nm, buf, sizeof(buf))) > 0  &&
    235                         (sd = sslConnect(ssl, av[1], atoi(av[2]))) >= 0 ) {
    236                   if (SSL_write(ssl, get, getLen) == getLen  &&
    237                         (!*av[4] || sslFile(ssl,av[4]))  &&          // key
    238                         (bin || SSL_write(ssl, buf, n) == n)  &&     // path
    239                         (bin || SSL_write(ssl, "\n", 1) == 1)  &&    // nl
    240                         sslFile(ssl, nm) )                           // file
    241                      unlink(nm);
    242                   sslClose(ssl,sd);
    243                }
    244             }
    245          }
    246          closedir(dp);
    247       }
    248       sleep(sec);
    249    }
    250 }