178189Sbrian/*- 278189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 378189Sbrian * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 478189Sbrian * Internet Initiative Japan, Inc (IIJ) 578189Sbrian * All rights reserved. 66059Samurai * 778189Sbrian * Redistribution and use in source and binary forms, with or without 878189Sbrian * modification, are permitted provided that the following conditions 978189Sbrian * are met: 1078189Sbrian * 1. Redistributions of source code must retain the above copyright 1178189Sbrian * notice, this list of conditions and the following disclaimer. 1278189Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1378189Sbrian * notice, this list of conditions and the following disclaimer in the 1478189Sbrian * documentation and/or other materials provided with the distribution. 156059Samurai * 1678189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1778189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1878189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1978189Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2078189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2178189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2278189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2378189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2478189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2578189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2678189Sbrian * SUCH DAMAGE. 276059Samurai * 2850479Speter * $FreeBSD: releng/11.0/usr.sbin/ppp/auth.c 231994 2012-02-22 06:27:20Z kevlo $ 296059Samurai */ 3078189Sbrian 3143313Sbrian#include <sys/param.h> 3230715Sbrian#include <netinet/in.h> 3336285Sbrian#include <netinet/in_systm.h> 3436285Sbrian#include <netinet/ip.h> 3581634Sbrian#include <sys/socket.h> 3636285Sbrian#include <sys/un.h> 3730715Sbrian 3836285Sbrian#include <pwd.h> 3930715Sbrian#include <stdio.h> 40121702Sru#include <stdlib.h> 4130715Sbrian#include <string.h> 4243525Sbrian#include <termios.h> 4330715Sbrian#include <unistd.h> 4430715Sbrian 45121702Sru#ifndef NOPAM 46121702Sru#include <security/pam_appl.h> 47174870Sdes#ifdef OPENPAM 48121702Sru#include <security/openpam.h> 49121702Sru#endif 50121702Sru#endif /* !NOPAM */ 51121702Sru 5246686Sbrian#include "layer.h" 5330715Sbrian#include "mbuf.h" 5430715Sbrian#include "defs.h" 5543525Sbrian#include "log.h" 5630715Sbrian#include "timer.h" 576059Samurai#include "fsm.h" 5836285Sbrian#include "iplist.h" 5936285Sbrian#include "throughput.h" 6036285Sbrian#include "slcompress.h" 6138557Sbrian#include "lqr.h" 6238557Sbrian#include "hdlc.h" 6381634Sbrian#include "ncpaddr.h" 646059Samurai#include "ipcp.h" 656735Samurai#include "auth.h" 6636285Sbrian#include "systems.h" 6736285Sbrian#include "lcp.h" 6836285Sbrian#include "ccp.h" 6936285Sbrian#include "link.h" 7036285Sbrian#include "descriptor.h" 7113389Sphk#include "chat.h" 7246686Sbrian#include "proto.h" 7336285Sbrian#include "filter.h" 7436285Sbrian#include "mp.h" 7543313Sbrian#ifndef NORADIUS 7643313Sbrian#include "radius.h" 7743313Sbrian#endif 7843525Sbrian#include "cbcp.h" 7943525Sbrian#include "chap.h" 8043525Sbrian#include "async.h" 8143525Sbrian#include "physical.h" 8243525Sbrian#include "datalink.h" 8381634Sbrian#include "ipv6cp.h" 8481634Sbrian#include "ncp.h" 8536285Sbrian#include "bundle.h" 866059Samurai 8736285Sbrianconst char * 8844106SbrianAuth2Nam(u_short auth, u_char type) 8913389Sphk{ 9044106Sbrian static char chap[10]; 9144106Sbrian 9236285Sbrian switch (auth) { 9336285Sbrian case PROTO_PAP: 9436285Sbrian return "PAP"; 9536285Sbrian case PROTO_CHAP: 9644106Sbrian snprintf(chap, sizeof chap, "CHAP 0x%02x", type); 9744106Sbrian return chap; 9836285Sbrian case 0: 9936285Sbrian return "none"; 10036285Sbrian } 10136285Sbrian return "unknown"; 1026735Samurai} 1036735Samurai 104174870Sdes#if !defined(NOPAM) && !defined(OPENPAM) 10536285Sbrianstatic int 106121702Srupam_conv(int n, const struct pam_message **msg, struct pam_response **resp, 107121702Sru void *data) 108121702Sru{ 109121702Sru 110121702Sru if (n != 1 || msg[0]->msg_style != PAM_PROMPT_ECHO_OFF) 111121702Sru return (PAM_CONV_ERR); 112121702Sru if ((*resp = malloc(sizeof(struct pam_response))) == NULL) 113121702Sru return (PAM_CONV_ERR); 114121702Sru (*resp)[0].resp = strdup((const char *)data); 115121702Sru (*resp)[0].resp_retcode = 0; 116121702Sru 117121702Sru return ((*resp)[0].resp != NULL ? PAM_SUCCESS : PAM_CONV_ERR); 118121702Sru} 119174870Sdes#endif /* !defined(NOPAM) && !defined(OPENPAM) */ 120121702Sru 121121702Srustatic int 12236285Sbrianauth_CheckPasswd(const char *name, const char *data, const char *key) 12328679Sbrian{ 12436285Sbrian if (!strcmp(data, "*")) { 125121702Sru#ifdef NOPAM 12636285Sbrian /* Then look up the real password database */ 12736285Sbrian struct passwd *pw; 12836285Sbrian int result; 129231994Skevlo char *cryptpw; 13036285Sbrian 131231994Skevlo cryptpw = crypt(key, pw->pw_passwd); 13236285Sbrian result = (pw = getpwnam(name)) && 133231994Skevlo (cryptpw == NULL || !strcmp(cryptpw, pw->pw_passwd)); 13436285Sbrian endpwent(); 13536285Sbrian return result; 136121702Sru#else /* !NOPAM */ 137121702Sru /* Then consult with PAM. */ 138121702Sru pam_handle_t *pamh; 139121702Sru int status; 140121702Sru 141121702Sru struct pam_conv pamc = { 142174870Sdes#ifdef OPENPAM 143121702Sru &openpam_nullconv, NULL 144121702Sru#else 145174870Sdes &pam_conv, key 146121702Sru#endif 147121702Sru }; 148121702Sru 149121702Sru if (pam_start("ppp", name, &pamc, &pamh) != PAM_SUCCESS) 150121702Sru return (0); 151174870Sdes#ifdef OPENPAM 152121702Sru if ((status = pam_set_item(pamh, PAM_AUTHTOK, key)) == PAM_SUCCESS) 153121702Sru#endif 154121702Sru status = pam_authenticate(pamh, 0); 155121702Sru pam_end(pamh, status); 156121702Sru return (status == PAM_SUCCESS); 157121702Sru#endif /* !NOPAM */ 15836285Sbrian } 15936285Sbrian 16036285Sbrian return !strcmp(data, key); 16136285Sbrian} 16236285Sbrian 16336285Sbrianint 16438174Sbrianauth_SetPhoneList(const char *name, char *phone, int phonelen) 16536285Sbrian{ 1666735Samurai FILE *fp; 16754914Sbrian int n, lineno; 16889072Sbrian char *vector[6], buff[LINE_LEN]; 16989072Sbrian const char *slash; 17038174Sbrian 17138174Sbrian fp = OpenSecret(SECRETFILE); 17238174Sbrian if (fp != NULL) { 17389072Sbrianagain: 17489072Sbrian lineno = 0; 17538174Sbrian while (fgets(buff, sizeof buff, fp)) { 17654914Sbrian lineno++; 17738174Sbrian if (buff[0] == '#') 17838174Sbrian continue; 17938174Sbrian buff[strlen(buff) - 1] = '\0'; 18038174Sbrian memset(vector, '\0', sizeof vector); 18155145Sbrian if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0) 18254914Sbrian log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno); 18338174Sbrian if (n < 5) 18438174Sbrian continue; 18538174Sbrian if (strcmp(vector[0], name) == 0) { 18643313Sbrian CloseSecret(fp); 18743313Sbrian if (*vector[4] == '\0') 18838174Sbrian return 0; 18938174Sbrian strncpy(phone, vector[4], phonelen - 1); 19038174Sbrian phone[phonelen - 1] = '\0'; 19143313Sbrian return 1; /* Valid */ 19238174Sbrian } 19338174Sbrian } 19489072Sbrian 19589072Sbrian if ((slash = strrchr(name, '\\')) != NULL && slash[1]) { 19689072Sbrian /* Look for the name without the leading domain */ 19789072Sbrian name = slash + 1; 19889072Sbrian rewind(fp); 19989072Sbrian goto again; 20089072Sbrian } 20189072Sbrian 20238174Sbrian CloseSecret(fp); 20338174Sbrian } 20438174Sbrian *phone = '\0'; 20538174Sbrian return 0; 20638174Sbrian} 20738174Sbrian 20838174Sbrianint 20938174Sbrianauth_Select(struct bundle *bundle, const char *name) 21038174Sbrian{ 21138174Sbrian FILE *fp; 21254914Sbrian int n, lineno; 21389072Sbrian char *vector[5], buff[LINE_LEN]; 21489072Sbrian const char *slash; 2156735Samurai 21636285Sbrian if (*name == '\0') { 21743313Sbrian ipcp_Setup(&bundle->ncp.ipcp, INADDR_NONE); 21836285Sbrian return 1; 21936285Sbrian } 22036285Sbrian 22143313Sbrian#ifndef NORADIUS 22293767Shosokawa if (bundle->radius.valid && bundle->radius.ip.s_addr != INADDR_NONE && 22393767Shosokawa bundle->radius.ip.s_addr != RADIUS_INADDR_POOL) { 22443313Sbrian /* We've got a radius IP - it overrides everything */ 22543313Sbrian if (!ipcp_UseHisIPaddr(bundle, bundle->radius.ip)) 22643313Sbrian return 0; 22743313Sbrian ipcp_Setup(&bundle->ncp.ipcp, bundle->radius.mask.s_addr); 22843313Sbrian /* Continue with ppp.secret in case we've got a new label */ 22943313Sbrian } 23043313Sbrian#endif 23143313Sbrian 23236285Sbrian fp = OpenSecret(SECRETFILE); 23336285Sbrian if (fp != NULL) { 23489072Sbrianagain: 23589072Sbrian lineno = 0; 23636285Sbrian while (fgets(buff, sizeof buff, fp)) { 23754914Sbrian lineno++; 23836285Sbrian if (buff[0] == '#') 23936285Sbrian continue; 24037763Sbrian buff[strlen(buff) - 1] = '\0'; 24136285Sbrian memset(vector, '\0', sizeof vector); 24255145Sbrian if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0) 24354914Sbrian log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno); 24436285Sbrian if (n < 2) 24536285Sbrian continue; 24637763Sbrian if (strcmp(vector[0], name) == 0) { 24743313Sbrian CloseSecret(fp); 24843313Sbrian#ifndef NORADIUS 24943313Sbrian if (!bundle->radius.valid || bundle->radius.ip.s_addr == INADDR_NONE) { 25043313Sbrian#endif 25143313Sbrian if (n > 2 && *vector[2] && strcmp(vector[2], "*") && 25243313Sbrian !ipcp_UseHisaddr(bundle, vector[2], 1)) 25343313Sbrian return 0; 25443313Sbrian ipcp_Setup(&bundle->ncp.ipcp, INADDR_NONE); 25543313Sbrian#ifndef NORADIUS 25643313Sbrian } 25743313Sbrian#endif 25843313Sbrian if (n > 3 && *vector[3] && strcmp(vector[3], "*")) 25943313Sbrian bundle_SetLabel(bundle, vector[3]); 26043313Sbrian return 1; /* Valid */ 26137763Sbrian } 2626735Samurai } 26389072Sbrian 26489072Sbrian if ((slash = strrchr(name, '\\')) != NULL && slash[1]) { 26589072Sbrian /* Look for the name without the leading domain */ 26689072Sbrian name = slash + 1; 26789072Sbrian rewind(fp); 26889072Sbrian goto again; 26989072Sbrian } 27089072Sbrian 27136285Sbrian CloseSecret(fp); 2726735Samurai } 27336285Sbrian 27436285Sbrian#ifndef NOPASSWDAUTH 27536285Sbrian /* Let 'em in anyway - they must have been in the passwd file */ 27643313Sbrian ipcp_Setup(&bundle->ncp.ipcp, INADDR_NONE); 27736285Sbrian return 1; 27836285Sbrian#else 27943313Sbrian#ifndef NORADIUS 28043313Sbrian if (bundle->radius.valid) 28143313Sbrian return 1; 28243313Sbrian#endif 28343313Sbrian 28443313Sbrian /* Disappeared from ppp.secret ??? */ 28536285Sbrian return 0; 28636285Sbrian#endif 2876735Samurai} 2886735Samurai 2896059Samuraiint 290134789Sbrianauth_Validate(struct bundle *bundle, const char *name, const char *key) 2916059Samurai{ 29236285Sbrian /* Used by PAP routines */ 29336285Sbrian 2946059Samurai FILE *fp; 29554914Sbrian int n, lineno; 29689072Sbrian char *vector[5], buff[LINE_LEN]; 29789072Sbrian const char *slash; 2986059Samurai 29936285Sbrian fp = OpenSecret(SECRETFILE); 30089072Sbrianagain: 30154914Sbrian lineno = 0; 30236285Sbrian if (fp != NULL) { 30336285Sbrian while (fgets(buff, sizeof buff, fp)) { 30454914Sbrian lineno++; 30536285Sbrian if (buff[0] == '#') 30636285Sbrian continue; 30736285Sbrian buff[strlen(buff) - 1] = 0; 30836285Sbrian memset(vector, '\0', sizeof vector); 30955145Sbrian if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0) 31054914Sbrian log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno); 31136285Sbrian if (n < 2) 31236285Sbrian continue; 31343313Sbrian if (strcmp(vector[0], name) == 0) { 31443313Sbrian CloseSecret(fp); 31543313Sbrian return auth_CheckPasswd(name, vector[1], key); 3166059Samurai } 3176059Samurai } 3186059Samurai } 31936285Sbrian 32089072Sbrian if ((slash = strrchr(name, '\\')) != NULL && slash[1]) { 32189072Sbrian /* Look for the name without the leading domain */ 32289072Sbrian name = slash + 1; 32389072Sbrian if (fp != NULL) { 32489072Sbrian rewind(fp); 32589072Sbrian goto again; 32689072Sbrian } 32789072Sbrian } 32889072Sbrian 32989072Sbrian if (fp != NULL) 33089072Sbrian CloseSecret(fp); 33189072Sbrian 33236285Sbrian#ifndef NOPASSWDAUTH 33336285Sbrian if (Enabled(bundle, OPT_PASSWDAUTH)) 33443313Sbrian return auth_CheckPasswd(name, "*", key); 33536285Sbrian#endif 33636285Sbrian 33736285Sbrian return 0; /* Invalid */ 3386059Samurai} 3396059Samurai 3406059Samuraichar * 341134789Sbrianauth_GetSecret(const char *name, size_t len) 3426059Samurai{ 34336285Sbrian /* Used by CHAP routines */ 34436285Sbrian 3456059Samurai FILE *fp; 34654914Sbrian int n, lineno; 34732267Sbrian char *vector[5]; 34889072Sbrian const char *slash; 34947843Sbrian static char buff[LINE_LEN]; /* vector[] will point here when returned */ 3506059Samurai 35136285Sbrian fp = OpenSecret(SECRETFILE); 3526059Samurai if (fp == NULL) 35328679Sbrian return (NULL); 35436285Sbrian 35589072Sbrianagain: 35654914Sbrian lineno = 0; 35731962Sbrian while (fgets(buff, sizeof buff, fp)) { 35854914Sbrian lineno++; 3596059Samurai if (buff[0] == '#') 3606059Samurai continue; 36147843Sbrian n = strlen(buff) - 1; 36247843Sbrian if (buff[n] == '\n') 36347843Sbrian buff[n] = '\0'; /* Trim the '\n' */ 36431962Sbrian memset(vector, '\0', sizeof vector); 36555145Sbrian if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0) 36654914Sbrian log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno); 3676059Samurai if (n < 2) 3686059Samurai continue; 36943313Sbrian if (strlen(vector[0]) == len && strncmp(vector[0], name, len) == 0) { 37036285Sbrian CloseSecret(fp); 37136285Sbrian return vector[1]; 3726059Samurai } 3736059Samurai } 37489072Sbrian 37589072Sbrian if ((slash = strrchr(name, '\\')) != NULL && slash[1]) { 37689072Sbrian /* Go back and look for the name without the leading domain */ 37789072Sbrian len -= slash - name + 1; 37889072Sbrian name = slash + 1; 37989072Sbrian rewind(fp); 38089072Sbrian goto again; 38189072Sbrian } 38289072Sbrian 3836059Samurai CloseSecret(fp); 38428679Sbrian return (NULL); /* Invalid */ 3856059Samurai} 3866735Samurai 3876735Samuraistatic void 38831343SbrianAuthTimeout(void *vauthp) 3896735Samurai{ 39031343Sbrian struct authinfo *authp = (struct authinfo *)vauthp; 3916735Samurai 39236285Sbrian timer_Stop(&authp->authtimer); 3936735Samurai if (--authp->retry > 0) { 39443693Sbrian authp->id++; 39543693Sbrian (*authp->fn.req)(authp); 39636285Sbrian timer_Start(&authp->authtimer); 39743525Sbrian } else { 39843525Sbrian log_Printf(LogPHASE, "Auth: No response from server\n"); 39943525Sbrian datalink_AuthNotOk(authp->physical->dl); 40043525Sbrian } 4016735Samurai} 4026735Samurai 4036735Samuraivoid 40443693Sbrianauth_Init(struct authinfo *authp, struct physical *p, auth_func req, 40543693Sbrian auth_func success, auth_func failure) 4066735Samurai{ 40743693Sbrian memset(authp, '\0', sizeof(struct authinfo)); 40844305Sbrian authp->cfg.fsm.timeout = DEF_FSMRETRY; 40944305Sbrian authp->cfg.fsm.maxreq = DEF_FSMAUTHTRIES; 41044305Sbrian authp->cfg.fsm.maxtrm = 0; /* not used */ 41143693Sbrian authp->fn.req = req; 41243693Sbrian authp->fn.success = success; 41343693Sbrian authp->fn.failure = failure; 41443693Sbrian authp->physical = p; 41536285Sbrian} 4166735Samurai 41736285Sbrianvoid 41843693Sbrianauth_StartReq(struct authinfo *authp) 41936285Sbrian{ 42036285Sbrian timer_Stop(&authp->authtimer); 42136285Sbrian authp->authtimer.func = AuthTimeout; 42236285Sbrian authp->authtimer.name = "auth"; 42344305Sbrian authp->authtimer.load = authp->cfg.fsm.timeout * SECTICKS; 42443693Sbrian authp->authtimer.arg = (void *)authp; 42544305Sbrian authp->retry = authp->cfg.fsm.maxreq; 4266735Samurai authp->id = 1; 42743693Sbrian (*authp->fn.req)(authp); 42836285Sbrian timer_Start(&authp->authtimer); 4296735Samurai} 4306735Samurai 4316735Samuraivoid 43236285Sbrianauth_StopTimer(struct authinfo *authp) 4336735Samurai{ 43436285Sbrian timer_Stop(&authp->authtimer); 4356735Samurai} 43643693Sbrian 43743693Sbrianstruct mbuf * 43843693Sbrianauth_ReadHeader(struct authinfo *authp, struct mbuf *bp) 43943693Sbrian{ 440134789Sbrian size_t len; 44143693Sbrian 44254912Sbrian len = m_length(bp); 44343693Sbrian if (len >= sizeof authp->in.hdr) { 44443693Sbrian bp = mbuf_Read(bp, (u_char *)&authp->in.hdr, sizeof authp->in.hdr); 44543693Sbrian if (len >= ntohs(authp->in.hdr.length)) 44643693Sbrian return bp; 44744159Sbrian authp->in.hdr.length = htons(0); 448134833Smarcel log_Printf(LogWARN, "auth_ReadHeader: Short packet (%u > %zu) !\n", 44944141Sbrian ntohs(authp->in.hdr.length), len); 45044159Sbrian } else { 45144159Sbrian authp->in.hdr.length = htons(0); 452134833Smarcel log_Printf(LogWARN, "auth_ReadHeader: Short packet header (%u > %zu) !\n", 45345193Sbrian (int)(sizeof authp->in.hdr), len); 45444159Sbrian } 45543693Sbrian 45654912Sbrian m_freem(bp); 45743693Sbrian return NULL; 45843693Sbrian} 45943693Sbrian 46043693Sbrianstruct mbuf * 461134789Sbrianauth_ReadName(struct authinfo *authp, struct mbuf *bp, size_t len) 46243693Sbrian{ 46343693Sbrian if (len > sizeof authp->in.name - 1) 464134833Smarcel log_Printf(LogWARN, "auth_ReadName: Name too long (%zu) !\n", len); 46543693Sbrian else { 466134789Sbrian size_t mlen = m_length(bp); 46743693Sbrian 46843693Sbrian if (len > mlen) 469134833Smarcel log_Printf(LogWARN, "auth_ReadName: Short packet (%zu > %zu) !\n", 47044141Sbrian len, mlen); 47143693Sbrian else { 47243693Sbrian bp = mbuf_Read(bp, (u_char *)authp->in.name, len); 47343693Sbrian authp->in.name[len] = '\0'; 47443693Sbrian return bp; 47543693Sbrian } 47643693Sbrian } 47743693Sbrian 47843693Sbrian *authp->in.name = '\0'; 47954912Sbrian m_freem(bp); 48043693Sbrian return NULL; 48143693Sbrian} 482