Example #1
0
/* Open new pptp_connection.  Returns NULL on failure. */
PPTP_CONN * pptp_conn_open(int inet_sock, int isclient, pptp_conn_cb callback)
{
    PPTP_CONN *conn;
    /* Allocate structure */
    if ((conn = malloc(sizeof(*conn))) == NULL) return NULL;
    if ((conn->call = vector_create()) == NULL) { free(conn); return NULL; }
    /* Initialize */
    conn->inet_sock = inet_sock;
    conn->conn_state = CONN_IDLE;
    conn->ka_state  = KA_NONE;
    conn->ka_id     = 1;
    conn->call_serial_number = 0;
    conn->callback  = callback;
    /* Create I/O buffers */
    conn->read_size = conn->write_size = 0;
    conn->read_alloc = conn->write_alloc = INITIAL_BUFSIZE;
    conn->read_buffer =
        malloc(sizeof(*(conn->read_buffer)) * conn->read_alloc);
    conn->write_buffer =
        malloc(sizeof(*(conn->write_buffer)) * conn->write_alloc);
    if (conn->read_buffer == NULL || conn->write_buffer == NULL) {
        if (conn->read_buffer  != NULL) free(conn->read_buffer);
        if (conn->write_buffer != NULL) free(conn->write_buffer);
        vector_destroy(conn->call); free(conn); return NULL;
    }
    /* Make this socket non-blocking. */
    fcntl(conn->inet_sock, F_SETFL, O_NONBLOCK);
    /* Request connection from server, if this is a client */
    if (isclient) {
        struct pptp_start_ctrl_conn packet = {
            PPTP_HEADER_CTRL(PPTP_START_CTRL_CONN_RQST),
            hton16(PPTP_VERSION), 0, 0, 
            hton32(PPTP_FRAME_CAP), hton32(PPTP_BEARER_CAP),
            hton16(PPTP_MAX_CHANNELS), hton16(PPTP_FIRMWARE_VERSION), 
            PPTP_HOSTNAME, PPTP_VENDOR
        };
        /* fix this packet, if necessary */
        int idx, rc;
        idx = get_quirk_index();
        if (idx != -1 && pptp_fixups[idx].start_ctrl_conn) {
            if ((rc = pptp_fixups[idx].start_ctrl_conn(&packet)))
                warn("calling the start_ctrl_conn hook failed (%d)", rc);
        }
        if (pptp_send_ctrl_packet(conn, &packet, sizeof(packet)))
            conn->conn_state = CONN_WAIT_CTL_REPLY;
        else
            return NULL; /* could not send initial start request. */
    }
    /* Set up interval/keep-alive timer */
    /*   First, register handler for SIGALRM */
    sigpipe_create();
    sigpipe_assign(SIGALRM);
    global.conn = conn;
    /* Reset event timer */
    pptp_reset_timer();
    /* all done. */
    return conn;
}
Example #2
0
int main(int argc, char **argv)
{
	char pppLocal[16];		/* local IP to pass to pppd */
	char pppRemote[16];		/* remote IP address to pass to pppd */
	struct sockaddr_in addr;	/* client address */
	socklen_t addrlen;
	int arg = 1;
	int flags;
	struct in_addr inetaddrs[2];
	char *pppaddrs[2] = { pppLocal, pppRemote };

        gargc = argc;
        gargv = argv;

	/* fail if argument count invalid */
	if (argc < 7) {
		fprintf(stderr, "pptpctrl: insufficient arguments, see man pptpctrl\n");
		exit(2);
	}

	/* open a connection to the syslog daemon */
	openlog("pptpd", LOG_PID, PPTP_FACILITY);

	/* autoreap if supported */
	signal(SIGCHLD, SIG_IGN);

	/* note: update pptpctrl.8 if the argument list format is changed */
	GETARG_INT(pptpctrl_debug);
	GETARG_INT(noipparam);
	GETARG_VALUE(pppdxfig);
	GETARG_VALUE(speed);
	GETARG_VALUE(pppLocal);
	GETARG_VALUE(pppRemote);
	if (arg < argc) GETARG_INT(unique_call_id);
	if (arg < argc) GETARG_STRING(ppp_binary);
	if (arg < argc) GETARG_INT(pptp_logwtmp);
	
	if (pptpctrl_debug) {
		if (*pppLocal)
			syslog(LOG_DEBUG, "CTRL: local address = %s", pppLocal);
		if (*pppRemote)
			syslog(LOG_DEBUG, "CTRL: remote address = %s", pppRemote);
		if (*speed)
			syslog(LOG_DEBUG, "CTRL: pppd speed = %s", speed);
		if (*pppdxfig)
			syslog(LOG_DEBUG, "CTRL: pppd options file = %s", pppdxfig);
	}

	addrlen = sizeof(addr);
	if (getsockname(clientSocket, (struct sockaddr *) &addr, &addrlen) != 0) {
		syslog(LOG_ERR, "CTRL: getsockname() failed");
		syslog_perror("getsockname");
		close(clientSocket);
		bail(0);	/* NORETURN */
	}
	inetaddrs[0] = addr.sin_addr;

	addrlen = sizeof(addr);
	if (getpeername(clientSocket, (struct sockaddr *) &addr, &addrlen) != 0) {
		syslog(LOG_ERR, "CTRL: getpeername() failed");
		syslog_perror("getpeername");
		close(clientSocket);
		bail(0);	/* NORETURN */
	}
	inetaddrs[1] = addr.sin_addr;

	/* Set non-blocking */
	if ((flags = fcntl(clientSocket, F_GETFL, arg /* ignored */)) == -1 ||
	    fcntl(clientSocket, F_SETFL, flags|OUR_NB_MODE) == -1) {
		syslog(LOG_ERR, "CTRL: Failed to set client socket non-blocking");
		syslog_perror("fcntl");
		close(clientSocket);
		bail(0);	/* NORETURN */
	}

	
	/* Fiddle with argv */
        my_setproctitle(gargc, gargv, "pptpd [%s]%20c",
            inet_ntoa(addr.sin_addr), ' ');

	/* be ready for a grisly death */
	sigpipe_create();
	sigpipe_assign(SIGTERM);
	NOTE_VALUE(PAC, call_id_pair, htons(-1));
	NOTE_VALUE(PNS, call_id_pair, htons(-1));

	syslog(LOG_INFO, "CTRL: Client %s control connection started", inet_ntoa(addr.sin_addr));
	pptp_handle_ctrl_connection(pppaddrs, inetaddrs);
	syslog(LOG_DEBUG, "CTRL: Reaping child PPP[%i]", pppfork);
	if (pppfork > 0)
		waitpid(pppfork, NULL, 0);
	syslog(LOG_INFO, "CTRL: Client %s control connection finished", inet_ntoa(addr.sin_addr));

	bail(0);		/* NORETURN */
	return 1;		/* make gcc happy */
}
Example #3
0
int pptp_manager(int argc, char **argv)
{
        int firstOpen = -1;
        int ctrl_pid;
        socklen_t addrsize;

        int hostSocket;
        fd_set connSet;

        int rc, sig_fd;

        rc = sigpipe_create();
        if (rc < 0) {
                syslog(LOG_ERR, "MGR: unable to setup sigchld pipe!");
                syslog_perror("sigpipe_create");
                exit(-1);
        }
        
        sigpipe_assign(SIGCHLD);
        sigpipe_assign(SIGTERM);
        sig_fd = sigpipe_fd();

        /* openlog() not required, done in pptpd.c */

        syslog(LOG_INFO, "MGR: Manager process started");

        if (!pptp_delegate) {
                syslog(LOG_INFO, "MGR: Maximum of %d connections available", 
                       pptp_connections);
        }

        /* Connect the host socket and activate it for listening */
        if (createHostSocket(&hostSocket) < 0) {
                syslog(LOG_ERR, "MGR: Couldn't create host socket");
                syslog_perror("createHostSocket");
                exit(-1);
        }

        while (1) {
                int max_fd;
                FD_ZERO(&connSet);
                if (pptp_delegate) {
                        FD_SET(hostSocket, &connSet);
                } else {
                        firstOpen = slot_find_empty();
                        if (firstOpen == -1) {
                                syslog(LOG_ERR, "MGR: No free connection slots or IPs - no more clients can connect!");
                        } else {
                                FD_SET(hostSocket, &connSet);
                        }
                }
                max_fd = hostSocket;

                FD_SET(sig_fd, &connSet);
                if (max_fd < sig_fd) max_fd = sig_fd;

                while (1) {
                        if (select(max_fd + 1, &connSet, NULL, NULL, NULL) != -1) break;
                        if (errno == EINTR) continue;
                        syslog(LOG_ERR, "MGR: Error with manager select()!");
                        syslog_perror("select");
                        exit(-1);
                }

                if (FD_ISSET(sig_fd, &connSet)) {       /* SIGCHLD */
                        int signum = sigpipe_read();
                        if (signum == SIGCHLD)
                                sigchld_responder(signum);
                        else if (signum == SIGTERM)
                        {
                                if (!keep_connections) sigterm_responder();
                                    return signum;
                        }
                }

                if (FD_ISSET(hostSocket, &connSet)) {   /* A call came! */
                        int clientSocket;
                        struct sockaddr_in client_addr;

                        /* Accept call and launch PPTPCTRL */
                        addrsize = sizeof(client_addr);
                        clientSocket = accept(hostSocket, (struct sockaddr *) &client_addr, &addrsize);

#ifdef HAVE_LIBWRAP
                        if (clientSocket != -1) {
                                struct request_info r;
                                request_init(&r, RQ_DAEMON, "pptpd", RQ_FILE, clientSocket, NULL);
                                fromhost(&r);
                                if (!hosts_access(&r)) {
                                        /* send a permission denied message? this is a tcp wrapper
                                         * type deny so probably best to just drop it immediately like
                                         * this, as tcp wrappers usually do.
                                         */
                                        close(clientSocket);
                                        /* this would never be file descriptor 0, so use it as a error
                                         * value
                                         */
                                        clientSocket = 0;
                                }
                        }
#endif
                        if (clientSocket == -1) {
                                /* accept failed, but life goes on... */
                                syslog(LOG_ERR, "MGR: accept() failed");
                                syslog_perror("accept");
                        } else if (clientSocket != 0) {
                                fd_set rfds;
                                struct timeval tv;
                                struct pptp_header ph;

                                /* TODO: this select below prevents
                                   other connections from being
                                   processed during the wait for the
                                   first data packet from the
                                   client. */

                                /*
                                 * DOS protection: get a peek at the first packet
                                 * and do some checks on it before we continue.
                                 * A 10 second timeout on the first packet seems reasonable
                                 * to me,  if anything looks sus,  throw it away.
                                 */

                                FD_ZERO(&rfds);
                                FD_SET(clientSocket, &rfds);
                                tv.tv_sec = pptp_stimeout;
                                tv.tv_usec = 0;
                                if (select(clientSocket + 1, &rfds, NULL, NULL, &tv) <= 0) {
                                        syslog(LOG_ERR, "MGR: dropped slow initial connection");
                                        close(clientSocket);
                                        continue;
                                }

                                if (recv(clientSocket, &ph, sizeof(ph), MSG_PEEK) !=
                                                sizeof(ph)) {
                                        syslog(LOG_ERR, "MGR: dropped small initial connection");
                                        close(clientSocket);
                                        continue;
                                }

                                ph.length = ntohs(ph.length);
                                ph.pptp_type = ntohs(ph.pptp_type);
                                ph.magic = ntohl(ph.magic);
                                ph.ctrl_type = ntohs(ph.ctrl_type);

                                if (ph.length <= 0 || ph.length > PPTP_MAX_CTRL_PCKT_SIZE) {
                                        syslog(LOG_WARNING, "MGR: initial packet length %d outside "
                                                        "(0 - %d)",  ph.length, PPTP_MAX_CTRL_PCKT_SIZE);
                                        goto dos_exit;
                                }

                                if (ph.magic != PPTP_MAGIC_COOKIE) {
                                        syslog(LOG_WARNING, "MGR: initial packet bad magic");
                                        goto dos_exit;
                                }

                                if (ph.pptp_type != PPTP_CTRL_MESSAGE) {
                                        syslog(LOG_WARNING, "MGR: initial packet has bad type");
                                        goto dos_exit;
                                }

                                if (ph.ctrl_type != START_CTRL_CONN_RQST) {
                                        syslog(LOG_WARNING, "MGR: initial packet has bad ctrl type "
                                                        "0x%x", ph.ctrl_type);
                dos_exit:
                                        close(clientSocket);
                                        continue;
                                }

#ifndef HAVE_FORK
                                switch (ctrl_pid = vfork()) {
#else
                                switch (ctrl_pid = fork()) {
#endif
                                case -1:        /* error */
                                        syslog(LOG_ERR, "MGR: fork() failed launching " PPTP_CTRL_BIN);
                                        close(clientSocket);
                                        break;

                                case 0: /* child */
                                        close(hostSocket);
                                        if (pptp_debug)
                                                syslog(LOG_DEBUG, "MGR: Launching " PPTP_CTRL_BIN " to handle client");
                                        connectCall(clientSocket, !pptp_delegate ? firstOpen : 0);
                                        _exit(1);
                                        /* NORETURN */
                                default:        /* parent */
                                        close(clientSocket);
                                        unique_call_id += MAX_CALLS_PER_TCP_LINK;
                                        if (!pptp_delegate)
                                                slot_set_pid(firstOpen, ctrl_pid);
                                        break;
                                }
                        }
                }               /* FD_ISSET(hostSocket, &connSet) */
        }                       /* while (1) */
}                               /* pptp_manager() */

/*
 * Author: Kevin Thayer
 * 
 * This creates a socket to listen on, sets the max # of pending connections and 
 * various other options.
 * 
 * Returns the fd of the host socket.
 * 
 * The function return values are:
 * 0 for sucessful
 * -1 for bad socket creation
 * -2 for bad socket options
 * -3 for bad bind
 * -4 for bad listen
 */
static int createHostSocket(int *hostSocket)
{
        int opt = 1;
        struct sockaddr_in address;
#ifdef HAVE_GETSERVBYNAME
        struct servent *serv;
#endif

        /* create the master socket and check it worked */
        if ((*hostSocket = vrf_socket(vrf, AF_INET, SOCK_STREAM, 0)) <= 0)
                return -1;

        /* set master socket to allow daemon to be restarted with connections active  */
        if (setsockopt(*hostSocket, SOL_SOCKET, SO_REUSEADDR,
                       (char *) &opt, sizeof(opt)) < 0)
                return -2;

        /* set up socket */
        memset(&address, 0, sizeof(address));
        address.sin_family = AF_INET;
        if(bindaddr)
                address.sin_addr.s_addr = inet_addr(bindaddr);
        else
                address.sin_addr.s_addr = INADDR_ANY;
#ifdef HAVE_GETSERVBYNAME
        if ((serv = getservbyname("pptp", "tcp")) != NULL) {
                address.sin_port = serv->s_port;
        } else
#endif
                address.sin_port = htons(PPTP_PORT);

        /* bind the socket to the pptp port */
        if (bind(*hostSocket, (struct sockaddr *) &address, sizeof(address)) < 0)
                return -3;

        /* minimal backlog to avoid DoS */
        if (listen(*hostSocket, 3) < 0)
                return -4;

        return 0;
}