/* * Layer Two Tunnelling Protocol Daemon * Copyright (C) 1998 Adtran, Inc. * Copyright (C) 2002 Jeff McAdams * * Mark Spencer * * This software is distributed under the terms * of the GPL, which you should have received * along with this source. * * File format handling * */ #include #include #include #include #include #include #include #include #include #include "l2tp.h" struct lns *lnslist; struct lac *laclist; struct lns *deflns; struct lac *deflac; struct global gconfig; char filerr[STRLEN]; int parse_config (FILE *); struct keyword words[]; int init_config () { FILE *f; int returnedValue; gconfig.port = UDP_LISTEN_PORT; lnslist = NULL; laclist = NULL; deflac = (struct lac *) malloc (sizeof (struct lac)); f = fopen (gconfig.configfile, "r"); if (!f) { f = fopen (gconfig.altconfigfile, "r"); if (f) { strncpy (gconfig.authfile, gconfig.altauthfile, sizeof (gconfig.authfile)); } else { log (LOG_CRIT, "%s: Unable to open config file %s or %s\n", __FUNCTION__, gconfig.configfile, gconfig.altconfigfile); return -1; } } returnedValue = parse_config (f); fclose (f); return (returnedValue); filerr[0] = 0; } struct lns *new_lns () { struct lns *tmp; tmp = (struct lns *) malloc (sizeof (struct lns)); if (!tmp) { log (LOG_CRIT, "%s: Unable to allocate memory for new LNS\n", __FUNCTION__); return NULL; } tmp->next = NULL; tmp->exclusive = 0; tmp->localaddr = 0; tmp->tun_rws = DEFAULT_RWS_SIZE; tmp->call_rws = DEFAULT_RWS_SIZE; tmp->hbit = 0; tmp->lbit = 0; tmp->authpeer = 0; tmp->authself = -1; tmp->authname[0] = 0; tmp->peername[0] = 0; tmp->hostname[0] = 0; tmp->entname[0] = 0; tmp->range = NULL; tmp->lacs = NULL; tmp->passwdauth = 0; tmp->pap_require = 0; tmp->pap_refuse = 0; tmp->chap_require = 0; tmp->chap_refuse = 0; tmp->idle = 0; tmp->pridns = 0; tmp->secdns = 0; tmp->priwins = 0; tmp->secwins = 0; tmp->proxyarp = 0; tmp->proxyauth = 0; tmp->challenge = 0; tmp->debug = 0; tmp->pppoptfile[0] = 0; tmp->t = NULL; return tmp; } struct lac *new_lac () { struct lac *tmp; tmp = (struct lac *) malloc (sizeof (struct lac)); if (!tmp) { log (LOG_CRIT, "%s: Unable to allocate memory for lac entry!\n", __FUNCTION__); return NULL; } tmp->next = NULL; tmp->rsched = NULL; tmp->localaddr = 0; tmp->remoteaddr = 0; tmp->lns = 0; tmp->tun_rws = DEFAULT_RWS_SIZE; tmp->call_rws = DEFAULT_RWS_SIZE; tmp->hbit = 0; tmp->lbit = 0; tmp->authpeer = 0; tmp->authself = -1; tmp->authname[0] = 0; tmp->peername[0] = 0; tmp->hostname[0] = 0; tmp->entname[0] = 0; tmp->pap_require = 0; tmp->pap_refuse = 0; tmp->chap_require = 0; tmp->chap_refuse = 0; tmp->t = NULL; tmp->redial = 0; tmp->rtries = 0; tmp->rmax = 0; tmp->challenge = 0; tmp->autodial = 0; tmp->rtimeout = 30; tmp->active = 0; tmp->debug = 0; tmp->pppoptfile[0] = 0; tmp->defaultroute = 0; return tmp; } int yesno (char *value) { if (!strcasecmp (value, "yes") || !strcasecmp (value, "y") || !strcasecmp (value, "true")) return 1; else if (!strcasecmp (value, "no") || !strcasecmp (value, "n") || !strcasecmp (value, "false")) return 0; else return -1; } int set_boolean (char *word, char *value, int *ptr) { int val; #ifdef DEBUG_FILE log (LOG_DEBUG, "set_%s: %s flag to '%s'\n", word, word, value); #endif /* ; */ if ((val = yesno (value)) < 0) { snprintf (filerr, sizeof (filerr), "%s must be 'yes' or 'no'\n", word); return -1; } *ptr = val; return 0; } int set_int (char *word, char *value, int *ptr) { int val; #ifdef DEBUG_FILE log (LOG_DEBUG, "set_%s: %s flag to '%s'\n", word, word, value); #endif /* ; */ if ((val = atoi (value)) < 0) { snprintf (filerr, sizeof (filerr), "%s must be a number\n", word); return -1; } *ptr = val; return 0; } int set_string (char *word, char *value, char *ptr, int len) { #ifdef DEBUG_FILE log (LOG_DEBUG, "set_%s: %s flag to '%s'\n", word, word, value); #endif /* ; */ strncpy (ptr, value, len); return 0; } int set_port (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_GLOBAL: #ifdef DEBUG_FILE log (LOG_DEBUG, "set_port: Setting global port number to %s\n", value); #endif set_int (word, value, &(((struct global *) item)->port)); break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_rtimeout (char *word, char *value, int context, void *item) { if (atoi (value) < 1) { snprintf (filerr, sizeof (filerr), "rtimeout value must be at least 1\n"); return -1; } switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: #ifdef DEBUG_FILE log (LOG_DEBUG, "set_rtimeout: Setting redial timeout to %s\n", value); #endif set_int (word, value, &(((struct lac *) item)->rtimeout)); break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_rws (char *word, char *value, int context, void *item) { if (atoi (value) < -1) { snprintf (filerr, sizeof (filerr), "receive window size must be at least -1\n"); return -1; } switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: if (word[0] == 'c') set_int (word, value, &(((struct lac *) item)->call_rws)); if (word[0] == 't') { set_int (word, value, &(((struct lac *) item)->tun_rws)); if (((struct lac *) item)->tun_rws < 1) { snprintf (filerr, sizeof (filerr), "receive window size for tunnels must be at least 1\n"); return -1; } } break; case CONTEXT_LNS: if (word[0] == 'c') set_int (word, value, &(((struct lns *) item)->call_rws)); if (word[0] == 't') { set_int (word, value, &(((struct lns *) item)->tun_rws)); if (((struct lns *) item)->tun_rws < 1) { snprintf (filerr, sizeof (filerr), "receive window size for tunnels must be at least 1\n"); return -1; } } break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_rmax (char *word, char *value, int context, void *item) { if (atoi (value) < 1) { snprintf (filerr, sizeof (filerr), "rmax value must be at least 1\n"); return -1; } switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: #ifdef DEBUG_FILE log (LOG_DEBUG, "set_rmax: Setting max redials to %s\n", value); #endif set_int (word, value, &(((struct lac *) item)->rmax)); break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_authfile (char *word, char *value, int context, void *item) { if (!strlen (value)) { snprintf (filerr, sizeof (filerr), "no filename specified for authentication\n"); return -1; } switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_GLOBAL: #ifdef DEBUG_FILE log (LOG_DEBUG, "set_authfile: Setting global auth file to '%s'\n", value); #endif /* ; */ strncpy (((struct global *) item)->authfile, value, sizeof (((struct global *)item)->authfile)); break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_autodial (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: if (set_boolean (word, value, &(((struct lac *) item)->autodial))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_flow (char *word, char *value, int context, void *item) { int v; set_boolean (word, value, &v); if (v < 0) return -1; switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: if (v) { if (((struct lac *) item)->call_rws < 0) ((struct lac *) item)->call_rws = 0; } else { ((struct lac *) item)->call_rws = -1; } break; case CONTEXT_LNS: if (v) { if (((struct lns *) item)->call_rws < 0) ((struct lns *) item)->call_rws = 0; } else { ((struct lns *) item)->call_rws = -1; } break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_defaultroute (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: if (set_boolean (word, value, &(((struct lac *) item)->defaultroute))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_authname (char *word, char *value, int context, void *item) { struct lac *l = (struct lac *) item; struct lns *n = (struct lns *) item; switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LNS: if (set_string (word, value, n->authname, sizeof (n->authname))) return -1; break; case CONTEXT_LAC: if (set_string (word, value, l->authname, sizeof (l->authname))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_hostname (char *word, char *value, int context, void *item) { struct lac *l = (struct lac *) item; struct lns *n = (struct lns *) item; switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LNS: if (set_string (word, value, n->hostname, sizeof (n->hostname))) return -1; break; case CONTEXT_LAC: if (set_string (word, value, l->hostname, sizeof (l->hostname))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_passwdauth (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LNS: if (set_boolean (word, value, &(((struct lns *) item)->passwdauth))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_hbit (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: if (set_boolean (word, value, &(((struct lac *) item)->hbit))) return -1; break; case CONTEXT_LNS: if (set_boolean (word, value, &(((struct lns *) item)->hbit))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_challenge (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: if (set_boolean (word, value, &(((struct lac *) item)->challenge))) return -1; break; case CONTEXT_LNS: if (set_boolean (word, value, &(((struct lns *) item)->challenge))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_lbit (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: if (set_boolean (word, value, &(((struct lac *) item)->lbit))) return -1; break; case CONTEXT_LNS: if (set_boolean (word, value, &(((struct lns *) item)->lbit))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_debug (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: if (set_boolean (word, value, &(((struct lac *) item)->debug))) return -1; break; case CONTEXT_LNS: if (set_boolean (word, value, &(((struct lns *) item)->debug))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_pppoptfile (char *word, char *value, int context, void *item) { struct lac *l = (struct lac *) item; struct lns *n = (struct lns *) item; switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LNS: if (set_string (word, value, n->pppoptfile, sizeof (n->pppoptfile))) return -1; break; case CONTEXT_LAC: if (set_string (word, value, l->pppoptfile, sizeof (l->pppoptfile))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_papchap (char *word, char *value, int context, void *item) { int result; char *c; struct lac *l = (struct lac *) item; struct lns *n = (struct lns *) item; if (set_boolean (word, value, &result)) return -1; c = strchr (word, ' '); c++; switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: if (c[0] == 'p') /* PAP */ if (word[2] == 'f') l->pap_refuse = result; else l->pap_require = result; else if (c[0] == 'a') /* Authentication */ if (word[2] == 'f') l->authself = result; else l->authpeer = result; else /* CHAP */ if (word[2] == 'f') l->chap_refuse = result; else l->chap_require = result; break; case CONTEXT_LNS: if (c[0] == 'p') /* PAP */ if (word[2] == 'f') n->pap_refuse = result; else n->pap_require = result; else if (c[0] == 'a') /* Authentication */ if (word[2] == 'f') n->authself = !result; else n->authpeer = result; else /* CHAP */ if (word[2] == 'f') n->chap_refuse = result; else n->chap_require = result; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_redial (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: if (set_boolean (word, value, &(((struct lac *) item)->redial))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_accesscontrol (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_GLOBAL: if (set_boolean (word, value, &(((struct global *) item)->accesscontrol))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_userspace (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_GLOBAL: if (set_boolean (word, value, &(((struct global *) item)->forceuserspace))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } struct iprange *set_range (char *word, char *value, struct iprange *in) { char *c, *d = NULL; struct iprange *ipr, *p; struct hostent *hp; c = strchr (value, '-'); if (c) { d = c + 1; *c = 0; while ((c >= value) && (*c < 33)) *(c--) = 0; while (*d && (*d < 33)) d++; } if (!strlen (value) || (c && !strlen (d))) { snprintf (filerr, sizeof (filerr), "format is '%s - '\n", word); return NULL; } ipr = (struct iprange *) malloc (sizeof (struct iprange)); ipr->next = NULL; hp = gethostbyname (value); if (!hp) { snprintf (filerr, sizeof (filerr), "Unknown host %s\n", value); free (ipr); return NULL; } bcopy (hp->h_addr, &ipr->start, sizeof (unsigned int)); if (c) { hp = gethostbyname (d); if (!hp) { snprintf (filerr, sizeof (filerr), "Unknown host %s\n", d); free (ipr); return NULL; } bcopy (hp->h_addr, &ipr->end, sizeof (unsigned int)); } else ipr->end = ipr->start; if (ntohl (ipr->start) > ntohl (ipr->end)) { snprintf (filerr, sizeof (filerr), "start is greater than end!\n"); free (ipr); return NULL; } if (word[0] == 'n') ipr->sense = SENSE_DENY; else ipr->sense = SENSE_ALLOW; p = in; if (p) { while (p->next) p = p->next; p->next = ipr; return in; } else return ipr; } int set_iprange (char *word, char *value, int context, void *item) { struct lns *lns = (struct lns *) item; switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LNS: break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } lns->range = set_range (word, value, lns->range); if (!lns->range) return -1; #ifdef DEBUG_FILE log (LOG_DEBUG, "range start = %x, end = %x, sense=%ud\n", ntohl (ipr->start), ntohl (ipr->end), ipr->sense); #endif return 0; } int set_lac (char *word, char *value, int context, void *item) { struct lns *lns = (struct lns *) item; switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LNS: break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } lns->lacs = set_range (word, value, lns->lacs); if (!lns->lacs) return -1; #ifdef DEBUG_FILE log (LOG_DEBUG, "lac start = %x, end = %x, sense=%ud\n", ntohl (ipr->start), ntohl (ipr->end), ipr->sense); #endif return 0; } int set_exclusive (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LNS: if (set_boolean (word, value, &(((struct lns *) item)->exclusive))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_ip (char *word, char *value, unsigned int *addr) { struct hostent *hp; hp = gethostbyname (value); if (!hp) { snprintf (filerr, sizeof (filerr), "%s: host '%s' not found\n", __FUNCTION__, value); return -1; } bcopy (hp->h_addr, addr, sizeof (unsigned int)); return 0; } int set_localaddr (char *word, char *value, int context, void *item) { struct lac *l; struct lns *n; switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: l = (struct lac *) item; return set_ip (word, value, &(l->localaddr)); case CONTEXT_LNS: n = (struct lns *) item; return set_ip (word, value, &(n->localaddr)); default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_remoteaddr (char *word, char *value, int context, void *item) { struct lac *l; switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: l = (struct lac *) item; return set_ip (word, value, &(l->remoteaddr)); default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_lns (char *word, char *value, int context, void *item) { struct hostent *hp; struct lac *l; struct host *ipr, *pos; char *d; switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: #ifdef DEBUG_FILE log (LOG_DEBUG, "set_lns: setting LNS to '%s'\n", value); #endif l = (struct lac *) item; d = strchr (value, ':'); if (d) { d[0] = 0; d++; } hp = gethostbyname (value); if (!hp) { snprintf (filerr, sizeof (filerr), "no such host '%s'\n", value); return -1; } ipr = malloc (sizeof (struct host)); ipr->next = NULL; pos = l->lns; if (!pos) { l->lns = ipr; } else { while (pos->next) pos = pos->next; pos->next = ipr; } strncpy (ipr->hostname, value, sizeof (ipr->hostname)); if (d) ipr->port = atoi (d); else ipr->port = UDP_LISTEN_PORT; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_rand_sys () { log(LOG_WARN, "The \"rand()\" function call is not a very good source" "of randomness\n"); rand_source = RAND_SYS; return 0; } int set_rand_dev () { rand_source = RAND_DEV; return 0; } int set_rand_egd (char *value) { log(LOG_WARN, "%s: not yet implemented!\n", __FUNCTION__); rand_source = RAND_EGD; return -1; } int set_rand_source (char *word, char *value, int context, void *item) { time_t seconds; /* * We're going to go ahead and seed the rand() function with srand() * because even if we set the randomness source to dev or egd, they * can fall back to sys if they fail, so we want to make sure we at * least have *some* semblance of randomness available from the * rand() function */ /* * This is a sucky random number seed...just the result from the * time() call...but...the user requested to use the rand() * function, which is a pretty sucky source of randomness * regardless...at least we can get a almost sorta decent seed. If * you have any better suggestions for creating a seed...lemme know * :/ */ seconds = time(NULL); srand(seconds); if (context != CONTEXT_GLOBAL) { log(LOG_WARN, "%s: %s not valid in context %d\n", __FUNCTION__, word, context); return -1; } /* WORKING HERE */ if (strlen(value) == 0) { snprintf(filerr, sizeof (filerr), "no randomness source specified\n"); return -1; } if (strncmp(value, "egd", 3) == 0) { return set_rand_egd(value); } else if (strncmp(value, "dev", 3) == 0) { return set_rand_dev(); } else if (strncmp(value, "sys", 3) == 0) { return set_rand_sys(); } else { log(LOG_WARN, "%s: %s is not a valid randomness source\n", __FUNCTION__, value); return -1; } } int parse_config (FILE * f) { /* Read in the configuration file handed to us */ /* FIXME: I should check for incompatible options */ int context = 0; char buf[STRLEN]; char *s, *d, *t; int linenum = 0; int def = 0; struct keyword *kw; void *data = NULL; struct lns *tl; struct lac *tc; while (!feof (f)) { fgets (buf, sizeof (buf), f); if (feof (f)) break; linenum++; s = buf; /* Strip comments */ while (*s && *s != ';') s++; *s = 0; s = buf; if (!strlen (buf)) continue; while ((*s < 33) && *s) s++; /* Skip over beginning white space */ t = s + strlen (s); while ((t >= s) && (*t < 33)) *(t--) = 0; /* Ditch trailing white space */ if (!strlen (s)) continue; if (s[0] == '[') { /* We've got a context description */ if (!(t = strchr (s, ']'))) { log (LOG_CRIT, "parse_config: line %d: No closing bracket\n", linenum); return -1; } t[0] = 0; s++; if ((d = strchr (s, ' '))) { /* There's a parameter */ d[0] = 0; d++; } if (d && !strcasecmp (d, "default")) def = CONTEXT_DEFAULT; else def = 0; if (!strcasecmp (s, "global")) { context = CONTEXT_GLOBAL; #ifdef DEBUG_FILE log (LOG_DEBUG, "parse_config: global context descriptor %s\n", d ? d : ""); #endif data = &gconfig; } else if (!strcasecmp (s, "lns")) { context = CONTEXT_LNS; if (def) { if (!deflns) { deflns = new_lns (); strncpy (deflns->entname, "default", sizeof (deflns->entname)); } data = deflns; continue; } data = NULL; tl = lnslist; if (d) { while (tl) { if (!strcasecmp (d, tl->entname)) break; tl = tl->next; } if (tl) data = tl; } if (!data) { data = new_lns (); if (!data) return -1; ((struct lns *) data)->next = lnslist; lnslist = (struct lns *) data; } if (d) strncpy (((struct lns *) data)->entname, d, sizeof (((struct lns *) data)->entname)); #ifdef DEBUG_FILE log (LOG_DEBUG, "parse_config: lns context descriptor %s\n", d ? d : ""); #endif } else if (!strcasecmp (s, "lac")) { context = CONTEXT_LAC; if (def) { if (!deflac) { deflac = new_lac (); strncpy (deflac->entname, "default", sizeof (deflac->entname)); } data = deflac; continue; } data = NULL; tc = laclist; if (d) { while (tc) { if (!strcasecmp (d, tc->entname)) break; tc = tc->next; } if (tc) data = tc; } if (!data) { data = new_lac (); if (!data) return -1; ((struct lac *) data)->next = laclist; laclist = (struct lac *) data; } if (d) strncpy (((struct lac *) data)->entname, d, sizeof (((struct lac *) data)->entname)); #ifdef DEBUG_FILE log (LOG_DEBUG, "parse_config: lac context descriptor %s\n", d ? d : ""); #endif } else { log (LOG_WARN, "parse_config: line %d: unknown context '%s'\n", linenum, s); return -1; } } else { if (!context) { log (LOG_WARN, "parse_config: line %d: data '%s' occurs with no context\n", linenum, s); return -1; } if (!(t = strchr (s, '='))) { log (LOG_WARN, "parse_config: line %d: no '=' in data\n", linenum); return -1; } d = t; d--; t++; while ((d >= s) && (*d < 33)) d--; d++; *d = 0; while (*t && (*t < 33)) t++; #ifdef DEBUG_FILE log (LOG_DEBUG, "parse_config: field is %s, value is %s\n", s, t); #endif /* Okay, bit twidling is done. Let's handle this */ for (kw = words; kw->keyword; kw++) { if (!strcasecmp (s, kw->keyword)) { if (kw->handler (s, t, context | def, data)) { log (LOG_WARN, "parse_config: line %d: %s", linenum, filerr); return -1; } break; } } if (!kw->keyword) { log (LOG_CRIT, "parse_config: line %d: Unknown field '%s'\n", linenum, s); return -1; } } } return 0; } struct keyword words[] = { {"port", &set_port}, {"rand source", &set_rand_source}, {"auth file", &set_authfile}, {"exclusive", &set_exclusive}, {"autodial", &set_autodial}, {"redial", &set_redial}, {"redial timeout", &set_rtimeout}, {"lns", &set_lns}, {"max redials", &set_rmax}, {"access control", &set_accesscontrol}, {"force userspace", &set_userspace}, {"ip range", &set_iprange}, {"no ip range", &set_iprange}, {"lac", &set_lac}, {"no lac", &set_lac}, {"local ip", &set_localaddr}, {"remote ip", &set_remoteaddr}, {"defaultroute", &set_defaultroute}, {"length bit", &set_lbit}, {"hidden bit", &set_hbit}, {"require pap", &set_papchap}, {"require chap", &set_papchap}, {"require authentication", &set_papchap}, {"require auth", &set_papchap}, {"refuse pap", &set_papchap}, {"refuse chap", &set_papchap}, {"refuse authentication", &set_papchap}, {"refuse auth", &set_papchap}, {"unix authentication", &set_passwdauth}, {"unix auth", &set_passwdauth}, {"name", &set_authname}, {"hostname", &set_hostname}, {"ppp debug", &set_debug}, {"pppoptfile", &set_pppoptfile}, {"call rws", &set_rws}, {"tunnel rws", &set_rws}, {"flow bit", &set_flow}, {"challenge", &set_challenge}, {NULL, NULL} };