picolisp

Unnamed repository; edit this file to name it for gitweb.
git clone https://logand.com/git/picolisp.git/
Log | Files | Refs | README | LICENSE

ssl.c (6806B)


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