time_t parse_duration (char const * pz) { while (isspace ((unsigned char)*pz)) pz++; switch (*pz) { case 'P': return parse_period (pz + 1); case 'T': return parse_time (pz + 1); default: if (isdigit ((unsigned char)*pz)) return parse_non_iso8601 (pz); errno = EINVAL; return BAD_TIME; } }
time_t parse_duration (char const * pz) { time_t res = 0; while (isspace ((unsigned char)*pz)) pz++; do { if (*pz == 'P') { res = parse_period (pz + 1); if ((errno != 0) || (res == BAD_TIME)) break; return res; } if (*pz == 'T') { res = parse_time (pz + 1); if ((errno != 0) || (res == BAD_TIME)) break; return res; } if (! isdigit ((unsigned char)*pz)) break; res = parse_non_iso8601 (pz); if ((errno == 0) && (res != BAD_TIME)) return res; } while (0); fprintf (stderr, _("Invalid time duration: %s\n"), pz); if (errno == 0) errno = EINVAL; return BAD_TIME; }
static void set_stats_limit (ezxml_t inner_xml, stats_limit_cfg * st) { const char *ptr = ezxml_attr (inner_xml, "name"); long value[4]; const char *val_ptr = ezxml_attr (inner_xml, "current"); if (val_ptr == NULL) { fprintf (stderr, "Error: attribute 'current' is absent\n"); exit (-1); } if( strcmp( ptr, "slow" ) == 0 ) { value[0] = parse_period( val_ptr ); value[1] = -1; value[2] = -1; value[3] = -1; } else { value[0] = atof (val_ptr); value[1] = ((val_ptr = ezxml_attr (inner_xml, "short")) == NULL) ? (-1) : atof (val_ptr); value[2] = ((val_ptr = ezxml_attr (inner_xml, "mid")) == NULL) ? (-1) : atof (val_ptr); value[3] = ((val_ptr = ezxml_attr (inner_xml, "long")) == NULL) ? (-1) : atof (val_ptr); } _set_val (&st->cpu, ptr, "cpu", value) || _set_val (&st->write, ptr, "write", value) || _set_val (&st->read, ptr, "read", value) || _set_val (&st->slow, ptr, "slow", value) || fprintf (stderr, "Unknown limit setting: %s\n", ptr); }
struct governor_config * config_init (const char *path) { ezxml_t xml = ezxml_parse_file (path); ezxml_t tmp_xml, inner_xml, tmp_xml_limit; const char *error_str; const char *ptr; if (xml == NULL) { fprintf (stderr, "Error reading config file %s\n", path); exit (-1); } if (strlen (error_str = ezxml_error (xml))) { fprintf (stderr, "Error in config file (%s): %s\n", path, error_str); ezxml_free (xml); exit (-1); } cfg = calloc (1, sizeof (struct governor_config)); memset (cfg, 0, sizeof (struct governor_config)); cfg->is_gpl = check_liblve(); cfg->account_limits = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) free, (GDestroyNotify) free); tmp_xml = ezxml_child (xml, "log"); if (tmp_xml == NULL) { fprintf (stderr, "No log path\n"); exit (-1); } cfg->log = strdup (ezxml_attr (tmp_xml, "file")); cfg->log_mode = ((ptr = ezxml_attr (tmp_xml, "mode")) == NULL) ? ERROR_MODE : mode_type_str_to_enum (ptr); tmp_xml = ezxml_child (xml, "intervals"); if (tmp_xml == NULL) { fprintf (stderr, "No 'intervals' parameter\n"); exit (-1); } cfg->interval_short = ((ptr = ezxml_attr (tmp_xml, "short")) == NULL) ? 5 : atoi (ptr); cfg->interval_mid = ((ptr = ezxml_attr (tmp_xml, "mid")) == NULL) ? 15 : atoi (ptr); cfg->interval_long = ((ptr = ezxml_attr (tmp_xml, "long")) == NULL) ? 30 : atoi (ptr); tmp_xml = ezxml_child (xml, "lve"); cfg->use_lve = 0; cfg->all_lve = 0; cfg->separate_lve = 0; if(tmp_xml != NULL){ if (ezxml_attr (tmp_xml, "use")){ if(!strcasecmp(ezxml_attr (tmp_xml, "use"),"On") || !strcasecmp(ezxml_attr (tmp_xml, "use"),"Single")){ cfg->use_lve = 1; } if(!strcasecmp(ezxml_attr (tmp_xml, "use"),"AbUsers")){ cfg->use_lve = 1; cfg->separate_lve = 1; } if(!strcasecmp(ezxml_attr (tmp_xml, "use"),"All")){ cfg->use_lve = 1; cfg->all_lve = 1; cfg->separate_lve = 1; } } } tmp_xml = ezxml_child (xml, "statistic"); cfg->statistic_mode = 1; if( tmp_xml != NULL ) { if( ezxml_attr( tmp_xml, "mode" ) ) { if( !strcasecmp( ezxml_attr( tmp_xml, "mode" ), "Off" ) ) { cfg->statistic_mode = 0; } } } tmp_xml = ezxml_child (xml, "debug_user"); cfg->debug_user = NULL; if( tmp_xml != NULL ) { if( ezxml_attr( tmp_xml, "name" ) ) { cfg->debug_user = strdup (ezxml_attr (tmp_xml, "name")); } } tmp_xml = ezxml_child( xml, "logqueries" ); cfg->logqueries_use = 0; if( tmp_xml != NULL ) { if( ezxml_attr( tmp_xml, "use" ) ) { if( !strcasecmp( ezxml_attr( tmp_xml, "use" ), "On" ) ) { cfg->logqueries_use = 1; } if( !strcasecmp( ezxml_attr( tmp_xml, "use" ), "Before" ) ) { cfg->logqueries_use = 2; } } } tmp_xml = ezxml_child (xml, "daemon"); cfg->daemon_monitor = 1; if( tmp_xml != NULL ) { if( ezxml_attr( tmp_xml, "monitor" ) ) { if( !strcasecmp( ezxml_attr( tmp_xml, "monitor" ), "Off" ) ) { cfg->daemon_monitor = 0; } } } tmp_xml = ezxml_child (xml, "slow_queries"); cfg->slow_queries = 0; if( tmp_xml != NULL ) { if( ezxml_attr( tmp_xml, "run" ) ) { if( !strcasecmp( ezxml_attr( tmp_xml, "run" ), "On" ) ) { cfg->slow_queries = 1; } } if( ezxml_attr( tmp_xml, "log" ) ) { cfg->slow_queries_log = strdup( ezxml_attr( tmp_xml, "log" ) ); } else { cfg->slow_queries_log = NULL; } } tmp_xml = ezxml_child( xml, "restrict_mode" ); cfg->restrict_mode = 1; cfg->l_unlimit = parse_period( "60s" ); if( tmp_xml != NULL ) { if( ezxml_attr( tmp_xml, "use" ) ) { if( !strcasecmp( ezxml_attr( tmp_xml, "use" ), "period" ) ) { cfg->restrict_mode = 0; } } if( ( ptr = ezxml_attr( tmp_xml, "unlimit" ) ) != NULL ) { cfg->l_unlimit = parse_period( ptr ); } } cfg->killuser = 0; cfg->max_user_connections = 30; tmp_xml = ezxml_child (xml, "restrict"); if (tmp_xml == NULL) { fprintf (stderr, "No 'restrict' parameter\n"); exit (-1); } if (ezxml_attr (tmp_xml, "log")) { cfg->restrict_log = strdup (ezxml_attr (tmp_xml, "log")); } else { cfg->restrict_log = NULL; } if(ezxml_attr (tmp_xml, "killuser")){ if(!strcasecmp(ezxml_attr (tmp_xml, "killuser"), "on")){ cfg->killuser = 1; } } if(ezxml_attr (tmp_xml, "user_max_connections")){ cfg->max_user_connections = atoi(ezxml_attr (tmp_xml, "user_max_connections")); if(cfg->max_user_connections<0) cfg->max_user_connections = 30; } cfg->restrict_format = getRestrictFormat (ezxml_attr (tmp_xml, "format")); cfg->level1 = ((ptr = ezxml_attr (tmp_xml, "level1")) == NULL) ? parse_period ("60s") : parse_period (ptr); cfg->level2 = ((ptr = ezxml_attr (tmp_xml, "level2")) == NULL) ? parse_period ("15m") : parse_period (ptr); cfg->level3 = ((ptr = ezxml_attr (tmp_xml, "level3")) == NULL) ? parse_period ("1h") : parse_period (ptr); cfg->level4 = ((ptr = ezxml_attr (tmp_xml, "level4")) == NULL) ? parse_period ("1d") : parse_period (ptr); cfg->timeout = ((ptr = ezxml_attr (tmp_xml, "timeout")) == NULL) ? parse_period ("1h") : parse_period (ptr); if (ezxml_attr (tmp_xml, "script")) { cfg->exec_script = strdup (ezxml_attr (tmp_xml, "script")); if (cfg->exec_script) { int status_script; struct stat buffer_script; status_script = stat (cfg->exec_script, &buffer_script); if (status_script) { fprintf (stderr, "Wrong script name - %s\n", cfg->exec_script); exit (-1); } else { if (S_ISDIR (buffer_script.st_mode)) { fprintf (stderr, "Script is directory - %s\n", cfg->exec_script); exit (-1); } } } } else { cfg->exec_script = NULL; } tmp_xml = ezxml_child (xml, "connector"); if (tmp_xml == NULL) { fprintf (stderr, "No connector parameter"); exit (-1); } cfg->db_login = strdup (!ezxml_attr (tmp_xml, "login") ? "" : ezxml_attr (tmp_xml, "login")); cfg->db_password = strdup (!ezxml_attr (tmp_xml, "password") ? "" : ezxml_attr (tmp_xml, "password")); cfg->host = strdup (!ezxml_attr (tmp_xml, "host") ? "" : ezxml_attr (tmp_xml, "host")); cfg->separator = !ezxml_attr (tmp_xml, "prefix_separator") ? '_' : *(ezxml_attr (tmp_xml, "prefix_separator")); tmp_xml = ezxml_child (xml, "default"); if (tmp_xml == NULL) { fprintf (stderr, "No default limits"); exit (-1); } cfg->default_limit.mode = RESTRICT_MODE; for (tmp_xml_limit = ezxml_child (tmp_xml, "limit"); tmp_xml_limit; tmp_xml_limit = tmp_xml_limit->next) { set_stats_limit (tmp_xml_limit, &cfg->default_limit); } cfg->default_limit.mode = RESTRICT_MODE; cfg->default_limit.account_flag = true; for (tmp_xml = ezxml_child (xml, "user"); tmp_xml; tmp_xml = tmp_xml->next) { const char *account = ezxml_attr (tmp_xml, "name"); const char *mysql_name = ezxml_attr (tmp_xml, "mysql_name"); if ((account == NULL) && (mysql_name == NULL)) { fprintf (stderr, "Error: both 'name' and 'mysql_name' attributes are absent\n"); exit (-1); } if ((account != NULL) && (mysql_name != NULL)) { fprintf (stderr, "Error: both 'name' and 'mysql_name' attributes are present\n"); exit (-1); } stats_limit_cfg *l = calloc (1, sizeof (stats_limit_cfg)); // inheritance of limits from default memcpy (l, &cfg->default_limit, sizeof (stats_limit_cfg)); l->account_flag = account != NULL; l->mode = ((ptr = ezxml_attr (tmp_xml, "mode")) == NULL) ? RESTRICT_MODE : mode_type_str_to_enum (ptr); for (tmp_xml_limit = ezxml_child (tmp_xml, "limit"); tmp_xml_limit; tmp_xml_limit = tmp_xml_limit->next) { set_stats_limit (tmp_xml_limit, l); } g_hash_table_replace (cfg->account_limits, (gpointer) strdup ((account == NULL) ? mysql_name : account), l); } ezxml_free (xml); return cfg; }
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 ); }
tms option_period(char* opt, char* dflt, char* descr) { return parse_period(option(opt, dflt, descr)); }