Back to index

opendkim  2.6.4
opendkim-genzone.c
Go to the documentation of this file.
00001 /*
00002 **  Copyright (c) 2010, 2011, The OpenDKIM Project.  All rights reserved.
00003 **
00004 **  $Id: opendkim-genzone.c,v 1.12.10.1 2010/10/27 21:43:09 cm-msk Exp $
00005 */
00006 
00007 #ifndef lint
00008 static char opendkim_genzone_c_id[] = "$Id: opendkim-genzone.c,v 1.12.10.1 2010/10/27 21:43:09 cm-msk Exp $";
00009 #endif /* !lint */
00010 
00011 #include "build-config.h"
00012 
00013 /* system includes */
00014 #include <sys/param.h>
00015 #include <sys/types.h>
00016 #include <sys/stat.h>
00017 #include <sysexits.h>
00018 #include <string.h>
00019 #include <assert.h>
00020 #include <fcntl.h>
00021 #include <ctype.h>
00022 #include <stdlib.h>
00023 #include <stdio.h>
00024 #include <errno.h>
00025 #include <unistd.h>
00026 #include <pwd.h>
00027 
00028 /* openssl includes */
00029 #ifdef USE_GNUTLS
00030 # include <gnutls/gnutls.h>
00031 # include <gnutls/crypto.h>
00032 # include <gnutls/abstract.h>
00033 # include <gnutls/x509.h>
00034 #else /* USE_GNUTLS */
00035 # include <openssl/rsa.h>
00036 # include <openssl/pem.h>
00037 # include <openssl/evp.h>
00038 # include <openssl/bio.h>
00039 #endif /* USE_GNUTLS */
00040 
00041 #ifndef FALSE
00042 # define FALSE              0
00043 #endif /* ! FALSE */
00044 #ifndef TRUE
00045 # define TRUE        1
00046 #endif /* ! TRUE */
00047 #ifndef MIN
00048 # define MIN(x,y)    ((x) < (y) ? (x) : (y))
00049 #endif /* ! MIN */
00050 
00051 /* libopendkim includes */
00052 #include <dkim.h>
00053 
00054 /* opendkim includes */
00055 #include "opendkim-db.h"
00056 #include "config.h"
00057 #include "opendkim-config.h"
00058 
00059 /* definitions */
00060 #define       BUFRSZ        1024
00061 #define       CMDLINEOPTS   "C:d:DE:o:N:r:R:St:T:vx:"
00062 #define       DEFCONFFILE   CONFIG_BASE "/opendkim.conf"
00063 #define       DEFEXPIRE     604800
00064 #define       DEFREFRESH    10800
00065 #define       DEFRETRY      1800
00066 #define       DEFTTL        86400
00067 #define       DKIMZONE      "._domainkey"
00068 #define       HOSTMASTER    "hostmaster"
00069 #define       LARGEBUFRSZ   8192
00070 #define       MARGIN        75
00071 #define       MAXNS         16
00072 
00073 /* globals */
00074 char *progname;
00075 
00076 /*
00077 **  STRFLEN -- determine length of a formatted string
00078 **
00079 **  Parameters:
00080 **     str -- string of interest
00081 **
00082 **  Return value:
00083 **     Rendered width (i.e. expand tabs, etc.).
00084 */
00085 
00086 int
00087 strflen(char *str)
00088 {
00089        int olen = 0;
00090        char *p;
00091 
00092        assert(str != NULL);
00093 
00094        for (p = str; *p != '\0'; p++)
00095        {
00096               if (*p == '\t')
00097                      olen += 8 - (olen % 8);
00098               else
00099                      olen++;
00100        }
00101 
00102        return olen;
00103 }
00104        
00105 /*
00106 **  LOADKEY -- resolve a key
00107 **
00108 **  Parameters:
00109 **     buf -- key buffer
00110 **     buflen -- pointer to key buffer's length (updated)
00111 **
00112 **  Return value:
00113 **     TRUE on successful load, false otherwise
00114 */
00115 
00116 int
00117 loadkey(char *buf, size_t *buflen)
00118 {
00119        assert(buf != NULL);
00120        assert(buflen != NULL);
00121 
00122        if (buf[0] == '/' || (buf[0] == '.' && buf[1] == '/') ||
00123            (buf[0] == '.' && buf[1] == '.' && buf[2] == '/'))
00124        {
00125               int fd;
00126               int status;
00127               ssize_t rlen;
00128               struct stat s;
00129 
00130               fd = open(buf, O_RDONLY);
00131               if (fd < 0)
00132                      return FALSE;
00133 
00134               status = fstat(fd, &s);
00135               if (status != 0)
00136               {
00137                      close(fd);
00138                      return FALSE;
00139               }
00140 
00141               *buflen = MIN(s.st_size, *buflen);
00142               rlen = read(fd, buf, *buflen);
00143               close(fd);
00144 
00145               if (rlen < *buflen)
00146                      return FALSE;
00147        }
00148        else
00149        {
00150               *buflen = strlen(buf);
00151        }
00152 
00153        return TRUE;
00154 }
00155 
00156 /*
00157 **  DESPACE -- remove spaces from a string
00158 **
00159 **  Parameters:
00160 **     str -- string to update
00161 **
00162 **  Return value:
00163 **     None.
00164 */
00165 
00166 void
00167 despace(char *str)
00168 {
00169        char *p;
00170        char *q;
00171 
00172        assert(str != NULL);
00173 
00174        for (p = str, q = str; ; p++)
00175        {
00176               if (isascii(*p) && isspace(*p))
00177                      continue;
00178               else
00179                      *q++ = *p;
00180               if (*p == '\0')
00181                      break;
00182        }
00183 }
00184        
00185 /*
00186 **  USAGE -- print usage message and exit
00187 **
00188 **  Parameters:
00189 **     None.
00190 **
00191 **  Return value:
00192 **     EX_USAGE
00193 */
00194 
00195 int
00196 usage(void)
00197 {
00198        fprintf(stderr, "%s: usage: %s [opts] [dataset]\n"
00199                        "\t-C user@host\tcontact address to include in SOA\n"
00200                        "\t-d domain   \twrite keys for named domain only\n"
00201                        "\t-D          \tinclude '._domainkey' suffix\n"
00202                        "\t-E secs     \tuse specified expiration time in SOA\n"
00203                        "\t-o file     \toutput file\n"
00204                        "\t-N ns[,...] \tlist NS records\n"
00205                        "\t-r secs     \tuse specified refresh time in SOA\n"
00206                        "\t-R secs     \tuse specified retry time in SOA\n"
00207                        "\t-S          \twrite an SOA record\n"
00208                        "\t-t secs     \tuse specified per-record TTL\n"
00209                        "\t-T secs     \tuse specified default TTL in SOA\n"
00210                        "\t-v          \tverbose output\n"
00211                        "\t-x file     \tconfiguration file\n",
00212               progname, progname);
00213 
00214        return EX_USAGE;
00215 }
00216 
00217 /*
00218 **  MAIN -- program mainline
00219 **
00220 **  Parameters:
00221 **     argc, argv -- the usual
00222 **
00223 **  Return value:
00224 **     Exit status.
00225 */
00226 
00227 int
00228 main(int argc, char **argv)
00229 {
00230        _Bool seenlf;
00231        _Bool suffix = FALSE;
00232        _Bool writesoa = FALSE;
00233        int c;
00234        int status;
00235        int verbose = 0;
00236        int olen;
00237        int ttl = -1;
00238        int defttl = DEFTTL;
00239        int expire = DEFEXPIRE;
00240        int refresh = DEFREFRESH;
00241        int retry = DEFRETRY;
00242        int nscount = 0;
00243        long len;
00244        time_t now;
00245        size_t keylen;
00246        char *p;
00247        char *dataset = NULL;
00248        char *outfile = NULL;
00249        char *onlydomain = NULL;
00250        char *contact = NULL;
00251        char *nameservers = NULL;
00252        char *configfile = NULL;
00253        char *nslist[MAXNS];
00254        FILE *out;
00255 #ifdef USE_GNUTLS
00256        gnutls_x509_privkey_t xprivkey;
00257        gnutls_privkey_t privkey;
00258        gnutls_pubkey_t pubkey;
00259        gnutls_datum_t key;
00260 #else /* USE_GNUTLS */
00261        BIO *private;
00262        BIO *outbio = NULL;
00263        EVP_PKEY *pkey;
00264        RSA *rsa;
00265 #endif /* USE_GNUTLS */
00266        DKIMF_DB db;
00267        char keyname[BUFRSZ + 1];
00268        char domain[BUFRSZ + 1];
00269        char selector[BUFRSZ + 1];
00270        char tmpbuf[BUFRSZ + 1];
00271        char hostname[DKIM_MAXHOSTNAMELEN + 1];
00272        char keydata[LARGEBUFRSZ];
00273        char derdata[LARGEBUFRSZ];
00274        struct dkimf_db_data dbd[3];
00275 
00276        progname = (p = strrchr(argv[0], '/')) == NULL ? argv[0] : p + 1;
00277 
00278        while ((c = getopt(argc, argv, CMDLINEOPTS)) != -1)
00279        {
00280               switch (c)
00281               {
00282                 case 'C':
00283                      contact = strdup(optarg);
00284                      break;
00285 
00286                 case 'd':
00287                      onlydomain = optarg;
00288                      break;
00289 
00290                 case 'D':
00291                      suffix = TRUE;
00292                      break;
00293 
00294                 case 'E':
00295                      expire = strtol(optarg, &p, 10);
00296                      if (*p != '\0' || expire < 0)
00297                      {
00298                             fprintf(stderr, "%s: invalid expire value\n",
00299                                     progname);
00300                             return EX_USAGE;
00301                      }
00302                      break;
00303 
00304                 case 'N':
00305                      nameservers = strdup(optarg);
00306                      break;
00307 
00308                 case 'o':
00309                      outfile = optarg;
00310                      break;
00311 
00312                 case 'r':
00313                      refresh = strtol(optarg, &p, 10);
00314                      if (*p != '\0' || refresh < 0)
00315                      {
00316                             fprintf(stderr, "%s: invalid refresh value\n",
00317                                     progname);
00318                             return EX_USAGE;
00319                      }
00320                      break;
00321 
00322                 case 'R':
00323                      retry = strtol(optarg, &p, 10);
00324                      if (*p != '\0' || retry < 0)
00325                      {
00326                             fprintf(stderr, "%s: invalid retry value\n",
00327                                     progname);
00328                             return EX_USAGE;
00329                      }
00330                      break;
00331 
00332                 case 't':
00333                      ttl = strtol(optarg, &p, 10);
00334                      if (*p != '\0' || ttl < 0)
00335                      {
00336                             fprintf(stderr, "%s: invalid TTL value\n",
00337                                     progname);
00338                             return EX_USAGE;
00339                      }
00340                      break;
00341 
00342                 case 'T':
00343                      defttl = strtol(optarg, &p, 10);
00344                      if (*p != '\0' || defttl < 0)
00345                      {
00346                             fprintf(stderr,
00347                                     "%s: invalid default TTL value\n",
00348                                     progname);
00349                             return EX_USAGE;
00350                      }
00351                      break;
00352 
00353                 case 'S':
00354                      writesoa = TRUE;
00355                      break;
00356 
00357                 case 'v':
00358                      verbose++;
00359                      break;
00360 
00361                 case 'x':
00362                      configfile = optarg;
00363                      break;
00364 
00365                 default:
00366                      return usage();
00367               }
00368        }
00369 
00370        if (optind != argc)
00371               dataset = argv[optind];
00372 
00373        /* process config file */
00374        if (configfile == NULL && access(DEFCONFFILE, R_OK) == 0)
00375               configfile = DEFCONFFILE;
00376        if (configfile != NULL)
00377        {
00378 #ifdef USE_LDAP
00379               _Bool ldap_usetls = FALSE;
00380 #endif /* USE_LDAP */
00381               u_int line = 0;
00382 #ifdef USE_LDAP
00383               char *ldap_authmech = NULL;
00384 # ifdef USE_SASL
00385               char *ldap_authname = NULL;
00386               char *ldap_authrealm = NULL;
00387               char *ldap_authuser = NULL;
00388 # endif /* USE_SASL */
00389               char *ldap_bindpw = NULL;
00390               char *ldap_binduser = NULL;
00391 #endif /* USE_LDAP */
00392               struct config *cfg;
00393               char path[MAXPATHLEN + 1];
00394 
00395               cfg = config_load(configfile, dkimf_config,
00396                                 &line, path, sizeof path);
00397 
00398               if (cfg == NULL)
00399               {
00400                      fprintf(stderr,
00401                              "%s: %s: configuration error at line %u\n",
00402                              progname, path, line);
00403                      return EX_CONFIG;
00404               }
00405 
00406               if (dataset == NULL)
00407               {
00408                      (void) config_get(cfg, "KeyTable",
00409                                        &dataset, sizeof dataset);
00410               }
00411 
00412 #ifdef USE_LDAP
00413               (void) config_get(cfg, "LDAPUseTLS",
00414                                 &ldap_usetls, sizeof ldap_usetls);
00415 
00416               if (ldap_usetls)
00417                      dkimf_db_set_ldap_param(DKIMF_LDAP_PARAM_USETLS, "y");
00418               else
00419                      dkimf_db_set_ldap_param(DKIMF_LDAP_PARAM_USETLS, "n");
00420 
00421               (void) config_get(cfg, "LDAPAuthMechanism",
00422                                 &ldap_authmech, sizeof ldap_authmech);
00423 
00424               dkimf_db_set_ldap_param(DKIMF_LDAP_PARAM_AUTHMECH,
00425                                       ldap_authmech);
00426 
00427 # ifdef USE_SASL
00428               (void) config_get(cfg, "LDAPAuthName",
00429                                 &ldap_authname, sizeof ldap_authname);
00430 
00431               dkimf_db_set_ldap_param(DKIMF_LDAP_PARAM_AUTHNAME,
00432                                       ldap_authname);
00433 
00434               (void) config_get(cfg, "LDAPAuthRealm",
00435                                 &ldap_authrealm, sizeof ldap_authrealm);
00436 
00437               dkimf_db_set_ldap_param(DKIMF_LDAP_PARAM_AUTHREALM,
00438                                       ldap_authrealm);
00439 
00440               (void) config_get(cfg, "LDAPAuthUser",
00441                                 &ldap_authuser, sizeof ldap_authuser);
00442 
00443               dkimf_db_set_ldap_param(DKIMF_LDAP_PARAM_AUTHUSER,
00444                                       ldap_authuser);
00445 # endif /* USE_SASL */
00446 
00447               (void) config_get(cfg, "LDAPBindPassword",
00448                                 &ldap_bindpw, sizeof ldap_bindpw);
00449 
00450               dkimf_db_set_ldap_param(DKIMF_LDAP_PARAM_BINDPW, ldap_bindpw);
00451 
00452               (void) config_get(cfg, "LDAPBindUser",
00453                                 &ldap_binduser, sizeof ldap_binduser);
00454 
00455               dkimf_db_set_ldap_param(DKIMF_LDAP_PARAM_BINDUSER,
00456                                       ldap_binduser);
00457 #endif /* USE_LDAP */
00458        }
00459 
00460        if (dataset == NULL)
00461               return usage();
00462 
00463 #ifndef USE_GNUTLS
00464        outbio = BIO_new(BIO_s_mem());
00465        if (outbio == NULL)
00466        {
00467               fprintf(stderr, "%s: BIO_new() failed\n", progname);
00468               return 1;
00469        }
00470 #endif /* ! USE_GNUTLS */
00471 
00472 #ifdef USE_GNUTLS
00473        (void) gnutls_global_init();
00474 #endif /* USE_GNUTLS */
00475 
00476        status = dkimf_db_open(&db, dataset, DKIMF_DB_FLAG_READONLY,
00477                               NULL, NULL);
00478        if (status != 0)
00479        {
00480               fprintf(stderr, "%s: dkimf_db_open() failed\n", progname);
00481 #ifndef USE_GNUTLS
00482               (void) BIO_free(outbio);
00483 #endif /* ! USE_GNUTLS */
00484               return 1;
00485        }
00486 
00487        if (dkimf_db_type(db) == DKIMF_DB_TYPE_REFILE)
00488        {
00489               fprintf(stderr, "%s: invalid data set type\n", progname);
00490 #ifndef USE_GNUTLS
00491               (void) BIO_free(outbio);
00492 #endif /* ! USE_GNUTLS */
00493               (void) dkimf_db_close(db);
00494               return 1;
00495        }
00496 
00497        if (verbose > 0)
00498               fprintf(stderr, "%s: database opened\n", progname);
00499 
00500        if (outfile != NULL)
00501        {
00502               out = fopen(outfile, "w");
00503               if (out == NULL)
00504               {
00505                      fprintf(stderr, "%s: %s: fopen(): %s\n",
00506                              progname, outfile, strerror(errno));
00507                      (void) dkimf_db_close(db);
00508 #ifndef USE_GNUTLS
00509                      (void) BIO_free(outbio);
00510 #endif /* ! USE_GNUTLS */
00511                      return 1;
00512               }
00513        }
00514        else
00515        {
00516               out = stdout;
00517        }
00518 
00519        if (nameservers != NULL)
00520        {
00521               for (p = strtok(nameservers, ",");
00522                    p != NULL && nscount < MAXNS;
00523                    p = strtok(NULL, ","))
00524                      nslist[nscount++] = p;
00525        }
00526 
00527        memset(hostname, '\0', sizeof hostname);
00528        gethostname(hostname, sizeof hostname);
00529 
00530        if (nscount == 0)
00531               nslist[nscount++] = hostname;
00532 
00533        (void) time(&now);
00534 
00535        fprintf(out, "; DKIM public key zone data\n");
00536        if (onlydomain != NULL)
00537               fprintf(out, "; for %s\n", onlydomain);
00538        fprintf(out, "; auto-generated by %s at %s\n", progname, ctime(&now));
00539 
00540        if (writesoa)
00541        {
00542               struct tm *tm;
00543 
00544               fprintf(out, "@\tIN\tSOA\t%s\t", nslist[0]);
00545 
00546               if (contact != NULL)
00547               {
00548                      for (p = contact; *p != '\0'; p++)
00549                      {
00550                             if (*p == '@')
00551                                    *p = '.';
00552                      }
00553 
00554                      fprintf(out, "%s", contact);
00555               }
00556               else
00557               {
00558                      struct passwd *pwd;
00559 
00560                      pwd = getpwuid(getuid());
00561 
00562                      fprintf(out, "%s.%s",
00563                              pwd == NULL ? HOSTMASTER : pwd->pw_name,
00564                              hostname);
00565               }
00566 
00567               tm = localtime(&now);
00568 
00569               fprintf(out,
00570                       "\t (\n"
00571                       "\t%04d%02d%02d%02d   ; Serial (yyyymmddhh)\n"
00572                       "\t%-10d   ; Refresh\n"
00573                       "\t%-10d   ; Retry\n"
00574                       "\t%-10d   ; Expire\n"
00575                       "\t%-10d ) ; Default\n\n",
00576                       tm->tm_year + 1900,
00577                       tm->tm_mon + 1,
00578                       tm->tm_mday,
00579                       tm->tm_hour,
00580                       refresh, retry, expire, defttl);
00581        }
00582 
00583        if (nameservers != NULL)
00584        {
00585               for (c = 0; c < nscount; c++)
00586                      fprintf(out, "\tIN\tNS\t%s\n", nslist[c]);
00587 
00588               fprintf(out, "\n");
00589        }
00590 
00591        dbd[0].dbdata_buffer = domain;
00592        dbd[1].dbdata_buffer = selector;
00593        dbd[2].dbdata_buffer = keydata;
00594 
00595        for (c = 0; ; c++)
00596        {
00597               memset(keyname, '\0', sizeof keyname);
00598               memset(domain, '\0', sizeof domain);
00599               memset(selector, '\0', sizeof selector);
00600               memset(keydata, '\0', sizeof keydata);
00601 
00602               dbd[0].dbdata_buflen = sizeof domain;
00603               dbd[1].dbdata_buflen = sizeof selector;
00604               dbd[2].dbdata_buflen = sizeof keydata;
00605 
00606               keylen = sizeof keyname;
00607 
00608               status = dkimf_db_walk(db, c == 0, keyname, &keylen, dbd, 3);
00609               if (status == -1)
00610               {
00611                      fprintf(stderr, "%s: dkimf_db_walk(%d) failed\n",
00612                              progname, c);
00613                      (void) dkimf_db_close(db);
00614 #ifndef USE_GNUTLS
00615                      (void) BIO_free(outbio);
00616 #endif /* ! USE_GNUTLS */
00617                      return 1;
00618               }
00619               else if (status == 1)
00620               {
00621                      break;
00622               }
00623 
00624               if (onlydomain != NULL && strcasecmp(domain, onlydomain) != 0)
00625               {
00626                      fprintf(stderr, "%s: record %d for '%s' skipped\n",
00627                              progname, c, keyname);
00628 
00629                      continue;
00630               }
00631 
00632               if (verbose > 1)
00633               {
00634                      fprintf(stderr, "%s: record %d for '%s' retrieved\n",
00635                              progname, c, keyname);
00636               }
00637 
00638               keylen = sizeof keydata;
00639               if (!loadkey(keydata, &keylen))
00640               {
00641                      fprintf(stderr, "%s: key for '%s' load failed\n",
00642                              progname, keyname);
00643                      (void) dkimf_db_close(db);
00644 #ifndef USE_GNUTLS
00645                      (void) BIO_free(outbio);
00646 #endif /* USE_GNUTLS */
00647                      return 1;
00648               }
00649 
00650               if (verbose > 1)
00651               {
00652                      fprintf(stderr, "%s: key for '%s' loaded\n",
00653                              progname, keyname);
00654               }
00655 
00656 #ifdef USE_GNUTLS
00657               if (gnutls_x509_privkey_init(&xprivkey) != GNUTLS_E_SUCCESS)
00658               {
00659                      fprintf(stderr,
00660                              "%s: gnutls_x509_privkey_init() failed\n",
00661                              progname);
00662                      (void) dkimf_db_close(db);
00663                      return 1;
00664               }
00665 
00666               key.data = keydata;
00667               key.size = keylen;
00668 
00669               status = gnutls_x509_privkey_import(xprivkey, &key,
00670                                                   GNUTLS_X509_FMT_PEM);
00671               if (status != GNUTLS_E_SUCCESS)
00672               {
00673                      status = gnutls_x509_privkey_import(xprivkey, &key,
00674                                                           GNUTLS_X509_FMT_DER);
00675               }
00676 
00677               if (status != GNUTLS_E_SUCCESS)
00678               {
00679                      fprintf(stderr,
00680                              "%s: gnutls_x509_privkey_import() failed\n",
00681                              progname);
00682                      (void) gnutls_x509_privkey_deinit(xprivkey);
00683                      return -1;
00684               }
00685 
00686               status = gnutls_privkey_init(&privkey);
00687               if (status != GNUTLS_E_SUCCESS)
00688               {
00689                      fprintf(stderr,
00690                              "%s: gnutls_privkey_init() failed\n",
00691                              progname);
00692                      (void) gnutls_x509_privkey_deinit(xprivkey);
00693                      return -1;
00694               }
00695 
00696               status = gnutls_privkey_import_x509(privkey, xprivkey, 0);
00697               if (status != GNUTLS_E_SUCCESS)
00698               {
00699                      fprintf(stderr,
00700                              "%s: gnutls_privkey_import_x509() failed\n",
00701                              progname);
00702                      (void) gnutls_x509_privkey_deinit(xprivkey);
00703                      (void) gnutls_privkey_deinit(privkey);
00704                      return -1;
00705               }
00706 #else /* USE_GNUTLS */
00707               /* create a BIO for the private key */
00708               if (strncmp(keydata, "-----", 5) == 0)
00709               {
00710                      private = BIO_new_mem_buf(keydata, keylen);
00711                      if (private == NULL)
00712                      {
00713                             fprintf(stderr,
00714                                     "%s: BIO_new_mem_buf() failed\n",
00715                                     progname);
00716                             (void) dkimf_db_close(db);
00717                             (void) BIO_free(outbio);
00718                             return 1;
00719                      }
00720 
00721                      pkey = PEM_read_bio_PrivateKey(private, NULL,
00722                                                     NULL, NULL);
00723                      if (pkey == NULL)
00724                      {
00725                             fprintf(stderr,
00726                                     "%s: PEM_read_bio_PrivateKey() failed\n",
00727                                     progname);
00728                             (void) dkimf_db_close(db);
00729                             (void) BIO_free(private);
00730                             (void) BIO_free(outbio);
00731                             return 1;
00732                      }
00733               }
00734               else
00735               {
00736                      int inlen;
00737                      int outlen;
00738                      BIO *b64;
00739                      BIO *bio;
00740                      BIO *decode;
00741                      char buf[BUFRSZ];
00742 
00743                      despace(keydata);
00744 
00745                      b64 = BIO_new(BIO_f_base64());
00746                      BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
00747                      bio = BIO_new_mem_buf(keydata, -1);
00748                      bio = BIO_push(b64, bio);
00749 
00750                      decode = BIO_new(BIO_s_mem());
00751 
00752                      for (;;)
00753                      {
00754                             inlen = BIO_read(bio, buf, sizeof buf);
00755                             if (inlen == 0)
00756                                    break;
00757                             BIO_write(decode, buf, inlen);
00758                      }
00759 
00760                      BIO_flush(decode);
00761 
00762                      outlen = BIO_get_mem_data(decode, &p);
00763                      memcpy(derdata, p, MIN(sizeof derdata, outlen));
00764 
00765                      BIO_free_all(b64);
00766                      BIO_free(decode);
00767 
00768                      private = BIO_new_mem_buf(derdata, outlen);
00769                      if (private == NULL)
00770                      {
00771                             fprintf(stderr,
00772                                     "%s: BIO_new_mem_buf() failed\n",
00773                                     progname);
00774                             (void) dkimf_db_close(db);
00775                             (void) BIO_free(outbio);
00776                             return 1;
00777                      }
00778 
00779                      pkey = d2i_PrivateKey_bio(private, NULL);
00780                      if (pkey == NULL)
00781                      {
00782                             fprintf(stderr,
00783                                     "%s: d2i_PrivateKey_bio() failed\n",
00784                                     progname);
00785                             (void) dkimf_db_close(db);
00786                             (void) BIO_free(private);
00787                             (void) BIO_free(outbio);
00788                             return 1;
00789                      }
00790               }
00791 
00792               rsa = EVP_PKEY_get1_RSA(pkey);
00793               if (rsa == NULL)
00794               {
00795                      fprintf(stderr,
00796                              "%s: EVP_PKEY_get1_RSA() failed\n",
00797                              progname);
00798                      (void) dkimf_db_close(db);
00799                      (void) BIO_free(private);
00800                      (void) EVP_PKEY_free(pkey);
00801                      (void) BIO_free(outbio);
00802                      return 1;
00803               }
00804 
00805               /* convert private to public */
00806               status = PEM_write_bio_RSA_PUBKEY(outbio, rsa);
00807               if (status == 0)
00808               {
00809                      fprintf(stderr,
00810                              "%s: PEM_write_bio_RSA_PUBKEY() failed\n",
00811                              progname);
00812                      (void) dkimf_db_close(db);
00813                      (void) BIO_free(private);
00814                      (void) EVP_PKEY_free(pkey);
00815                      (void) BIO_free(outbio);
00816                      return 1;
00817               }
00818 #endif /* USE_GNUTLS */
00819 
00820               /* write the record */
00821               if (ttl == -1)
00822               {
00823                      snprintf(tmpbuf, sizeof tmpbuf,
00824                               "%s%s\tIN\tTXT\t( \"v=DKIM1; k=rsa; p=",
00825                               selector, suffix ? DKIMZONE : "");
00826               }
00827               else
00828               {
00829                      snprintf(tmpbuf, sizeof tmpbuf,
00830                               "%s%s\t%d\tIN\tTXT\t( \"v=DKIM1; k=rsa; p=",
00831                               selector, suffix ? DKIMZONE : "", ttl);
00832               }
00833 
00834               fprintf(out, "%s", tmpbuf);
00835 
00836               olen = strflen(tmpbuf);
00837 
00838               seenlf = FALSE;
00839 
00840 #ifdef USE_GNUTLS
00841               if (gnutls_pubkey_init(&pubkey) != GNUTLS_E_SUCCESS)
00842               {
00843                      fprintf(stderr, "%s: gnutls_pubkey_init() failed\n",
00844                              progname);
00845                      (void) dkimf_db_close(db);
00846                      (void) gnutls_x509_privkey_deinit(xprivkey);
00847                      return 1;
00848               }
00849 
00850               if (gnutls_pubkey_import_privkey(pubkey,
00851                                                privkey,
00852                                                GNUTLS_KEY_DIGITAL_SIGNATURE,
00853                                                0) != GNUTLS_E_SUCCESS)
00854               {
00855                      fprintf(stderr,
00856                              "%s: gnutls_pubkey_import_privkey() failed\n",
00857                              progname);
00858                      (void) dkimf_db_close(db);
00859                      (void) gnutls_x509_privkey_deinit(xprivkey);
00860                      (void) gnutls_pubkey_deinit(pubkey);
00861                      return 1;
00862               }
00863 
00864               keylen = sizeof keydata;
00865               if (gnutls_pubkey_export(pubkey, GNUTLS_X509_FMT_PEM,
00866                                        keydata, &keylen) != GNUTLS_E_SUCCESS)
00867               {
00868                      fprintf(stderr, "%s: gnutls_pubkey_export() failed\n",
00869                              progname);
00870                      (void) dkimf_db_close(db);
00871                      (void) gnutls_x509_privkey_deinit(xprivkey);
00872                      return 1;
00873               }
00874 
00875               for (len = keylen, p = keydata; len > 0; len--, p++)
00876 #else /* USE_GNUTLS */
00877               for (len = BIO_get_mem_data(outbio, &p); len > 0; len--, p++)
00878 #endif /* USE_GNUTLS */
00879               {
00880                      if (*p == '\n')
00881                      {
00882                             seenlf = TRUE;
00883                      }
00884                      else if (seenlf && *p == '-')
00885                      {
00886                             break;
00887                      }
00888                      else if (!seenlf)
00889                      {
00890                             continue;
00891                      }
00892                      else if (isascii(*p) && !isspace(*p))
00893                      {
00894                             (void) fputc(*p, out);
00895                             olen++;
00896                      }
00897 
00898                      if (olen >= MARGIN)
00899                      {
00900                             fprintf(out, "\"\n\t\"");
00901                             olen = 9;
00902                      }
00903               }
00904 
00905               fprintf(out, "\" )\n");
00906 
00907               /* prepare for the next one */
00908 #ifdef USE_GNUTLS
00909               (void) gnutls_x509_privkey_deinit(xprivkey);
00910               (void) gnutls_privkey_deinit(privkey);
00911               (void) gnutls_pubkey_deinit(pubkey);
00912 #else /* USE_GNUTLS */
00913               (void) BIO_reset(outbio);
00914 #endif /* USE_GNUTLS */
00915        }
00916 
00917 #ifndef USE_GNUTLS
00918        (void) BIO_flush(outbio);
00919        (void) BIO_free(outbio);
00920 #endif /* ! USE_GNUTLS */
00921        (void) dkimf_db_close(db);
00922 
00923        if (out != stdout)
00924               fclose(out);
00925 
00926        if (verbose > 0)
00927        {
00928               fprintf(stdout, "%s: %d record%s written\n",
00929                       progname, c, c == 1 ? "" : "s");
00930        }
00931 
00932        return 0;
00933 }