+/* 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;
+
+/* Remote telephone number, if available */
+char remote_number[MAXNAMELEN];
+
+/* Wordlist giving remote telephone numbers which may connect. */
+static struct wordlist *permitted_numbers;
+
+/* Extra options to apply, from the secrets file entry for the peer. */
+static struct wordlist *extra_options;
+
+/* Number of network protocols which we have opened. */
+static int num_np_open;
+
+/* Number of network protocols which have come up. */
+static int num_np_up;
+
+/* Set if we got the contents of passwd[] from the pap-secrets file. */
+static int passwd_from_file;
+
+/* Set if we require authentication only because we have a default route. */
+static bool default_auth;
+
+/* 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 know about the PAP user logout */
+void (*pap_logout_hook) __P((void)) = NULL;
+
+/* Hook for a plugin to get the PAP password for authenticating us */
+int (*pap_passwd_hook) __P((char *user, char *passwd)) = NULL;
+
+/* Hook for a plugin to say if we can possibly authenticate a peer using CHAP */
+int (*chap_check_hook) __P((void)) = NULL;
+
+/* Hook for a plugin to get the CHAP password for authenticating us */
+int (*chap_passwd_hook) __P((char *user, char *passwd)) = NULL;
+
+/* Hook for a plugin to say whether it is OK if the peer
+ refuses to authenticate. */
+int (*null_auth_hook) __P((struct wordlist **paddrs,
+ struct wordlist **popts)) = NULL;
+
+int (*allowed_address_hook) __P((u_int32_t addr)) = NULL;
+
+/* A notifier for when the peer has authenticated itself,
+ and we are proceeding to the network phase. */
+struct notifier *auth_up_notifier = NULL;
+
+/* A notifier for when the link goes down. */
+struct notifier *link_down_notifier = NULL;
+
+/*
+ * This is used to ensure that we don't start an auth-up/down
+ * script while one is already running.
+ */
+enum script_state {
+ s_down,
+ s_up
+};
+
+static enum script_state auth_state = s_down;
+static enum script_state auth_script_state = s_down;
+static pid_t auth_script_pid = 0;
+
+static int used_login; /* peer authenticated against login database */
+
+/*
+ * Option variables.
+ */
+bool uselogin = 0; /* Use /etc/passwd for checking PAP */
+bool cryptpap = 0; /* Passwords in pap-secrets are encrypted */
+bool refuse_pap = 0; /* Don't wanna auth. ourselves with PAP */
+bool refuse_chap = 0; /* Don't wanna auth. ourselves with CHAP */
+bool refuse_eap = 0; /* Don't wanna auth. ourselves with EAP */
+#ifdef CHAPMS
+bool refuse_mschap = 0; /* Don't wanna auth. ourselves with MS-CHAP */
+bool refuse_mschap_v2 = 0; /* Don't wanna auth. ourselves with MS-CHAPv2 */
+#else
+bool refuse_mschap = 1; /* Don't wanna auth. ourselves with MS-CHAP */
+bool refuse_mschap_v2 = 1; /* Don't wanna auth. ourselves with MS-CHAPv2 */
+#endif
+bool usehostname = 0; /* Use hostname for our_name */
+bool auth_required = 0; /* Always require authentication from peer */
+bool allow_any_ip = 0; /* Allow peer to use any IP address */
+bool explicit_remote = 0; /* User specified explicit remote name */
+char remote_name[MAXNAMELEN]; /* Peer's name for authentication */
+
+static char *uafname; /* name of most recent +ua file */
+
+extern char *crypt __P((const char *, const char *));
+
+/* Prototypes for procedures local to this file. */
+
+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 **));
+static void plogout __P((void));
+static int null_login __P((int));
+static int get_pap_passwd __P((char *));
+static int have_pap_secret __P((int *));
+static int have_chap_secret __P((char *, char *, int, int *));
+static int have_srp_secret __P((char *client, char *server, int need_ip,
+ int *lacks_ipp));
+static int ip_addr_check __P((u_int32_t, struct permitted_ip *));
+static int scan_authfile __P((FILE *, char *, char *, char *,
+ struct wordlist **, struct wordlist **,
+ char *, int));
+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 *, 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 int set_permitted_number __P((char **));
+static void check_access __P((FILE *, char *));
+static int wordlist_count __P((struct wordlist *));
+
+#ifdef MAXOCTETS
+static void check_maxoctets __P((void *));
+#endif
+
+/*
+ * Authentication-related options.
+ */
+option_t auth_options[] = {
+ { "auth", o_bool, &auth_required,
+ "Require authentication from peer", OPT_PRIO | 1 },
+ { "noauth", o_bool, &auth_required,
+ "Don't require peer to authenticate", OPT_PRIOSUB | OPT_PRIV,
+ &allow_any_ip },
+ { "require-pap", o_bool, &lcp_wantoptions[0].neg_upap,
+ "Require PAP authentication from peer",
+ OPT_PRIOSUB | 1, &auth_required },
+ { "+pap", o_bool, &lcp_wantoptions[0].neg_upap,
+ "Require PAP authentication from peer",
+ OPT_ALIAS | OPT_PRIOSUB | 1, &auth_required },
+ { "require-chap", o_bool, &auth_required,
+ "Require CHAP authentication from peer",
+ OPT_PRIOSUB | OPT_A2OR | MDTYPE_MD5,
+ &lcp_wantoptions[0].chap_mdtype },
+ { "+chap", o_bool, &auth_required,
+ "Require CHAP authentication from peer",
+ OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MD5,
+ &lcp_wantoptions[0].chap_mdtype },
+#ifdef CHAPMS
+ { "require-mschap", o_bool, &auth_required,
+ "Require MS-CHAP authentication from peer",
+ OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT,
+ &lcp_wantoptions[0].chap_mdtype },
+ { "+mschap", o_bool, &auth_required,
+ "Require MS-CHAP authentication from peer",
+ OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT,
+ &lcp_wantoptions[0].chap_mdtype },
+ { "require-mschap-v2", o_bool, &auth_required,
+ "Require MS-CHAPv2 authentication from peer",
+ OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT_V2,
+ &lcp_wantoptions[0].chap_mdtype },
+ { "+mschap-v2", o_bool, &auth_required,
+ "Require MS-CHAPv2 authentication from peer",
+ OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT_V2,
+ &lcp_wantoptions[0].chap_mdtype },
+#endif
+
+ { "refuse-pap", o_bool, &refuse_pap,
+ "Don't agree to auth to peer with PAP", 1 },
+ { "-pap", o_bool, &refuse_pap,
+ "Don't allow PAP authentication with peer", OPT_ALIAS | 1 },
+ { "refuse-chap", o_bool, &refuse_chap,
+ "Don't agree to auth to peer with CHAP",
+ OPT_A2CLRB | MDTYPE_MD5,
+ &lcp_allowoptions[0].chap_mdtype },
+ { "-chap", o_bool, &refuse_chap,
+ "Don't allow CHAP authentication with peer",
+ OPT_ALIAS | OPT_A2CLRB | MDTYPE_MD5,
+ &lcp_allowoptions[0].chap_mdtype },
+#ifdef CHAPMS
+ { "refuse-mschap", o_bool, &refuse_mschap,
+ "Don't agree to auth to peer with MS-CHAP",
+ OPT_A2CLRB | MDTYPE_MICROSOFT,
+ &lcp_allowoptions[0].chap_mdtype },
+ { "-mschap", o_bool, &refuse_mschap,
+ "Don't allow MS-CHAP authentication with peer",
+ OPT_ALIAS | OPT_A2CLRB | MDTYPE_MICROSOFT,
+ &lcp_allowoptions[0].chap_mdtype },
+ { "refuse-mschap-v2", o_bool, &refuse_mschap_v2,
+ "Don't agree to auth to peer with MS-CHAPv2",
+ OPT_A2CLRB | MDTYPE_MICROSOFT_V2,
+ &lcp_allowoptions[0].chap_mdtype },
+ { "-mschap-v2", o_bool, &refuse_mschap_v2,
+ "Don't allow MS-CHAPv2 authentication with peer",
+ OPT_ALIAS | OPT_A2CLRB | MDTYPE_MICROSOFT_V2,
+ &lcp_allowoptions[0].chap_mdtype },
+#endif
+
+ { "require-eap", o_bool, &lcp_wantoptions[0].neg_eap,
+ "Require EAP authentication from peer", OPT_PRIOSUB | 1,
+ &auth_required },
+ { "refuse-eap", o_bool, &refuse_eap,
+ "Don't agree to authenticate to peer with EAP", 1 },
+
+ { "name", o_string, our_name,
+ "Set local name for authentication",
+ OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, MAXNAMELEN },
+
+ { "+ua", o_special, (void *)setupapfile,
+ "Get PAP user and password from file",
+ OPT_PRIO | OPT_A2STRVAL, &uafname },
+
+ { "user", o_string, user,
+ "Set name for auth with peer", OPT_PRIO | OPT_STATIC, NULL, MAXNAMELEN },
+
+ { "password", o_string, passwd,
+ "Password for authenticating us to the peer",
+ OPT_PRIO | OPT_STATIC | OPT_HIDE, NULL, MAXSECRETLEN },
+
+ { "usehostname", o_bool, &usehostname,
+ "Must use hostname for authentication", 1 },
+
+ { "remotename", o_string, remote_name,
+ "Set remote name for authentication", OPT_PRIO | OPT_STATIC,
+ &explicit_remote, MAXNAMELEN },
+
+ { "login", o_bool, &uselogin,
+ "Use system password database for PAP", 1 },
+
+ { "papcrypt", o_bool, &cryptpap,
+ "PAP passwords are encrypted", 1 },
+
+ { "privgroup", o_special, (void *)privgroup,
+ "Allow group members to use privileged options", OPT_PRIV | OPT_A2LIST },
+
+ { "allow-ip", o_special, (void *)set_noauth_addr,
+ "Set IP address(es) which can be used without authentication",
+ OPT_PRIV | OPT_A2LIST },
+
+ { "remotenumber", o_string, remote_number,
+ "Set remote telephone number for authentication", OPT_PRIO | OPT_STATIC,
+ NULL, MAXNAMELEN },
+
+ { "allow-number", o_special, (void *)set_permitted_number,
+ "Set telephone number(s) which are allowed to connect",
+ OPT_PRIV | OPT_A2LIST },
+
+ { NULL }
+};
+
+/*
+ * setupapfile - specifies UPAP info for authenticating with peer.
+ */
+static int
+setupapfile(argv)
+ char **argv;
+{
+ FILE *ufile;
+ int l;
+ char u[MAXNAMELEN], p[MAXSECRETLEN];
+ char *fname;
+
+ lcp_allowoptions[0].neg_upap = 1;
+
+ /* open user info file */
+ fname = strdup(*argv);
+ if (fname == NULL)
+ novm("+ua file name");
+ seteuid(getuid());
+ ufile = fopen(fname, "r");
+ seteuid(0);
+ if (ufile == NULL) {
+ option_error("unable to open user login data file %s", fname);
+ return 0;
+ }
+ check_access(ufile, fname);
+ uafname = fname;
+
+ /* get username */
+ if (fgets(u, MAXNAMELEN - 1, ufile) == NULL
+ || fgets(p, MAXSECRETLEN - 1, ufile) == NULL) {
+ fclose(ufile);
+ option_error("unable to read user login data file %s", fname);
+ return 0;
+ }
+ fclose(ufile);
+
+ /* get rid of newlines */
+ l = strlen(u);
+ if (l > 0 && u[l-1] == '\n')
+ u[l-1] = 0;
+ l = strlen(p);
+ if (l > 0 && p[l-1] == '\n')
+ p[l-1] = 0;
+
+ if (override_value("user", option_priority, fname))
+ strlcpy(user, u, sizeof(user));
+ if (override_value("passwd", option_priority, fname))
+ strlcpy(passwd, p, sizeof(passwd));
+
+ return (1);
+}
+
+
+/*
+ * privgroup - allow members of the group to have privileged access.
+ */
+static int
+privgroup(argv)
+ char **argv;
+{
+ struct group *g;
+ int i;
+
+ g = getgrnam(*argv);
+ if (g == 0) {
+ option_error("group %s is unknown", *argv);
+ return 0;
+ }
+ for (i = 0; i < ngroups; ++i) {
+ if (groups[i] == g->gr_gid) {
+ privileged = 1;
+ break;
+ }
+ }
+ return 1;
+}
+