Add plugin support plus an initial selection of hooks.
authorPaul Mackerras <paulus@samba.org>
Sat, 11 Sep 1999 12:09:00 +0000 (12:09 +0000)
committerPaul Mackerras <paulus@samba.org>
Sat, 11 Sep 1999 12:09:00 +0000 (12:09 +0000)
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
pppd/auth.c
pppd/lcp.c
pppd/main.c
pppd/options.c
pppd/pppd.h
pppd/sys-linux.c
pppd/upap.c

index bf2bcc55cd774542bb3641a466f60d98e438e82b..705f549fabfdf34a644571a19444c228d17180b2 100644 (file)
@@ -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
index 716d849ae8546a51a0cefc12e5bac2fb44873d78..ac2eee93a654066c15a2c3553d102081fc79b426 100644 (file)
@@ -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 <stdio.h>
 #include <stddef.h>
@@ -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)
index 95b13b33572f2cd5120dc1c927e8670bae77137c..7f643b2ca7d21230b51437f7eda08cead334f43b 100644 (file)
@@ -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,
index a84fd4251f90ed71f231e58a697cbc334be3fd35..e5d2977fc2363d99bccf9b98d5cf01dc804d2d15 100644 (file)
@@ -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 <stdio.h>
 #include <ctype.h>
@@ -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)
index 630285f0d213508be3cd6c948856dca4e0c54a8b..edee078245a2d43b1699befbb2b25468c698bf4a 100644 (file)
@@ -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 <ctype.h>
 #include <stdio.h>
@@ -34,6 +34,9 @@
 #include <sys/stat.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+#ifdef PLUGIN
+#include <dlfcn.h>
+#endif
 #ifdef PPP_FILTER
 #include <pcap.h>
 #include <pcap-int.h>  /* 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 */
index 15a503cbd5b341791169d94f6606c57ffa4a23d8..f08487730676dac9eaa38a71f051b11662ef5bd2 100644 (file)
@@ -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
index 4c40b3655321b2c6a00e7bcd9b974d8a8bd87f44..06c5f7fdc457d48402912669f1b8732523675df4 100644 (file)
@@ -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;
 }
index 6bf8dece21411fc3cc94c89a99683485b9499f45..5cf9c683098894f2acca9567472835bfa5986b83 100644 (file)
@@ -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);