📄 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. */#ifndef lintstatic char rcsid[] = "$Id: auth.c,v 1.15 1995/05/19 03:16:12 paulus Exp $";#endif#include <stdio.h>#include <stddef.h>/* #include <stdlib.h> */#include <syslog.h>#include <pwd.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#ifdef HAS_SHADOW#include <shadow.h>#include <shadow/pwauth.h>#ifndef PW_PPP#define PW_PPP PW_LOGIN#endif#endif#include "pppd.h"#include "fsm.h"#include "lcp.h"#include "upap.h"#include "chap.h"#include "ipcp.h"#include "ccp.h"#include "pathnames.h"#if defined(sun) && defined(sparc)#include <alloca.h>#endif /*sparc*/extern char *crypt _P((const char *, const char *));/* Used for storing a sequence of words. Usually malloced. */struct wordlist { struct wordlist *next; char word[1];};/* Bits in scan_authfile return value */#define NONWILD_SERVER 1#define NONWILD_CLIENT 2#define ISWILD(word) (word[0] == '*' && word[1] == 0)#undef FALSE#define FALSE 0#undef TRUE#define TRUE 1#ifndef IN_LOOPBACKNET#define IN_LOOPBACKNET 127#endif#ifndef IN_MULTICAST#define IN_MULTICAST(i) (((long)(i) & 0xf0000000) == 0xe0000000)#endif#ifndef IN_BADCLASS#define IN_BADCLASS(i) (((long)(i) & 0xf0000000) == 0xf0000000)#endif/* Records which authentication operations haven't completed yet. */static int auth_pending[NUM_PPP];static int logged_in;static struct wordlist *addresses[NUM_PPP];/* Bits in auth_pending[] */#define UPAP_WITHPEER 1#define UPAP_PEER 2#define CHAP_WITHPEER 4#define CHAP_PEER 8/* Prototypes */void check_access __P((FILE *, char *));static void network_phase __P((int));static int login __P((char *, char *, char **, int *));static void logout __P((void));static int null_login __P((int));static int get_upap_passwd __P((void));static int have_upap_secret __P((void));static int have_chap_secret __P((char *, char *));static int scan_authfile __P((FILE *, char *, char *, char *, int, struct wordlist **, char *));static void free_wordlist __P((struct wordlist *));/* * 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 (logged_in) logout(); phase = PHASE_DEAD; do_syslog(LOG_NOTICE, "Connection terminated."); if (ppp_exit) slirp_exit(0);}/* * LCP has gone down; it will either die or try to re-establish. */voidlink_down(unit) int unit;{ ipcp_close(0); ccp_close(0); 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]; 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 (!wo->neg_upap || !null_login(unit)) { do_syslog(LOG_WARNING, "peer refused to authenticate"); lcp_close(unit); phase = PHASE_TERMINATE; return; } } phase = PHASE_AUTHENTICATE; 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 |= UPAP_PEER; } if (ho->neg_chap) { ChapAuthWithPeer(unit, our_name, ho->chap_mdtype); auth |= CHAP_WITHPEER; } else if (ho->neg_upap) { upap_authwithpeer(unit, user, passwd); auth |= UPAP_WITHPEER; } auth_pending[unit] = auth; if (!auth) network_phase(unit);}/* * Proceed to the network phase. */static voidnetwork_phase(unit) int unit;{ phase = PHASE_NETWORK; ipcp_open(unit); ccp_open(unit);}/* * The peer has failed to authenticate himself using `protocol'. */voidauth_peer_fail(unit, protocol) int unit, protocol;{ /* * Authentication failure: take the link down */ lcp_close(unit); phase = PHASE_TERMINATE;}/* * The peer has been successfully authenticated using `protocol'. */voidauth_peer_success(unit, protocol) int unit, protocol;{ int bit; switch (protocol) { case PPP_CHAP: bit = CHAP_PEER; break; case PPP_PAP: bit = UPAP_PEER; break; default: do_syslog(LOG_WARNING, "auth_peer_success: unknown protocol %x", protocol); return; } /* * If there is no more authentication still to be done, * proceed to the network phase. */ if ((auth_pending[unit] &= ~bit) == 0) { phase = PHASE_NETWORK; ipcp_open(unit); ccp_open(unit); }}/* * We have failed to authenticate ourselves to the peer using `protocol'. */voidauth_withpeer_fail(unit, protocol) int unit, protocol;{ /* * We've failed to authenticate ourselves to our peer. * He'll probably take the link down, and there's not much * we can do except wait for that. */}/* * We have successfully authenticated ourselves with the peer using `protocol'. */voidauth_withpeer_success(unit, protocol) int unit, protocol;{ int bit; switch (protocol) { case PPP_CHAP: bit = CHAP_WITHPEER; break; case PPP_PAP: bit = UPAP_WITHPEER; break; default: do_syslog(LOG_WARNING, "auth_peer_success: unknown protocol %x", protocol); bit = 0; } /* * If there is no more authentication still being done, * proceed to the network phase. */ if ((auth_pending[unit] &= ~bit) == 0) network_phase(unit);}/* * check_auth_options - called to check authentication options. */voidcheck_auth_options(){ lcp_options *wo = &lcp_wantoptions[0]; lcp_options *ao = &lcp_allowoptions[0]; /* Default our_name to hostname, and user to our_name */ if (our_name[0] == 0 || usehostname) strncpy2(our_name, hostname, sizeof(our_name)); if (user[0] == 0) strncpy2(user, our_name, sizeof(user)); /* If authentication is required, ask peer for CHAP or PAP. */ if (auth_required && !wo->neg_chap && !wo->neg_upap) { wo->neg_chap = 1; wo->neg_upap = 1; } /* * Check whether we have appropriate secrets to use * to authenticate ourselves and/or the peer. */ if (ao->neg_upap && passwd[0] == 0 && !get_upap_passwd()) ao->neg_upap = 0; if (wo->neg_upap && !uselogin && !have_upap_secret()) wo->neg_upap = 0; if (ao->neg_chap && !have_chap_secret(our_name, remote_name)) ao->neg_chap = 0; if (wo->neg_chap && !have_chap_secret(remote_name, our_name)) wo->neg_chap = 0; if (auth_required && !wo->neg_chap && !wo->neg_upap) { fprintf(stderr, "\pppd: peer authentication required but no authentication files accessible\n"); exit(1); }}/* * check_passwd - Check the user name and passwd against the PAP secrets * file. If requested, also check against the system password database, * and login the user if OK. * * returns: * UPAP_AUTHNAK: Authentication failed. * UPAP_AUTHACK: Authentication succeeded. * In either case, msg points to an appropriate message. */intcheck_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen) int unit; char *auser; int userlen; char *apasswd; int passwdlen; char **msg; int *msglen;{ int ret; char *filename; FILE *f; struct wordlist *addrs; char passwd[256], user[256]; char secret[MAXWORDLEN]; static int attempts = 0; /* * Make copies of apasswd and auser, then null-terminate them. */ BCOPY(apasswd, passwd, passwdlen); passwd[passwdlen] = '\0'; BCOPY(auser, user, userlen); user[userlen] = '\0'; /* * Open the file of upap secrets and scan for a suitable secret * for authenticating this user. */ filename = _PATH_UPAPFILE; addrs = NULL; ret = UPAP_AUTHACK; f = fopen(filename, "r"); if (f == NULL) { if (!uselogin) { do_syslog(LOG_ERR, "Can't open upap password file %s: %m", filename); ret = UPAP_AUTHNAK; } } else { check_access(f, filename); if (scan_authfile(f, user, our_name, secret, sizeof(secret), &addrs, filename) < 0 || (secret[0] != 0 && (cryptpap || strcmp(passwd, secret) != 0) && strcmp(crypt(passwd, secret), secret) != 0)) { do_syslog(LOG_WARNING, "upap authentication failure for %s", user); ret = UPAP_AUTHNAK; } fclose(f); } if (uselogin && ret == UPAP_AUTHACK) { ret = login(user, passwd, msg, msglen); if (ret == UPAP_AUTHNAK) { do_syslog(LOG_WARNING, "upap login failure for %s", user); } } if (ret == UPAP_AUTHNAK) { *msg = "Login incorrect"; *msglen = strlen(*msg); /* * Frustrate passwd stealer programs. * Allow 10 tries, but start backing off after 3 (stolen from login). * On 10'th, drop the connection. */ if (attempts++ >= 10) { do_syslog(LOG_WARNING, "%d LOGIN FAILURES ON %s, %s", attempts, devnam, user); quit(); } if (attempts > 3) sleep((u_int) (attempts - 3) * 5); if (addrs != NULL) free_wordlist(addrs); } else { attempts = 0; /* Reset count */ *msg = "Login ok"; *msglen = strlen(*msg); if (addresses[unit] != NULL) free_wordlist(addresses[unit]); addresses[unit] = addrs; } return ret;}/* * login - Check the user name and password against the system * password database, and login the user if OK. * * returns: * UPAP_AUTHNAK: Login failed. * UPAP_AUTHACK: Login succeeded. * In either case, msg points to an appropriate message. */static intlogin(user, passwd, msg, msglen) char *user; char *passwd; char **msg; int *msglen;{ struct passwd *pw; char *epasswd; char *tty;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -