#ifdef CS_ANTICASC
static void account_fixups_fn(void *var)
{
struct s_auth *account = var;
if(account->ac_users < -1) { account->ac_users = DEFAULT_AC_USERS; }
if(account->ac_penalty < -1) { account->ac_penalty = DEFAULT_AC_PENALTY; }
}
#endif
#define OFS(X) offsetof(struct s_auth, X)
#define SIZEOF(X) sizeof(((struct s_auth *)0)->X)
static const struct config_list account_opts[] =
{
#ifdef CS_ANTICASC
DEF_OPT_FIXUP_FUNC(account_fixups_fn),
#endif
DEF_OPT_INT8("disabled" , OFS(disabled), 0),
DEF_OPT_SSTR("user" , OFS(usr), "", SIZEOF(usr)),
DEF_OPT_STR("pwd" , OFS(pwd), NULL),
#ifdef WEBIF
DEF_OPT_STR("description" , OFS(description), NULL),
#endif
DEF_OPT_STR("hostname" , OFS(dyndns), NULL),
DEF_OPT_FUNC("caid" , OFS(ctab), check_caidtab_fn),
DEF_OPT_INT8("uniq" , OFS(uniq), 0),
DEF_OPT_UINT8("sleepsend" , OFS(c35_sleepsend), 0),
DEF_OPT_INT32("failban" , OFS(failban), 0),
DEF_OPT_INT8("monlevel" , OFS(monlvl), 0),
DEF_OPT_FUNC("sleep" , OFS(tosleep), account_tosleep_fn),
DEF_OPT_FUNC("suppresscmd08" , OFS(c35_suppresscmd08), account_c35_suppresscmd08_fn),
DEF_OPT_FUNC("umaxidle" , OFS(umaxidle), account_umaxidle_fn),
DEF_OPT_FUNC("keepalive" , OFS(ncd_keepalive), account_ncd_keepalive_fn),
DEF_OPT_FUNC("au" , 0, account_au_fn),
DEF_OPT_UINT8("emmreassembly" , OFS(emm_reassembly), 2),
DEF_OPT_FUNC("expdate" , 0, account_expdate_fn),
DEF_OPT_FUNC("allowedprotocols" , 0, account_allowedprotocols_fn),
DEF_OPT_FUNC("allowedtimeframe" , 0, account_allowedtimeframe_fn),
DEF_OPT_FUNC("betatunnel" , OFS(ttab), account_tuntab_fn),
DEF_OPT_FUNC("group" , OFS(grp), group_fn),
DEF_OPT_FUNC("services" , OFS(sidtabs), services_fn),
DEF_OPT_FUNC_X("ident" , OFS(ftab), ftab_fn, FTAB_ACCOUNT | FTAB_PROVID),
DEF_OPT_FUNC_X("chid" , OFS(fchid), ftab_fn, FTAB_ACCOUNT | FTAB_CHID),
DEF_OPT_FUNC("class" , OFS(cltab), class_fn),
#ifdef CS_CACHEEX
DEF_OPT_INT8("cacheex" , OFS(cacheex.mode), 0),
DEF_OPT_INT8("cacheex_maxhop" , OFS(cacheex.maxhop), 0),
DEF_OPT_FUNC("cacheex_ecm_filter" , OFS(cacheex.filter_caidtab), cacheex_hitvaluetab_fn),
DEF_OPT_UINT8("cacheex_drop_csp" , OFS(cacheex.drop_csp), 0),
DEF_OPT_UINT8("cacheex_allow_request" , OFS(cacheex.allow_request), 1),
#endif
#ifdef MODULE_CCCAM
DEF_OPT_INT32("cccmaxhops" , OFS(cccmaxhops), DEFAULT_CC_MAXHOPS),
DEF_OPT_INT8("cccreshare" , OFS(cccreshare), DEFAULT_CC_RESHARE),
DEF_OPT_INT8("cccignorereshare" , OFS(cccignorereshare), DEFAULT_CC_IGNRSHR),
DEF_OPT_INT8("cccstealth" , OFS(cccstealth), DEFAULT_CC_STEALTH),
#endif
#ifdef CS_ANTICASC
DEF_OPT_INT32("fakedelay" , OFS(ac_fakedelay), -1),
DEF_OPT_INT32("numusers" , OFS(ac_users), DEFAULT_AC_USERS),
DEF_OPT_INT8("penalty" , OFS(ac_penalty), DEFAULT_AC_PENALTY),
#endif
#ifdef WITH_LB
DEF_OPT_INT32("lb_nbest_readers" , OFS(lb_nbest_readers), -1),
DEF_OPT_INT32("lb_nfb_readers" , OFS(lb_nfb_readers), -1),
DEF_OPT_FUNC("lb_nbest_percaid" , OFS(lb_nbest_readers_tab), caidvaluetab_fn),
#endif
DEF_LAST_OPT
};
void chk_account(const char *token, char *value, struct s_auth *account)
{
if(config_list_parse(account_opts, token, value, account))
{ return; }
else if(token[0] != '#')
{ fprintf(stderr, "Warning: keyword '%s' in account section not recognized\n", token); }
}
void account_set_defaults(struct s_auth *account)
{
config_list_set_defaults(account_opts, account);
}
struct s_auth *init_userdb(void)
{
FILE *fp = open_config_file(cs_user);
if(!fp)
{ return NULL; }
struct s_auth *authptr = NULL;
int32_t tag = 0, nr = 0, expired = 0, disabled = 0;
char *token;
struct s_auth *account = NULL;
struct s_auth *probe = NULL;
if(!cs_malloc(&token, MAXLINESIZE))
{ return NULL; }
while(fgets(token, MAXLINESIZE, fp))
{
int32_t l;
void *ptr;
if((l = strlen(trim(token))) < 3)
{ continue; }
if(token[0] == '[' && token[l - 1] == ']')
{
token[l - 1] = 0;
tag = streq("account", strtolower(token + 1));
if(!cs_malloc(&ptr, sizeof(struct s_auth)))
{ break; }
if(account)
{ account->next = ptr; }
else
{ authptr = ptr; }
account = ptr;
account_set_defaults(account);
nr++;
continue;
}
if(!tag)
{ continue; }
char *value = strchr(token, '=');
if(!value)
{ continue; }
*value++ = '\0';
// check for duplicate useraccounts and make the name unique
if(streq(trim(strtolower(token)), "user"))
{
for(probe = authptr; probe; probe = probe->next)
{
if(!strcmp(probe->usr, trim(value)))
{
fprintf(stderr, "Warning: duplicate account '%s'\n", value);
strncat(value, "_x", sizeof(probe->usr) - strlen(value) - 1);
}
}
}
chk_account(trim(strtolower(token)), trim(value), account);
}
free(token);
fclose(fp);
for(account = authptr; account; account = account->next)
{
if(account->expirationdate && account->expirationdate < time(NULL))
{ ++expired; }
if(account->disabled)
{ ++disabled; }
}
cs_log("userdb reloaded: %d accounts loaded, %d expired, %d disabled", nr, expired, disabled);
return authptr;
}
int32_t init_free_userdb(struct s_auth *ptr)
{
int32_t nro;
for(nro = 0; ptr; nro++)
{
struct s_auth *ptr_next;
ptr_next = ptr->next;
ll_destroy(ptr->aureader_list);
ptr->next = NULL;
config_list_gc_values(account_opts, ptr);
add_garbage(ptr);
ptr = ptr_next;
}
cs_log("userdb %d accounts freed", nro);
return nro;
}
int32_t write_userdb(void)
{
struct s_auth *account;
FILE *f = create_config_file(cs_user);
if(!f)
{ return 1; }
for(account = cfg.account; account; account = account->next)
{
fprintf(f, "[account]\n");
config_list_apply_fixups(account_opts, account);
config_list_save(f, account_opts, account, cfg.http_full_cfg);
fprintf(f, "\n");
}
return flush_config_file(f, cs_user);
}
void cs_accounts_chk(void)
{
struct s_auth *account1, *account2;
struct s_auth *new_accounts = init_userdb();
cs_writelock(&config_lock);
struct s_auth *old_accounts = cfg.account;
for(account1 = cfg.account; account1; account1 = account1->next)
{
for(account2 = new_accounts; account2; account2 = account2->next)
{
if(!strcmp(account1->usr, account2->usr))
{
account2->cwfound = account1->cwfound;
account2->cwcache = account1->cwcache;
account2->cwnot = account1->cwnot;
account2->cwtun = account1->cwtun;
account2->cwignored = account1->cwignored;
account2->cwtout = account1->cwtout;
account2->emmok = account1->emmok;
account2->emmnok = account1->emmnok;
account2->firstlogin = account1->firstlogin;
ac_copy_vars(account1, account2);
}
}
}
cs_reinit_clients(new_accounts);
cfg.account = new_accounts;
init_free_userdb(old_accounts);
ac_clear();
cs_writeunlock(&config_lock);
}