]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
Merge branch 'maint'
authorAndre Noll <maan@tuebingen.mpg.de>
Sun, 31 Dec 2017 14:04:16 +0000 (15:04 +0100)
committerAndre Noll <maan@tuebingen.mpg.de>
Sun, 31 Dec 2017 14:05:15 +0000 (15:05 +0100)
A conflict in init_random_seed_or_die() of gcrypt.c. The fix added
in the maint branch conflicted against the master branch which also
modified the function to bump the required libgcrypt version.

* maint:
  resample filter: Don't discard const.
  gcrypt: Seed PRNG in init_random_seed_or_die().
  bash_completion: Get rid of weird retry logic.

1  2 
bash_completion
gcrypt.c
resample_filter.c

diff --combined bash_completion
index 4b1a4be55508d70f4f34a170327967d067ba24ef,3dd25e5ae6d1630996ca005cf328cfefc846581a..88b37dc28fb0dc175f48ac9fa364f26a434bedde
@@@ -1,4 -1,7 +1,4 @@@
 -# Copyright (C) 2007 Andre Noll <maan@tuebingen.mpg.de>
 -#
 -# Licensed under the GPL v2. For licencing details see COPYING.
 -
 +# Copyright (C) 2007 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING.
  _para_complete()
  {
        local prg="$1" # the program to execute
@@@ -6,10 -9,6 +6,6 @@@
        local line="$COMP_LINE" OLD_IFS="$IFS"
        local opts n
  
-       if [[ "$COMP_WORDBREAKS" != ' '  ]]; then
-               COMP_WORDBREAKS=' '
-               return 124 # try again with proper value
-       fi
        # This extracts short and long options from the help output
        local script='{
                if ($1 ~ "-[a-zA-Z]," && $2 ~ "--[a-zA-Z]") {
diff --combined gcrypt.c
index d5cb49a45c2d6da4e6249b6810a298a0460c8b1f,f30e8166b01badc08de69487dcb99645d4d15990..052546dd60733d143e6c12bdcfcc92ce36ac5e50
+++ b/gcrypt.c
@@@ -1,4 -1,8 +1,4 @@@
 -/*
 - * Copyright (C) 2011 Andre Noll <maan@tuebingen.mpg.de>
 - *
 - * Licensed under the GPL v2. For licencing details see COPYING.
 - */
 +/* Copyright (C) 2011 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
  
  /** \file gcrypt.c Libgrcypt-based encryption/decryption routines. */
  
@@@ -15,6 -19,9 +15,6 @@@
  
  //#define GCRYPT_DEBUG 1
  
 -static bool libgcrypt_has_oaep;
 -static const char *rsa_decrypt_sexp;
 -
  #ifdef GCRYPT_DEBUG
  static void dump_buffer(const char *msg, unsigned char *buf, int len)
  {
@@@ -52,29 -59,139 +52,30 @@@ void get_random_bytes_or_die(unsigned c
  }
  
  /*
-  * This is called at the beginning of every program that uses libgcrypt. We
-  * don't have to initialize any random seed here, but we must initialize the
-  * gcrypt library. This task is performed by gcry_check_version() which can
-  * also check that the gcrypt library version is at least the minimal required
-  * version.
+  * This is called at the beginning of every program that uses libgcrypt. The
+  * call to gcry_check_version() initializes the gcrypt library and checks that
 - * we have at least the minimal required version. This function also tells us
 - * whether we have to use our own OAEP padding code.
++ * we have at least the minimal required version.
   */
  void init_random_seed_or_die(void)
  {
 -      const char *ver, *req_ver;
 +      const char *req_ver = "1.5.0";
+       int seed;
  
-       if (gcry_check_version(req_ver))
-               return;
-       PARA_EMERG_LOG("fatal: need at least libgcrypt-%s, have: %s\n",
-               req_ver, gcry_check_version(NULL));
-       exit(EXIT_FAILURE);
 -      ver = gcry_check_version(NULL);
 -      req_ver = "1.4.0";
+       if (!gcry_check_version(req_ver)) {
+               PARA_EMERG_LOG("fatal: need at least libgcrypt-%s, have: %s\n",
 -                      req_ver, ver);
++                      req_ver, gcry_check_version(NULL));
+               exit(EXIT_FAILURE);
+       }
 -      req_ver = "1.5.0";
 -      if (gcry_check_version(req_ver)) {
 -              libgcrypt_has_oaep = true;
 -              rsa_decrypt_sexp = "(enc-val(flags oaep)(rsa(a %m)))";
 -      } else {
 -              libgcrypt_has_oaep = false;
 -              rsa_decrypt_sexp = "(enc-val(rsa(a %m)))";
 -      }
+       get_random_bytes_or_die((unsigned char *)&seed, sizeof(seed));
+       srandom(seed);
  }
  
  /** S-expression for the public part of an RSA key. */
  #define RSA_PUBKEY_SEXP "(public-key (rsa (n %m) (e %m)))"
  /** S-expression for a private RSA key. */
  #define RSA_PRIVKEY_SEXP "(private-key (rsa (n %m) (e %m) (d %m) (p %m) (q %m) (u %m)))"
 -
 -/* rfc 3447, appendix B.2 */
 -static void mgf1(unsigned char *seed, size_t seed_len, unsigned result_len,
 -              unsigned char *result)
 -{
 -      gcry_error_t gret;
 -      gcry_md_hd_t handle;
 -      size_t n;
 -      unsigned char *md;
 -      unsigned char octet_string[4], *rp = result, *end = rp + result_len;
 -
 -      assert(result_len / HASH_SIZE < 1ULL << 31);
 -      gret = gcry_md_open(&handle, GCRY_MD_SHA1, 0);
 -      assert(gret == 0);
 -      for (n = 0; rp < end; n++) {
 -              gcry_md_write(handle, seed, seed_len);
 -              octet_string[0] = (unsigned char)((n >> 24) & 255);
 -              octet_string[1] = (unsigned char)((n >> 16) & 255);
 -              octet_string[2] = (unsigned char)((n >> 8)) & 255;
 -              octet_string[3] = (unsigned char)(n & 255);
 -              gcry_md_write(handle, octet_string, 4);
 -              gcry_md_final(handle);
 -              md = gcry_md_read(handle, GCRY_MD_SHA1);
 -              memcpy(rp, md, PARA_MIN(HASH_SIZE, (int)(end - rp)));
 -              rp += HASH_SIZE;
 -              gcry_md_reset(handle);
 -      }
 -      gcry_md_close(handle);
 -}
 -
 -/** The sha1 hash of an empty file. */
 -static const unsigned char empty_hash[HASH_SIZE] =
 -      "\xda" "\x39" "\xa3" "\xee" "\x5e"
 -      "\x6b" "\x4b" "\x0d" "\x32" "\x55"
 -      "\xbf" "\xef" "\x95" "\x60" "\x18"
 -      "\x90" "\xaf" "\xd8" "\x07" "\x09";
 -
 -/* rfc3447, section 7.1.1 */
 -static void pad_oaep(unsigned char *in, size_t in_len, unsigned char *out,
 -              size_t out_len)
 -{
 -      size_t ps_len = out_len - in_len - 2 * HASH_SIZE - 2;
 -      size_t n, mask_len = out_len - HASH_SIZE - 1;
 -      unsigned char *seed = out + 1, *db = seed + HASH_SIZE,
 -              *ps = db + HASH_SIZE, *one = ps + ps_len;
 -      unsigned char *db_mask, seed_mask[HASH_SIZE];
 -
 -      assert(in_len <= out_len - 2 - 2 * HASH_SIZE);
 -      assert(out_len > 2 * HASH_SIZE + 2);
 -      PARA_DEBUG_LOG("padding %zu byte input -> %zu byte output\n",
 -              in_len, out_len);
 -      dump_buffer("unpadded buffer", in, in_len);
 -
 -      out[0] = '\0';
 -      get_random_bytes_or_die(seed, HASH_SIZE);
 -      memcpy(db, empty_hash, HASH_SIZE);
 -      memset(ps, 0, ps_len);
 -      *one = 0x01;
 -      memcpy(one + 1, in, in_len);
 -      db_mask = para_malloc(mask_len);
 -      mgf1(seed, HASH_SIZE, mask_len, db_mask);
 -      for (n = 0; n < mask_len; n++)
 -              db[n] ^= db_mask[n];
 -      mgf1(db, mask_len, HASH_SIZE, seed_mask);
 -      for (n = 0; n < HASH_SIZE; n++)
 -              seed[n] ^= seed_mask[n];
 -      free(db_mask);
 -      dump_buffer("padded buffer", out, out_len);
 -}
 -
 -/* rfc 3447, section 7.1.2 */
 -static int unpad_oaep(unsigned char *in, size_t in_len, unsigned char *out,
 -              size_t *out_len)
 -{
 -      unsigned char *masked_seed = in + 1;
 -      unsigned char *db = in + 1 + HASH_SIZE;
 -      unsigned char seed[HASH_SIZE], seed_mask[HASH_SIZE];
 -      unsigned char *db_mask, *p;
 -      size_t n, mask_len = in_len - HASH_SIZE - 1;
 -
 -      mgf1(db, mask_len, HASH_SIZE, seed_mask);
 -      for (n = 0; n < HASH_SIZE; n++)
 -              seed[n] = masked_seed[n] ^ seed_mask[n];
 -      db_mask = para_malloc(mask_len);
 -      mgf1(seed, HASH_SIZE, mask_len, db_mask);
 -      for (n = 0; n < mask_len; n++)
 -              db[n] ^= db_mask[n];
 -      free(db_mask);
 -      if (memcmp(db, empty_hash, HASH_SIZE))
 -              return -E_OEAP;
 -      for (p = db + HASH_SIZE; p < in + in_len - 1; p++)
 -              if (*p != '\0')
 -                      break;
 -      if (p >= in + in_len - 1)
 -              return -E_OEAP;
 -      p++;
 -      *out_len = in + in_len - p;
 -      memcpy(out, p, *out_len);
 -      return 1;
 -}
 +/** S-expression for decryption. */
 +#define RSA_DECRYPT_SEXP "(enc-val(flags oaep)(rsa(a %m)))"
  
  struct asymmetric_key {
        gcry_sexp_t sexp;
@@@ -185,6 -302,64 +186,6 @@@ static inline int get_long_form_num_len
        return c & 0x7f;
  }
  
 -static int find_pubkey_bignum_offset(const unsigned char *data, int len)
 -{
 -      const unsigned char *p = data, *end = data + len;
 -
 -      /* the whole thing starts with one sequence */
 -      if (*p != ASN1_TYPE_SEQUENCE)
 -              return -E_ASN1_PARSE;
 -      p++;
 -      if (p >= end)
 -              return -E_ASN1_PARSE;
 -      if (is_short_form(*p))
 -              p++;
 -      else
 -              p += 1 + get_long_form_num_length_bytes(*p);
 -      if (p >= end)
 -              return -E_ASN1_PARSE;
 -      /* another sequence containing the object id, skip it */
 -      if (*p != ASN1_TYPE_SEQUENCE)
 -              return -E_ASN1_PARSE;
 -      p++;
 -      if (p >= end)
 -              return -E_ASN1_PARSE;
 -      if (!is_short_form(*p))
 -              return -E_ASN1_PARSE;
 -      p += 1 + get_short_form_length(*p);
 -      if (p >= end)
 -              return -E_ASN1_PARSE;
 -      /* all numbers are wrapped in a bit string object that follows */
 -      if (*p != ASN1_TYPE_BIT_STRING)
 -              return -E_ASN1_PARSE;
 -      p++;
 -      if (p >= end)
 -              return -E_ASN1_PARSE;
 -      if (is_short_form(*p))
 -              p++;
 -      else
 -              p += 1 + get_long_form_num_length_bytes(*p);
 -      p++; /* skip number of unused bits in the bit string */
 -      if (p >= end)
 -              return -E_ASN1_PARSE;
 -
 -      /* next, we have a sequence of two integers (n and e) */
 -      if (*p != ASN1_TYPE_SEQUENCE)
 -              return -E_ASN1_PARSE;
 -      p++;
 -      if (p >= end)
 -              return -E_ASN1_PARSE;
 -      if (is_short_form(*p))
 -              p++;
 -      else
 -              p += 1 + get_long_form_num_length_bytes(*p);
 -      if (p >= end)
 -              return -E_ASN1_PARSE;
 -      if (*p != ASN1_TYPE_INTEGER)
 -              return -E_ASN1_PARSE;
 -      return p - data;
 -}
 -
  /*
   * Returns: Number of bytes scanned. This may differ from the value returned via
   * bn_bytes because the latter does not include the ASN.1 prefix and a leading
@@@ -286,7 -461,6 +287,7 @@@ static int get_private_key(const char *
        gcry_sexp_t sexp;
        struct asymmetric_key *key;
  
 +      *result = NULL;
        ret = decode_key(key_file, PRIVATE_KEY_HEADER, PRIVATE_KEY_FOOTER,
                &blob);
        if (ret < 0)
@@@ -365,6 -539,65 +366,6 @@@ free_blob
        return ret;
  }
  
 -/** Public keys start with this header. */
 -#define PUBLIC_KEY_HEADER "-----BEGIN PUBLIC KEY-----"
 -/** Public keys end with this footer. */
 -#define PUBLIC_KEY_FOOTER "-----END PUBLIC KEY-----"
 -
 -static int get_asn_public_key(const char *key_file, struct asymmetric_key **result)
 -{
 -      gcry_mpi_t n = NULL, e = NULL;
 -      unsigned char *blob, *cp, *end;
 -      int blob_size, ret, n_size;
 -      gcry_error_t gret;
 -      size_t erroff;
 -      gcry_sexp_t sexp;
 -      struct asymmetric_key *key;
 -
 -      ret = decode_key(key_file, PUBLIC_KEY_HEADER, PUBLIC_KEY_FOOTER,
 -              &blob);
 -      if (ret < 0)
 -              return ret;
 -      blob_size = ret;
 -      end = blob + blob_size;
 -      ret = find_pubkey_bignum_offset(blob, blob_size);
 -      if (ret < 0)
 -              goto free_blob;
 -      PARA_DEBUG_LOG("decoding public RSA params at offset %d\n", ret);
 -      cp = blob + ret;
 -
 -      ret = read_bignum(cp, end, &n, &n_size);
 -      if (ret < 0)
 -              goto free_blob;
 -      cp += ret;
 -
 -      ret = read_bignum(cp, end, &e, NULL);
 -      if (ret < 0)
 -              goto release_n;
 -
 -      gret = gcry_sexp_build(&sexp, &erroff, RSA_PUBKEY_SEXP, n, e);
 -      if (gret) {
 -              PARA_ERROR_LOG("offset %zu: %s\n", erroff,
 -                      gcry_strerror(gcry_err_code(gret)));
 -              ret = -E_SEXP_BUILD;
 -              goto release_e;
 -      }
 -      key = para_malloc(sizeof(*key));
 -      key->sexp = sexp;
 -      key->num_bytes = n_size;
 -      *result = key;
 -      ret = n_size;
 -      PARA_INFO_LOG("successfully read %d bit asn public key\n", n_size * 8);
 -
 -release_e:
 -      gcry_mpi_release(e);
 -release_n:
 -      gcry_mpi_release(n);
 -free_blob:
 -      free(blob);
 -      return ret;
 -}
 -
  static int get_ssh_public_key(unsigned char *data, int size, gcry_sexp_t *result)
  {
        int ret;
@@@ -426,7 -659,8 +427,7 @@@ free_blob
        return ret;
  }
  
 -int get_asymmetric_key(const char *key_file, int private,
 -              struct asymmetric_key **result)
 +int get_public_key(const char *key_file, struct asymmetric_key **result)
  {
        int ret, ret2;
        void *map;
        gcry_sexp_t sexp;
        struct asymmetric_key *key;
  
 -      if (private)
 -              return get_private_key(key_file, result);
        ret = mmap_full_file(key_file, O_RDONLY, &map, &map_size, NULL);
        if (ret < 0)
                return ret;
        ret = is_ssh_rsa_key(map, map_size);
        if (!ret) {
 -              ret = para_munmap(map, map_size);
 -              if (ret < 0)
 -                      return ret;
 -              return get_asn_public_key(key_file, result);
 +              para_munmap(map, map_size);
 +              return -E_SSH_PARSE;
        }
        start = map + ret;
        end = map + map_size;
@@@ -462,7 -700,7 +463,7 @@@ unmap
        return ret;
  }
  
 -void free_asymmetric_key(struct asymmetric_key *key)
 +void free_public_key(struct asymmetric_key *key)
  {
        if (!key)
                return;
        free(key);
  }
  
 -static int decode_rsa(gcry_sexp_t sexp, int key_size, unsigned char *outbuf,
 -              size_t *nbytes)
 +static int decode_rsa(gcry_sexp_t sexp, unsigned char *outbuf, size_t *nbytes)
  {
 -      int ret;
 -      gcry_error_t gret;
 -      unsigned char oaep_buf[512];
 -      gcry_mpi_t out_mpi;
 -
 -      if (libgcrypt_has_oaep) {
 -              const char *p = gcry_sexp_nth_data(sexp, 1, nbytes);
 -
 -              if (!p) {
 -                      PARA_ERROR_LOG("could not get data from list\n");
 -                      return -E_OEAP;
 -              }
 -              memcpy(outbuf, p, *nbytes);
 -              return 1;
 -      }
 -      out_mpi = gcry_sexp_nth_mpi(sexp, 0, GCRYMPI_FMT_USG);
 -      if (!out_mpi)
 -              return -E_SEXP_FIND;
 -      gret = gcry_mpi_print(GCRYMPI_FMT_USG, oaep_buf, sizeof(oaep_buf),
 -              nbytes, out_mpi);
 -      if (gret) {
 -              PARA_ERROR_LOG("mpi_print: %s\n", gcrypt_strerror(gret));
 -              ret = -E_MPI_PRINT;
 -              goto out_mpi_release;
 -      }
 -      /*
 -       * An oaep-encoded buffer always starts with at least one zero byte.
 -       * However, leading zeroes in an mpi are omitted in the output of
 -       * gcry_mpi_print() when using the GCRYMPI_FMT_USG format. The
 -       * alternative, GCRYMPI_FMT_STD, does not work either because here the
 -       * leading zero(es) might also be omitted, depending on the value of
 -       * the second byte.
 -       *
 -       * To circumvent this, we shift the oaep buffer to the right. But first
 -       * we check that the buffer actually started with a zero byte, i.e. that
 -       * nbytes < key_size. Otherwise a decoding error occurred.
 -       */
 -      ret = -E_SEXP_DECRYPT;
 -      if (*nbytes >= key_size)
 -              goto out_mpi_release;
 -      memmove(oaep_buf + key_size - *nbytes, oaep_buf, *nbytes);
 -      memset(oaep_buf, 0, key_size - *nbytes);
 +      const char *p = gcry_sexp_nth_data(sexp, 1, nbytes);
  
 -      PARA_DEBUG_LOG("decrypted buffer before unpad (%d bytes):\n",
 -              key_size);
 -      dump_buffer("non-unpadded decrypted buffer", oaep_buf, key_size);
 -      ret = unpad_oaep(oaep_buf, key_size, outbuf, nbytes);
 -      if (ret < 0)
 -              goto out_mpi_release;
 -      PARA_DEBUG_LOG("decrypted buffer after unpad (%zu bytes):\n",
 -              *nbytes);
 -      dump_buffer("unpadded decrypted buffer", outbuf, *nbytes);
 -      ret = 1;
 -out_mpi_release:
 -      gcry_mpi_release(out_mpi);
 -      return ret;
 +      if (!p)
 +              return -E_RSA_DECODE;
 +      memcpy(outbuf, p, *nbytes);
 +      return 1;
  }
  
  int priv_decrypt(const char *key_file, unsigned char *outbuf,
                unsigned char *inbuf, int inlen)
  {
        gcry_error_t gret;
 -      int ret, key_size;
 +      int ret;
        struct asymmetric_key *priv;
        gcry_mpi_t in_mpi = NULL;
        gcry_sexp_t in, out, priv_key;
        size_t nbytes;
  
 -      ret = check_key_file(key_file, true);
 +      ret = check_private_key_file(key_file);
        if (ret < 0)
                return ret;
        PARA_INFO_LOG("decrypting %d byte input\n", inlen);
        ret = get_private_key(key_file, &priv);
        if (ret < 0)
                return ret;
 -      key_size = ret / 8;
  
        /* asymmetric key priv -> sexp priv_key */
        ret = -E_SEXP_FIND;
                goto key_release;
        }
        /* in_mpi -> in sexp */
 -      gret = gcry_sexp_build(&in, NULL, rsa_decrypt_sexp, in_mpi);
 +      gret = gcry_sexp_build(&in, NULL, RSA_DECRYPT_SEXP, in_mpi);
        if (gret) {
                PARA_ERROR_LOG("%s\n", gcrypt_strerror(gret));
                ret = -E_SEXP_BUILD;
                ret = -E_SEXP_DECRYPT;
                goto in_release;
        }
 -      ret = decode_rsa(out, key_size, outbuf, &nbytes);
 +      ret = decode_rsa(out, outbuf, &nbytes);
        if (ret < 0)
                goto out_release;
        PARA_INFO_LOG("successfully decrypted %zu byte message\n", nbytes);
@@@ -542,8 -832,7 +543,8 @@@ in_mpi_release
  key_release:
        gcry_sexp_release(priv_key);
  free_key:
 -      free_asymmetric_key(priv);
 +      gcry_sexp_release(priv->sexp);
 +      free(priv);
        return ret;
  }
  
@@@ -562,7 -851,18 +563,7 @@@ int pub_encrypt(struct asymmetric_key *
        pub_key = gcry_sexp_find_token(pub->sexp, "public-key", 0);
        if (!pub_key)
                return -E_SEXP_FIND;
 -      if (libgcrypt_has_oaep) {
 -              gret = gcry_sexp_build(&in, NULL,
 -                      "(data(flags oaep)(value %b))", len, inbuf);
 -      } else {
 -              unsigned char padded_input[256];
 -              const size_t pad_size = 256;
 -              /* inbuf -> padded inbuf */
 -              pad_oaep(inbuf, len, padded_input, pad_size);
 -              /* padded inbuf -> in sexp */
 -              gret = gcry_sexp_build(&in, NULL,
 -                      "(data(flags raw)(value %b))", pad_size, padded_input);
 -      }
 +      gret = gcry_sexp_build(&in, NULL, "(data(flags oaep)(value %b))", len, inbuf);
        if (gret) {
                PARA_ERROR_LOG("%s\n", gcrypt_strerror(gret));
                ret = -E_SEXP_BUILD;
@@@ -613,20 -913,33 +614,20 @@@ struct stream_cipher 
        gcry_cipher_hd_t handle;
  };
  
 -struct stream_cipher *sc_new(const unsigned char *data, int len,
 -              bool use_aes)
 +struct stream_cipher *sc_new(const unsigned char *data, int len)
  {
        gcry_error_t gret;
        struct stream_cipher *sc = para_malloc(sizeof(*sc));
  
 -      if (use_aes) {
 -              assert(len >= 2 * AES_CRT128_BLOCK_SIZE);
 -              gret = gcry_cipher_open(&sc->handle, GCRY_CIPHER_AES128,
 -                      GCRY_CIPHER_MODE_CTR, 0);
 -              assert(gret == 0);
 -              gret = gcry_cipher_setkey(sc->handle, data,
 -                      AES_CRT128_BLOCK_SIZE);
 -              assert(gret == 0);
 -              gret = gcry_cipher_setctr(sc->handle,
 -                      data + AES_CRT128_BLOCK_SIZE, AES_CRT128_BLOCK_SIZE);
 -              assert(gret == 0);
 -              return sc;
 -      }
 -      gret = gcry_cipher_open(&sc->handle, GCRY_CIPHER_ARCFOUR,
 -              GCRY_CIPHER_MODE_STREAM, 0);
 -      if (gret) {
 -              PARA_ERROR_LOG("%s\n", gcrypt_strerror(gret));
 -              free(sc);
 -              return NULL;
 -      }
 -      gret = gcry_cipher_setkey(sc->handle, data, (size_t)len);
 +      assert(len >= 2 * AES_CRT128_BLOCK_SIZE);
 +      gret = gcry_cipher_open(&sc->handle, GCRY_CIPHER_AES128,
 +              GCRY_CIPHER_MODE_CTR, 0);
 +      assert(gret == 0);
 +      gret = gcry_cipher_setkey(sc->handle, data,
 +              AES_CRT128_BLOCK_SIZE);
 +      assert(gret == 0);
 +      gret = gcry_cipher_setctr(sc->handle,
 +              data + AES_CRT128_BLOCK_SIZE, AES_CRT128_BLOCK_SIZE);
        assert(gret == 0);
        return sc;
  }
diff --combined resample_filter.c
index 8a87b1f33fb063ca8d105683ddd74b091e4ffe2b,84a2ee700aae4c2d4dcbe50a186ccbcf54d0cdce..bbdda51c525630c6d1411dfa547193f8ccdae9ce
@@@ -1,27 -1,27 +1,27 @@@
 -/*
 - * Copyright (C) 2012 Andre Noll <maan@tuebingen.mpg.de>
 - *
 - * Licensed under the GPL v2. For licencing details see COPYING.
 - */
 +/* Copyright (C) 2012 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
  
  /** \file resample_filter.c A sample rate converter based on libsamplerate. */
  
  #include <regex.h>
  #include <samplerate.h>
 +#include <lopsub.h>
  
 -#include "resample_filter.cmdline.h"
 +#include "filter_cmd.lsg.h"
  #include "para.h"
  #include "error.h"
  #include "list.h"
  #include "sched.h"
 -#include "ggo.h"
  #include "buffer_tree.h"
  #include "filter.h"
  #include "string.h"
  #include "check_wav.h"
  
 +#define U32_OPTVAL(_opt, _lpr) (FILTER_CMD_OPT_UINT32_VAL(RESAMPLE, _opt, _lpr))
 +#define OPT_GIVEN(_opt, _lpr) (FILTER_CMD_OPT_GIVEN(RESAMPLE, _opt, _lpr))
 +
 +/* effective values, may differ from config arg */
  struct resample_context {
 -      int channels;
 +      uint32_t channels;
        int source_sample_rate;
        float ratio;
        SRC_STATE *src_state;
@@@ -32,8 -32,10 +32,8 @@@ static int resample_execute(struct btr_
  {
        struct filter_node *fn = btr_context(btrn);
        struct resample_context *ctx = fn->private_data;
 -      struct resample_filter_args_info *conf = fn->conf;
 -
 -      return decoder_execute(cmd, conf->dest_sample_rate_arg, ctx->channels,
 -              result);
 +      uint32_t dsr = U32_OPTVAL(DEST_SAMPLE_RATE, fn->lpr);
 +      return decoder_execute(cmd, dsr, ctx->channels, result);
  }
  
  static void resample_close(struct filter_node *fn)
  static void resample_open(struct filter_node *fn)
  {
        struct resample_context *ctx = para_calloc(sizeof(*ctx));
 -      struct resample_filter_args_info *conf = fn->conf;
        struct btr_node *btrn = fn->btrn;
        struct wav_params wp;
  
        fn->private_data = ctx;
        fn->min_iqs = 2;
 -      COPY_WAV_PARMS(&wp, conf);
 +      LLS_COPY_WAV_PARMS(&wp, LSG_FILTER_CMD_RESAMPLE, fn->lpr);
        ctx->cwc = check_wav_init(btr_parent(btrn), btrn, &wp, NULL);
        btr_log_tree(btr_parent(btr_parent(btrn)), LL_INFO);
  }
@@@ -92,17 -95,18 +92,17 @@@ static int resample_set_params(struct f
  {
        int ret;
        struct resample_context *ctx = fn->private_data;
 -      struct resample_filter_args_info *conf = fn->conf;
        struct btr_node *btrn = fn->btrn;
 +      struct lls_parse_result *lpr = fn->lpr;
  
 -      ctx->channels = conf->channels_arg;
 -      if (!conf->channels_given) {
 +      ctx->channels = U32_OPTVAL(CHANNELS, lpr);
 +      if (!OPT_GIVEN(CHANNELS, lpr)) {
                ret = get_btr_val("channels", btrn);
                if (ret >= 0)
                        ctx->channels = ret;
        }
 -
 -      ctx->source_sample_rate = conf->sample_rate_arg;
 -      if (!conf->sample_rate_given) {
 +      ctx->source_sample_rate = U32_OPTVAL(SAMPLE_RATE, lpr);
 +      if (!OPT_GIVEN(SAMPLE_RATE, lpr)) {
                ret = get_btr_val("sample_rate", btrn);
                if (ret >= 0)
                        ctx->source_sample_rate = ret;
        /* reject all sample formats except 16 bit signed, little endian */
        ret = get_btr_val("sample_format", btrn);
        if (ret >= 0 && ret != SF_S16_LE) {
 -              const char *sample_formats[] = {SAMPLE_FORMATS};
 +              const char * const sample_formats[] = {SAMPLE_FORMATS};
                PARA_ERROR_LOG("unsupported sample format: %s\n",
                        sample_formats[ret]);
                return -ERRNO_TO_PARA_ERROR(EINVAL);
        }
 -      ctx->ratio = (float)conf->dest_sample_rate_arg / ctx->source_sample_rate;
 +      ctx->ratio = U32_OPTVAL(DEST_SAMPLE_RATE, lpr)
 +              / (float)ctx->source_sample_rate;
        return 1;
  }
  
  static int resample_init(struct filter_node *fn)
  {
 -      int ret, converter;
 +      int ret;
 +      const uint32_t trafo[] = {
 +              [RCT_BEST] = SRC_SINC_BEST_QUALITY,
 +              [RCT_MEDIUM] = SRC_SINC_MEDIUM_QUALITY,
 +              [RCT_FASTEST] = SRC_SINC_FASTEST,
 +              [RCT_ZERO_ORDER_HOLD] = SRC_ZERO_ORDER_HOLD,
 +              [RCT_LINEAR] = SRC_LINEAR
 +      };
        struct resample_context *ctx = fn->private_data;
 -      struct resample_filter_args_info *conf = fn->conf;
 +      const struct lls_option *o_c = FILTER_CMD_OPT(RESAMPLE, CONVERTER);
 +      uint32_t converter = U32_OPTVAL(CONVERTER, fn->lpr);
  
 +      PARA_INFO_LOG("converter type: %s\n",
 +              lls_enum_string_val(converter, o_c));
        ret = resample_set_params(fn);
        if (ret < 0)
                return ret;
 -      switch (conf->converter_arg) {
 -      case converter_arg_best:
 -              converter = SRC_SINC_BEST_QUALITY;
 -              break;
 -      case converter_arg_medium:
 -              converter = SRC_SINC_MEDIUM_QUALITY;
 -              break;
 -      case converter_arg_fastest:
 -              converter = SRC_SINC_FASTEST;
 -              break;
 -      case converter_arg_zero_order_hold:
 -              converter = SRC_ZERO_ORDER_HOLD;
 -              break;
 -      case converter_arg_linear:
 -              converter = SRC_LINEAR;
 -              break;
 -      default:
 -              assert(0);
 -      }
 -      ctx->src_state = src_new(converter, conf->channels_arg, &ret);
 +      ctx->src_state = src_new(trafo[converter],
 +              U32_OPTVAL(CHANNELS, fn->lpr), &ret);
        if (!ctx->src_state) {
                PARA_ERROR_LOG("%s\n", src_strerror(ret));
                return -E_LIBSAMPLERATE;
@@@ -155,6 -166,7 +155,7 @@@ static int resample_frames(int16_t *in
                size_t *result_frames)
  {
        int ret, num_samples, out_samples;
+       float *in_float;
        int16_t *out;
        SRC_DATA data;
  
        data.output_frames = num_frames * ctx->ratio + 1;
        out_samples = data.output_frames * ctx->channels;
  
-       data.data_in = para_malloc(num_samples * sizeof(float));
-       src_short_to_float_array(in, data.data_in, num_samples);
+       in_float = para_malloc(num_samples * sizeof(float));
+       src_short_to_float_array(in, in_float, num_samples);
+       data.data_in = in_float;
        data.data_out = para_malloc(out_samples * sizeof(float));
        ret = src_process(ctx->src_state, &data);
-       free(data.data_in);
+       free(in_float);
        if (ret != 0) {
                PARA_ERROR_LOG("%s\n", src_strerror(ret));
                free(data.data_out);
@@@ -190,6 -203,7 +192,6 @@@ static int resample_post_select(__a_unu
        int ret;
        struct filter_node *fn = context;
        struct resample_context *ctx = fn->private_data;
 -      struct resample_filter_args_info *conf = fn->conf;
        struct btr_node *btrn = fn->btrn;
        int16_t *in, *out;
        size_t in_bytes, num_frames;
                if (ret <= 0)
                        goto out;
        }
 -      if (ctx->source_sample_rate == conf->dest_sample_rate_arg) {
 +      if (ctx->source_sample_rate == U32_OPTVAL(DEST_SAMPLE_RATE, fn->lpr)) {
                /*
                 * No resampling necessary. We do not splice ourselves out
                 * though, since our children might want to ask us through the
@@@ -239,45 -253,58 +241,45 @@@ out
        return ret;
  }
  
 -static int resample_parse_config(int argc, char **argv, void **config)
 +static void *resample_setup(const struct lls_parse_result *lpr)
  {
 -      int ret, val, given;
 -      struct resample_filter_args_info *conf = para_calloc(sizeof(*conf));
 -
 -      resample_filter_cmdline_parser(argc, argv, conf);
 +      int given;
 +      uint32_t u32;
  
        /* sanity checks */
 -      ret = -ERRNO_TO_PARA_ERROR(EINVAL);
 -      val = conf->channels_arg;
 -      given = conf->channels_given;
 -      if (val < 0 || (val == 0 && given))
 -              goto err;
 -      val = conf->sample_rate_arg;
 -      given = conf->sample_rate_given;
 -      if (val < 0 || (val == 0 && given))
 -              goto err;
 -      val = conf->dest_sample_rate_arg;
 -      given = conf->dest_sample_rate_given;
 -      if (val < 0 || (val == 0 && given))
 -              goto err;
 -      *config = conf;
 -      return 1;
 -err:
 -      free(conf);
 -      return ret;
 +      u32 = U32_OPTVAL(CHANNELS, lpr);
 +      given = OPT_GIVEN(CHANNELS, lpr);
 +      if (u32 == 0 && given) {
 +              PARA_EMERG_LOG("fatal: zero channels?!\n");
 +              exit(EXIT_FAILURE);
 +      }
 +      u32 = U32_OPTVAL(SAMPLE_RATE, lpr);
 +      given = OPT_GIVEN(SAMPLE_RATE, lpr);
 +      if (u32 == 0 && given) {
 +              PARA_EMERG_LOG("fatal: input sample rate can not be 0\n");
 +              exit(EXIT_FAILURE);
 +      }
 +      u32 = U32_OPTVAL(DEST_SAMPLE_RATE, lpr);
 +      given = OPT_GIVEN(DEST_SAMPLE_RATE, lpr);
 +      if (u32 == 0 && given) {
 +              PARA_EMERG_LOG("fatal: destination sample rate can not be 0\n");
 +              exit(EXIT_FAILURE);
 +      }
 +      return NULL;
  }
  
 -static void resample_free_config(void *conf)
 +static void resample_teardown(__a_unused const struct lls_parse_result *lpr,
 +              void *conf)
  {
 -      if (!conf)
 -              return;
 -      resample_filter_cmdline_parser_free(conf);
        free(conf);
  }
  
 -/**
 - * The init function of the resample filter.
 - *
 - * \param f Structure to initialize.
 - */
 -void resample_filter_init(struct filter *f)
 -{
 -      struct resample_filter_args_info dummy;
 -
 -      resample_filter_cmdline_parser_init(&dummy);
 -      f->close = resample_close;
 -      f->open = resample_open;
 -      f->pre_select = resample_pre_select;
 -      f->post_select = resample_post_select;
 -      f->parse_config = resample_parse_config;
 -      f->free_config = resample_free_config;
 -      f->execute = resample_execute;
 -      f->help = (struct ggo_help)DEFINE_GGO_HELP(resample_filter);
 -}
 +const struct filter lsg_filter_cmd_com_resample_user_data = {
 +      .setup = resample_setup,
 +      .open = resample_open,
 +      .pre_select = resample_pre_select,
 +      .post_select = resample_post_select,
 +      .close = resample_close,
 +      .teardown = resample_teardown,
 +      .execute = resample_execute
 +};