root/trunk/wifidog/src/conf.c @ 290

Revision 290, 18.8 KB (checked in by alexcv, 8 years ago)

Massive update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/********************************************************************\
2 * This program is free software; you can redistribute it and/or    *
3 * modify it under the terms of the GNU General Public License as   *
4 * published by the Free Software Foundation; either version 2 of   *
5 * the License, or (at your option) any later version.              *
6 *                                                                  *
7 * This program is distributed in the hope that it will be useful,  *
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
10 * GNU General Public License for more details.                     *
11 *                                                                  *
12 * You should have received a copy of the GNU General Public License*
13 * along with this program; if not, contact:                        *
14 *                                                                  *
15 * Free Software Foundation           Voice:  +1-617-542-5942       *
16 * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652       *
17 * Boston, MA  02111-1307,  USA       gnu@gnu.org                   *
18 *                                                                  *
19 \********************************************************************/
20
21/* $Header$ */
22/** @file conf.c
23  @brief Config file parsing
24  @author Copyright (C) 2004 Philippe April <papril777@yahoo.com>
25 */
26
27#define _GNU_SOURCE
28
29#include <stdio.h>
30#include <stdlib.h>
31#include <syslog.h>
32
33#include <pthread.h>
34
35#include <string.h>
36#include <ctype.h>
37
38#include "common.h"
39
40#include "debug.h"
41#include "conf.h"
42#include "http.h"
43#include "auth.h"
44#include "firewall.h"
45
46/** @internal
47 * Holds the current configuration of the gateway */
48static s_config config;
49
50/**
51 * Mutex for the configuration file, used by the auth_servers related
52 * functions. */
53pthread_mutex_t config_mutex = PTHREAD_MUTEX_INITIALIZER;
54
55/** @internal
56 * A flag.  If set to 1, there are missing or empty mandatory parameters in the config
57 */
58static int missing_parms;
59
60/** @internal
61 The different configuration options */
62typedef enum {
63        oBadOption,
64        oDaemon,
65        oDebugLevel,
66        oExternalInterface,
67        oGatewayID,
68        oGatewayInterface,
69        oGatewayAddress,
70        oGatewayPort,
71        oAuthServer,
72        oAuthServHostname,
73        oAuthServSSLAvailable,
74        oAuthServSSLPort,
75        oAuthServHTTPPort,
76        oAuthServPath,
77        oAuthServMaxTries,
78        oHTTPDMaxConn,
79        oHTTPDName,
80        oClientTimeout,
81        oCheckInterval,
82        oWdctlSocket,
83        oSyslogFacility,
84        oFirewallRule,
85        oFirewallRuleSet
86} OpCodes;
87
88/** @internal
89 The config file keywords for the different configuration options */
90static const struct {
91        const char *name;
92        OpCodes opcode;
93        int required;
94} keywords[] = {
95        { "daemon",             oDaemon },
96        { "debuglevel",         oDebugLevel },
97        { "externalinterface",  oExternalInterface },
98        { "gatewayid",          oGatewayID },
99        { "gatewayinterface",   oGatewayInterface },
100        { "gatewayaddress",     oGatewayAddress },
101        { "gatewayport",        oGatewayPort },
102        { "authserver",         oAuthServer },
103        { "authservmaxtries",   oAuthServMaxTries },
104        { "httpdmaxconn",       oHTTPDMaxConn },
105        { "httpdname",          oHTTPDName },
106        { "clienttimeout",      oClientTimeout },
107        { "checkinterval",      oCheckInterval },
108        { "syslogfacility",     oSyslogFacility },
109        { "wdctlsocket",        oWdctlSocket },
110        { "hostname",           oAuthServHostname },
111        { "sslavailable",       oAuthServSSLAvailable },
112        { "sslport",            oAuthServSSLPort },
113        { "httpport",           oAuthServHTTPPort },
114        { "path",               oAuthServPath },
115        { "firewallruleset",    oFirewallRuleSet },
116        { "firewallrule",       oFirewallRule },
117        { NULL,                 oBadOption },
118};
119
120static OpCodes config_parse_token(const char *cp, const char *filename, int linenum);
121static void config_notnull(void *parm, char *parmname);
122static int parse_boolean_value(char *);
123static void parse_auth_server(FILE *, char *, int *);
124static int parse_firewall_rule(char *ruleset, char *leftover);
125static void parse_firewall_ruleset(char *, FILE *, char *, int *);
126
127/** Accessor for the current gateway configuration
128@return:  A pointer to the current config.  The pointer isn't opaque, but should be treated as READ-ONLY
129 */
130s_config *
131config_get_config(void)
132{
133    return &config;
134}
135
136/** Sets the default config parameters and initialises the configuration system */
137void
138config_init(void)
139{
140        debug(LOG_DEBUG, "Setting default config parameters");
141        strncpy(config.configfile, DEFAULT_CONFIGFILE, sizeof(config.configfile));
142        config.debuglevel = DEFAULT_DEBUGLEVEL;
143        config.httpdmaxconn = DEFAULT_HTTPDMAXCONN;
144        config.external_interface = NULL;
145        config.gw_id = DEFAULT_GATEWAYID;
146        config.gw_interface = NULL;
147        config.gw_address = NULL;
148        config.gw_port = DEFAULT_GATEWAYPORT;
149        config.auth_servers = NULL;
150        config.authserv_maxtries = DEFAULT_AUTHSERVMAXTRIES;
151        config.httpdname = NULL;
152        config.clienttimeout = DEFAULT_CLIENTTIMEOUT;
153        config.checkinterval = DEFAULT_CHECKINTERVAL;
154        config.syslog_facility = DEFAULT_SYSLOG_FACILITY;
155        config.daemon = -1;
156        config.log_syslog = DEFAULT_LOG_SYSLOG;
157        config.wdctl_sock = strdup(DEFAULT_WDCTL_SOCK);
158        config.rulesets = NULL;
159}
160
161/**
162 * If the command-line didn't provide a config, use the default.
163 */
164void
165config_init_override(void)
166{
167    if (config.daemon == -1) config.daemon = DEFAULT_DAEMON;
168}
169
170/** @internal
171Parses a single token from the config file
172*/
173static OpCodes
174config_parse_token(const char *cp, const char *filename, int linenum)
175{
176        int i;
177
178        for (i = 0; keywords[i].name; i++)
179                if (strcasecmp(cp, keywords[i].name) == 0)
180                        return keywords[i].opcode;
181
182        debug(LOG_ERR, "%s: line %d: Bad configuration option: %s", 
183                        filename, linenum, cp);
184        return oBadOption;
185}
186
187/** @internal
188Parses auth server information
189*/
190static void
191parse_auth_server(FILE *file, char *filename, int *linenum)
192{
193        char            *host = NULL,
194                        *path = NULL,
195                        line[MAX_BUF],
196                        *p1,
197                        *p2;
198        int             http_port,
199                        ssl_port,
200                        ssl_available,
201                        opcode;
202        t_auth_serv     *new,
203                        *tmp;
204
205        /* Defaults */
206        path = strdup(DEFAULT_AUTHSERVPATH);
207        http_port = DEFAULT_AUTHSERVPORT;
208        ssl_port = DEFAULT_AUTHSERVSSLPORT;
209        ssl_available = DEFAULT_AUTHSERVSSLAVAILABLE;
210       
211        /* Read first line */   
212        memset(line, 0, MAX_BUF);
213        fgets(line, MAX_BUF - 1, file);
214        (*linenum)++; /* increment line counter. */
215
216        /* Parsing loop */
217        while ((line[0] != '\0') && (strchr(line, '}') == NULL)) {
218                /* skip leading blank spaces */
219                for (p1 = line; isblank(*p1); p1++);
220
221                /* End at end of line */
222                if ((p2 = strchr(p1, '#')) != NULL) {
223                        *p2 = '\0';
224                } else if ((p2 = strchr(p1, '\r')) != NULL) {
225                        *p2 = '\0';
226                } else if ((p2 = strchr(p1, '\n')) != NULL) {
227                        *p2 = '\0';
228                }
229
230                /* next, we coopt the parsing of the regular config */
231                if (strlen(p1) > 0) {
232                        p2 = p1;
233                        /* keep going until word boundary is found. */
234                        while ((*p2 != '\0') && (!isblank(*p2)))
235                                p2++;
236
237                        /* Terminate first word. */
238                        *p2 = '\0';
239                        p2++;
240
241                        /* skip all further blanks. */
242                        while (isblank(*p2))
243                                p2++;
244                       
245                        /* Get opcode */
246                        opcode = config_parse_token(p1, filename, *linenum);
247                       
248                        switch (opcode) {
249                                case oAuthServHostname:
250                                        host = strdup(p2);
251                                        break;
252                                case oAuthServPath:
253                                        free(path);
254                                        path = strdup(p2);
255                                        break;
256                                case oAuthServSSLPort:
257                                        ssl_port = atoi(p2);
258                                        break;
259                                case oAuthServHTTPPort:
260                                        http_port = atoi(p2);
261                                        break;
262                                case oAuthServSSLAvailable:
263                                        ssl_available = parse_boolean_value(p2);
264                                        if (ssl_available < 0)
265                                                ssl_available = 0;
266                                        break;
267                                case oBadOption:
268                                default:
269                                        debug(LOG_ERR, "Bad option on line %d "
270                                                        "in %s.", *linenum,
271                                                        filename);
272                                        debug(LOG_ERR, "Exiting...");
273                                        exit(-1);
274                                        break;
275                        }
276                }
277
278                /* Read next line */
279                memset(line, 0, MAX_BUF);
280                fgets(line, MAX_BUF - 1, file);
281                (*linenum)++; /* increment line counter. */
282        }
283
284        /* only proceed if we have an host and a path */
285        if (host == NULL)
286                return;
287       
288        debug(LOG_DEBUG, "Adding %s:%d (SSL: %d) %s to the auth server list",
289                        host, http_port, ssl_port, path);
290
291        /* Allocate memory */
292        new = (t_auth_serv *)malloc(sizeof(t_auth_serv));
293        if (new == NULL) {
294                debug(LOG_ERR, "Could not allocate memory for auth server "
295                                "configuration");
296                exit(1);
297        }
298       
299        /* Fill in struct */
300        new->authserv_hostname = host;
301        new->authserv_use_ssl = ssl_available;
302        new->authserv_path = path;
303        new->authserv_http_port = http_port;
304        new->authserv_ssl_port = ssl_port;
305        new->next = NULL;
306       
307        /* If it's the first, add to config, else append to last server */
308        if (config.auth_servers == NULL) {
309                config.auth_servers = new;
310        } else {
311                for (tmp = config.auth_servers; tmp->next != NULL;
312                                tmp = tmp->next);
313                tmp->next = new;
314        }
315       
316        debug(LOG_DEBUG, "Auth server added");
317}
318
319/**
320@param token first keyword
321@param leftover rest of the line
322*/
323#define TO_NEXT_WORD(s, e) do { \
324        while (*s != '\0' && !isblank(*s)) { \
325                s++; \
326        } \
327        if (*s != '\0') { \
328                *s = '\0'; \
329                s++; \
330                while (isblank(*s)) \
331                        s++; \
332        } else { \
333                e = 1; \
334        } \
335} while (0)
336
337/** @internal
338Parses firewall rule set information
339*/
340static void
341parse_firewall_ruleset(char *ruleset, FILE *file, char *filename, int *linenum)
342{
343        char            line[MAX_BUF],
344                        *p1,
345                        *p2;
346        int             opcode;
347
348        debug(LOG_DEBUG, "Adding Firewall Rule Set %s", ruleset);
349       
350        /* Read first line */   
351        memset(line, 0, MAX_BUF);
352        fgets(line, MAX_BUF - 1, file);
353        (*linenum)++; /* increment line counter. */
354
355        /* Parsing loop */
356        while ((line[0] != '\0') && (strchr(line, '}') == NULL)) {
357                /* skip leading blank spaces */
358                for (p1 = line; isblank(*p1); p1++);
359
360                /* End at end of line */
361                if ((p2 = strchr(p1, '#')) != NULL) {
362                        *p2 = '\0';
363                } else if ((p2 = strchr(p1, '\r')) != NULL) {
364                        *p2 = '\0';
365                } else if ((p2 = strchr(p1, '\n')) != NULL) {
366                        *p2 = '\0';
367                }
368
369                /* next, we coopt the parsing of the regular config */
370                if (strlen(p1) > 0) {
371                        p2 = p1;
372                        /* keep going until word boundary is found. */
373                        while ((*p2 != '\0') && (!isblank(*p2)))
374                                p2++;
375
376                        /* Terminate first word. */
377                        *p2 = '\0';
378                        p2++;
379
380                        /* skip all further blanks. */
381                        while (isblank(*p2))
382                                p2++;
383                       
384                        /* Get opcode */
385                        opcode = config_parse_token(p1, filename, *linenum);
386
387                        debug(LOG_DEBUG, "p1 = [%s]; p2 = [%s]", p1, p2);
388                       
389                        switch (opcode) {
390                                case oFirewallRule:
391                                        parse_firewall_rule(ruleset, p2);
392                                        break;
393
394                                case oBadOption:
395                                default:
396                                        debug(LOG_ERR, "Bad option on line %d "
397                                                        "in %s.", *linenum,
398                                                        filename);
399                                        debug(LOG_ERR, "Exiting...");
400                                        exit(-1);
401                                        break;
402                        }
403                }
404
405                /* Read next line */
406                memset(line, 0, MAX_BUF);
407                fgets(line, MAX_BUF - 1, file);
408                (*linenum)++; /* increment line counter. */
409        }
410
411        debug(LOG_DEBUG, "Firewall Rule Set %s added.", ruleset);
412}
413
414static int
415parse_firewall_rule(char *ruleset, char *leftover)
416{
417        int i;
418        int block_allow = 0; /**< 0 == block, 1 == allow */
419        int all_nums = 1; /**< If 0, port contained non-numerics */
420        int finished = 0; /**< reached end of line */
421        char *token = NULL; /**< First word */
422        char *port = NULL; /**< port to open/block */
423        char *protocol = NULL; /**< protocol to block, tcp/udp/icmp */
424        char *mask = NULL; /**< Netmask */
425        char *other_kw = NULL; /**< other key word */
426        t_firewall_ruleset *tmpr;
427        t_firewall_ruleset *tmpr2;
428        t_firewall_rule *tmp;
429        t_firewall_rule *tmp2;
430
431        debug(LOG_DEBUG, "leftover: %s", leftover);
432
433        /* lower case */
434        for (i = 0; *(leftover + i) != '\0'
435                        && (*(leftover + i) = tolower(*(leftover + i))); i++);
436       
437        token = leftover;
438        TO_NEXT_WORD(leftover, finished);
439       
440        /* Parse token */
441        if (!strcasecmp(token, "block") || finished) {
442                block_allow = 0;
443        } else if (!strcasecmp(token, "allow")) {
444                block_allow = 1;
445        } else {
446                debug(LOG_ERR, "Invalid rule type %s, expecting "
447                                "\"block\" or \"allow\"", token);
448                return -1;
449        }
450
451        /* Parse the remainder */
452        /* Get the protocol */
453        if (strncmp(leftover, "tcp", 3) == 0
454                        || strncmp(leftover, "udp", 3) == 0
455                        || strncmp(leftover, "icmp", 4) == 0) {
456                protocol = leftover;
457                TO_NEXT_WORD(leftover, finished);
458        }
459
460        /* should be exactly "port" */
461        if (strncmp(leftover, "port", 4) == 0) {
462                TO_NEXT_WORD(leftover, finished);
463                /* Get port now */
464                port = leftover;
465                TO_NEXT_WORD(leftover, finished);
466                for (i = 0; *(port + i) != '\0'; i++)
467                        if (!isdigit(*(port + i)))
468                                all_nums = 0; /*< No longer only digits */
469                if (!all_nums) {
470                        debug(LOG_ERR, "Invalid port %s", port);
471                        return -3; /*< Fail */
472                }
473        }
474
475        /* Now, further stuff is optional */
476        if (!finished) {
477                /* should be exactly "to" */
478                other_kw = leftover;
479                TO_NEXT_WORD(leftover, finished);
480                if (strcmp(other_kw, "to") || finished) {
481                        debug(LOG_ERR, "Invalid or unexpected keyword %s, "
482                                        "expecting \"to\"", other_kw);
483                        return -4; /*< Fail */
484                }
485
486                /* Get port now */
487                mask = leftover;
488                TO_NEXT_WORD(leftover, finished);
489                all_nums = 1;
490                for (i = 0; *(mask + i) != '\0'; i++)
491                        if (!isdigit(*(mask + i)) && (*(mask + i) != '.')
492                                        && (*(mask + i) != '/'))
493                                all_nums = 0; /*< No longer only digits */
494                if (!all_nums) {
495                        debug(LOG_ERR, "Invalid mask %s", mask);
496                        return -3; /*< Fail */
497                }
498        }
499
500        /* Generate rule record */
501        tmp = (t_firewall_rule *)malloc(sizeof(t_firewall_rule));
502        memset((void *)tmp, 0, sizeof(t_firewall_rule));
503        tmp->block_allow = block_allow;
504        if (protocol != NULL)
505                tmp->protocol = strdup(protocol);
506        if (port != NULL)
507                tmp->port = strdup(port);
508        if (mask == NULL)
509                tmp->mask = strdup("0.0.0.0/0");
510        else
511                tmp->mask = strdup(mask);
512
513        debug(LOG_DEBUG, "Adding Firewall Rule %s %s port %s to %s",
514                        token, tmp->protocol, tmp->port, tmp->mask);
515       
516        /* Append the rule record */
517        if (config.rulesets == NULL) {
518                config.rulesets = (t_firewall_ruleset *)malloc(
519                                        sizeof(t_firewall_ruleset));
520                memset(config.rulesets, 0, sizeof(t_firewall_ruleset));
521                config.rulesets->name = strdup(ruleset);
522                tmpr = config.rulesets;
523        } else {
524                tmpr2 = tmpr = config.rulesets;
525                while (tmpr != NULL && (strcmp(tmpr->name, ruleset) != 0)) {
526                        tmpr2 = tmpr;
527                        tmpr = tmpr->next;
528                }
529                if (tmpr == NULL) {
530                        /* Rule did not exist */
531                        tmpr = (t_firewall_ruleset *)malloc(
532                                                sizeof(t_firewall_ruleset));
533                        memset(tmpr, 0, sizeof(t_firewall_ruleset));
534                        tmpr->name = strdup(ruleset);
535                        tmpr2->next = tmpr;
536                }
537        }
538
539        /* At this point, tmpr == current ruleset */
540        if (tmpr->rules == NULL) {
541                /* No rules... */
542                tmpr->rules = tmp;
543        } else {
544                tmp2 = tmpr->rules;
545                while (tmp2->next != NULL)
546                        tmp2 = tmp2->next;
547                tmp2->next = tmp;
548        }
549       
550        return 1;
551}
552
553t_firewall_rule *
554get_ruleset(char *ruleset)
555{
556        t_firewall_ruleset      *tmp;
557
558        for (tmp = config.rulesets; tmp != NULL
559                        && strcmp(tmp->name, ruleset) != 0; tmp = tmp->next);
560
561        return(tmp->rules);
562}
563
564/**
565@param filename Full path of the configuration file to be read
566*/
567void
568config_read(char *filename)
569{
570        FILE *fd;
571        char line[MAX_BUF], *s, *p1, *p2;
572        int linenum = 0, opcode, value;
573
574        debug(LOG_INFO, "Reading configuration file '%s'", filename);
575
576        if (!(fd = fopen(filename, "r"))) {
577                debug(LOG_ERR, "Could not open configuration file '%s', "
578                                "exiting...", filename);
579                exit(1);
580        }
581
582        while (!feof(fd) && fgets(line, MAX_BUF, fd)) {
583                linenum++;
584                s = line;
585
586                if (s[strlen(s) - 1] == '\n')
587                        s[strlen(s) - 1] = '\0';
588
589                if ((p1 = strchr(s, ' '))) {
590                        p1[0] = '\0';
591                } else if ((p1 = strchr(s, '\t'))) {
592                        p1[0] = '\0';
593                }
594
595                if (p1) {
596                        p1++;
597
598                        if ((p2 = strchr(p1, ' '))) {
599                                p2[0] = '\0';
600                        } else if ((p2 = strstr(p1, "\r\n"))) {
601                                p2[0] = '\0';
602                        } else if ((p2 = strchr(p1, '\n'))) {
603                                p2[0] = '\0';
604                        }
605                }
606
607                if (p1 && p1[0] != '\0') {
608                        /* Strip trailing spaces */
609                        /* Strip tailing spaces */
610
611                        if ((strncmp(s, "#", 1)) != 0) {
612                                debug(LOG_DEBUG, "Parsing token: %s, "
613                                                "value: %s", s, p1);
614                                opcode = config_parse_token(s, filename, linenum);
615
616                                switch(opcode) {
617                                case oDaemon:
618                                        if (config.daemon == -1 && ((value = parse_boolean_value(p1)) != -1)) {
619                                                config.daemon = value;
620                                        }
621                                        break;
622                                case oExternalInterface:
623                                        config.external_interface = strdup(p1);
624                                        break;
625                                case oGatewayID:
626                                        config.gw_id = strdup(p1);
627                                        break;
628                                case oGatewayInterface:
629                                        config.gw_interface = strdup(p1);
630                                        break;
631                                case oGatewayAddress:
632                                        config.gw_address = strdup(p1);
633                                        break;
634                                case oGatewayPort:
635                                        sscanf(p1, "%d", &config.gw_port);
636                                        break;
637                                case oAuthServer:
638                                        parse_auth_server(fd, filename,
639                                                        &linenum);
640                                        break;
641                                case oFirewallRuleSet:
642                                        parse_firewall_ruleset(p1, fd,
643                                                        filename, &linenum);
644                                        break;
645                                case oHTTPDName:
646                                        config.httpdname = strdup(p1);
647                                        break;
648                                case oHTTPDMaxConn:
649                                        sscanf(p1, "%d", &config.httpdmaxconn);
650                                        break;
651                                case oAuthServMaxTries:
652                                        sscanf(p1, "%d", &config.authserv_maxtries);
653                                        break;
654                                case oBadOption:
655                                        debug(LOG_ERR, "Bad option on line %d "
656                                                        "in %s.", linenum,
657                                                        filename);
658                                        debug(LOG_ERR, "Exiting...");
659                                        exit(-1);
660                                        break;
661                                case oCheckInterval:
662                                        sscanf(p1, "%d", &config.checkinterval);
663                                        break;
664                                case oWdctlSocket:
665                                        free(config.wdctl_sock);
666                                        config.wdctl_sock = strdup(p1);
667                                        break;
668                                case oClientTimeout:
669                                        sscanf(p1, "%d", &config.clienttimeout);
670                                        break;
671                                case oSyslogFacility:
672                                        sscanf(p1, "%d", &config.syslog_facility);
673                                        break;
674                                }
675                        }
676                }
677        }
678
679        fclose(fd);
680}
681
682/** @internal
683Parses a boolean value from the config file
684*/
685static int
686parse_boolean_value(char *line)
687{
688        if (strcasecmp(line, "yes") == 0) {
689                return 1;
690        }
691        if (strcasecmp(line, "no") == 0) {
692                return 0;
693        }
694        if (strcmp(line, "1") == 0) {
695                return 1;
696        }
697        if (strcmp(line, "0") == 0) {
698                return 0;
699        }
700
701        return -1;
702}
703
704/** Verifies if the configuration is complete and valid.  Terminates the program if it isn't */
705void
706config_validate(void)
707{
708        config_notnull(config.external_interface, "ExternalInterface");
709        config_notnull(config.gw_id, "GatewayID");
710        config_notnull(config.gw_interface, "GatewayInterface");
711        config_notnull(config.gw_address, "GatewayAddress");
712        config_notnull(config.auth_servers, "AuthServer");
713
714        if (missing_parms) {
715                debug(LOG_ERR, "Configuration is not complete, exiting...");
716                exit(-1);
717        }
718}
719
720/** @internal
721    Verifies that a required parameter is not a null pointer
722*/
723static void
724config_notnull(void *parm, char *parmname)
725{
726        if (parm == NULL) {
727                debug(LOG_ERR, "%s is not set", parmname);
728                missing_parms = 1;
729        }
730}
731
732/**
733 * This function returns the current (first auth_server)
734 */
735t_auth_serv *
736get_auth_server(void)
737{
738
739        /* This is as good as atomic */
740        return config.auth_servers;
741}
742
743/**
744 * This function marks the current auth_server, if it matches the argument,
745 * as bad. Basically, the "bad" server becomes the last one on the list.
746 */
747void
748mark_auth_server_bad(t_auth_serv *bad_server)
749{
750        t_auth_serv     *tmp;
751
752        /* lock mutex so two different threads both don't mark the same
753         * server as bad */
754        pthread_mutex_lock(&config_mutex);
755
756        if (config.auth_servers == bad_server && bad_server->next != NULL) {
757                /* Go to the last */
758                for (tmp = config.auth_servers; tmp->next != NULL; tmp = tmp->next);
759                /* Set bad server as last */
760                tmp->next = bad_server;
761                /* Remove bad server from start of list */
762                config.auth_servers = bad_server->next;
763                /* Set the next pointe to NULL in the last element */
764                bad_server->next = NULL;
765        }
766
767        pthread_mutex_unlock(&config_mutex);
768
769        fw_clear_authservers();
770        fw_set_authservers();
771}
Note: See TracBrowser for help on using the browser.