📄 auth.c
字号:
/* * auth.c - PPP authentication and phase control. * * Copyright (c) 1993 The Australian National University. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the Australian National University. The name of the University * may not be used to endorse or promote products derived from this * software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Copyright (c) 1989 Carnegie Mellon University. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by Carnegie Mellon University. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */#define RCSID "$Id: auth.c,v 1.69 2001/03/12 22:50:01 paulus Exp $"#include <stdio.h>#include <stddef.h>#include <stdlib.h>#include <unistd.h>#include <pwd.h>#include <grp.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/socket.h>#include <utmp.h>#include <fcntl.h>#if defined(_PATH_LASTLOG) && defined(_linux_)#include <lastlog.h>#endif#include <netdb.h>#include <netinet/in.h>#include <arpa/inet.h>#ifdef USE_PAM#include <security/pam_appl.h>#endif#ifdef HAS_SHADOW#include <shadow.h>#ifndef PW_PPP#define PW_PPP PW_LOGIN#endif#endif#include "pppd.h"#include "fsm.h"#include "lcp.h"#include "ipcp.h"#include "upap.h"#include "chap.h"#ifdef CBCP_SUPPORT#include "cbcp.h"#endif#include "pathnames.h"static const char rcsid[] = RCSID;/* Bits in scan_authfile return value */#define NONWILD_SERVER 1#define NONWILD_CLIENT 2#define ISWILD(word) (word[0] == '*' && word[1] == 0)/* The name by which the peer authenticated itself to us. */char peer_authname[MAXNAMELEN];/* Records which authentication operations haven't completed yet. */static int auth_pending[NUM_PPP];/* Set if we have successfully called plogin() */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;/* 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;/* * 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 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 *//* Bits in auth_pending[] */#define PAP_WITHPEER 1#define PAP_PEER 2#define CHAP_WITHPEER 4#define CHAP_PEER 8extern 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 ip_addr_check __P((u_int32_t, struct permitted_ip *));static int scan_authfile __P((FILE *, char *, char *, 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 *, 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 *));static int wordlist_count __P((struct wordlist *));/* * 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, &lcp_wantoptions[0].neg_chap, "Require CHAP authentication from peer", OPT_PRIOSUB | 1, &auth_required }, { "+chap", o_bool, &lcp_wantoptions[0].neg_chap, "Require CHAP authentication from peer", OPT_ALIAS | OPT_PRIOSUB | 1, &auth_required }, { "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", 1 }, { "-chap", o_bool, &refuse_chap, "Don't allow CHAP authentication with peer", OPT_ALIAS | 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 }, { NULL }};/* * setupapfile - specifies UPAP info for authenticating with peer. */static intsetupapfile(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){ 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 intprivgroup(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;}/* * set_noauth_addr - set address(es) that can be used without authentication. * Equivalent to specifying an entry like `"" * "" addr' in pap-secrets. */static intset_noauth_addr(argv) char **argv;{ char *addr = *argv; int l = strlen(addr) + 1; struct wordlist *wp; wp = (struct wordlist *) malloc(sizeof(struct wordlist) + l); 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. */voidlink_required(unit) int unit;{}/* * LCP has terminated the link; go to the Dead phase and take the * physical layer down. */voidlink_terminated(unit) int unit;{ if (phase == PHASE_DEAD) return; if (pap_logout_hook) { pap_logout_hook(); } else { if (logged_in) plogout(); } new_phase(PHASE_DEAD); notice("Connection terminated.");}/* * LCP has gone down; it will either die or try to re-establish. */voidlink_down(unit) int unit;{ int i; struct protent *protp; 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); } for (i = 0; (protp = protocols[i]) != NULL; ++i) { if (!protp->enabled_flag) continue; if (protp->protocol != PPP_LCP && protp->lowerdown != NULL) (*protp->lowerdown)(unit); if (protp->protocol < 0xC000 && protp->close != NULL) (*protp->close)(unit, "LCP down"); } num_np_open = 0; num_np_up = 0; if (phase != PHASE_DEAD) new_phase(PHASE_TERMINATE);}/* * The link is established. * Proceed to the Dead, Authenticate or Network phase as appropriate. */voidlink_established(unit) int unit;{ int auth; lcp_options *wo = &lcp_wantoptions[unit]; lcp_options *go = &lcp_gotoptions[unit]; lcp_options *ho = &lcp_hisoptions[unit]; int i; struct protent *protp; /* * Tell higher-level protocols that LCP is up. */ for (i = 0; (protp = protocols[i]) != NULL; ++i) if (protp->protocol != PPP_LCP && protp->enabled_flag && protp->lowerup != NULL) (*protp->lowerup)(unit); if (auth_required && !(go->neg_chap || go->neg_upap)) { /* * We wanted the peer to authenticate itself, and it refused: * 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 (noauth_addrs != NULL) { 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; return; } } new_phase(PHASE_AUTHENTICATE); used_login = 0; auth = 0; if (go->neg_chap) { ChapAuthPeer(unit, our_name, go->chap_mdtype); auth |= CHAP_PEER; } else if (go->neg_upap) { upap_authpeer(unit); auth |= PAP_PEER; } if (ho->neg_chap) { ChapAuthWithPeer(unit, user, ho->chap_mdtype); auth |= CHAP_WITHPEER; } else if (ho->neg_upap) { if (passwd[0] == 0) { passwd_from_file = 1; if (!get_pap_passwd(passwd)) error("No secret found for PAP login"); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -