- fix for ticker #4787
[oscam.git] / oscam-config-account.c
blobcf113e2987e7816499f74ee9656be9744cbcd606
1 #define MODULE_LOG_PREFIX "config"
3 #include "globals.h"
4 #include "module-anticasc.h"
5 #include "oscam-array.h"
6 #include "oscam-client.h"
7 #include "oscam-conf.h"
8 #include "oscam-conf-chk.h"
9 #include "oscam-conf-mk.h"
10 #include "oscam-config.h"
11 #include "oscam-garbage.h"
12 #include "oscam-lock.h"
13 #include "oscam-string.h"
15 #define cs_user "oscam.user"
17 static void account_tosleep_fn(const char *token, char *value, void *setting, FILE *f)
19 int32_t *tosleep = setting;
20 if(value)
22 *tosleep = strToIntVal(value, cfg.tosleep);
23 return;
25 if(*tosleep != cfg.tosleep || cfg.http_full_cfg)
26 { fprintf_conf(f, token, "%d\n", *tosleep); }
29 static void account_c35_suppresscmd08_fn(const char *token, char *value, void *setting, FILE *f)
31 int8_t *c35_suppresscmd08 = setting;
32 if(value)
34 *c35_suppresscmd08 = (int8_t)strToIntVal(value, cfg.c35_suppresscmd08);
35 return;
37 if(*c35_suppresscmd08 != cfg.c35_suppresscmd08 || cfg.http_full_cfg)
38 { fprintf_conf(f, token, "%d\n", *c35_suppresscmd08); }
41 /*static void account_umaxidle_fn(const char *token, char *value, void *setting, FILE *f)
43 int32_t *umaxidle = setting;
44 if(value)
46 *umaxidle = (int32_t)strToIntVal(value, cfg.umaxidle);
47 return;
49 if(*umaxidle != cfg.umaxidle || cfg.http_full_cfg)
50 { fprintf_conf(f, token, "%u\n", *umaxidle); }
54 static void account_ncd_keepalive_fn(const char *token, char *value, void *setting, FILE *f)
56 int8_t *ncd_keepalive = setting;
57 int8_t def_value = 0;
58 #ifdef MODULE_NEWCAMD
59 def_value = cfg.ncd_keepalive;
60 #endif
61 if(value)
63 *ncd_keepalive = (int8_t)strToIntVal(value, def_value);
64 return;
66 if(*ncd_keepalive != def_value || cfg.http_full_cfg)
67 { fprintf_conf(f, token, "%d\n", *ncd_keepalive); }
70 static void account_allowedprotocols_fn(const char *token, char *value, void *setting, FILE *f)
72 struct s_auth *account = setting;
73 if(value)
75 account->allowedprotocols = 0;
76 if(strlen(value) > 3)
78 int i;
79 char *ptr, *saveptr1 = NULL;
80 for(i = 0, ptr = strtok_r(value, ",", &saveptr1); ptr; ptr = strtok_r(NULL, ",", &saveptr1), i++)
82 if(streq(ptr, "camd33")) { account->allowedprotocols |= LIS_CAMD33TCP; }
83 else if(streq(ptr, "camd35")) { account->allowedprotocols |= LIS_CAMD35UDP; }
84 else if(streq(ptr, "cs357x")) { account->allowedprotocols |= LIS_CAMD35UDP; }
85 else if(streq(ptr, "cs378x")) { account->allowedprotocols |= LIS_CAMD35TCP; }
86 else if(streq(ptr, "newcamd")) { account->allowedprotocols |= LIS_NEWCAMD; }
87 else if(streq(ptr, "cccam")) { account->allowedprotocols |= LIS_CCCAM; }
88 else if(streq(ptr, "csp")) { account->allowedprotocols |= LIS_CSPUDP; }
89 else if(streq(ptr, "gbox")) { account->allowedprotocols |= LIS_GBOX; }
90 else if(streq(ptr, "radegast")) { account->allowedprotocols |= LIS_RADEGAST; }
91 else if(streq(ptr, "scam")) { account->allowedprotocols |= LIS_SCAM; }
92 // these have no listener ports so it doesn't make sense
93 else if(streq(ptr, "dvbapi")) { account->allowedprotocols |= LIS_DVBAPI; }
94 else if(streq(ptr, "constcw")) { account->allowedprotocols |= LIS_CONSTCW; }
95 else if(streq(ptr, "serial")) { account->allowedprotocols |= LIS_SERIAL; }
98 return;
100 if(account->allowedprotocols || cfg.http_full_cfg)
102 value = mk_t_allowedprotocols(account);
103 fprintf_conf(f, token, "%s\n", value);
104 free_mk_t(value);
108 static void account_au_fn(const char *token, char *value, void *setting, FILE *f)
110 struct s_auth *account = setting;
111 if(value)
113 // set default values for usage during runtime from Webif
114 account->autoau = 0;
115 if(!account->aureader_list)
116 { account->aureader_list = ll_create("aureader_list"); }
117 if(streq(value, "1"))
118 { account->autoau = 1; }
119 ll_clear(account->aureader_list);
120 LL_ITER itr = ll_iter_create(configured_readers);
121 struct s_reader *rdr;
122 char *pch, *saveptr1 = NULL;
123 for(pch = strtok_r(value, ",", &saveptr1); pch != NULL; pch = strtok_r(NULL, ",", &saveptr1))
125 ll_iter_reset(&itr);
126 while((rdr = ll_iter_next(&itr)))
128 if(streq(rdr->label, pch) || account->autoau)
130 ll_append(account->aureader_list, rdr);
134 return;
136 if(account->autoau == 1)
138 fprintf_conf(f, token, "%d\n", account->autoau);
140 else if(account->aureader_list)
142 value = mk_t_aureader(account);
143 if(strlen(value) > 0)
144 { fprintf_conf(f, token, "%s\n", value); }
145 free_mk_t(value);
147 else if(cfg.http_full_cfg)
149 fprintf_conf(f, token, "%s\n", "");
153 static void account_expdate_fn(const char *token, char *value, void *setting, FILE *f)
155 struct s_auth *account = setting;
156 if(value)
158 if(!value[0])
160 account->expirationdate = (time_t)NULL;
161 return;
163 int i;
164 struct tm cstime;
165 char *ptr1, *saveptr1 = NULL;
166 memset(&cstime, 0, sizeof(cstime));
167 for(i = 0, ptr1 = strtok_r(value, "-/", &saveptr1); i < 3 && ptr1; ptr1 = strtok_r(NULL, "-/", &saveptr1), i++)
169 switch(i)
171 case 0:
172 cstime.tm_year = atoi(ptr1) - 1900;
173 break;
174 case 1:
175 cstime.tm_mon = atoi(ptr1) - 1;
176 break;
177 case 2:
178 cstime.tm_mday = atoi(ptr1);
179 break;
182 cstime.tm_hour = 23;
183 cstime.tm_min = 59;
184 cstime.tm_sec = 59;
185 cstime.tm_isdst = -1;
186 account->expirationdate = mktime(&cstime);
187 return;
189 if(account->expirationdate || cfg.http_full_cfg)
191 char buf[16];
192 struct tm timeinfo;
193 localtime_r(&account->expirationdate, &timeinfo);
194 strftime(buf, 16, "%Y-%m-%d", &timeinfo);
195 fprintf_conf(f, token, "%s\n", streq(buf, "1970-01-01") ? "" : buf);
199 static void account_allowedtimeframe_fn(const char *token, char *value, void *setting, FILE *f)
201 struct s_auth *account = setting;
202 int32_t i, j, t, startt, endt;
203 char *dest;
204 uint8_t day_idx;
205 int32_t allowed[4];
206 uint32_t tempo = 0;
208 char *ptr1, *ptr2, *ptr3, *saveptr1 = NULL, *saveptr2 = NULL;
210 if(value)
212 //First empty allowedtimeframe array very important otherwise new config won't be properly set
213 for(i = 0; i < SIZE_SHORTDAY; i++)
215 for(j = 0; j < 24; j++)
217 account->allowedtimeframe[i][j][0] = 0;
218 account->allowedtimeframe[i][j][1] = 0;
221 account->allowedtimeframe_set=0;
222 strtoupper(value);
224 for(i = 0, ptr1 = strtok_r(value, ";", &saveptr1); (ptr1); ptr1 = strtok_r(NULL, ";", &saveptr1), i++)
226 if((ptr2 = strchr(trim(ptr1), '@')))
228 *ptr2++ = '\0'; // clean up @ symbol
229 // ptr1 is the day
230 dest = strstr(weekdstr,ptr1);
231 day_idx = (dest - weekdstr) / 3;
233 for(j = 0, ptr3 = strtok_r(ptr2, ",", &saveptr2); (ptr3); ptr3 = strtok_r(NULL, ",", &saveptr2), j++)
235 if((sscanf(ptr3, "%2d:%2d-%2d:%2d", &allowed[0], &allowed[1], &allowed[2], &allowed[3]) == 4) && (day_idx < SIZE_SHORTDAY))
237 startt = allowed[0] * 60 + allowed[1];
238 endt = allowed[2] * 60 + allowed[3];
240 if(startt == endt) { endt++; } // end time cannot be the same as the star time
241 if((startt < 0) || (startt > 1439)) { startt = 0; } // could not start later than 23H59, avoid overflow
242 if((endt < 0) || (endt > 1440)) { endt = 1440; } // could not be higher than 24H00, avoid overflow
244 account->allowedtimeframe_set = 1;
246 if(startt > endt)
248 for(t = startt; t < 1440; t++)
250 tempo = (1 << (t % 30));
251 account->allowedtimeframe[day_idx][t / 60][(t / 30) % 2] = account->allowedtimeframe[day_idx][t / 60][(t / 30) % 2] | tempo;
253 startt = 0;
256 for(t = startt; t < endt; t++)
258 tempo = (1 << (t % 30));
259 account->allowedtimeframe[day_idx][t / 60][((t / 30) % 2)] = account->allowedtimeframe[day_idx][t / 60][(t / 30) % 2] | tempo;
262 else
264 fprintf(stderr, "WARNING: Value '%s' is not valid for allowedtimeframe (DAY@HH:MM-HH:MM)\n", value);
268 else // No day specified so whole week (ALL)
270 if(sscanf(ptr1, "%2d:%2d-%2d:%2d", &allowed[0], &allowed[1], &allowed[2], &allowed[3]) == 4)
272 startt = allowed[0] * 60 + allowed[1];
273 endt = allowed[2] * 60 + allowed[3];
275 if(startt == endt) { endt++; } // end time cannot be the same as the star time
276 if((startt <0) || (startt > 1439)) { startt = 0; } // could not start later than 23H59, avoid overflow
277 if((endt <0) || (endt > 1440)) { endt = 1440; } // could not be higher than 24H00, avoid overflow
279 account->allowedtimeframe_set = 1;
280 dest = strstr(weekdstr,"ALL");
281 day_idx = (dest - weekdstr) / 3;
283 if(startt > endt)
285 for(t = startt; t < 1440; t++)
287 tempo = (1 << (t % 30));
288 account->allowedtimeframe[day_idx][t / 60][(t / 30) % 2] = account->allowedtimeframe[7][t / 60][(t / 30) % 2] | tempo;
290 startt=0;
293 for(t = startt; t < endt; t++)
295 tempo = (1 << (t % 30));
296 account->allowedtimeframe[day_idx][t / 60][(t / 30) % 2] = account->allowedtimeframe[7][t / 60][(t / 30) % 2] | tempo;
299 else
301 fprintf(stderr, "WARNING: Value '%s' is not valid for allowedtimeframe (hh:mm-hh:mm)\n", value);
306 return;
308 if(account->allowedtimeframe_set)
310 value = mk_t_allowedtimeframe(account);
311 fprintf_conf(f, token, "%s\n", value);
312 free_mk_t(value);
314 else if(cfg.http_full_cfg)
316 fprintf_conf(f, token, "%s\n", "");
320 static void account_tuntab_fn(const char *token, char *value, void *setting, FILE *f)
322 TUNTAB *ttab = setting;
323 if(value)
325 if(strlen(value) == 0)
327 tuntab_clear(ttab);
329 else
331 chk_tuntab(value, ttab);
333 return;
335 if((ttab->ttdata && ttab->ttdata[0].bt_caidfrom) || cfg.http_full_cfg)
337 value = mk_t_tuntab(ttab);
338 fprintf_conf(f, token, "%s\n", value);
339 free_mk_t(value);
343 void group_fn(const char *token, char *value, void *setting, FILE *f)
345 uint64_t *grp = setting;
346 if(value)
348 char *ptr1, *saveptr1 = NULL;
349 *grp = 0;
350 for(ptr1 = strtok_r(value, ",", &saveptr1); ptr1; ptr1 = strtok_r(NULL, ",", &saveptr1))
352 int32_t g;
353 g = atoi(ptr1);
354 if(g > 0 && g < 65)
355 { *grp |= (((uint64_t)1) << (g - 1)); }
357 return;
359 if(*grp || cfg.http_full_cfg)
361 value = mk_t_group(*grp);
362 fprintf_conf(f, token, "%s\n", value);
363 free_mk_t(value);
367 void services_fn(const char *token, char *value, void *setting, FILE *f)
369 SIDTABS *sidtabs = setting;
370 if(value)
372 strtolower(value);
373 chk_services(value, sidtabs);
374 return;
376 value = mk_t_service(sidtabs);
377 if(strlen(value) > 0 || cfg.http_full_cfg)
378 { fprintf_conf(f, token, "%s\n", value); }
379 free_mk_t(value);
382 void class_fn(const char *token, char *value, void *setting, FILE *f)
384 CLASSTAB *cltab = setting;
385 if(value)
387 strtolower(value);
388 chk_cltab(value, cltab);
389 return;
391 value = mk_t_cltab(cltab);
392 if(strlen(value) > 0 || cfg.http_full_cfg)
394 fprintf_conf(f, token, "%s\n", value);
395 free_mk_t(value);
399 #ifdef CS_ANTICASC
400 static void account_fixups_fn(void *var)
402 struct s_auth *account = var;
403 if(account->ac_users < -1) { account->ac_users = DEFAULT_AC_USERS; }
404 if(account->ac_penalty < -1) { account->ac_penalty = DEFAULT_AC_PENALTY; }
405 if(account->acosc_max_ecms_per_minute < -1) { account->acosc_max_ecms_per_minute = -1; }
406 if(account->acosc_max_active_sids < -1) { account->acosc_max_active_sids = -1; }
407 if(account->acosc_zap_limit < -1) { account->acosc_zap_limit = -1; }
408 if(account->acosc_penalty < -1) { account->acosc_penalty = -1; }
409 if(account->acosc_penalty_duration < -1) { account->acosc_penalty_duration = -1; }
410 if(account->acosc_delay < -1) { account->acosc_delay = -1; }
411 if((account->acosc_penalty == 4) || ((cfg.acosc_penalty == 4) && (account->acosc_penalty == -1)))
413 account->acosc_max_active_sids = -1; // use global value
414 account->acosc_zap_limit = -1; // use global value
415 account->acosc_penalty_duration = -1; // use global value
417 if((account->acosc_max_ecms_per_minute != -1) && (account->acosc_max_ecms_per_minute != 0))
419 if(account->acosc_max_ecms_per_minute < 6) { account->acosc_max_ecms_per_minute = 6; }
420 if(account->acosc_max_ecms_per_minute > 20) { account->acosc_max_ecms_per_minute = 20; }
421 account->acosc_penalty_duration = (60 / account->acosc_max_ecms_per_minute);
425 #endif
427 #define OFS(X) offsetof(struct s_auth, X)
428 #define SIZEOF(X) sizeof(((struct s_auth *)0)->X)
430 static const struct config_list account_opts[] =
432 #ifdef CS_ANTICASC
433 DEF_OPT_FIXUP_FUNC(account_fixups_fn),
434 #endif
435 DEF_OPT_INT8("disabled" , OFS(disabled), 0),
436 DEF_OPT_SSTR("user" , OFS(usr), "", SIZEOF(usr)),
437 DEF_OPT_STR("pwd" , OFS(pwd), NULL),
438 #ifdef WEBIF
439 DEF_OPT_STR("description" , OFS(description), NULL),
440 #endif
441 DEF_OPT_STR("hostname" , OFS(dyndns), NULL),
442 DEF_OPT_FUNC("caid" , OFS(ctab), check_caidtab_fn),
443 DEF_OPT_INT8("uniq" , OFS(uniq), 0),
444 DEF_OPT_UINT8("sleepsend" , OFS(c35_sleepsend), 0),
445 DEF_OPT_INT32("failban" , OFS(failban), 0),
446 DEF_OPT_INT8("monlevel" , OFS(monlvl), 0),
447 DEF_OPT_FUNC("sleep" , OFS(tosleep), account_tosleep_fn),
448 DEF_OPT_FUNC("suppresscmd08" , OFS(c35_suppresscmd08), account_c35_suppresscmd08_fn),
449 DEF_OPT_INT32("umaxidle" , OFS(umaxidle), -1),
450 DEF_OPT_FUNC("keepalive" , OFS(ncd_keepalive), account_ncd_keepalive_fn),
451 DEF_OPT_FUNC("au" , 0, account_au_fn),
452 DEF_OPT_UINT8("emmreassembly" , OFS(emm_reassembly), 2),
453 DEF_OPT_FUNC("expdate" , 0, account_expdate_fn),
454 DEF_OPT_FUNC("allowedprotocols" , 0, account_allowedprotocols_fn),
455 DEF_OPT_FUNC("allowedtimeframe" , 0, account_allowedtimeframe_fn),
456 DEF_OPT_FUNC("betatunnel" , OFS(ttab), account_tuntab_fn),
457 DEF_OPT_FUNC("group" , OFS(grp), group_fn),
458 DEF_OPT_FUNC("services" , OFS(sidtabs), services_fn),
459 DEF_OPT_INT8("preferlocalcards" , OFS(preferlocalcards), -1),
460 DEF_OPT_FUNC_X("ident" , OFS(ftab), ftab_fn, FTAB_ACCOUNT | FTAB_PROVID),
461 DEF_OPT_FUNC_X("chid" , OFS(fchid), ftab_fn, FTAB_ACCOUNT | FTAB_CHID),
462 DEF_OPT_FUNC("class" , OFS(cltab), class_fn),
463 DEF_OPT_UINT32("max_connections" , OFS(max_connections), 1),
464 #ifdef CS_CACHEEX
465 DEF_OPT_INT8("cacheex" , OFS(cacheex.mode), 0),
466 DEF_OPT_INT8("cacheex_maxhop" , OFS(cacheex.maxhop), 0),
467 DEF_OPT_FUNC("cacheex_ecm_filter" , OFS(cacheex.filter_caidtab), cacheex_hitvaluetab_fn),
468 DEF_OPT_UINT8("cacheex_drop_csp" , OFS(cacheex.drop_csp), 0),
469 DEF_OPT_UINT8("cacheex_allow_request" , OFS(cacheex.allow_request), 0),
470 DEF_OPT_UINT8("no_wait_time" , OFS(no_wait_time), 0),
471 DEF_OPT_UINT8("cacheex_allow_filter" , OFS(cacheex.allow_filter), 1),
472 DEF_OPT_UINT8("cacheex_block_fakecws" , OFS(cacheex.block_fakecws), 0),
473 DEF_OPT_UINT8("disablecrccacheex" , OFS(disablecrccacheex), 0),
474 DEF_OPT_FUNC_X("disablecrccacheex_only_for", OFS(disablecrccacheex_only_for), ftab_fn, FTAB_ACCOUNT | FTAB_IGNCRCCEX4USERONLYFOR),
475 #endif
476 #ifdef MODULE_CCCAM
477 DEF_OPT_INT32("cccmaxhops" , OFS(cccmaxhops), DEFAULT_CC_MAXHOPS),
478 DEF_OPT_INT8("cccreshare" , OFS(cccreshare), DEFAULT_CC_RESHARE),
479 DEF_OPT_INT8("cccignorereshare" , OFS(cccignorereshare), DEFAULT_CC_IGNRSHR),
480 DEF_OPT_INT8("cccstealth" , OFS(cccstealth), DEFAULT_CC_STEALTH),
481 #endif
482 #ifdef CS_ANTICASC
483 DEF_OPT_INT32("fakedelay" , OFS(ac_fakedelay), -1),
484 DEF_OPT_INT32("numusers" , OFS(ac_users), DEFAULT_AC_USERS),
485 DEF_OPT_INT8("penalty" , OFS(ac_penalty), DEFAULT_AC_PENALTY),
486 DEF_OPT_INT8("acosc_max_ecms_per_minute" , OFS(acosc_max_ecms_per_minute), -1 ),
487 DEF_OPT_INT8("acosc_max_active_sids" , OFS(acosc_max_active_sids), -1 ),
488 DEF_OPT_INT8("acosc_zap_limit" , OFS(acosc_zap_limit), -1 ),
489 DEF_OPT_INT8("acosc_penalty" , OFS(acosc_penalty), -1 ),
490 DEF_OPT_INT32("acosc_penalty_duration" , OFS(acosc_penalty_duration), -1 ),
491 DEF_OPT_INT32("acosc_delay" , OFS(acosc_delay), -1 ),
492 #endif
493 #ifdef WITH_LB
494 DEF_OPT_INT32("lb_nbest_readers" , OFS(lb_nbest_readers), -1),
495 DEF_OPT_INT32("lb_nfb_readers" , OFS(lb_nfb_readers), -1),
496 DEF_OPT_FUNC("lb_nbest_percaid" , OFS(lb_nbest_readers_tab), caidvaluetab_fn),
497 #endif
498 #ifdef CW_CYCLE_CHECK
499 DEF_OPT_INT8("cwc_disable" , OFS(cwc_disable), 0),
500 #endif
501 DEF_LAST_OPT
504 void chk_account(const char *token, char *value, struct s_auth *account)
506 if(config_list_parse(account_opts, token, value, account))
507 { return; }
508 else if(token[0] != '#')
509 { fprintf(stderr, "Warning: keyword '%s' in account section not recognized\n", token); }
512 void account_set_defaults(struct s_auth *account)
514 config_list_set_defaults(account_opts, account);
517 struct s_auth *init_userdb(void)
519 FILE *fp = open_config_file(cs_user);
520 if(!fp)
521 { return NULL; }
523 struct s_auth *authptr = NULL;
524 int32_t tag = 0, nr = 0, expired = 0, disabled = 0;
525 char *token;
526 struct s_auth *account = NULL;
527 struct s_auth *probe = NULL;
528 if(!cs_malloc(&token, MAXLINESIZE))
529 { return NULL; }
531 while(fgets(token, MAXLINESIZE, fp))
533 int32_t l;
534 void *ptr;
536 if((l = strlen(trim(token))) < 3)
537 { continue; }
538 if(token[0] == '[' && token[l - 1] == ']')
540 token[l - 1] = 0;
541 tag = streq("account", strtolower(token + 1));
542 if(!cs_malloc(&ptr, sizeof(struct s_auth)))
543 { break; }
544 if(account)
545 { account->next = ptr; }
546 else
547 { authptr = ptr; }
549 account = ptr;
550 account_set_defaults(account);
551 nr++;
553 continue;
556 if(!tag)
557 { continue; }
558 char *value = strchr(token, '=');
559 if(!value)
560 { continue; }
562 *value++ = '\0';
564 // check for duplicate useraccounts and make the name unique
565 if(streq(trim(strtolower(token)), "user"))
567 for(probe = authptr; probe; probe = probe->next)
569 if(!strcmp(probe->usr, trim(value)))
571 fprintf(stderr, "Warning: duplicate account '%s'\n", value);
572 strncat(value, "_x", sizeof(probe->usr) - strlen(value) - 1);
576 chk_account(trim(strtolower(token)), trim(value), account);
578 NULLFREE(token);
579 fclose(fp);
581 for(account = authptr; account; account = account->next)
583 if(account->expirationdate && account->expirationdate < time(NULL))
584 { ++expired; }
585 if(account->disabled)
586 { ++disabled; }
588 cs_log("userdb reloaded: %d accounts loaded, %d expired, %d disabled", nr, expired, disabled);
589 return authptr;
592 int32_t init_free_userdb(struct s_auth *ptr)
594 int32_t nro;
595 for(nro = 0; ptr; nro++)
597 struct s_auth *ptr_next;
598 ptr_next = ptr->next;
599 ll_destroy(&ptr->aureader_list);
600 ptr->next = NULL;
601 config_list_gc_values(account_opts, ptr);
602 ftab_clear(&ptr->ftab);
603 ftab_clear(&ptr->fchid);
604 tuntab_clear(&ptr->ttab);
605 caidtab_clear(&ptr->ctab);
606 NULLFREE(ptr->cltab.aclass);
607 NULLFREE(ptr->cltab.bclass);
608 #ifdef CS_CACHEEX
609 cecspvaluetab_clear(&ptr->cacheex.filter_caidtab);
610 #endif
611 #ifdef WITH_LB
612 caidvaluetab_clear(&ptr->lb_nbest_readers_tab);
613 #endif
614 add_garbage(ptr);
615 ptr = ptr_next;
617 cs_log("userdb %d accounts freed", nro);
618 return nro;
621 int32_t write_userdb(void)
623 struct s_auth *account;
624 FILE *f = create_config_file(cs_user);
625 if(!f)
626 { return 1; }
627 for(account = cfg.account; account; account = account->next)
629 fprintf(f, "[account]\n");
630 config_list_apply_fixups(account_opts, account);
631 config_list_save(f, account_opts, account, cfg.http_full_cfg);
632 fprintf(f, "\n");
634 return flush_config_file(f, cs_user);
637 void cs_accounts_chk(void)
639 struct s_auth *account1, *account2;
640 struct s_auth *new_accounts = init_userdb();
641 cs_writelock(__func__, &config_lock);
642 struct s_auth *old_accounts = cfg.account;
643 for(account1 = cfg.account; account1; account1 = account1->next)
645 for(account2 = new_accounts; account2; account2 = account2->next)
647 if(!strcmp(account1->usr, account2->usr))
649 account2->cwfound = account1->cwfound;
650 account2->cwcache = account1->cwcache;
651 account2->cwnot = account1->cwnot;
652 account2->cwtun = account1->cwtun;
653 account2->cwignored = account1->cwignored;
654 account2->cwtout = account1->cwtout;
655 account2->emmok = account1->emmok;
656 account2->emmnok = account1->emmnok;
657 account2->firstlogin = account1->firstlogin;
658 ac_copy_vars(account1, account2);
662 cs_reinit_clients(new_accounts);
663 cfg.account = new_accounts;
664 init_free_userdb(old_accounts);
665 ac_clear();
666 cs_writeunlock(__func__, &config_lock);