From 07de73a331240b97d915c1851431a743449dd0f4 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 11 Sep 1999 12:09:00 +0000 Subject: [PATCH] Add plugin support plus an initial selection of hooks. Add the allow-ip option as a better way of specifying what IP addresses an unauthenticated peer may use. Translate unprintable chars in PAP user/password into visible form. Clean up the processing of extra options in the secrets files. Add ktune/noktune options to enable/disable changing kernel settings. --- pppd/Makefile.linux | 12 +- pppd/auth.c | 280 ++++++++++++++++++++++++++++++-------------- pppd/lcp.c | 4 +- pppd/main.c | 48 ++++++-- pppd/options.c | 86 +++++++++++++- pppd/pppd.h | 27 ++++- pppd/sys-linux.c | 144 ++++++++++++++--------- pppd/upap.c | 7 +- 8 files changed, 441 insertions(+), 167 deletions(-) diff --git a/pppd/Makefile.linux b/pppd/Makefile.linux index bf2bcc5..705f549 100644 --- a/pppd/Makefile.linux +++ b/pppd/Makefile.linux @@ -1,6 +1,6 @@ # # pppd makefile for Linux -# $Id: Makefile.linux,v 1.33 1999/08/24 05:31:08 paulus Exp $ +# $Id: Makefile.linux,v 1.34 1999/09/11 12:08:56 paulus Exp $ # # Default installation locations @@ -46,6 +46,8 @@ HAS_SHADOW=y #USE_PAM=y #HAVE_INET6=y +PLUGIN=y + INCLUDE_DIRS= -I../include COMPILE_FLAGS= -D_linux_=1 -DHAVE_PATHS_H -DIPX_CHANGE @@ -85,6 +87,12 @@ LIBS := -llock $(LIBS) CFLAGS += -DLOCKLIB=1 endif +ifdef PLUGIN +CFLAGS += -DPLUGIN +LDFLAGS += -Wl,-E +LIBS += -ldl +endif + ifdef HAVE_INET6 PPPDSRCS += ipv6cp.c eui64.c HEADERS += ipv6cp.h eui64.h @@ -103,7 +111,7 @@ install: pppd $(INSTALL) -c -m 444 pppd.8 $(MANDIR)/man8 pppd: $(PPPDOBJS) - $(CC) $(CFLAGS) -o pppd $(PPPDOBJS) $(LIBS) + $(CC) $(CFLAGS) $(LDFLAGS) -o pppd $(PPPDOBJS) $(LIBS) clean: rm -f $(PPPDOBJS) pppd *~ #* core diff --git a/pppd/auth.c b/pppd/auth.c index 716d849..ac2eee9 100644 --- a/pppd/auth.c +++ b/pppd/auth.c @@ -32,7 +32,7 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#define RCSID "$Id: auth.c,v 1.57 1999/08/13 06:46:10 paulus Exp $" +#define RCSID "$Id: auth.c,v 1.58 1999/09/11 12:08:56 paulus Exp $" #include #include @@ -96,6 +96,10 @@ static int logged_in; /* List of addresses which the peer may use. */ static struct permitted_ip *addresses[NUM_PPP]; +/* Wordlist giving addresses which the peer may use + without authenticating itself. */ +static struct wordlist *noauth_addrs; + /* Extra options to apply, from the secrets file entry for the peer. */ static struct wordlist *extra_options; @@ -108,6 +112,20 @@ static int num_np_up; /* Set if we got the contents of passwd[] from the pap-secrets file. */ static int passwd_from_file; +/* Hook to enable a plugin to control the idle time limit */ +int (*idle_time_hook) __P((struct ppp_idle *)) = NULL; + +/* Hook for a plugin to say whether we can possibly authenticate any peer */ +int (*pap_check_hook) __P((void)) = NULL; + +/* Hook for a plugin to check the PAP user and password */ +int (*pap_auth_hook) __P((char *user, char *passwd, char **msgp, + struct wordlist **paddrs, + struct wordlist **popts)) = NULL; + +/* Hook for a plugin to get the PAP password for authenticating us */ +int (*pap_passwd_hook) __P((char *user, char *passwd)) = NULL; + /* * This is used to ensure that we don't start an auth-up/down * script while one is already running. @@ -147,7 +165,7 @@ extern char *crypt __P((const char *, const char *)); static void network_phase __P((int)); static void check_idle __P((void *)); static void connect_time_expired __P((void *)); -static int plogin __P((char *, char *, char **, int *)); +static int plogin __P((char *, char *, char **)); static void plogout __P((void)); static int null_login __P((int)); static int get_pap_passwd __P((char *)); @@ -155,14 +173,16 @@ static int have_pap_secret __P((int *)); static int have_chap_secret __P((char *, char *, int, int *)); static int ip_addr_check __P((u_int32_t, struct permitted_ip *)); static int scan_authfile __P((FILE *, char *, char *, char *, - struct wordlist **, char *)); + struct wordlist **, struct wordlist **, + char *)); static void free_wordlist __P((struct wordlist *)); static void auth_script __P((char *)); static void auth_script_done __P((void *)); -static void set_allowed_addrs __P((int, struct wordlist *)); +static void set_allowed_addrs __P((int, struct wordlist *, struct wordlist *)); static int some_ip_ok __P((struct wordlist *)); static int setupapfile __P((char **)); static int privgroup __P((char **)); +static int set_noauth_addr __P((char **)); static void check_access __P((FILE *, char *)); /* @@ -210,6 +230,9 @@ option_t auth_options[] = { NULL, MAXSECRETLEN }, { "privgroup", o_special, privgroup, "Allow group members to use privileged options", OPT_PRIV }, + { "allow-ip", o_special, set_noauth_addr, + "Set IP address(es) which can be used without authentication", + OPT_PRIV }, { NULL } }; @@ -280,6 +303,29 @@ privgroup(argv) } +/* + * set_noauth_addr - set address(es) that can be used without authentication. + * Equivalent to specifying an entry like `"" * "" addr' in pap-secrets. + */ +static int +set_noauth_addr(argv) + char **argv; +{ + char *addr = *argv; + int l = strlen(addr); + struct wordlist *wp; + + wp = (struct wordlist *) malloc(sizeof(struct wordlist) + l + 1); + if (wp == NULL) + novm("allow-ip argument"); + wp->word = (char *) (wp + 1); + wp->next = noauth_addrs; + BCOPY(addr, wp->word, l); + noauth_addrs = wp; + return 1; +} + + /* * An Open on LCP has requested a change from Dead to Establish phase. * Do what's necessary to bring the physical layer up. @@ -302,7 +348,7 @@ link_terminated(unit) return; if (logged_in) plogout(); - phase = PHASE_DEAD; + new_phase(PHASE_DEAD); notice("Connection terminated."); } @@ -318,6 +364,7 @@ link_down(unit) auth_state = s_down; if (auth_script_state == s_up && auth_script_pid == 0) { + update_link_stats(unit); auth_script_state = s_down; auth_script(_PATH_AUTHDOWN); } @@ -332,7 +379,7 @@ link_down(unit) num_np_open = 0; num_np_up = 0; if (phase != PHASE_DEAD) - phase = PHASE_TERMINATE; + new_phase(PHASE_TERMINATE); } /* @@ -361,10 +408,14 @@ link_established(unit) if (auth_required && !(go->neg_chap || go->neg_upap)) { /* * We wanted the peer to authenticate itself, and it refused: - * treat it as though it authenticated with PAP using a username - * of "" and a password of "". If that's not OK, boot it out. + * if we have some address(es) it can use without auth, fine, + * otherwise treat it as though it authenticated with PAP using + * a username * of "" and a password of "". If that's not OK, + * boot it out. */ - if (!wo->neg_upap || !null_login(unit)) { + if (noauth_addrs != NULL) { + set_allowed_addrs(unit, noauth_addrs, NULL); + } else if (!wo->neg_upap || !null_login(unit)) { warn("peer refused to authenticate: terminating link"); lcp_close(unit, "peer refused to authenticate"); status = EXIT_PEER_AUTH_FAILED; @@ -372,7 +423,7 @@ link_established(unit) } } - phase = PHASE_AUTHENTICATE; + new_phase(PHASE_AUTHENTICATE); auth = 0; if (go->neg_chap) { ChapAuthPeer(unit, our_name, go->chap_mdtype); @@ -424,7 +475,7 @@ network_phase(unit) * If we negotiated callback, do it now. */ if (go->neg_cbcp) { - phase = PHASE_CALLBACK; + new_phase(PHASE_CALLBACK); (*cbcp_protent.open)(unit); return; } @@ -447,7 +498,7 @@ start_networks() int i; struct protent *protp; - phase = PHASE_NETWORK; + new_phase(PHASE_NETWORK); #if 0 if (!demand) set_filters(&pass_filter, &active_filter); @@ -577,15 +628,22 @@ void np_up(unit, proto) int unit, proto; { + int tlim; + if (num_np_up == 0) { /* * At this point we consider that the link has come up successfully. */ status = EXIT_OK; unsuccess = 0; + new_phase(PHASE_RUNNING); - if (idle_time_limit > 0) - TIMEOUT(check_idle, NULL, idle_time_limit); + if (idle_time_hook != 0) + tlim = (*idle_time_hook)(NULL); + else + tlim = idle_time_limit; + if (tlim > 0) + TIMEOUT(check_idle, NULL, tlim); /* * Set a timeout to close the connection once the maximum @@ -610,8 +668,9 @@ void np_down(unit, proto) int unit, proto; { - if (--num_np_up == 0 && idle_time_limit > 0) { + if (--num_np_up == 0) { UNTIMEOUT(check_idle, NULL); + new_phase(PHASE_NETWORK); } } @@ -634,22 +693,28 @@ np_finished(unit, proto) */ static void check_idle(arg) - void *arg; + void *arg; { struct ppp_idle idle; time_t itime; + int tlim; if (!get_idle_time(0, &idle)) return; - itime = MIN(idle.xmit_idle, idle.recv_idle); - if (itime >= idle_time_limit) { + if (idle_time_hook != 0) { + tlim = idle_time_hook(&idle); + } else { + itime = MIN(idle.xmit_idle, idle.recv_idle); + tlim = idle_time_limit - itime; + } + if (tlim <= 0) { /* link is idle: shut it down. */ notice("Terminating connection due to lack of activity."); lcp_close(0, "Link inactive"); need_holdoff = 0; status = EXIT_IDLE_TIMEOUT; } else { - TIMEOUT(check_idle, NULL, idle_time_limit - itime); + TIMEOUT(check_idle, NULL, tlim); } } @@ -710,7 +775,7 @@ auth_check_options() our_name, 1, &lacks_ip); } - if (auth_required && !can_auth) { + if (auth_required && !can_auth && noauth_addrs == NULL) { if (explicit_remote) option_error( "The remote system (%s) is required to authenticate itself but I", @@ -769,38 +834,50 @@ auth_reset(unit) * In either case, msg points to an appropriate message. */ int -check_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen) +check_passwd(unit, auser, userlen, apasswd, passwdlen, msg) int unit; char *auser; int userlen; char *apasswd; int passwdlen; char **msg; - int *msglen; { int ret; char *filename; FILE *f; - struct wordlist *addrs; + struct wordlist *addrs = NULL, *opts = NULL; char passwd[256], user[256]; char secret[MAXWORDLEN]; static int attempts = 0; /* * Make copies of apasswd and auser, then null-terminate them. + * If there are unprintable characters in the password, make + * them visible. */ - BCOPY(apasswd, passwd, passwdlen); - passwd[passwdlen] = '\0'; - BCOPY(auser, user, userlen); - user[userlen] = '\0'; - *msg = (char *) 0; + slprintf(passwd, sizeof(passwd), "%.*v", passwdlen, apasswd); + slprintf(user, sizeof(user), "%.*v", userlen, auser); + *msg = ""; + + /* + * Check if a plugin wants to handle this. + */ + if (pap_auth_hook) { + ret = (*pap_auth_hook)(user, passwd, msg, &addrs, &opts); + if (ret >= 0) { + if (ret) + set_allowed_addrs(unit, addrs, opts); + BZERO(passwd, sizeof(passwd)); + return ret? UPAP_AUTHACK: UPAP_AUTHNAK; + } + } /* * Open the file of pap secrets and scan for a suitable secret * for authenticating this user. */ filename = _PATH_UPAPFILE; - addrs = NULL; + addrs = opts = NULL; ret = UPAP_AUTHNAK; f = fopen(filename, "r"); if (f == NULL) { @@ -808,7 +885,7 @@ check_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen) } else { check_access(f, filename); - if (scan_authfile(f, user, our_name, secret, &addrs, filename) < 0) { + if (scan_authfile(f, user, our_name, secret, &addrs, &opts, filename) < 0) { warn("no PAP secret found for %s", user); } else if (secret[0] != 0) { /* password given in pap-secrets - must match */ @@ -819,7 +896,7 @@ check_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen) warn("PAP authentication failure for %s", user); } else if (uselogin) { /* empty password in pap-secrets and login option */ - ret = plogin(user, passwd, msg, msglen); + ret = plogin(user, passwd, msg); if (ret == UPAP_AUTHNAK) warn("PAP login failure for %s", user); } else { @@ -830,9 +907,8 @@ check_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen) } if (ret == UPAP_AUTHNAK) { - if (*msg == (char *) 0) + if (**msg == 0) *msg = "Login incorrect"; - *msglen = strlen(*msg); /* * XXX can we ever get here more than once?? * Frustrate passwd stealer programs. @@ -847,13 +923,14 @@ check_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen) sleep((u_int) (attempts - 3) * 5); if (addrs != NULL) free_wordlist(addrs); + if (opts != NULL) + free_wordlist(opts); } else { attempts = 0; /* Reset count */ - if (*msg == (char *) 0) + if (**msg == 0) *msg = "Login ok"; - *msglen = strlen(*msg); - set_allowed_addrs(unit, addrs); + set_allowed_addrs(unit, addrs, opts); } BZERO(passwd, sizeof(passwd)); @@ -938,11 +1015,10 @@ static struct pam_conv PAM_conversation = { */ static int -plogin(user, passwd, msg, msglen) +plogin(user, passwd, msg) char *user; char *passwd; char **msg; - int *msglen; { char *tty; @@ -1098,12 +1174,11 @@ null_login(unit) char *filename; FILE *f; int i, ret; - struct wordlist *addrs; + struct wordlist *addrs, *opts; char secret[MAXWORDLEN]; /* * Open the file of pap secrets and scan for a suitable secret. - * We don't accept a wildcard client. */ filename = _PATH_UPAPFILE; addrs = NULL; @@ -1112,14 +1187,16 @@ null_login(unit) return 0; check_access(f, filename); - i = scan_authfile(f, "", our_name, secret, &addrs, filename); - ret = i >= 0 && (i & NONWILD_CLIENT) != 0 && secret[0] == 0; + i = scan_authfile(f, "", our_name, secret, &addrs, &opts, filename); + ret = i >= 0 && secret[0] == 0; BZERO(secret, sizeof(secret)); if (ret) - set_allowed_addrs(unit, addrs); - else + set_allowed_addrs(unit, addrs, opts); + else { free_wordlist(addrs); + free_wordlist(opts); + } fclose(f); return ret; @@ -1142,6 +1219,15 @@ get_pap_passwd(passwd) struct wordlist *addrs; char secret[MAXWORDLEN]; + /* + * Check whether a plugin wants to supply this. + */ + if (pap_passwd_hook) { + ret = (*pap_passwd_hook)(user, passwd); + if (ret >= 0) + return ret; + } + filename = _PATH_UPAPFILE; addrs = NULL; f = fopen(filename, "r"); @@ -1150,7 +1236,7 @@ get_pap_passwd(passwd) check_access(f, filename); ret = scan_authfile(f, user, (remote_name[0]? remote_name: NULL), - secret, NULL, filename); + secret, NULL, NULL, filename); fclose(f); if (ret < 0) return 0; @@ -1174,13 +1260,20 @@ have_pap_secret(lacks_ipp) char *filename; struct wordlist *addrs; + /* let the plugin decide, if there is one */ + if (pap_check_hook) { + ret = (*pap_check_hook)(); + if (ret >= 0) + return ret; + } + filename = _PATH_UPAPFILE; f = fopen(filename, "r"); if (f == NULL) return 0; ret = scan_authfile(f, (explicit_remote? remote_name: NULL), our_name, - NULL, &addrs, filename); + NULL, &addrs, NULL, filename); fclose(f); if (ret >= 0 && !some_ip_ok(addrs)) { if (lacks_ipp != 0) @@ -1222,7 +1315,7 @@ have_chap_secret(client, server, need_ip, lacks_ipp) else if (server != NULL && server[0] == 0) server = NULL; - ret = scan_authfile(f, client, server, NULL, &addrs, filename); + ret = scan_authfile(f, client, server, NULL, &addrs, NULL, filename); fclose(f); if (ret >= 0 && need_ip && !some_ip_ok(addrs)) { if (lacks_ipp != 0) @@ -1253,7 +1346,7 @@ get_secret(unit, client, server, secret, secret_len, am_server) FILE *f; int ret, len; char *filename; - struct wordlist *addrs; + struct wordlist *addrs, *opts; char secbuf[MAXWORDLEN]; if (!am_server && passwd[0] != 0) { @@ -1270,13 +1363,17 @@ get_secret(unit, client, server, secret, secret_len, am_server) } check_access(f, filename); - ret = scan_authfile(f, client, server, secbuf, &addrs, filename); + ret = scan_authfile(f, client, server, secbuf, &addrs, &opts, filename); fclose(f); if (ret < 0) return 0; if (am_server) - set_allowed_addrs(unit, addrs); + set_allowed_addrs(unit, addrs, opts); + else { + free_wordlist(addrs); + free_wordlist(opts); + } } len = strlen(secbuf); @@ -1297,9 +1394,10 @@ get_secret(unit, client, server, secret, secret_len, am_server) * and leaves the following words in extra_options. */ static void -set_allowed_addrs(unit, addrs) +set_allowed_addrs(unit, addrs, opts) int unit; struct wordlist *addrs; + struct wordlist *opts; { int n; struct wordlist *ap, **pap; @@ -1316,21 +1414,13 @@ set_allowed_addrs(unit, addrs) addresses[unit] = NULL; if (extra_options != NULL) free_wordlist(extra_options); - extra_options = NULL; + extra_options = opts; /* - * Count the number of IP addresses given, and chop off - * any extra options for this peer. + * Count the number of IP addresses given. */ - for (n = 0, pap = &addrs; (ap = *pap) != NULL; pap = &ap->next, ++n) { - if (strcmp(ap->word, "--") == 0) { - /* rest are options */ - *pap = 0; - extra_options = ap->next; - free(ap); - break; - } - } + for (n = 0, pap = &addrs; (ap = *pap) != NULL; pap = &ap->next) + ++n; if (n == 0) return; ip = (struct permitted_ip *) malloc((n + 1) * sizeof(struct permitted_ip)); @@ -1452,12 +1542,20 @@ auth_ip_addr(unit, addr) int unit; u_int32_t addr; { - if (addresses[unit] == NULL) { - if (auth_required) - return 0; /* no addresses authorized */ - return allow_any_ip || !have_route_to(addr); + int ok; + + /* don't allow loopback or multicast address */ + if (bad_ip_adrs(addr)) + return 0; + + if (addresses[unit] != NULL) { + ok = ip_addr_check(addr, addresses[unit]); + if (ok >= 0) + return ok; } - return ip_addr_check(addr, addresses[unit]); + if (auth_required) + return 0; /* no addresses authorized */ + return allow_any_ip || !have_route_to(addr); } static int @@ -1465,10 +1563,6 @@ ip_addr_check(addr, addrs) u_int32_t addr; struct permitted_ip *addrs; { - /* don't allow loopback or multicast address */ - if (bad_ip_adrs(addr)) - return 0; - for (; ; ++addrs) if ((addr & addrs->mask) == addrs->base) return addrs->permit; @@ -1497,7 +1591,7 @@ some_ip_ok(addrs) struct wordlist *addrs; { for (; addrs != 0; addrs = addrs->next) { - if (strcmp(addrs->word, "-") == 0) + if (addrs->word[0] == '-') break; if (addrs->word[0] != '!') return 1; /* some IP address is allowed */ @@ -1530,29 +1624,34 @@ check_access(f, filename) * if no secret is found, otherwise >= 0. The return value has * NONWILD_CLIENT set if the secret didn't have "*" for the client, and * NONWILD_SERVER set if the secret didn't have "*" for the server. - * Any following words on the line (i.e. address authorization - * info) are placed in a wordlist and returned in *addrs. + * Any following words on the line up to a "--" (i.e. address authorization + * info) are placed in a wordlist and returned in *addrs. Any + * following words (extra options) are placed in a wordlist and + * returned in *opts. * We assume secret is NULL or points to MAXWORDLEN bytes of space. */ static int -scan_authfile(f, client, server, secret, addrs, filename) +scan_authfile(f, client, server, secret, addrs, opts, filename) FILE *f; char *client; char *server; char *secret; struct wordlist **addrs; + struct wordlist **opts; char *filename; { int newline, xxx; int got_flag, best_flag; FILE *sf; - struct wordlist *ap, *addr_list, *alist, *alast; + struct wordlist *ap, *addr_list, *alist, **app; char word[MAXWORDLEN]; char atfile[MAXWORDLEN]; char lsecret[MAXWORDLEN]; if (addrs != NULL) *addrs = NULL; + if (opts != NULL) + *opts = NULL; addr_list = NULL; if (!getword(f, word, &newline, filename)) return -1; /* file is empty??? */ @@ -1629,23 +1728,20 @@ scan_authfile(f, client, server, secret, addrs, filename) /* * Now read address authorization info and make a wordlist. */ - alist = alast = NULL; + app = &alist; for (;;) { if (!getword(f, word, &newline, filename) || newline) break; ap = (struct wordlist *) malloc(sizeof(struct wordlist)); if (ap == NULL) novm("authorized addresses"); - ap->next = NULL; ap->word = strdup(word); if (ap->word == NULL) - novm("authorized address"); - if (alist == NULL) - alist = ap; - else - alast->next = ap; - alast = ap; + novm("authorized addresses"); + *app = ap; + app = &ap->next; } + *app = NULL; /* * This is the best so far; remember it. @@ -1661,6 +1757,20 @@ scan_authfile(f, client, server, secret, addrs, filename) break; } + /* scan for a -- word indicating the start of options */ + for (app = &addr_list; (ap = *app) != NULL; app = &ap->next) + if (strcmp(ap->word, "--") == 0) + break; + /* ap = start of options */ + if (ap != NULL) { + ap = ap->next; /* first option */ + free(*app); /* free the "--" word */ + *app = NULL; /* terminate addr list */ + } + if (opts != NULL) + *opts = ap; + else if (ap != NULL) + free_wordlist(ap); if (addrs != NULL) *addrs = addr_list; else if (addr_list != NULL) diff --git a/pppd/lcp.c b/pppd/lcp.c index 95b13b3..7f643b2 100644 --- a/pppd/lcp.c +++ b/pppd/lcp.c @@ -17,7 +17,7 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#define RCSID "$Id: lcp.c,v 1.44 1999/08/13 06:46:14 paulus Exp $"; +#define RCSID "$Id: lcp.c,v 1.45 1999/09/11 12:08:56 paulus Exp $"; /* * TODO: @@ -336,7 +336,7 @@ lcp_close(unit, reason) fsm *f = &lcp_fsm[unit]; if (phase != PHASE_DEAD) - phase = PHASE_TERMINATE; + new_phase(PHASE_TERMINATE); if (f->state == STOPPED && f->flags & (OPT_PASSIVE|OPT_SILENT)) { /* * This action is not strictly according to the FSM in RFC1548, diff --git a/pppd/main.c b/pppd/main.c index a84fd42..e5d2977 100644 --- a/pppd/main.c +++ b/pppd/main.c @@ -17,7 +17,7 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#define RCSID "$Id: main.c,v 1.85 1999/08/24 05:59:15 paulus Exp $" +#define RCSID "$Id: main.c,v 1.86 1999/09/11 12:08:57 paulus Exp $" #include #include @@ -92,6 +92,8 @@ int prepass = 0; /* doing prepass to find device name */ int devnam_fixed; /* set while in options.ttyxx file */ volatile int status; /* exit status for pppd */ int unsuccess; /* # unsuccessful connection attempts */ +int (*holdoff_hook) __P((void)) = NULL; +int (*new_phase_hook) __P((int)) = NULL; static int fd_ppp = -1; /* fd for talking PPP */ static int fd_loop; /* fd for getting demand-dial packets */ @@ -215,7 +217,7 @@ main(argc, argv) int argc; char *argv[]; { - int i, fdflags; + int i, fdflags, t; struct sigaction sa; char *p; struct passwd *pw; @@ -225,7 +227,7 @@ main(argc, argv) struct stat statbuf; char numbuf[16]; - phase = PHASE_INITIALIZE; + new_phase(PHASE_INITIALIZE); /* * Ensure that fds 0, 1, 2 are open, to /dev/null if nowhere else. @@ -340,6 +342,9 @@ main(argc, argv) option_error("connect script is required for demand-dialling\n"); exit(EXIT_OPTION_ERROR); } + /* default holdoff to 0 if no connect script has been given */ + if (connector == 0 && !holdoff_specified) + holdoff = 0; if (using_pty) { if (!default_device) { @@ -521,7 +526,7 @@ main(argc, argv) * Don't do anything until we see some activity. */ kill_link = 0; - phase = PHASE_DORMANT; + new_phase(PHASE_DORMANT); demand_unblock(); add_fd(fd_loop); for (;;) { @@ -558,7 +563,7 @@ main(argc, argv) info("Starting link"); } - phase = PHASE_SERIALCONN; + new_phase(PHASE_SERIALCONN); /* * Get a pty master/slave pair if the pty, notty, or record @@ -786,7 +791,8 @@ main(argc, argv) open_ccp_flag = 0; add_fd(fd_ppp); status = EXIT_NEGOTIATION_FAILED; - for (phase = PHASE_ESTABLISH; phase != PHASE_DEAD; ) { + new_phase(PHASE_ESTABLISH); + while (phase != PHASE_DEAD) { if (sigsetjmp(sigjmp, 1) == 0) { sigprocmask(SIG_BLOCK, &mask, NULL); if (kill_link || open_ccp_flag || got_sigchld) { @@ -805,7 +811,7 @@ main(argc, argv) kill_link = 0; } if (open_ccp_flag) { - if (phase == PHASE_NETWORK) { + if (phase == PHASE_NETWORK || phase == PHASE_RUNNING) { ccp_fsm[0].flags = OPT_RESTART; /* clears OPT_SILENT */ (*ccp_protent.open)(0); } @@ -857,6 +863,7 @@ main(argc, argv) */ disconnect: if (disconnector && !hungup) { + new_phase(PHASE_DISCONNECT); if (real_ttyfd >= 0) set_up_tty(real_ttyfd, 1); if (device_script(disconnector, ttyfd, ttyfd, 0) < 0) { @@ -891,9 +898,12 @@ main(argc, argv) kill_link = 0; if (demand) demand_discard(); - if (holdoff > 0 && need_holdoff) { - phase = PHASE_HOLDOFF; - TIMEOUT(holdoff_end, NULL, holdoff); + t = need_holdoff? holdoff: 0; + if (holdoff_hook) + t = (*holdoff_hook)(); + if (t > 0) { + new_phase(PHASE_HOLDOFF); + TIMEOUT(holdoff_end, NULL, t); do { if (sigsetjmp(sigjmp, 1) == 0) { sigprocmask(SIG_BLOCK, &mask, NULL); @@ -909,7 +919,7 @@ main(argc, argv) calltimeout(); if (kill_link) { kill_link = 0; - phase = PHASE_DORMANT; /* allow signal to end holdoff */ + new_phase(PHASE_DORMANT); /* allow signal to end holdoff */ } if (got_sigchld) reap_kids(0); @@ -1036,7 +1046,7 @@ static void holdoff_end(arg) void *arg; { - phase = PHASE_DORMANT; + new_phase(PHASE_DORMANT); } /* @@ -1117,6 +1127,17 @@ get_input() lcp_sprotrej(0, p - PPP_HDRLEN, len + PPP_HDRLEN); } +/* + * new_phase - signal the start of a new phase of pppd's operation. + */ +void +new_phase(p) + int p; +{ + phase = p; + if (new_phase_hook) + (*new_phase_hook)(p); +} /* * die - clean up state and exit with the specified status. @@ -1277,7 +1298,7 @@ untimeout(func, arg) for (copp = &callout; (freep = *copp); copp = &freep->c_next) if (freep->c_func == func && freep->c_arg == arg) { *copp = freep->c_next; - (void) free((char *) freep); + free((char *) freep); break; } } @@ -1766,6 +1787,7 @@ script_setenv(var, value) } } } else { + /* no space allocated for script env. ptrs. yet */ i = 0; script_env = (char **) malloc(16 * sizeof(char *)); if (script_env == 0) diff --git a/pppd/options.c b/pppd/options.c index 630285f..edee078 100644 --- a/pppd/options.c +++ b/pppd/options.c @@ -17,7 +17,7 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#define RCSID "$Id: options.c,v 1.65 1999/09/08 01:13:45 masputra Exp $" +#define RCSID "$Id: options.c,v 1.66 1999/09/11 12:08:58 paulus Exp $" #include #include @@ -34,6 +34,9 @@ #include #include #include +#ifdef PLUGIN +#include +#endif #ifdef PPP_FILTER #include #include /* XXX: To get struct pcap */ @@ -88,6 +91,7 @@ bool demand = 0; /* do dial-on-demand */ char *ipparam = NULL; /* Extra parameter for ip up/down scripts */ int idle_time_limit = 0; /* Disconnect if idle for this many seconds */ int holdoff = 30; /* # seconds to pause before reconnecting */ +bool holdoff_specified; /* true if a holdoff value has been given */ bool notty = 0; /* Stdin/out is not a tty */ char *record_file = NULL; /* File to record chars sent/received */ int using_pty = 0; @@ -95,6 +99,7 @@ bool sync_serial = 0; /* Device is synchronous serial device */ int log_to_fd = 1; /* send log messages to this fd too */ int maxfail = 10; /* max # of unsuccessful connection attempts */ char linkname[MAXPATHLEN]; /* logical name for link */ +bool tune_kernel; /* may alter kernel settings */ extern option_t auth_options[]; extern struct stat devstat; @@ -134,18 +139,30 @@ static int showversion __P((char **)); static int showhelp __P((char **)); static void usage __P((void)); static int setlogfile __P((char **)); +#ifdef PLUGIN +static int loadplugin __P((char **)); +#endif #ifdef PPP_FILTER static int setpassfilter __P((char **)); static int setactivefilter __P((char **)); #endif - static option_t *find_option __P((char *name)); static int process_option __P((option_t *, char **)); static int n_arguments __P((option_t *)); static int number_option __P((char *, u_int32_t *, int)); +/* + * Structure to store extra lists of options. + */ +struct option_list { + option_t *options; + struct option_list *next; +}; + +static struct option_list *extra_options = NULL; + /* * Valid arguments. */ @@ -246,6 +263,14 @@ option_t general_options[] = { OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN }, { "maxfail", o_int, &maxfail, "Maximum number of unsuccessful connection attempts to allow" }, + { "ktune", o_bool, &tune_kernel, + "Alter kernel settings as necessary", 1 }, + { "noktune", o_bool, &tune_kernel, + "Don't alter kernel settings", 0 }, +#ifdef PLUGIN + { "plugin", o_special, loadplugin, + "Load a plug-in module into pppd", OPT_PRIV }, +#endif #ifdef PPP_FILTER { "pdebug", o_int, &dflag, @@ -324,7 +349,8 @@ parse_args(argc, argv) */ if ((ret = setdevname(arg)) == 0 && (ret = setspeed(arg)) == 0 - && (ret = setipaddr(arg)) == 0) { + && (ret = setipaddr(arg)) == 0 + && !prepass) { option_error("unrecognized option '%s'", arg); usage(); return 0; @@ -585,8 +611,13 @@ find_option(name) char *name; { option_t *opt; + struct option_list *list; int i; + for (list = extra_options; list != NULL; list = list->next) + for (opt = list->options; opt->name != NULL; ++opt) + if (strcmp(name, opt->name) == 0) + return opt; for (opt = general_options; opt->name != NULL; ++opt) if (strcmp(name, opt->name) == 0) return opt; @@ -743,6 +774,23 @@ n_arguments(opt) || (opt->flags & OPT_NOARG))? 0: 1; } +/* + * add_options - add a list of options to the set we grok. + */ +void +add_options(opt) + option_t *opt; +{ + struct option_list *list; + + list = malloc(sizeof(*list)); + if (list == 0) + novm("option list entry"); + list->options = opt; + list->next = extra_options; + extra_options = list; +} + /* * usage - print out a message telling how to use the program. */ @@ -1274,6 +1322,8 @@ setspeed(arg) char *ptr; int spd; + if (prepass) + return 1; spd = strtol(arg, &ptr, 0); if (ptr == arg || *ptr != 0 || spd == 0) return 0; @@ -1488,3 +1538,33 @@ setlogfile(argv) log_to_file = 1; return 1; } + +#ifdef PLUGIN +static int +loadplugin(argv) + char **argv; +{ + char *arg = *argv; + void *handle; + const char *err; + void (*init) __P((void)); + + handle = dlopen(arg, RTLD_GLOBAL | RTLD_NOW); + if (handle == 0) { + err = dlerror(); + if (err != 0) + option_error("%s", err); + option_error("Couldn't load plugin %s", arg); + return 0; + } + init = dlsym(handle, "plugin_init"); + if (init == 0) { + option_error("%s has no initialization entry point", arg); + dlclose(handle); + return 0; + } + info("Plugin %s loaded.", arg); + (*init)(); + return 1; +} +#endif /* PLUGIN */ diff --git a/pppd/pppd.h b/pppd/pppd.h index 15a503c..f084877 100644 --- a/pppd/pppd.h +++ b/pppd/pppd.h @@ -16,7 +16,7 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: pppd.h,v 1.47 1999/09/08 01:13:45 masputra Exp $ + * $Id: pppd.h,v 1.48 1999/09/11 12:08:59 paulus Exp $ */ /* @@ -159,6 +159,7 @@ extern GIDSET_TYPE groups[NGROUPS_MAX]; /* groups the user is in */ extern int ngroups; /* How many groups valid in groups */ extern struct pppd_stats link_stats; /* byte/packet counts etc. for link */ extern int link_stats_valid; /* set if link_stats is valid */ +extern int link_connect_time; /* time the link was up for */ extern int using_pty; /* using pty as device (notty or pty opt.) */ extern int log_to_fd; /* logging to this fd as well as syslog */ extern char *no_ppp_msg; /* message to print if ppp not in kernel */ @@ -200,11 +201,13 @@ extern char *ipparam; /* Extra parameter for ip up/down scripts */ extern bool cryptpap; /* Others' PAP passwords are encrypted */ extern int idle_time_limit;/* Shut down link if idle for this long */ extern int holdoff; /* Dead time before restarting */ +extern bool holdoff_specified; /* true if user gave a holdoff value */ extern bool notty; /* Stdin/out is not a tty */ extern char *record_file; /* File to record chars sent/received */ extern bool sync_serial; /* Device is synchronous serial device */ extern int maxfail; /* Max # of unsuccessful connection attempts */ extern char linkname[MAXPATHLEN]; /* logical name for link */ +extern bool tune_kernel; /* May alter kernel settings as necessary */ #ifdef PPP_FILTER extern struct bpf_program pass_filter; /* Filter for pkts to pass */ @@ -231,8 +234,10 @@ extern char *option_source; /* string saying where the option came from */ #define PHASE_AUTHENTICATE 5 #define PHASE_CALLBACK 6 #define PHASE_NETWORK 7 -#define PHASE_TERMINATE 8 -#define PHASE_HOLDOFF 9 +#define PHASE_RUNNING 8 +#define PHASE_TERMINATE 9 +#define PHASE_DISCONNECT 10 +#define PHASE_HOLDOFF 11 /* * The following struct gives the addresses of procedures to call @@ -295,6 +300,7 @@ void reopen_log __P((void)); /* (re)open the connection to syslog */ void update_link_stats __P((int)); /* Get stats at link termination */ void script_setenv __P((char *, char *)); /* set script env var */ void script_unsetenv __P((char *)); /* unset script env var */ +void new_phase __P((int)); /* signal start of new phase */ /* Procedures exported from utils.c. */ void log_packet __P((u_char *, int, char *, int)); @@ -332,7 +338,7 @@ void auth_withpeer_success __P((int, int)); void auth_check_options __P((void)); /* check authentication options supplied */ void auth_reset __P((int)); /* check what secrets we have */ -int check_passwd __P((int, char *, int, char *, int, char **, int *)); +int check_passwd __P((int, char *, int, char *, int, char **)); /* Check peer-supplied username/password */ int get_secret __P((int, char *, char *, char *, int *, int)); /* get "secret" for chap */ @@ -444,6 +450,7 @@ void option_error __P((char *fmt, ...)); /* Print an error message about an option */ int int_option __P((char *, int *)); /* Simplified number_option for decimal ints */ +void add_options __P((option_t *)); /* Add extra options */ /* * This structure is used to store information about certain @@ -463,6 +470,18 @@ extern struct option_info disconnector_info; extern struct option_info welcomer_info; extern struct option_info ptycommand_info; +/* + * Hooks to enable plugins to change various things. + */ +extern int (*new_phase_hook) __P((int)); +extern int (*idle_time_hook) __P((struct ppp_idle *)); +extern int (*holdoff_hook) __P((void)); +extern int (*pap_check_hook) __P((void)); +extern int (*pap_auth_hook) __P((char *user, char *passwd, char **msgp, + struct wordlist **paddrs, + struct wordlist **popts)); +extern int (*pap_passwd_hook) __P((char *user, char *passwd)); + /* * Inline versions of get/put char/short/long. * Pointer is advanced; we assume that both arguments diff --git a/pppd/sys-linux.c b/pppd/sys-linux.c index 4c40b36..06c5f7f 100644 --- a/pppd/sys-linux.c +++ b/pppd/sys-linux.c @@ -145,6 +145,9 @@ static int if_is_up; /* Interface has been marked up */ static u_int32_t default_route_gateway; /* Gateway for default route added */ static u_int32_t proxy_arp_addr; /* Addr for proxy arp entry added */ static char proxy_arp_dev[16]; /* Device for proxy arp entry */ +static u_int32_t our_old_addr; /* for detecting address changes */ +static int dynaddr_set; /* 1 if ip_dynaddr set */ +static int looped; /* 1 if using loop */ static struct utsname utsname; /* for the kernel version */ static int kernel_version; @@ -156,6 +159,8 @@ static int kernel_version; #define FLAGS_MASK (IFF_UP | IFF_BROADCAST | \ IFF_POINTOPOINT | IFF_LOOPBACK | IFF_NOARP) +#define SIN_ADDR(x) (((struct sockaddr_in *) (&(x)))->sin_addr.s_addr) + /* Prototypes for procedures local to this file. */ static int get_flags (int fd); static void set_flags (int fd, int flags); @@ -372,7 +377,7 @@ int establish_ppp (int tty_fd) /* * Demand mode - prime the old ppp device to relinquish the unit. */ - if (!new_style_driver && demand + if (!new_style_driver && looped && ioctl(slave_fd, PPPIOCXFERUNIT, 0) < 0) fatal("ioctl(transfer ppp unit): %m(%d)", errno); /* @@ -386,7 +391,7 @@ int establish_ppp (int tty_fd) * Find out which interface we were given. */ if (new_style_driver) { - if (!demand) { + if (!looped) { /* allocate ourselves a ppp unit */ ifunit = -1; if (ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &ifunit) < 0) @@ -406,7 +411,7 @@ int establish_ppp (int tty_fd) fatal("ioctl(PPPIOCGUNIT): %m(%d)", errno); } /* Check that we got the same unit again. */ - if (demand && x != ifunit) + if (looped && x != ifunit) fatal("transfer_ppp failed: wanted unit %d, got %d", ifunit, x); ifunit = x; } @@ -414,8 +419,9 @@ int establish_ppp (int tty_fd) /* * Enable debug in the driver if requested. */ - if (!demand) + if (!looped) set_kdebugflag (kdebugflag); + looped = 0; set_flags(tty_fd, get_flags(tty_fd) & ~(SC_RCV_B7_0 | SC_RCV_B7_1 | SC_RCV_EVNP | SC_RCV_ODDP)); @@ -470,8 +476,25 @@ void disestablish_ppp(int tty_fd) } } initfdflags = -1; - if (new_style_driver) + if (new_style_driver && !looped) { + if (ioctl(ppp_dev_fd, PPPIOCDETACH) < 0) { + if (errno == ENOTTY) { + /* first version of new driver didn't have PPPIOCDETACH */ + int flags; + + close(ppp_dev_fd); + ppp_dev_fd = open("/dev/ppp", O_RDWR); + if (ppp_dev_fd < 0) + fatal("Couldn't reopen /dev/ppp: %m"); + flags = fcntl(ppp_dev_fd, F_GETFL); + if (flags == -1 + || fcntl(ppp_dev_fd, F_SETFL, flags | O_NONBLOCK) == -1) + warn("Couldn't set /dev/ppp to nonblock: %m"); + } else + error("Couldn't release PPP unit: %m"); + } set_ppp_fd(-1); + } } /******************************************************************** @@ -1207,14 +1230,9 @@ static int read_route_table(struct rtentry *rt) p = NULL; } - ((struct sockaddr_in *) &rt->rt_dst)->sin_addr.s_addr = - strtoul(cols[route_dest_col], NULL, 16); - - ((struct sockaddr_in *) &rt->rt_gateway)->sin_addr.s_addr = - strtoul(cols[route_gw_col], NULL, 16); - - ((struct sockaddr_in *) &rt->rt_genmask)->sin_addr.s_addr = - strtoul(cols[route_mask_col], NULL, 16); + SIN_ADDR(rt->rt_dst) = strtoul(cols[route_dest_col], NULL, 16); + SIN_ADDR(rt->rt_gateway) = strtoul(cols[route_gw_col], NULL, 16); + SIN_ADDR(rt->rt_genmask) = strtoul(cols[route_mask_col], NULL, 16); rt->rt_flags = (short) strtoul(cols[route_flags_col], NULL, 16); rt->rt_dev = cols[route_dev_col]; @@ -1238,7 +1256,9 @@ static int defaultroute_exists (struct rtentry *rt) if ((rt->rt_flags & RTF_UP) == 0) continue; - if (((struct sockaddr_in *) (&rt->rt_dst))->sin_addr.s_addr == 0L) { + if (kernel_version > KVERSION(2,1,0) && SIN_ADDR(rt->rt_genmask) != 0) + continue; + if (SIN_ADDR(rt->rt_dst) == 0L) { result = 1; break; } @@ -1266,8 +1286,7 @@ int have_route_to(u_int32_t addr) while (read_route_table(&rt)) { if ((rt.rt_flags & RTF_UP) == 0 || strcmp(rt.rt_dev, ifname) == 0) continue; - if ((addr & ((struct sockaddr_in *)&rt.rt_genmask)->sin_addr.s_addr) - == ((struct sockaddr_in *)&rt.rt_dst)->sin_addr.s_addr) { + if ((addr & SIN_ADDR(rt.rt_genmask)) == SIN_ADDR(rt.rt_dst)) { result = 1; break; } @@ -1287,10 +1306,9 @@ int sifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway) struct rtentry rt; if (defaultroute_exists(&rt) && strcmp(rt.rt_dev, ifname) != 0) { - struct in_addr old_gateway = - ((struct sockaddr_in *) (&rt.rt_gateway))-> sin_addr; + u_int32_t old_gateway = SIN_ADDR(rt.rt_gateway); - if (old_gateway.s_addr != gateway) + if (old_gateway != gateway) error("not replacing existing default route to %s [%I]", rt.rt_dev, old_gateway); return 0; @@ -1302,10 +1320,10 @@ int sifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway) if (kernel_version > KVERSION(2,1,0)) { SET_SA_FAMILY (rt.rt_genmask, AF_INET); - ((struct sockaddr_in *) &rt.rt_genmask)->sin_addr.s_addr = 0L; + SIN_ADDR(rt.rt_genmask) = 0L; } - ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = gateway; + SIN_ADDR(rt.rt_gateway) = gateway; rt.rt_flags = RTF_UP | RTF_GATEWAY; if (ioctl(sock_fd, SIOCADDRT, &rt) < 0) { @@ -1335,10 +1353,10 @@ int cifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway) if (kernel_version > KVERSION(2,1,0)) { SET_SA_FAMILY (rt.rt_genmask, AF_INET); - ((struct sockaddr_in *) &rt.rt_genmask)->sin_addr.s_addr = 0L; + SIN_ADDR(rt.rt_genmask) = 0L; } - ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = gateway; + SIN_ADDR(rt.rt_gateway) = gateway; rt.rt_flags = RTF_UP | RTF_GATEWAY; if (ioctl(sock_fd, SIOCDELRT, &rt) < 0 && errno != ESRCH) { @@ -1366,7 +1384,7 @@ int sifproxyarp (int unit, u_int32_t his_adr) memset (&arpreq, '\0', sizeof(arpreq)); SET_SA_FAMILY(arpreq.arp_pa, AF_INET); - ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = his_adr; + SIN_ADDR(arpreq.arp_pa) = his_adr; arpreq.arp_flags = ATF_PERM | ATF_PUBL; /* * Get the hardware address of an interface on the same subnet @@ -1387,12 +1405,15 @@ int sifproxyarp (int unit, u_int32_t his_adr) proxy_arp_addr = his_adr; has_proxy_arp = 1; - forw_path = path_to_procfs("/sys/net/ipv4/ip_forward"); - if (forw_path != 0) { - int fd = open(forw_path, O_WRONLY); - if (fd >= 0) { - write(fd, "1", 1); - close(fd); + if (tune_kernel) { + forw_path = path_to_procfs("/sys/net/ipv4/ip_forward"); + if (forw_path != 0) { + int fd = open(forw_path, O_WRONLY); + if (fd >= 0) { + if (write(fd, "1", 1) != 1) + error("Couldn't enable IP forwarding: %m"); + close(fd); + } } } } @@ -1413,7 +1434,7 @@ int cifproxyarp (int unit, u_int32_t his_adr) has_proxy_arp = 0; memset (&arpreq, '\0', sizeof(arpreq)); SET_SA_FAMILY(arpreq.arp_pa, AF_INET); - ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = his_adr; + SIN_ADDR(arpreq.arp_pa) = his_adr; arpreq.arp_flags = ATF_PERM | ATF_PUBL; strlcpy(arpreq.arp_dev, proxy_arp_dev, sizeof(arpreq.arp_dev)); @@ -1460,7 +1481,7 @@ static int get_ether_addr (u_int32_t ipaddr, ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq)); for (ifr = ifc.ifc_req; ifr < ifend; ifr++) { if (ifr->ifr_addr.sa_family == AF_INET) { - ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr; + ina = SIN_ADDR(ifr->ifr_addr); strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); SYSDEBUG ((LOG_DEBUG, "proxy arp: examining interface %s", ifreq.ifr_name)); @@ -1479,7 +1500,7 @@ static int get_ether_addr (u_int32_t ipaddr, if (ioctl(sock_fd, SIOCGIFNETMASK, &ifreq) < 0) continue; - mask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr; + mask = SIN_ADDR(ifreq.ifr_addr); SYSDEBUG ((LOG_DEBUG, "proxy arp: interface addr %s mask %lx", ip_ntoa(ina), ntohl(mask))); @@ -1572,7 +1593,7 @@ u_int32_t GetMask (u_int32_t addr) */ if (ifr->ifr_addr.sa_family != AF_INET) continue; - ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr; + ina = SIN_ADDR(ifr->ifr_addr); if (((ntohl(ina) ^ addr) & nmask) != 0) continue; /* @@ -1589,7 +1610,7 @@ u_int32_t GetMask (u_int32_t addr) */ if (ioctl(sock_fd, SIOCGIFNETMASK, &ifreq) < 0) continue; - mask |= ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr; + mask |= SIN_ADDR(ifreq.ifr_addr); break; } return mask; @@ -1973,7 +1994,7 @@ int sifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr, /* * Set our IP address */ - ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = our_adr; + SIN_ADDR(ifr.ifr_addr) = our_adr; if (ioctl(sock_fd, SIOCSIFADDR, (caddr_t) &ifr) < 0) { if (errno != EEXIST) { if (! ok_error (errno)) @@ -1987,7 +2008,7 @@ int sifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr, /* * Set the gateway address */ - ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = his_adr; + SIN_ADDR(ifr.ifr_dstaddr) = his_adr; if (ioctl(sock_fd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) { if (! ok_error (errno)) error("ioctl(SIOCSIFDSTADDR): %m(%d)", errno); @@ -2000,7 +2021,7 @@ int sifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr, if (kernel_version >= KVERSION(2,1,16)) net_mask = ~0L; if (net_mask != 0) { - ((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr.s_addr = net_mask; + SIN_ADDR(ifr.ifr_netmask) = net_mask; if (ioctl(sock_fd, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) { if (! ok_error (errno)) error("ioctl(SIOCSIFNETMASK): %m(%d)", errno); @@ -2015,13 +2036,13 @@ int sifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr, SET_SA_FAMILY (rt.rt_gateway, AF_INET); rt.rt_dev = ifname; - ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = 0L; - ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = his_adr; + SIN_ADDR(rt.rt_gateway) = 0L; + SIN_ADDR(rt.rt_dst) = his_adr; rt.rt_flags = RTF_UP | RTF_HOST; if (kernel_version > KVERSION(2,1,0)) { SET_SA_FAMILY (rt.rt_genmask, AF_INET); - ((struct sockaddr_in *) &rt.rt_genmask)->sin_addr.s_addr = -1L; + SIN_ADDR(rt.rt_genmask) = -1L; } if (ioctl(sock_fd, SIOCADDRT, &rt) < 0) { @@ -2030,6 +2051,24 @@ int sifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr, return (0); } } + + /* set ip_dynaddr in demand mode if address changes */ + if (demand && tune_kernel && !dynaddr_set + && our_old_addr && our_old_addr != our_adr) { + /* set ip_dynaddr if possible */ + char *path; + int fd; + + path = path_to_procfs("/sys/net/ipv4/ip_dynaddr"); + if (path != 0 && (fd = open(path, O_WRONLY)) >= 0) { + if (write(fd, "1", 1) != 1) + error("Couldn't enable dynamic IP addressing: %m"); + close(fd); + } + dynaddr_set = 1; /* only 1 attempt */ + } + our_old_addr = 0; + return 1; } @@ -2054,13 +2093,13 @@ int cifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr) SET_SA_FAMILY (rt.rt_gateway, AF_INET); rt.rt_dev = ifname; - ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = 0; - ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = his_adr; + SIN_ADDR(rt.rt_gateway) = 0; + SIN_ADDR(rt.rt_dst) = his_adr; rt.rt_flags = RTF_UP | RTF_HOST; if (kernel_version > KVERSION(2,1,0)) { SET_SA_FAMILY (rt.rt_genmask, AF_INET); - ((struct sockaddr_in *) &rt.rt_genmask)->sin_addr.s_addr = -1L; + SIN_ADDR(rt.rt_genmask) = -1L; } if (ioctl(sock_fd, SIOCDELRT, &rt) < 0 && errno != ESRCH) { @@ -2082,6 +2121,8 @@ int cifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr) } } + our_old_addr = our_adr; + return 1; } @@ -2251,6 +2292,7 @@ open_ppp_loopback(void) { int flags; + looped = 1; if (new_style_driver) { /* allocate ourselves a ppp unit */ ifunit = -1; @@ -2309,6 +2351,7 @@ open_ppp_loopback(void) void restore_loop(void) { + looped = 1; if (new_style_driver) { set_flags(ppp_dev_fd, get_flags(ppp_dev_fd) | SC_LOOP_TRAFFIC); return; @@ -2335,11 +2378,9 @@ sifnpmode(u, proto, mode) npi.protocol = proto; npi.mode = mode; if (ioctl(ppp_dev_fd, PPPIOCSNPMODE, (caddr_t) &npi) < 0) { - if (! ok_error (errno)) { + if (! ok_error (errno)) error("ioctl(PPPIOCSNPMODE, %d, %d): %m (%d)", proto, mode, errno); - error("ppp_dev_fd=%d slave_fd=%d\n", ppp_dev_fd, slave_fd); - } return 0; } return 1; @@ -2466,7 +2507,6 @@ sys_check_options(void) * Disable the IPX protocol if the support is not present in the kernel. */ char *path; - int fd; if (ipxcp_protent.enabled_flag) { struct stat stat_buf; @@ -2483,13 +2523,5 @@ sys_check_options(void) driver_patch); return 0; } - if (demand) { - /* set ip_dynaddr if possible */ - path = path_to_procfs("/sys/net/ipv4/ip_dynaddr"); - if (path != 0 && (fd = open(path, O_WRONLY)) >= 0) { - write(fd, "1", 1); - close(fd); - } - } return 1; } diff --git a/pppd/upap.c b/pppd/upap.c index 6bf8dec..5cf9c68 100644 --- a/pppd/upap.c +++ b/pppd/upap.c @@ -17,7 +17,7 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#define RCSID "$Id: upap.c,v 1.20 1999/08/24 05:29:26 paulus Exp $" +#define RCSID "$Id: upap.c,v 1.21 1999/09/11 12:09:00 paulus Exp $" /* * TODO: @@ -395,8 +395,11 @@ upap_rauthreq(u, inp, id, len) * Check the username and password given. */ retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd, - rpasswdlen, &msg, &msglen); + rpasswdlen, &msg); BZERO(rpasswd, rpasswdlen); + msglen = strlen(msg); + if (msglen > 255) + msglen = 255; upap_sresp(u, retcode, id, msg, msglen); -- 2.39.2