Exemplo n.º 1
0
int main( int argc, char* argv[] ) {
    int err = 0;
    int opt, bits=20, str_type = TYPE_WILD, ignore_boundary_flag;
    int case_flag = 0, check_flag = 0, db_flag = 0, core, res = HASHCASH_FAIL;
    int mint_flag = 0, purge_flag = 0, core_flag = 0;
    int time_width = 6, compress = 0, checked = 0;
    long anon_random = 0, anon_period = 0, purge_period = 0, time_period = 0;
    time_t real_time = time(0); /* now, in UTCTIME */
    time_t now_time = real_time, token_time;
    int speed_flag = 0, utc_flag = 0, version_flag = 0, hdr_flag = 0;
    char* header = NULL;
    char* db_filename = "hashcash.sdb";
    char* purge_resource = NULL;
    char* resource = NULL;
    char* ext = NULL;
    int purge_all = 0;
    long validity_period = 28*TIME_DAY; /* default validity period: 28 days */
    long purge_validity_period = 28*TIME_DAY; /* same default */
    long grace_period = 2*TIME_DAY; /* default grace period: 2 days */
    long valid_for = HASHCASH_INVALID;
    char *new_token = NULL ;
    char token[MAX_TOK+1], token_utime[MAX_UTC+1], period[MAX_PERIOD+1];
    double tries_taken = 0;
    void** compile = NULL;
    char* re_err = NULL;
    DB db;
    hashcash_callback callback = NULL;

    while ( (opt=getopt( argc, argv, 
	 "-a:b:cde:f:g:hij:klmnop:qr:sSt:uvwx:yz:CEMO:PSVXZ:")) >0 ) {
	switch( opt ) {
	case 'a': 
	    if ( !parse_period( optarg, &anon_period ) ) {
		usage( "error: -a invalid period arg" );
	    }
	    break;
	case 'b': bits = atoi( optarg+1 );
	    if ( bits < 0 ) { usage( "error: -b invalid bits arg" ); }
	    break;
	case 'C': case_flag = 1; break;
	case 'c': check_flag = 1; break;
	case 'd': db_flag = 1; break;
	case 'e': 
	    if ( !parse_period( optarg, &validity_period ) ||
		 validity_period < 0 ) {
		usage( "error: -e invalid validity period" ); 
	    }
	    break;
	case 'E': str_type = TYPE_REGEXP; break;
	case 'f': db_filename = strdup( optarg ); break;
	case 'g': 
	    if ( optarg[0] == '-' ) {
		usage( "error: -g -ve grace period not valid" );
	    }
	    if ( !parse_period( optarg, &grace_period ) ) {
		usage( "error: -g invalid grace period format" );
	    }
	    break;
	case 'h': usage( "" ); break;
	case 'i': ignore_boundary_flag = 1; break;
	case 'j': purge_resource = optarg; break;
	case 'k': purge_all = 1; break;
	case 'm': mint_flag = 1; break;
	case 'M': str_type = TYPE_WILD; break;
	case 'O': core_flag = 1; 
	    core = atoi( optarg ); 
	    res = hashcash_use_core( core );
	    if ( res < 1 ) {
		usage( res == -1 ? "error: -O no such core\n" : 
		       "error: -O core does not work on this platform" );
	    }
	    break;
	case 'p': 
	    purge_flag = 1;
	    if ( strcmp( optarg, "now" ) == 0 ) { purge_period = 0; }
	    else if ( !parse_period( optarg, &purge_period ) ||
		      purge_period < 0 ) {
		usage( "error: -p invalid purge interval" ); 
	    }
	    break;
	case 'P': callback = progress_callback; break;
	case 1:
	case 'r': resource = optarg; break;
	case 's': speed_flag = 1; break;
	case 'S': str_type = TYPE_STR; break;
	case 't':
	    if ( optarg[0] == '-' || optarg[0] == '+' ) {
		if ( !parse_period( optarg, &time_period ) ) {
		    usage( "error: -t invalid relative time format" );
		}
		now_time += time_period;
	    } else {
		now_time = hashcash_from_utctimestr( optarg, utc_flag );
		if ( now_time == (time_t)-1 ) { 
		    usage( "error: -t invalid time format" ); 
		}
	    }
	    break;
	case 'u': utc_flag = 1; break;
        case 'V': version_flag = 1; break;
	case 'x': ext = strdup( optarg ); break;
	case 'X':
	    hdr_flag = 1;
	    sstrncpy( header, "X-Hashcash: ", MAX_HDR );
	    break;
	case 'z': 
	    time_width = atoi( optarg );
	    if ( time_width != 6 && time_width != 10 && time_width != 12 ) {
	        usage( "error: -z invalid time width: must be 6, 10 or 12" );
	    }
	    break;
	case 'Z': compress = atoi( optarg ); break;
	case '?': 
	    fprintf( stderr, "error: unrecognized option -%c", optopt );
	    usage( "" );
	    break;
	case ':':
	    fprintf( stderr, "error: option -%c missing argument", optopt );
	    usage( "" );
	    break;
	default:
	    usage( "error with argument processing" );
	    break;
	}
    }

    if ( version_flag ) {
	fprintf( stdout, "%s\n", HASHCASH_VERSION_STRING );
	exit( EXIT_FAILURE );
    }

    if ( speed_flag ) {
	if ( core_flag ) { 
	    hashcash_benchtest( 3, core );
	} else {
	    hashcash_benchtest( 3, -1 );
	}
	exit( EXIT_FAILURE ); 
    }

    if ( mint_flag ) {
	err = hashcash_mint( now_time, time_width, resource, bits, 
			     anon_period, &new_token, &anon_random, 
			     &tries_taken, ext, compress, 
			     callback, NULL );
    } else if ( purge_flag ) {
	if ( !hashcash_db_open( &db, db_filename, &err ) ) {
	    die(err);
	}
	if ( !hashcash_db_purge( &db, purge_resource, str_type, case_flag,
				 validity_period, grace_period, purge_all,
				 purge_period, now_time, &err ) ) {
	    die(err);
	}
	if ( !hashcash_db_close( &db, &err ) ) {
	    die(err);
	}
    } else if ( check_flag ) {
	valid_for = hashcash_check( token, case_flag, resource, compile, 
				    &re_err, str_type, now_time, 
				    validity_period, grace_period, bits, 
				    &token_time );
	if ( valid_for < 0 ) {
	    switch ( valid_for ) {
	    case HASHCASH_INSUFFICIENT_BITS:
		fprintf( stderr, "no match: token has insufficient bits\n" );
		break;
	    case HASHCASH_VALID_IN_FUTURE:
		fprintf( stderr, "no match: valid in future\n" );
		break;
	    case HASHCASH_EXPIRED:
		fprintf( stderr, "no match: token expired\n" );
		break;
	    case HASHCASH_WRONG_RESOURCE:
		fprintf( stderr, "no match: wrong resource\n" );
		break;
	    case HASHCASH_REGEXP_ERROR:
		fprintf( stderr, "regexp error: " );
		die_msg( re_err );
		break;
		
	    default:
		die_msg( "internal error" );
		break;
	    }
	    exit( EXIT_FAILURE );
	}
	checked = 1;
    } 

    if ( db_flag && check_flag && checked ) {
	if ( !hashcash_db_open( &db, db_filename, &err ) ) {
	    die(err);
	}
	if ( hashcash_db_in( &db, token, token_utime, &err ) ) {
	    if ( err ) { die(err); }
	    fprintf( stderr, "stamp: double spent\n" );
	}
	sprintf( period, "%ld", (long)validity_period );
	if ( !hashcash_db_add( &db, token, period, &err ) ) {
	    die(err);
	}
	if ( !hashcash_db_close( &db, &err ) ) {
	    die(err);
	}
    }

    exit( EXIT_SUCCESS );
}
Exemplo n.º 2
0
void main(int argc,char **argv)
{
  char *dir;
  int fdlock;
  char *sender;
  int match;
  int flaginheader;
  int flagmodpost;
  int flagremote;
  const char *pmod;
  const char *err;
  int opt;
  unsigned int i;
  char szchar[2] = "-";
  int child;

  (void) umask(022);
  sig_pipeignore();

  if (!stralloc_copys(&sendopt,"-")) die_nomem();
  while ((opt = getopt(argc,argv,"bBcCmMpPrRsSvVyY")) != opteof)
    switch(opt) {
      case 'b': flagbody = 1; break;
      case 'B': flagbody = 0; break;
      case 'm': flagmime = 1; break;
      case 'M': flagmime = 0; break;
      case 'p': flagpublic = 1; break;	/* anyone can post (still moderated)*/
      case 'P': flagpublic = 0; break;	/* only moderators can post */
      case 's': flagself = 1; break;	/* modpost and DIR/mod diff fxns */
      case 'S': flagself = 0; break;	/* same fxn */
      case 'y': flagconfirm = 1; break; /* force post confirmation */
      case 'Y': flagconfirm = 0; break; /* disable post confirmation */
      case 'c':				/* ezmlm-send flags */
      case 'C':
      case 'r':
      case 'R':
        szchar[0] = (char) opt & 0xff;
        if (!stralloc_append(&sendopt,szchar)) die_nomem();
        break;
      case 'v':
      case 'V': strerr_die2x(0,"ezmlm-store version: ",auto_version);
      default:
	die_usage();
    }

  sender = env_get("SENDER");

  if (sender) {
    if (!*sender || str_equal(sender,"#@[]"))
      strerr_die2x(100,FATAL,ERR_BOUNCE);
  }

  startup(dir = argv[optind]);
  load_config(dir);

  if (flagconfirm == -1)
    flagconfirm = getconf_line(&confirmpost,"confirmpost",0,dir);
  else
    getconf_line(&confirmpost,"confirmpost",0,dir);

  flagmodpost = getconf_line(&moderators,"modpost",0,dir);
  flagremote = getconf_line(&line,"remote",0,dir);
  if (!flagmodpost && !flagconfirm) {	/* not msg-mod. Pipe to ezmlm-send */
    if ((child = wrap_fork()) == 0)
      wrap_execbin("/ezmlm-send", &sendopt, dir);
    /* parent */
    wrap_exitcode(child);
  }

  if (!moderators.len || !(moderators.s[0] == '/')) {
    if (!stralloc_copys(&moderators,dir)) die_nomem();
    if (!stralloc_cats(&moderators,"/mod")) die_nomem();
  }
  if (!stralloc_0(&moderators)) die_nomem();

  if (sender) {
      pmod = issub(moderators.s,0,sender);
      closesub();
				/* sender = moderator? */
  } else
    pmod = 0;

  if (!pmod && !flagpublic)
    strerr_die2x(100,FATAL,ERR_NO_POST);

  fdlock = lockfile("mod/lock");

  if (!stralloc_copys(&mydtline, flagconfirm
    ? "Delivered-To: confirm to "
    : "Delivered-To: moderator for ")) die_nomem();
  if (!stralloc_catb(&mydtline,outlocal.s,outlocal.len)) die_nomem();
  if (!stralloc_append(&mydtline,"@")) die_nomem();
  if (!stralloc_catb(&mydtline,outhost.s,outhost.len)) die_nomem();
  if (!stralloc_cats(&mydtline,"\n")) die_nomem();

  if (!stralloc_copys(&returnpath,"Return-Path: <")) die_nomem();
  if (sender) {
    if (!stralloc_cats(&returnpath,sender)) die_nomem();
    for (i = 14; i < returnpath.len;++i)
      if (returnpath.s[i] == '\n' || !returnpath.s[i] )
        returnpath.s[i] = '_';
		/* NUL and '\n' are bad, but we don't quote since this is */
		/* only for ezmlm-moderate, NOT for SMTP */
  }
  if (!stralloc_cats(&returnpath,">\n")) die_nomem();

 pid = getpid();		/* unique file name */
 for (i = 0;;++i)		/* got lock - nobody else can add files */
  {
   when = now();		/* when is also used later for date! */
   if (!stralloc_copys(&fnmsg, flagconfirm?"mod/unconfirmed/":"mod/pending/")) die_nomem();
   if (!stralloc_copyb(&fnbase,strnum,fmt_ulong(strnum,when))) die_nomem();
   if (!stralloc_append(&fnbase,".")) die_nomem();
   if (!stralloc_catb(&fnbase,strnum,fmt_ulong(strnum,pid))) die_nomem();
   if (!stralloc_cat(&fnmsg,&fnbase)) die_nomem();
   if (!stralloc_0(&fnmsg)) die_nomem();
   if (stat(fnmsg.s,&st) == -1) if (errno == error_noent) break;
   /* really should never get to this point */
   if (i == 2)
     strerr_die2x(111,FATAL,ERR_UNIQUE);
   sleep(2);
  }

  if (!stralloc_copys(&action,"-")) die_nomem();
  if (!stralloc_cats(&action,flagconfirm?ACTION_DISCARD:ACTION_REJECT)) die_nomem();
  if (!stralloc_cat(&action,&fnbase)) die_nomem();
  if (!stralloc_0(&action)) die_nomem();
  makeacthash(&action);
  if (!quote(&quoted,&outlocal)) die_nomem();
  if (!stralloc_copy(&reject,&quoted)) die_nomem();
  if (!stralloc_cat(&reject,&action)) die_nomem();
  if (!stralloc_0(&reject)) die_nomem();

  if (!stralloc_copys(&action,"-")) die_nomem();
  if (!stralloc_cats(&action,flagconfirm?ACTION_CONFIRM:ACTION_ACCEPT)) die_nomem();
  if (!stralloc_cat(&action,&fnbase)) die_nomem();
  if (!stralloc_0(&action)) die_nomem();
  makeacthash(&action);
  if (!stralloc_copy(&accept,&quoted)) die_nomem();
  if (!stralloc_cat(&accept,&action)) die_nomem();
  if (!stralloc_0(&accept)) die_nomem();

  set_cptarget(accept.s);	/* for copy () */
  set_cpconfirm(reject.s,quoted.len);

  fdmsg = open_trunc(fnmsg.s);
  if (fdmsg == -1)
    strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnmsg.s,": ");
  substdio_fdbuf(&ssmsg,write,fdmsg,msgbuf,sizeof(msgbuf));

  if (qmail_open(&qq, (stralloc *) 0) == -1)		/* Open mailer */
    strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE);

  hdr_add2("Mailing-List: ",mailinglist.s,mailinglist.len);
  if (listid.len > 0)
    hdr_add2("List-ID: ",listid.s,listid.len);
  hdr_datemsgid(when);
  if (flagconfirm)
    hdr_from("-owner");
  else
    hdr_add2s("From: ",reject.s);
  hdr_add2s("Reply-To: ",accept.s);
  if (!flagconfirm && !pmod && flagremote) {	/* if remote admin add -allow- address */
    qmail_puts(&qq,"Cc: ");	/* for ezmlm-gate users */
    strnum[fmt_ulong(strnum,(unsigned long) when)] = 0;
    cookie(hash,key.s,key.len-FLD_ALLOW,strnum,sender,"t");
    if (!stralloc_copy(&line,&outlocal)) die_nomem();
    if (!stralloc_cats(&line,"-allow-tc.")) die_nomem();
    if (!stralloc_cats(&line,strnum)) die_nomem();
    if (!stralloc_append(&line,".")) die_nomem();
    if (!stralloc_catb(&line,hash,COOKIE)) die_nomem();
    if (!stralloc_append(&line,"-")) die_nomem();
    i = str_rchr(sender,'@');
    if (!stralloc_catb(&line,sender,i)) die_nomem();
    if (sender[i]) {
      if (!stralloc_append(&line,"=")) die_nomem();
      if (!stralloc_cats(&line,sender + i + 1)) die_nomem();
    }
    qmail_put(&qq,line.s,line.len);
    qmail_puts(&qq,"@");
    qmail_put(&qq,outhost.s,outhost.len);
    qmail_puts(&qq,"\n");
  }
  qmail_puts(&qq,"To: <");
  if (flagconfirm) {
    if (sender)
      qmail_puts(&qq, sender);
  } else {
    if (!quote(&quoted,&outlocal))
      die_nomem();
    qmail_put(&qq,quoted.s,quoted.len);
    qmail_puts(&qq,"-moderators@");
    qmail_put(&qq,outhost.s,outhost.len);
  }
  qmail_puts(&qq,">\n");
  /* FIXME: Drop the custom subject hack and use hdr_listsubject1 */
  if (!stralloc_copys(&subject,"Subject: ")) die_nomem();
  if (flagconfirm) {
    if (confirmpost.len) {
      if (!stralloc_cat(&subject,&confirmpost)) die_nomem();
      if (!stralloc_cats(&subject," ")) die_nomem();
    } else {
      if (!stralloc_cats(&subject,TXT_CONFIRM_POST)) die_nomem();
    }
  } else {
    if (!stralloc_cats(&subject,TXT_MODERATE)) die_nomem();
  }
  if (!quote(&quoted,&outlocal)) die_nomem();
  if (!stralloc_cat(&subject,&quoted)) die_nomem();
  if (!stralloc_append(&subject,"@")) die_nomem();
  if (!stralloc_cat(&subject,&outhost)) die_nomem();
  if (flagmime) {
    hdr_mime(CTYPE_MULTIPART);
    qmail_put(&qq,subject.s,subject.len);
    hdr_boundary(0);
    hdr_ctype(CTYPE_TEXT);
    hdr_transferenc();
  } else {
    qmail_put(&qq,subject.s,subject.len);
    qmail_puts(&qq,"\n\n");
  }
  copy(&qq,flagconfirm?"text/post-confirm":"text/mod-request",flagcd);
  if (flagcd == 'B') {
    encodeB("",0,&line,2);
    qmail_put(&qq,line.s,line.len);
  }
  if (substdio_put(&ssmsg,returnpath.s,returnpath.len) == -1) die_msg();
  if (substdio_put(&ssmsg,mydtline.s,mydtline.len) == -1) die_msg();
  substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf));

  if (flagmime) {
    hdr_boundary(0);
    hdr_ctype(CTYPE_MESSAGE);
    qmail_puts(&qq, "\n");
  }

  qmail_put(&qq,returnpath.s,returnpath.len);
  qmail_put(&qq,mydtline.s,mydtline.len);
  flaginheader = 1;
  for (;;) {
    if (getln(&ssin,&line,&match,'\n') == -1)
      strerr_die2sys(111,FATAL,ERR_READ_INPUT);
    if (!match) break;
    if (line.len == 1) flaginheader = 0;
    if (flaginheader) {
      if ((line.len == mydtline.len) &&
		!byte_diff(line.s,line.len,mydtline.s)) {
	close(fdmsg);			/* be nice - clean up */
	unlink(fnmsg.s);
        strerr_die2x(100,FATAL,ERR_LOOPING);
      }
      if (case_startb(line.s,line.len,"mailing-list:")) {
	close(fdmsg);			/* be nice - clean up */
	unlink(fnmsg.s);
        strerr_die2x(100,FATAL,ERR_MAILING_LIST);
      }
    }

    if (flagbody || flaginheader)	/* skip body if !flagbody */
      qmail_put(&qq,line.s,line.len);
    if (substdio_put(&ssmsg,line.s,line.len) == -1) die_msg();
  }

  if (flagmime)
    hdr_boundary(1);

/* close archive before qmail. Loss of qmail will result in re-run, and   */
/* worst case this results in a duplicate msg sitting orphaned until it's */
/* cleaned out.                                                           */

  if (substdio_flush(&ssmsg) == -1) die_msg();
  if (fsync(fdmsg) == -1) die_msg();
  if (fchmod(fdmsg,MODE_MOD_MSG | 0700) == -1) die_msg();
  if (close(fdmsg) == -1) die_msg(); /* NFS stupidity */

  close(fdlock);

  if (flagconfirm) {
    qmail_from(&qq,reject.s);			/* envelope sender */
  } else {
    if (!stralloc_copy(&line,&outlocal)) die_nomem();
    if (!stralloc_cats(&line,"-return-@")) die_nomem();
    if (!stralloc_cat(&line,&outhost)) die_nomem();
    if (!stralloc_0(&line)) die_nomem();
    qmail_from(&qq,line.s);			/* envelope sender */
  }
  if (flagconfirm)				/* to sender */
    qmail_to(&qq,sender);
  else if (pmod)				/* to moderator only */
    qmail_to(&qq,pmod);
  else {
    if (flagself) {				/* to all moderators */
      if (!stralloc_copys(&moderators,dir)) die_nomem();
      if (!stralloc_cats(&moderators,"/mod")) die_nomem();
      if (!stralloc_0(&moderators)) die_nomem();
    }
    putsubs(moderators.s,0,0,52,subto,1);
  }

  if (*(err = qmail_close(&qq)) == '\0') {
      strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
      strerr_die2x(0,"ezmlm-store: info: qp ",strnum);
  } else
      strerr_die3x(111,FATAL,ERR_TMP_QMAIL_QUEUE,err+1);
}