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