Exemple #1
0
/**********************************************************************
* %FUNCTION: load_handler
* %ARGUMENTS:
*  fname -- filename to load
* %RETURNS:
*  -1 on error, 0 if OK
* %DESCRIPTION:
*  Dynamically-loads a handler and initializes it.  If fname is not
*  an absolute path name, we load the handler from /usr/lib/l2tp/plugins
***********************************************************************/
int
l2tp_load_handler(EventSelector *es,
		  char const *fname)
{
    char buf[1024];
    void *handle;
    void *init;
    void (*init_fn)(EventSelector *);

    if (*fname == '/') {
	handle = dlopen(fname, RTLD_NOW);
    } else {
	snprintf(buf, sizeof(buf), PREFIX"/lib/l2tp/%s", fname);
	buf[sizeof(buf)-1] = 0;
	handle = dlopen(buf, RTLD_NOW);
    }

    if (!handle) {
	l2tp_set_errmsg("Could not dload %s: %s",
			fname, dlerror());
	return -1;
    }

    init = dlsym(handle, "handler_init");
    if (!init) {
	dlclose(handle);
	l2tp_set_errmsg("No handler_init found in %s", fname);
	return -1;
    }
    init_fn = (void (*)(EventSelector *)) init;
    init_fn(es);
    return 0;
}
Exemple #2
0
/**********************************************************************
* %FUNCTION: pty_get
* %ARGUMENTS:
*  mfp -- pointer to master file descriptor
*  sfp -- pointer to slave file descriptor
* %RETURNS:
*  0 on success, -1 on failure
* %DESCRIPTION:
*  Opens a PTY and sets line discipline to N_HDLC for ppp.
*  Taken almost verbatim from Linux pppd code.
***********************************************************************/
int
pty_get(int *mfp, int *sfp)
{
    char pty_name[24];
    struct termios tios;
    int mfd, sfd;
    int disc = N_HDLC;

    mfd = -1;
    sfd = -1;

    mfd = open("/dev/ptmx", O_RDWR);
    if (mfd >= 0) {
	int ptn;
	if (ioctl(mfd, TIOCGPTN, &ptn) >= 0) {
	    snprintf(pty_name, sizeof(pty_name), "/dev/pts/%d", ptn);
	    ptn = 0;
	    if (ioctl(mfd, TIOCSPTLCK, &ptn) < 0) {
		/* warn("Couldn't unlock pty slave %s: %m", pty_name); */
	    }
	    if ((sfd = open(pty_name, O_RDWR | O_NOCTTY)) < 0) {
		/* warn("Couldn't open pty slave %s: %m", pty_name); */
	    }
	}
    }

    if (sfd < 0 || mfd < 0) {
	if (sfd >= 0) close(sfd);
	if (mfd >= 0) close(mfd);
	return -1;
    }

    *mfp = mfd;
    *sfp = sfd;
    if (tcgetattr(sfd, &tios) == 0) {
	tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB);
	tios.c_cflag |= CS8 | CREAD | CLOCAL;
	tios.c_iflag  = IGNPAR;
	tios.c_oflag  = 0;
	tios.c_lflag  = 0;
	tcsetattr(sfd, TCSAFLUSH, &tios);
    }
    if (ioctl(sfd, TIOCSETD, &disc) < 0) {
	l2tp_set_errmsg("Unable to set line discipline to N_HDLC");
	close(mfd);
	close(sfd);
	return -1;
    }
    disc = N_HDLC;
    if (ioctl(mfd, TIOCSETD, &disc) < 0) {
	l2tp_set_errmsg("Unable to set line discipline to N_HDLC");
	close(mfd);
	close(sfd);
	return -1;
    }
    return 0;
}
Exemple #3
0
/**********************************************************************
* %FUNCTION: process_option
* %ARGUMENTS:
*  es -- event selector
*  name, value -- name and value of option
* %RETURNS:
*  0 on success; -1 on failure.
* %DESCRIPTION:
*  Processes options.  When last option has been processed, begins
*  command handler.
***********************************************************************/
static int
process_option(EventSelector *es,
	       char const *name,
	       char const *value)
{
    struct sockaddr_un addr;
    socklen_t len;
    int fd;

    if (!strcmp(name, "*begin*")) return 0;
    if (strcmp(name, "*end*")) {
	return l2tp_option_set(es, name, value, my_opts);
    }

    /* We have hit the end of our options.  Open command socket */
    if (!sockname) {
	sockname = "/var/run/l2tpctrl";
    }

    (void) remove(sockname);
    fd = socket(AF_LOCAL, SOCK_STREAM, 0);
    if (fd < 0) {
	l2tp_set_errmsg("cmd: process_option: socket: %s", strerror(errno));
	return -1;
    }

    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_LOCAL;
    strncpy(addr.sun_path, sockname, sizeof(addr.sun_path) - 1);

    len = sizeof(addr);
    if (bind(fd, (struct sockaddr *) &addr, SUN_LEN(&addr)) < 0) {
	l2tp_set_errmsg("cmd: process_option: bind: %s", strerror(errno));
	close(fd);
	return -1;
    }
    (void) chmod(sockname, 0600);
    if (listen(fd, 5) < 0) {
	l2tp_set_errmsg("cmd: process_option: listen: %s", strerror(errno));
	close(fd);
	return -1;
    }

    /* Ignore sigpipe */
    signal(SIGPIPE, SIG_IGN);

    /* Add an accept handler */
    if (!EventTcp_CreateAcceptor(es, fd, cmd_acceptor)) {
	l2tp_set_errmsg("cmd: process_option: EventTcp_CreateAcceptor: %s", strerror(errno));
	close(fd);
	return -1;
    }
    return 0;
}
Exemple #4
0
/**********************************************************************
* %FUNCTION: parser_switch_context
* %ARGUMENTS:
*  name, value -- words read from line.  Either "global ..ignored.."
*                 or "section context"
* %RETURNS:
*  0 if context-switch proceeded OK, -1 if not.
* %DESCRIPTION:
*  Switches configuration contexts
***********************************************************************/
static int
parser_switch_context(EventSelector *es,
		      char const *name,
		      char const *value)
{
    int r;
    option_handler *handler;

    /* Switch out of old context */
    if (option_context_fn) {
	r = option_context_fn(es, "*end*", "*end*");
	option_context_fn = NULL;
	if (r < 0) return r;
    }

    if (!strcasecmp(name, "global")) {
	return 0;
    }

    /* Must be "section foo" */
    handler = option_handlers;
    while(handler) {
	if (!strcasecmp(value, handler->section)) {
	    option_context_fn = handler->process_option;
	    option_context_fn(es, "*begin*", "*begin*");
	    return 0;
	}
	handler = handler->next;
    }
    l2tp_set_errmsg("No handler for section %s", value);
    return -1;
}
Exemple #5
0
/**********************************************************************
* %FUNCTION: network_init
* %ARGUMENTS:
*  es -- an event selector
* %RETURNS:
*  >= 0 if all is OK, <0 if not
* %DESCRIPTION:
*  Initializes network; opens socket on UDP port 1701; sets up
*  event handler for incoming packets.
***********************************************************************/
int
l2tp_network_init(EventSelector *es)
{
    struct sockaddr_in me;
    int flags;

    gethostname(Hostname, sizeof(Hostname));
    Hostname[sizeof(Hostname)-1] = 0;

    Event_HandleSignal(es, SIGINT, sigint_handler);
    if (Sock >= 0) {
	if (NetworkReadHandler) {
	    Event_DelHandler(es, NetworkReadHandler);
	    NetworkReadHandler = NULL;
	}
	close(Sock);
	Sock = -1;
    }
    Sock = socket(PF_INET, SOCK_DGRAM, 0);
    if (Sock < 0) {
	l2tp_set_errmsg("network_init: socket: %s", strerror(errno));
	return -1;
    }

    me.sin_family = AF_INET;
    me.sin_addr = Settings.listen_addr;
    me.sin_port = htons((uint16_t) Settings.listen_port);
    if (bind(Sock, (struct sockaddr *) &me, sizeof(me)) < 0) {
	l2tp_set_errmsg("network_init: bind: %s", strerror(errno));
	close(Sock);
	Sock = -1;
	return -1;
    }

    /* Set socket non-blocking */
    flags = fcntl(Sock, F_GETFL);
    flags |= O_NONBLOCK;
    fcntl(Sock, F_SETFL, flags);

    /* Set up the network read handler */
    Event_AddHandler(es, Sock, EVENT_FLAG_READABLE,
		     network_readable, NULL);
    return Sock;
}
static int
set_lns_handler(EventSelector *es,
		l2tp_opt_descriptor *desc,
		char const *value)
{
    l2tp_lns_handler *handler = l2tp_session_find_lns_handler(value);
    if (!handler) {
	l2tp_set_errmsg("No LNS handler named '%s'", value);
	return -1;
    }
    prototype.lns_ops = handler->call_ops;
    return 0;
}
/**********************************************************************
* %FUNCTION: peer_insert
* %ARGUMENTS:
*  addr -- IP address of peer
* %RETURNS:
*  NULL if insert failed, pointer to new peer structure otherwise
* %DESCRIPTION:
*  Inserts a new peer in the all_peers table
***********************************************************************/
l2tp_peer *
l2tp_peer_insert(struct sockaddr_in *addr)
{
    l2tp_peer *peer = malloc(sizeof(l2tp_peer));
    if (!peer) {
	l2tp_set_errmsg("peer_insert: Out of memory");
	return NULL;
    }
    memset(peer, 0, sizeof(*peer));

    peer->addr = *addr;
    hash_insert(&all_peers, peer);
    return peer;
}
Exemple #8
0
/**********************************************************************
* %FUNCTION: option_set
* %ARGUMENTS:
*  es -- event selector
*  name -- name of option
*  value -- value of option
*  descriptors -- array of option descriptors for this context
* %RETURNS:
*  0 on success, -1 on failure
* %DESCRIPTION:
*  Sets an option
***********************************************************************/
int
l2tp_option_set(EventSelector *es,
		char const *name,
		char const *value,
		l2tp_opt_descriptor descriptors[])
{
    int i;

    for (i=0; descriptors[i].name; i++) {
	if (!strcasecmp(descriptors[i].name, name)) {
	    return set_option(es, &descriptors[i], value);
	}
    }
    l2tp_set_errmsg("Option %s is not known in this context",
	       name);
    return -1;
}
Exemple #9
0
/**********************************************************************
* %FUNCTION: set_option
* %ARGUMENTS:
*  es -- event selector
*  desc -- option descriptor
*  value -- value string parsed from config file
* %RETURNS:
*  -1 on error, 0 if all is OK
* %DESCRIPTION:
*  Sets an option value.
***********************************************************************/
static int
set_option(EventSelector *es,
	   l2tp_opt_descriptor *desc,
	   char const *value)
{
    long x;
    char *end;
    struct hostent *he;
    int (*fn)(EventSelector *, l2tp_opt_descriptor *, char const *);

    switch(desc->type) {
    case OPT_TYPE_BOOL:
	if (!strcasecmp(value, "true") ||
	    !strcasecmp(value, "yes") ||
	    !strcasecmp(value, "on") ||
	    !strcasecmp(value, "1")) {
	    * (int *) (desc->addr) = 1;
	    return 0;
	}
	if (!strcasecmp(value, "false") ||
	    !strcasecmp(value, "no") ||
	    !strcasecmp(value, "off") ||
	    !strcasecmp(value, "0")) {
	    * (int *) (desc->addr) = 0;
	    return 0;
	}
	l2tp_set_errmsg("Expecting boolean value, found '%s'", value);
	return -1;

    case OPT_TYPE_INT:
    case OPT_TYPE_PORT:
	x = strtol(value, &end, 0);
	if (*end) {
	    l2tp_set_errmsg("Expecting integer value, found '%s'", value);
	    return -1;
	}
	if (desc->type == OPT_TYPE_PORT) {
	    if (x < 1 || x > 65535) {
		l2tp_set_errmsg("Port values must range from 1 to 65535");
		return -1;
	    }
	}

	* (int *) desc->addr = (int) x;
	return 0;

    case OPT_TYPE_IPADDR:
	he = gethostbyname(value);
	if (!he) {
	    l2tp_set_errmsg("Could not resolve %s as IP address: %s",
		       value, strerror(errno));
	    return -1;
	}

	memcpy(desc->addr, he->h_addr, sizeof(he->h_addr));
	return 0;

    case OPT_TYPE_STRING:
	if (* (char **) desc->addr) {
	    free(* (char **) desc->addr);
	}
	* (char **) desc->addr = strdup(value);
	if (! * (char **) desc->addr) {
	    l2tp_set_errmsg("Out of memory");
	    return -1;
	}
	return 0;

    case OPT_TYPE_CALLFUNC:
	fn = (int (*)(EventSelector *, l2tp_opt_descriptor *, char const *)) desc->addr;
	return fn(es, desc, value);
    }
    l2tp_set_errmsg("Unknown value type %d", desc->type);
    return -1;
}
Exemple #10
0
/**********************************************************************
* %FUNCTION: parse_config_file
* %ARGUMENTS:
*  es -- event selector
*  fname -- filename to parse
* %RETURNS:
*  -1 on error, 0 if all is OK
* %DESCRIPTION:
*  Parses configuration file.
***********************************************************************/
int
l2tp_parse_config_file(EventSelector *es,
		       char const *fname)
{
    char buf[512];
    char name[512];
    char value[512];
    int r = 0;
    size_t l;
    char *line;
    FILE *fp;

    /* Defaults */
    Settings.listen_port = 1701;
    Settings.listen_addr.s_addr = htonl(INADDR_ANY);

    fp = fopen(fname, "r");
    if (!fp) {
	l2tp_set_errmsg("Could not open '%s' for reading: %s",
		   fname, strerror(errno));
	return -1;
    }

    /* Start in global context */
    option_context_fn = NULL;
    while (fgets(buf, sizeof(buf), fp) != NULL) {
	l = strlen(buf);
	if (l && (buf[l] == '\n')) {
	    buf[l--] = 0;
	}

	/* Skip leading whitespace */
	line = buf;
	while(*line && isspace(*line)) line++;

	/* Ignore blank lines and comments */
	if (!*line || *line == '#') {
	    continue;
	}

	/* Split line into two words */
	split_line_into_words(line, name, value);

	/* Check for context switch */
	if (!strcasecmp(name, "global") ||
	    !strcasecmp(name, "section")) {
	    r = parser_switch_context(es, name, value);
	    if (r < 0) break;
	    continue;
	}

	r = handle_option(es, name, value);
	if (r < 0) break;
    }
    fclose(fp);
    if (r >= 0) {
	if (option_context_fn) {
	    r = option_context_fn(es, "*end*", "*end*");
	    option_context_fn = NULL;
	}
    }

    return r;
}
/**********************************************************************
* %FUNCTION: peer_process_option
* %ARGUMENTS:
*  es -- event selector
*  name, value -- name and value of option
* %RETURNS:
*  0 on success, -1 on failure
* %DESCRIPTION:
*  Processes an option in the "peer" section
***********************************************************************/
static int
peer_process_option(EventSelector *es,
		    char const *name,
		    char const *value)
{
    l2tp_peer *peer;

    /* Special cases: begin and end */
    if (!strcmp(name, "*begin*")) {
	/* Switching in to peer context */
	memset(&prototype, 0, sizeof(prototype));
	prototype.mask_bits = 32;
	prototype.validate_peer_ip = 1;
	port = 1701;
	return 0;
    }

    if (!strcmp(name, "*end*")) {
	/* Validate settings */
	uint16_t u16 = (uint16_t) port;
	prototype.addr.sin_port = htons(u16);
	prototype.addr.sin_family = AF_INET;

	/* Allow non-authenticated tunnels
	if (!prototype.secret_len) {
	    l2tp_set_errmsg("No secret supplied for peer");
	    return -1;
	}
	*/
	if (!prototype.lns_ops && !prototype.lac_ops) {
	    l2tp_set_errmsg("You must enable at least one of lns-handler or lac-handler");
	    return -1;
	}

	/* Add the peer */
	peer = l2tp_peer_insert(&prototype.addr);
	if (!peer) return -1;

	peer->mask_bits = prototype.mask_bits;
	memcpy(&peer->hostname,&prototype.hostname, sizeof(prototype.hostname));
	peer->hostname_len = prototype.hostname_len;
	memcpy(&peer->peername,&prototype.peername, sizeof(prototype.peername));
	peer->peername_len = prototype.peername_len;
	memcpy(&peer->secret, &prototype.secret, MAX_SECRET_LEN);
	peer->secret_len = prototype.secret_len;
	peer->lns_ops = prototype.lns_ops;
        memcpy(&peer->lns_options,&prototype.lns_options,sizeof(prototype.lns_options));
	peer->lac_ops = prototype.lac_ops;
        memcpy(&peer->lac_options,&prototype.lac_options,sizeof(prototype.lac_options));
	peer->hide_avps = prototype.hide_avps;
	peer->retain_tunnel = prototype.retain_tunnel;
	peer->persist = prototype.persist;
	peer->holdoff = prototype.holdoff;
	peer->maxfail = prototype.maxfail;
	peer->fail = 0;
	peer->validate_peer_ip = prototype.validate_peer_ip;
	return 0;
    }

    /* Process option */
    return l2tp_option_set(es, name, value, peer_opts);
}