[exim-cvs] cvs commit: exim/exim-src/src expand.c functions.…

Góra strony
Delete this message
Reply to this message
Autor: Tom Kistner
Data:  
Dla: exim-cvs
Temat: [exim-cvs] cvs commit: exim/exim-src/src expand.c functions.h globals.c globals.h
tom 2005/06/16 21:01:29 BST

  Modified files:
    exim-src/src         expand.c functions.h globals.c globals.h 
  Log:
  added "prvs" and "prvscheck" expansion items


  Revision  Changes    Path
  1.27      +269 -0    exim/exim-src/src/expand.c
  1.15      +2 -0      exim/exim-src/src/functions.h
  1.29      +4 -0      exim/exim-src/src/globals.c
  1.21      +3 -0      exim/exim-src/src/globals.h


  Index: expand.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/expand.c,v
  retrieving revision 1.26
  retrieving revision 1.27
  diff -u -r1.26 -r1.27
  --- expand.c    16 Jun 2005 14:10:13 -0000    1.26
  +++ expand.c    16 Jun 2005 20:01:29 -0000    1.27
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/expand.c,v 1.26 2005/06/16 14:10:13 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/expand.c,v 1.27 2005/06/16 20:01:29 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -57,6 +57,8 @@
     US"lookup",
     US"nhash",
     US"perl",
  +  US"prvs",
  +  US"prvscheck",
     US"readfile",
     US"readsocket",
     US"run",
  @@ -74,6 +76,8 @@
     EITEM_LOOKUP,
     EITEM_NHASH,
     EITEM_PERL,
  +  EITEM_PRVS,
  +  EITEM_PRVSCHECK,
     EITEM_READFILE,
     EITEM_READSOCK,
     EITEM_RUN,
  @@ -433,6 +437,9 @@
     { "parent_local_part",   vtype_stringptr,   &deliver_localpart_parent },
     { "pid",                 vtype_pid,         NULL },
     { "primary_hostname",    vtype_stringptr,   &primary_hostname },
  +  { "prvscheck_address",   vtype_stringptr,   &prvscheck_address },
  +  { "prvscheck_keynum",    vtype_stringptr,   &prvscheck_keynum },
  +  { "prvscheck_result",    vtype_stringptr,   &prvscheck_result },
     { "qualify_domain",      vtype_stringptr,   &qualify_domain_sender },
     { "qualify_recipient",   vtype_stringptr,   &qualify_domain_recipient },
     { "rcpt_count",          vtype_int,         &rcpt_count },
  @@ -3163,6 +3170,172 @@
         }
       #endif /* EXIM_PERL */


  +    /* Transform email address to "prvs" scheme to use
  +       as BATV-signed return path */
  +
  +    case EITEM_PRVS:
  +      {
  +      uschar *sub_arg[3];
  +      uschar *p,*domain;
  +
  +      switch(read_subs(sub_arg, 3, 2, &s, skipping, TRUE, US"prvs"))
  +        {
  +        case 1: goto EXPAND_FAILED_CURLY;
  +        case 2:
  +        case 3: goto EXPAND_FAILED;
  +        }
  +
  +      /* If skipping, we don't actually do anything */
  +      if (skipping) continue;
  +
  +      /* sub_arg[0] is the address */
  +      domain = Ustrrchr(sub_arg[0],'@');
  +      if ( (domain == NULL) || (domain == sub_arg[0]) || (Ustrlen(domain) == 1) )
  +        {
  +        expand_string_message = US"first parameter must be a qualified email address";
  +        goto EXPAND_FAILED;
  +        }
  +
  +      /* Calculate the hash */
  +      p = prvs_hmac_sha1(sub_arg[0],sub_arg[1],sub_arg[2],prvs_daystamp(7));
  +      if (p == NULL)
  +        {
  +        expand_string_message = US"hmac-sha1 conversion failed";
  +        goto EXPAND_FAILED;
  +        }
  +
  +      /* Now separate the domain from the local part */
  +      *domain++ = '\0';
  +
  +      yield = string_cat(yield,&size,&ptr,US"prvs=",5);
  +      string_cat(yield,&size,&ptr,sub_arg[0],Ustrlen(sub_arg[0]));
  +      string_cat(yield,&size,&ptr,US"/",1);
  +      string_cat(yield,&size,&ptr,(sub_arg[2] != NULL) ? sub_arg[2] : US"0", 1);
  +      string_cat(yield,&size,&ptr,prvs_daystamp(7),3);
  +      string_cat(yield,&size,&ptr,p,6);
  +      string_cat(yield,&size,&ptr,US"@",1);
  +      string_cat(yield,&size,&ptr,domain,Ustrlen(domain));
  +
  +      continue;
  +      }
  +
  +    /* Check a prvs-encoded address for validity */
  +
  +    case EITEM_PRVSCHECK:
  +      {
  +      uschar *sub_arg[3];
  +      int mysize = 0, myptr = 0;
  +      const pcre *re;
  +      uschar *p;
  +      /* Ugliness: We want to expand parameter 1 first, then set
  +         up expansion variables that are used in the expansion of
  +         parameter 2. So we clone the string for the first
  +         expansion, where we only expand paramter 1. */
  +      uschar *s_backup = string_copy(s);
  +
  +      /* Reset expansion variables */
  +      prvscheck_result = NULL;
  +      prvscheck_address = NULL;
  +      prvscheck_keynum = NULL;
  +
  +      switch(read_subs(sub_arg, 1, 1, &s_backup, skipping, FALSE, US"prvs"))
  +        {
  +        case 1: goto EXPAND_FAILED_CURLY;
  +        case 2:
  +        case 3: goto EXPAND_FAILED;
  +        }
  +
  +      re = regex_must_compile(US"^prvs\\=(.+)\\/([0-9])([0-9]{3})([A-F0-9]{6})\\@(.+)$",
  +                              TRUE,FALSE);
  +
  +      if (regex_match_and_setup(re,sub_arg[0],0,-1)) {
  +        uschar *local_part = string_copyn(expand_nstring[1],expand_nlength[1]);
  +        uschar *key_num = string_copyn(expand_nstring[2],expand_nlength[2]);
  +        uschar *daystamp = string_copyn(expand_nstring[3],expand_nlength[3]);
  +        uschar *hash = string_copyn(expand_nstring[4],expand_nlength[4]);
  +        uschar *domain = string_copyn(expand_nstring[5],expand_nlength[5]);
  +
  +        DEBUG(D_expand) debug_printf("prvscheck localpart: %s\n", local_part);
  +        DEBUG(D_expand) debug_printf("prvscheck key number: %s\n", key_num);
  +        DEBUG(D_expand) debug_printf("prvscheck daystamp: %s\n", daystamp);
  +        DEBUG(D_expand) debug_printf("prvscheck hash: %s\n", hash);
  +        DEBUG(D_expand) debug_printf("prvscheck domain: %s\n", domain);
  +
  +        /* Set up expansion variables */
  +        prvscheck_address = string_cat(NULL, &mysize, &myptr, local_part, Ustrlen(local_part));
  +        string_cat(prvscheck_address,&mysize,&myptr,"@",1);
  +        string_cat(prvscheck_address,&mysize,&myptr,domain,Ustrlen(domain));
  +        prvscheck_address[myptr] = '\0';
  +        prvscheck_keynum = string_copy(key_num);
  +
  +        /* Now re-expand all arguments in the usual manner */
  +        switch(read_subs(sub_arg, 3, 3, &s, skipping, TRUE, US"prvs"))
  +          {
  +          case 1: goto EXPAND_FAILED_CURLY;
  +          case 2:
  +          case 3: goto EXPAND_FAILED;
  +          }
  +
  +        if (*sub_arg[2] == '\0')
  +          yield = string_cat(yield,&size,&ptr,prvscheck_address,Ustrlen(prvscheck_address));
  +        else
  +          yield = string_cat(yield,&size,&ptr,sub_arg[2],Ustrlen(sub_arg[2]));
  +
  +        /* Now we have the key and can check the address. */
  +        p = prvs_hmac_sha1(prvscheck_address, sub_arg[1], prvscheck_keynum, daystamp);
  +        if (p == NULL)
  +          {
  +          expand_string_message = US"hmac-sha1 conversion failed";
  +          goto EXPAND_FAILED;
  +          }
  +
  +        DEBUG(D_expand) debug_printf("prvscheck: received hash is %s\n", hash);
  +        DEBUG(D_expand) debug_printf("prvscheck:      own hash is %s\n", p);
  +        if (Ustrcmp(p,hash) == 0)
  +          {
  +          /* Success, valid BATV address. Now check the expiry date. */
  +          uschar *now = prvs_daystamp(0);
  +          unsigned int inow = 0,iexpire = 1;
  +
  +          sscanf(now,"%u",&inow);
  +          sscanf(daystamp,"%u",&iexpire);
  +
  +          /* When "iexpire" is < 7, a "flip" has occured.
  +             Adjust "inow" accordingly. */
  +          if ( (iexpire < 7) && (inow >= 993) ) inow = 0;
  +
  +          if (iexpire > inow)
  +            {
  +            prvscheck_result = US"1";
  +            DEBUG(D_expand) debug_printf("prvscheck: success, $pvrs_result set to 1\n");
  +            }
  +            else
  +            {
  +            prvscheck_result = NULL;
  +            DEBUG(D_expand) debug_printf("prvscheck: signature expired, $pvrs_result unset\n");
  +            }
  +          }
  +        else
  +          {
  +          prvscheck_result = NULL;
  +          DEBUG(D_expand) debug_printf("prvscheck: hash failure, $pvrs_result unset\n");
  +          }
  +      }
  +      else
  +        {
  +        /* Does not look like a prvs encoded address, return the empty string.
  +           We need to make sure all subs are expanded first. */
  +        switch(read_subs(sub_arg, 3, 3, &s, skipping, TRUE, US"prvs"))
  +          {
  +          case 1: goto EXPAND_FAILED_CURLY;
  +          case 2:
  +          case 3: goto EXPAND_FAILED;
  +          }
  +        }
  +
  +      continue;
  +      }
  +
       /* Handle "readfile" to insert an entire file */


       case EITEM_READFILE:
  @@ -4768,7 +4941,103 @@
   return -2;
   }


  +/********************************************************
  +* prvs: Get last three digits of days since Jan 1, 1970 *
  +********************************************************/
  +
  +/* This is needed to implement the "prvs" BATV reverse
  +   path signing scheme
  +
  +Argument: integer "days" offset to add or substract to
  +          or from the current number of days.
  +
  +Returns:  pointer to string containing the last three
  +          digits of the number of days since Jan 1, 1970,
  +          modified by the offset argument, NULL if there
  +          was an error in the conversion.
  +
  +*/
  +
  +uschar *
  +prvs_daystamp(int day_offset)
  +{
  +uschar *days = store_get(10);
  +snprintf(days, 9, "%lld", (((long long)time(NULL))+(day_offset*86400))/86400);
  +return (Ustrlen(days) >= 3) ? &days[Ustrlen(days)-3] : NULL;
  +}


  +/********************************************************
  +*   prvs: perform HMAC-SHA1 computation of prvs bits    *
  +********************************************************/
  +
  +/* This is needed to implement the "prvs" BATV reverse
  +   path signing scheme
  +
  +Arguments:
  +  address RFC2821 Address to use
  +      key The key to use (must be less than 64 characters
  +          in size)
  +  key_num Single-digit key number to use. Defaults to
  +          '0' when NULL.
  +
  +Returns:  pointer to string containing the first three
  +          bytes of the final hash in hex format, NULL if
  +          there was an error in the process.
  +*/
  +
  +uschar *
  +prvs_hmac_sha1(uschar *address, uschar *key, uschar *key_num, uschar *daystamp)
  +{
  +uschar *hash_source, *p;
  +int size = 0,offset = 0,i;
  +sha1 sha1_base;
  +void *use_base = &sha1_base;
  +uschar innerhash[20];
  +uschar finalhash[20];
  +uschar innerkey[64];
  +uschar outerkey[64];
  +uschar *finalhash_hex = store_get(40);
  +
  +if (key_num == NULL)
  +  key_num = US"0";
  +
  +if (Ustrlen(key) > 64)
  +  return NULL;
  +
  +hash_source = string_cat(NULL,&size,&offset,key_num,1);
  +string_cat(hash_source,&size,&offset,daystamp,3);
  +string_cat(hash_source,&size,&offset,address,Ustrlen(address));
  +hash_source[offset] = '\0';
  +
  +DEBUG(D_expand) debug_printf("prvs: hash source is '%s'\n", hash_source);
  +
  +memset(innerkey, 0x36, 64);
  +memset(outerkey, 0x5c, 64);
  +
  +for (i = 0; i < Ustrlen(key); i++)
  +  {
  +  innerkey[i] ^= key[i];
  +  outerkey[i] ^= key[i];
  +  }
  +
  +chash_start(HMAC_SHA1, use_base);
  +chash_mid(HMAC_SHA1, use_base, innerkey);
  +chash_end(HMAC_SHA1, use_base, hash_source, offset, innerhash);
  +
  +chash_start(HMAC_SHA1, use_base);
  +chash_mid(HMAC_SHA1, use_base, outerkey);
  +chash_end(HMAC_SHA1, use_base, innerhash, 20, finalhash);
  +
  +p = finalhash_hex;
  +for (i = 0; i < 3; i++)
  +  {
  +  *p++ = hex_digits[(finalhash[i] & 0xf0) >> 4];
  +  *p++ = hex_digits[finalhash[i] & 0x0f];
  +  }
  +*p = '\0';
  +
  +return finalhash_hex;
  +}


/*************************************************
**************************************************

  Index: functions.h
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/functions.h,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- functions.h    6 Apr 2005 14:40:24 -0000    1.14
  +++ functions.h    16 Jun 2005 20:01:29 -0000    1.15
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/functions.h,v 1.14 2005/04/06 14:40:24 ph10 Exp $ */
  +/* $Cambridge: exim/exim-src/src/functions.h,v 1.15 2005/06/16 20:01:29 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -173,6 +173,8 @@
   extern uschar *parse_find_at(uschar *);
   extern uschar *parse_fix_phrase(uschar *, int, uschar *, int);
   extern uschar *parse_quote_2047(uschar *, int, uschar *, uschar *, int);
  +extern uschar *prvs_daystamp(int);
  +extern uschar *prvs_hmac_sha1(uschar *, uschar *, uschar *, uschar *);


   extern BOOL    queue_action(uschar *, int, uschar **, int, int);
   extern void    queue_check_only(void);


  Index: globals.c
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/globals.c,v
  retrieving revision 1.28
  retrieving revision 1.29
  diff -u -r1.28 -r1.29
  --- globals.c    10 Jun 2005 19:27:05 -0000    1.28
  +++ globals.c    16 Jun 2005 20:01:29 -0000    1.29
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/globals.c,v 1.28 2005/06/10 19:27:05 fanf2 Exp $ */
  +/* $Cambridge: exim/exim-src/src/globals.c,v 1.29 2005/06/16 20:01:29 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -756,6 +756,10 @@
   uschar  process_info[PROCESS_INFO_SIZE];
   uschar *process_log_path       = NULL;
   BOOL    prod_requires_admin    = TRUE;
  +uschar *prvscheck_address      = NULL;
  +uschar *prvscheck_keynum       = NULL;
  +uschar *prvscheck_result       = NULL;
  +


uschar *qualify_domain_recipient = NULL;
uschar *qualify_domain_sender = NULL;

  Index: globals.h
  ===================================================================
  RCS file: /home/cvs/exim/exim-src/src/globals.h,v
  retrieving revision 1.20
  retrieving revision 1.21
  diff -u -r1.20 -r1.21
  --- globals.h    10 Jun 2005 19:27:05 -0000    1.20
  +++ globals.h    16 Jun 2005 20:01:29 -0000    1.21
  @@ -1,4 +1,4 @@
  -/* $Cambridge: exim/exim-src/src/globals.h,v 1.20 2005/06/10 19:27:05 fanf2 Exp $ */
  +/* $Cambridge: exim/exim-src/src/globals.h,v 1.21 2005/06/16 20:01:29 tom Exp $ */


   /*************************************************
   *     Exim - an Internet mail transport agent    *
  @@ -480,6 +480,9 @@
   extern uschar  process_info[];         /* For SIGUSR1 output */
   extern uschar *process_log_path;       /* Alternate path */
   extern BOOL    prod_requires_admin;    /* TRUE if prodding requires admin */
  +extern uschar *prvscheck_address;      /* Set during prvscheck expansion item */
  +extern uschar *prvscheck_keynum;       /* Set during prvscheck expansion item */
  +extern uschar *prvscheck_result;       /* Set during prvscheck expansion item */


extern uschar *qualify_domain_recipient; /* Domain to qualify recipients with */
extern uschar *qualify_domain_sender; /* Domain to qualify senders with */