* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
-#define RCSID "$Id: auth.c,v 1.58 1999/09/11 12:08:56 paulus Exp $"
+#define RCSID "$Id: auth.c,v 1.67 2000/08/01 01:38:29 paulus Exp $"
#include <stdio.h>
#include <stddef.h>
/* 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;
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;
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.
*/
static int privgroup __P((char **));
static int set_noauth_addr __P((char **));
static void check_access __P((FILE *, char *));
+static int wordlist_count __P((struct wordlist *));
/*
* Authentication-related options.
"Use system password database for PAP", 1 },
{ "papcrypt", o_bool, &cryptpap,
"PAP passwords are encrypted", 1 },
- { "+ua", o_special, setupapfile,
+ { "+ua", o_special, (void *)setupapfile,
"Get PAP user and password from file" },
{ "password", o_string, passwd,
"Password for authenticating us to the peer", OPT_STATIC,
NULL, MAXSECRETLEN },
- { "privgroup", o_special, privgroup,
+ { "privgroup", o_special, (void *)privgroup,
"Allow group members to use privileged options", OPT_PRIV },
- { "allow-ip", o_special, set_noauth_addr,
+ { "allow-ip", o_special, (void *)set_noauth_addr,
"Set IP address(es) which can be used without authentication",
OPT_PRIV },
{ NULL }
char **argv;
{
char *addr = *argv;
- int l = strlen(addr);
+ int l = strlen(addr) + 1;
struct wordlist *wp;
- wp = (struct wordlist *) malloc(sizeof(struct wordlist) + l + 1);
+ wp = (struct wordlist *) malloc(sizeof(struct wordlist) + l);
if (wp == NULL)
novm("allow-ip argument");
wp->word = (char *) (wp + 1);
{
if (phase == PHASE_DEAD)
return;
- if (logged_in)
- plogout();
+ if (pap_logout_hook) {
+ pap_logout_hook();
+ } else {
+ if (logged_in)
+ plogout();
+ }
new_phase(PHASE_DEAD);
notice("Connection terminated.");
}
* boot it out.
*/
if (noauth_addrs != NULL) {
- set_allowed_addrs(unit, noauth_addrs, NULL);
- } else if (!wo->neg_upap || !null_login(unit)) {
+ set_allowed_addrs(unit, NULL, NULL);
+ } else if (!wo->neg_upap || uselogin || !null_login(unit)) {
warn("peer refused to authenticate: terminating link");
lcp_close(unit, "peer refused to authenticate");
status = EXIT_PEER_AUTH_FAILED;
}
new_phase(PHASE_AUTHENTICATE);
+ used_login = 0;
auth = 0;
if (go->neg_chap) {
ChapAuthPeer(unit, our_name, go->chap_mdtype);
struct protent *protp;
new_phase(PHASE_NETWORK);
-#if 0
+
+#ifdef HAVE_MULTILINK
+ if (multilink) {
+ if (mp_join_bundle()) {
+ if (updetach && !nodetach)
+ detach();
+ return;
+ }
+ }
+#endif /* HAVE_MULTILINK */
+
+#ifdef PPP_FILTER
if (!demand)
set_filters(&pass_filter, &active_filter);
#endif
namelen = sizeof(peer_authname) - 1;
BCOPY(name, peer_authname, namelen);
peer_authname[namelen] = 0;
- script_setenv("PEERNAME", peer_authname);
+ script_setenv("PEERNAME", peer_authname, 0);
/*
* If there is no more authentication still to be done,
/*
* If we have a default route, require the peer to authenticate
- * unless the noauth option was given.
+ * unless the noauth option was given or the real user is root.
*/
- if (!auth_required && !allow_any_ip && have_route_to(0))
+ if (!auth_required && !allow_any_ip && have_route_to(0) && !privileged) {
auth_required = 1;
+ default_auth = 1;
+ }
/* If authentication is required, ask peer for CHAP or PAP. */
if (auth_required) {
}
if (auth_required && !can_auth && noauth_addrs == NULL) {
- if (explicit_remote)
+ if (default_auth) {
option_error(
-"The remote system (%s) is required to authenticate itself but I",
- remote_name);
- else
+"By default the remote system is required to authenticate itself");
option_error(
-"The remote system is required to authenticate itself but I");
-
- if (!lacks_ip)
+"(because this system has a default route to the internet)");
+ } else if (explicit_remote)
option_error(
-"couldn't find any suitable secret (password) for it to use to do so.");
+"The remote system (%s) is required to authenticate itself",
+ remote_name);
else
option_error(
-"couldn't find any secret (password) which would let it use an IP address.");
+"The remote system is required to authenticate itself");
+ option_error(
+"but I couldn't find any suitable secret (password) for it to use to do so.");
+ if (lacks_ip)
+ option_error(
+"(None of the available passwords would let it use an IP address.)");
exit(1);
}
if (ret)
set_allowed_addrs(unit, addrs, opts);
BZERO(passwd, sizeof(passwd));
+ if (addrs != 0)
+ free_wordlist(addrs);
return ret? UPAP_AUTHACK: UPAP_AUTHNAK;
}
}
check_access(f, filename);
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 */
- if ((!cryptpap && strcmp(passwd, secret) == 0)
- || strcmp(crypt(passwd, secret), secret) == 0)
- ret = UPAP_AUTHACK;
- else
- warn("PAP authentication failure for %s", user);
- } else if (uselogin) {
- /* empty password in pap-secrets and login option */
- ret = plogin(user, passwd, msg);
- if (ret == UPAP_AUTHNAK)
- warn("PAP login failure for %s", user);
} else {
- /* empty password in pap-secrets and login option not used */
+ /*
+ * If the secret is "@login", it means to check
+ * the password against the login database.
+ */
+ int login_secret = strcmp(secret, "@login") == 0;
ret = UPAP_AUTHACK;
+ if (uselogin || login_secret) {
+ /* login option or secret is @login */
+ ret = plogin(user, passwd, msg);
+ if (ret == UPAP_AUTHNAK)
+ warn("PAP login failure for %s", user);
+ else
+ used_login = 1;
+ }
+ if (secret[0] != 0 && !login_secret) {
+ /* password given in pap-secrets - must match */
+ if ((cryptpap || strcmp(passwd, secret) != 0)
+ && strcmp(crypt(passwd, secret), secret) != 0) {
+ ret = UPAP_AUTHNAK;
+ warn("PAP authentication failure for %s", user);
+ }
+ }
}
fclose(f);
}
}
if (attempts > 3)
sleep((u_int) (attempts - 3) * 5);
- if (addrs != NULL)
- free_wordlist(addrs);
if (opts != NULL)
free_wordlist(opts);
set_allowed_addrs(unit, addrs, opts);
}
+ if (addrs != NULL)
+ free_wordlist(addrs);
BZERO(passwd, sizeof(passwd));
BZERO(secret, sizeof(secret));
if (ret)
set_allowed_addrs(unit, addrs, opts);
- else {
- free_wordlist(addrs);
+ else if (opts != 0)
free_wordlist(opts);
- }
+ if (addrs != 0)
+ free_wordlist(addrs);
fclose(f);
return ret;
char *filename;
FILE *f;
int ret;
- struct wordlist *addrs;
char secret[MAXWORDLEN];
/*
}
filename = _PATH_UPAPFILE;
- addrs = NULL;
f = fopen(filename, "r");
if (f == NULL)
return 0;
if (am_server)
set_allowed_addrs(unit, addrs, opts);
- else {
- free_wordlist(addrs);
+ else if (opts != 0)
free_wordlist(opts);
- }
+ if (addrs != 0)
+ free_wordlist(addrs);
}
len = strlen(secbuf);
struct wordlist *opts;
{
int n;
- struct wordlist *ap, **pap;
+ struct wordlist *ap, **plink;
struct permitted_ip *ip;
char *ptr_word, *ptr_mask;
struct hostent *hp;
/*
* Count the number of IP addresses given.
*/
- for (n = 0, pap = &addrs; (ap = *pap) != NULL; pap = &ap->next)
- ++n;
+ n = wordlist_count(addrs) + wordlist_count(noauth_addrs);
if (n == 0)
return;
ip = (struct permitted_ip *) malloc((n + 1) * sizeof(struct permitted_ip));
if (ip == 0)
return;
+ /* temporarily append the noauth_addrs list to addrs */
+ for (plink = &addrs; *plink != NULL; plink = &(*plink)->next)
+ ;
+ *plink = noauth_addrs;
+
n = 0;
for (ap = addrs; ap != NULL; ap = ap->next) {
/* "-" means no addresses authorized, "*" means any address allowed */
if (~mask == 0 && suggested_ip == 0)
suggested_ip = a;
}
+ *plink = NULL;
ip[n].permit = 0; /* make the last entry forbid all addresses */
ip[n].base = 0; /* to terminate the list */
}
if (auth_required)
return 0; /* no addresses authorized */
- return allow_any_ip || !have_route_to(addr);
+ return allow_any_ip || privileged || !have_route_to(addr);
}
static int
if (newline)
continue;
- /*
- * Special syntax: @filename means read secret from file.
- */
- if (word[0] == '@') {
- strlcpy(atfile, word+1, sizeof(atfile));
- if ((sf = fopen(atfile, "r")) == NULL) {
- warn("can't open indirect secret file %s", atfile);
- continue;
- }
- check_access(sf, atfile);
- if (!getword(sf, word, &xxx, atfile)) {
- warn("no secret in indirect secret file %s", atfile);
+ if (secret != NULL) {
+ /*
+ * Special syntax: @/pathname means read secret from file.
+ */
+ if (word[0] == '@' && word[1] == '/') {
+ strlcpy(atfile, word+1, sizeof(atfile));
+ if ((sf = fopen(atfile, "r")) == NULL) {
+ warn("can't open indirect secret file %s", atfile);
+ continue;
+ }
+ check_access(sf, atfile);
+ if (!getword(sf, word, &xxx, atfile)) {
+ warn("no secret in indirect secret file %s", atfile);
+ fclose(sf);
+ continue;
+ }
fclose(sf);
- continue;
}
- fclose(sf);
- }
- if (secret != NULL)
strlcpy(lsecret, word, sizeof(lsecret));
+ }
/*
* Now read address authorization info and make a wordlist.
return best_flag;
}
+/*
+ * wordlist_count - return the number of items in a wordlist
+ */
+static int
+wordlist_count(wp)
+ struct wordlist *wp;
+{
+ int n;
+
+ for (n = 0; wp != NULL; wp = wp->next)
+ ++n;
+ return n;
+}
+
/*
* free_wordlist - release memory allocated for a wordlist.
*/