"Fossies" - the Fresh Open Source Software Archive

Member "rgdbm-2.1.42/sock.c" (20 Jun 2007, 13259 Bytes) of package /linux/privat/old/rgdbm-2.1.42.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "sock.c" see the Fossies "Dox" file reference documentation.

    1 #include "config.h"
    2 
    3 #if STDC_HEADERS
    4 # include <stdlib.h>
    5 # include <stdarg.h>
    6 # include <string.h>
    7 #else
    8 # ifndef HAVE_STRCHR
    9 #  define strchr index
   10 #  define strrchr rindex
   11 # endif
   12 char *strchr (), *strrchr ();
   13 # ifndef HAVE_MEMCPY
   14 #  define memcpy(d, s, n) bcopy ((s), (d), (n))
   15 #  define memmove(d, s, n) bcopy ((s), (d), (n))
   16 # endif
   17 #endif          /* STDC_HEADERS */
   18 #ifdef HAVE_UNISTD_H
   19 # include <unistd.h>
   20 #endif /* HAVE_UNISTD_H */
   21 #include <fcntl.h>      /* for F_SETFL */
   22 
   23 #include <errno.h>      /* for EINVAL etc */
   24 #include <signal.h>     /* for SIGPIPE */
   25 #include <sys/socket.h> /* for struct linger, shutdown */
   26 
   27 
   28 #ifdef HAVE_UNISTD_H
   29 # include <unistd.h>
   30 #endif /* HAVE_UNISTD_H */
   31 #ifdef HAVE_OPENSSL_SSL_H
   32 #include <openssl/ssl.h>
   33 #include <openssl/bio.h>
   34 #include <openssl/x509.h>
   35 #include <openssl/err.h>
   36 #endif /* defined(HAVE_OPENSSL_SSL_H) */
   37 
   38 #ifdef HAVE_GDBM_H         /* won't get far without gdbm.h */
   39 # include <gdbm.h>
   40 #elif defined(HAVE_NDBM_H) /* worth checking for ndbm too */
   41 # include <ndbm.h>
   42 #elif defined(HAVE_DBM_H)  /* even worth checking for dbm */
   43 # include <dbm.h>
   44 #endif
   45 
   46 #include "rgdbm.h"
   47 #include "io.h"
   48 #include "sock.h"
   49 
   50 #ifdef HAVE_OPENSSL_SSL_H
   51 static SSL_CTX *ssl_ctx = NULL;
   52 #endif /* defined(HAVE_OPENSSL_SSL_H) */
   53 
   54 #if defined(HAVE_OPENSSL_SSL_H)
   55 /*
   56  * Set up the (server's) certificate file, and its key 
   57  */
   58 static int
   59 ssl_set_cert_stuff (SSL_CTX * ctx, char *cert_file, char *key_file)
   60 {
   61     int err;
   62 
   63     //fprintf (stderr, "  certificate file=\"%s\"\n", cert_file);
   64     //fprintf (stderr, "  key file=\"%s\"\n", key_file);
   65 
   66     if (!cert_file)
   67         return 0;
   68 
   69     err = SSL_CTX_use_certificate_file (ctx, cert_file, SSL_FILETYPE_PEM);
   70     if (err != 1) {
   71         fprintf (stderr,  "unable to get certificate from '%s' (%d)\n",
   72             cert_file, err);
   73         ERR_print_errors_fp(stderr);
   74         return -EINVAL;
   75     }
   76 
   77     if (!key_file)
   78         key_file = cert_file;
   79 
   80     err = SSL_CTX_use_PrivateKey_file (ctx, key_file, SSL_FILETYPE_PEM);
   81     if (err != 1) {
   82         fprintf (stderr,  "unable to get private key from '%s' (%d)\n",
   83             key_file, err);
   84         ERR_print_errors_fp(stderr);
   85         return -EINVAL;
   86     }
   87 
   88     /* If we are using DSA, we can copy the parameters from
   89      * the private key */
   90 
   91     /* Now we know that a key and cert have been set against
   92      * the SSL context */
   93     err = SSL_CTX_check_private_key (ctx);
   94     if (err != 1) {
   95         fprintf (stderr, "Private key does not match the certificate public key (%d)\n", err);
   96         ERR_print_errors_fp(stderr);
   97         return -EINVAL;
   98     }
   99     return 0;
  100 }
  101 
  102 /*
  103  * this appears to be in the path of each verification, successful or not.
  104  * I've set it to ignore depth errors, I think.
  105  */
  106 static int
  107 ssl_verify_callback (int ok, X509_STORE_CTX * ctx)
  108 {
  109     char buf[256];
  110     X509 *cert;
  111     int err;
  112     int depth;
  113 
  114     cert = X509_STORE_CTX_get_current_cert (ctx);
  115 
  116     if (!ok) {
  117 
  118         err = X509_STORE_CTX_get_error (ctx);
  119 
  120         depth = X509_STORE_CTX_get_error_depth (ctx);
  121 
  122         X509_NAME_oneline (X509_get_subject_name (cert), buf, sizeof(buf));
  123         fprintf (stderr, "verify depth = %d (%s)\n", depth, buf);
  124 
  125         fprintf (stderr, "verify error num = %d (%s)\n", err,
  126                     X509_verify_cert_error_string (err));
  127         //if (verify_depth >= depth) {
  128             ok = 1;
  129         //    verify_error = X509_V_OK;
  130         //} else {
  131         //    ok = 0;
  132         //    verify_error = X509_V_ERR_CERT_CHAIN_TOO_LONG;
  133         //}
  134     }
  135 
  136     switch (ctx->error) {
  137       case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
  138           X509_NAME_oneline (X509_get_issuer_name (ctx->current_cert), buf, sizeof(buf));
  139           fprintf (stderr, "verify has no cert for issuer = '%s'\n", buf);
  140           ok = 0;
  141           break;
  142       case X509_V_ERR_CERT_NOT_YET_VALID:
  143       case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
  144           //X509_NAME_oneline (ASN1_STRING_data(X509_get_notBefore (ctx->current_cert)), buf, sizeof(buf));
  145           fprintf (stderr, "verify cert notBefore = (future)\n");
  146           ok = 0;
  147           break;
  148       case X509_V_ERR_CERT_HAS_EXPIRED:
  149       case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
  150           //X509_NAME_oneline (ASN1_STRING_data(X509_get_notAfter (ctx->current_cert)), buf, sizeof(buf));
  151           fprintf (stderr, "verify cert notAfter = (past)\n");
  152           ok = 0;
  153           break;
  154     }
  155     //fprintf (stderr, "verify return:%d\n", ok);
  156     return ok;
  157 }
  158 
  159 /*
  160  * setup ssl. 
  161  */
  162 static SSL_CTX *
  163 ssl_new_ctx (int flags)
  164 {
  165     static char *cert_file // what the server presents
  166                         = NULL;
  167     static char *key_file // key to what the server presents
  168                         = NULL; // take as being .key of the cert file
  169     static char *CApath   // where the client checks received certs
  170                         = NULL;
  171     static char *CAfile   // should always be null
  172                         = NULL;
  173     SSL_CTX *ctx;
  174     int err;
  175 
  176     if (!cert_file) 
  177         cert_file = strdup(SOCK_CERT_FILE);
  178     if (!CApath)
  179         CApath = strdup(SOCK_CAPATH);
  180 
  181     signal(SIGPIPE,SIG_IGN);
  182     SSLeay_add_ssl_algorithms ();
  183 
  184     if ((flags&0xf) == SOCK_CLIENT) {
  185         ctx = SSL_CTX_new (SSLv23_client_method ());
  186     } else if ((flags&0xf) == SOCK_SERVER) {
  187         ctx = SSL_CTX_new (SSLv23_server_method ());
  188     } else {
  189         fprintf (stderr, "unrecognized ssl ctx flags %d\n", flags & 0xf);
  190         return NULL;
  191     }
  192     if (!ctx) {
  193         fprintf (stderr, "could not open an SSL context\n");
  194         return NULL;
  195     }
  196 
  197     /* tells the server to send a certificate, but not to ask for one
  198      * from the client */
  199     SSL_CTX_set_verify (ctx, SSL_VERIFY_NONE, ssl_verify_callback);
  200 
  201     /* if we're the client, we don't want to send a cert.
  202      * if we're the server, we look for a cert and matching key.
  203      */
  204     if ((flags&0xf) == SOCK_SERVER) {
  205 
  206         char *p, *q;
  207 
  208         do {
  209 
  210             p = strchr(cert_file, ':');
  211             if (p)
  212                 *p++ = 0;
  213 
  214             if (access(cert_file, R_OK) < 0)
  215                 continue;
  216 
  217             // make the corresponding key file name
  218             q = strrchr(cert_file, '.');
  219             if (q) {
  220                 *q = 0;
  221                 key_file = malloc(strlen(cert_file) + 5);
  222                 if (key_file)
  223                     sprintf(key_file, "%s.key", cert_file);
  224                 *q = '.';
  225                 if (key_file && access(key_file, R_OK) < 0) {
  226                     free(key_file);
  227                     key_file = NULL;
  228                 }
  229             } else {
  230                 key_file = NULL;
  231             }
  232             err = ssl_set_cert_stuff (ctx, cert_file, key_file);
  233             // free the key file we made, if any
  234             if (key_file)
  235                 free(key_file);
  236             if (err >= 0)
  237                 break; // found it
  238             
  239         } while (cert_file = p, cert_file);
  240 
  241         if (!cert_file) {
  242             SSL_CTX_free (ctx);
  243             fprintf (stderr, "could not find a valid SSL cert\n");
  244             return NULL;
  245         }
  246     }
  247 
  248     /*
  249      * says where to look for CA certs if we are a CLIENT, so where to
  250      * check for the CA for a certificate that the server sends
  251      */
  252     err = SSL_CTX_load_verify_locations (ctx, CAfile, CApath);
  253     if (err != 1) {
  254         fprintf (stderr, "could not open an SSL context\n");
  255         SSL_CTX_free (ctx);
  256         return NULL;
  257     }
  258 
  259     err = SSL_CTX_set_default_verify_paths (ctx);
  260     if (err != 1) {
  261         fprintf (stderr, "could not verify our SSL certificate\n");
  262         SSL_CTX_free (ctx);
  263         return NULL;
  264     }
  265 
  266     return ctx;
  267 }
  268 
  269 #endif /*defined(HAVE_OPENSSL_SSL_H) */
  270 
  271 /*
  272  * run select on a ctx (its underlying socket).
  273  */
  274 static int
  275 io_select (struct io_ctx *ctx, int rw, struct timeval *tv)
  276 {
  277     fd_set rfds;
  278     fd_set wfds;
  279     fd_set xfds;
  280 
  281     FD_ZERO (&rfds);
  282     FD_ZERO (&wfds);
  283     FD_ZERO (&xfds);
  284 
  285     FD_SET (ctx->sock, rw ? &wfds : &rfds);
  286     FD_SET (ctx->sock, &xfds);
  287 
  288     return select (ctx->sock + 1, &rfds, &wfds, &xfds, tv);
  289 }
  290 
  291 
  292 #if defined(HAVE_OPENSSL_SSL_H)
  293 static int
  294 ssl_read(struct io_ctx  *ctx, char *buf, size_t len)
  295 {
  296     return SSL_read(ctx->data, buf, len);
  297 }
  298 
  299 static int
  300 ssl_write(struct io_ctx  *ctx, char *buf, size_t len)
  301 {
  302     return SSL_write(ctx->data, buf, len);
  303 }
  304 
  305 static void
  306 ssl_disconnect (struct io_ctx *ctx)
  307 {
  308     static const struct linger linger = {
  309       .l_onoff = 0,    /* linger active/inactive */
  310       .l_linger = 0,   /* how many seconds to linger for */
  311     };
  312     setsockopt(ctx->sock, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger));
  313     fcntl(ctx->sock, F_SETFL, O_NONBLOCK);
  314     if (ctx->data)
  315         SSL_shutdown(ctx->data);
  316     shutdown(ctx->sock, SHUT_RDWR);
  317     close(ctx->sock);
  318 }
  319 
  320 static int
  321 ssl_accept (struct io_ctx *ctx)
  322 {
  323     SSL *con;
  324     int err;
  325 
  326     if (!ssl_ctx)
  327         ssl_ctx = ssl_new_ctx (SOCK_SERVER);
  328 
  329     if (!ssl_ctx) {
  330         //fprintf (stderr, "could not init ssl contxt, using tcp only\n");
  331         return -EINVAL;
  332     }
  333 
  334     con = SSL_new (ssl_ctx);
  335     if (!con) {
  336         //fprintf (stderr, "ssl socket connect failed %m, using tcp only\n");
  337         return -ENOMEM;
  338     }
  339 
  340     err = SSL_set_fd (con, ctx->sock);
  341     if (err != 1) {
  342         SSL_free(con);
  343         //fprintf (stderr, "ssl socket bind failed %m, using tcp only\n");
  344         return -EINVAL;
  345     }
  346 
  347     err = SSL_accept(con);
  348     if (err != 1) {
  349         SSL_shutdown(con);
  350         SSL_free(con);
  351         return -EINVAL;
  352     }
  353     ctx->data = con;
  354     ctx->flags  = 0;
  355     ctx->type   = RGDBM_CRYPTO_SSL;
  356     ctx->read   = ssl_read;
  357     ctx->write  = ssl_write;
  358     ctx->disconnect  = ssl_disconnect;
  359     return 0;
  360 }
  361 
  362 static int
  363 ssl_connect (struct io_ctx *ctx)
  364 {
  365     SSL *con;
  366     int err;
  367 
  368     if (!ssl_ctx)
  369         ssl_ctx = ssl_new_ctx (SOCK_CLIENT);
  370 
  371     if (!ssl_ctx) {
  372         //fprintf (stderr, "could not init ssl context, using tcp only\n");
  373         return -EINVAL;
  374     }
  375 
  376     con = SSL_new (ssl_ctx);
  377     if (!con) {
  378         //fprintf (stderr, "ssl socket connect failed %m, using tcp only\n");
  379         return -ENOMEM;
  380     }
  381 
  382     err = SSL_set_fd (con, ctx->sock);
  383     if (err != 1) {
  384         SSL_free(con);
  385         //fprintf (stderr, "ssl socket bind failed %m, using tcp only\n");
  386         return -EINVAL;
  387     }
  388 
  389     err = SSL_connect (con);
  390     if (err < 0) {
  391         SSL_free(con);
  392         //fprintf (stderr, "ssl connect failed %m, using tcp only\n");
  393         return -EINVAL;
  394     }
  395     ctx->data = con;
  396     ctx->flags = 0;
  397     ctx->type = RGDBM_CRYPTO_SSL;
  398     ctx->read = ssl_read;
  399     ctx->write = ssl_write;
  400     ctx->disconnect = ssl_disconnect;
  401     return 0;
  402 }
  403 
  404 #endif /* defined(HAVE_OPENSSL_SSL_H) */
  405 
  406 static int
  407 sock_read(struct io_ctx  *ctx, char *buf, size_t len)
  408 {
  409     return read(ctx->sock, buf, len);
  410 }
  411 static int
  412 sock_write(struct io_ctx  *ctx, char *buf, size_t len)
  413 {
  414     return write(ctx->sock, buf, len);
  415 }
  416 static void
  417 sock_disconnect (struct io_ctx *ctx)
  418 {
  419     static const struct linger linger = {
  420       .l_onoff = 0,    /* linger active/inactive */
  421       .l_linger = 0,   /* how many seconds to linger for */
  422     };
  423     setsockopt(ctx->sock, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger));
  424     fcntl(ctx->sock, F_SETFL, O_NONBLOCK);
  425     shutdown(ctx->sock, SHUT_RDWR);
  426     close(ctx->sock);
  427 }
  428 
  429 /*
  430  * set up a ctx for a tcp (server) socket connection.
  431  */
  432 static int
  433 sock_accept (struct io_ctx *ctx)
  434 {
  435     ctx->type = 0;
  436     ctx->data = NULL;
  437     ctx->flags &= ~0xf;
  438     ctx->read = sock_read;
  439     ctx->write = sock_write;
  440     ctx->disconnect  = sock_disconnect;
  441     return 0;
  442 }
  443 
  444 
  445 /*
  446  * set up a ctx for a tcp (client) socket connection.
  447  */
  448 static int
  449 sock_connect (struct io_ctx *ctx)
  450 {
  451     ctx->type = 0;
  452     ctx->data = NULL;
  453     ctx->flags &= ~0xf;
  454     ctx->read = sock_read;
  455     ctx->write = sock_write;
  456     ctx->disconnect = sock_disconnect;
  457     return 0;
  458 }
  459 
  460 /*
  461  * this binds ssl to a socket in server mode, or else does nothing.
  462  */
  463 static int
  464 io_accept (struct io_ctx *ctx, int flags)
  465 {
  466     int err = -EINVAL;
  467 
  468 #ifdef HAVE_OPENSSL_SSL_H
  469     if ((flags & 0xf) & RGDBM_CRYPTO_SSL) {
  470         err = ssl_accept (ctx);
  471         if (err >= 0)
  472             goto end;
  473     }
  474 #endif          /* HAVE_OPENSSL_SSL_H */
  475     if ((flags & 0xf) & RGDBM_CRYPTO_NONE) {
  476         err = sock_accept (ctx);    // can't fail
  477         if (err >= 0)
  478             goto end;
  479     }
  480  end:
  481     return err;
  482 }
  483 
  484 
  485 /*
  486  * this binds ssl to a socket in client mode, or else does nothing.
  487  */
  488 static int
  489 io_connect(struct io_ctx *ctx, int flags)
  490 {
  491     int err = -EINVAL;
  492 
  493 #ifdef HAVE_OPENSSL_SSL_H
  494     if ((flags & 0xf) & RGDBM_CRYPTO_SSL) {
  495         err = ssl_connect(ctx); // need to have set ctx->sock first
  496         if (err >= 0)
  497             goto end;
  498     }
  499 #endif /* HAVE_OPENSSL_SSL_H */
  500     if ((flags & 0xf) & RGDBM_CRYPTO_NONE) {
  501         err = sock_connect(ctx); // can't fail as it's trivial
  502         if (err >= 0)
  503             goto end;
  504     }
  505  end:
  506     return err;
  507 }
  508 
  509 
  510 struct io_ctx *
  511 new_io_ctx(int sock)
  512 {
  513     struct io_ctx *ctx = calloc(1, sizeof (*ctx));
  514 
  515     if (!ctx)
  516         return NULL;
  517 
  518     ctx->sock    = sock;
  519     ctx->accept  = io_accept;
  520     ctx->connect = io_connect;
  521     ctx->select  = io_select;
  522     ctx->disconnect  = sock_disconnect;
  523     return ctx;
  524 }
  525 
  526