Home | History | Annotate | Download | only in src
      1 /*-
      2  * Copyright (c) 1996 - 2001 Brian Somers <brian (at) Awfulhak.org>
      3  *          based on work by Toshiharu OHNO <tony-o (at) iij.ad.jp>
      4  *                           Internet Initiative Japan, Inc (IIJ)
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  *
     28  * $FreeBSD: src/usr.sbin/ppp/auth.c,v 1.58.10.1.8.1 2010/12/21 17:10:29 kensmith Exp $
     29  */
     30 
     31 #include <sys/param.h>
     32 #include <netinet/in.h>
     33 #include <netinet/in_systm.h>
     34 #include <netinet/ip.h>
     35 #include <sys/socket.h>
     36 #include <sys/un.h>
     37 
     38 #include <pwd.h>
     39 #include <stdio.h>
     40 #include <stdlib.h>
     41 #include <string.h>
     42 #include <termios.h>
     43 #include <unistd.h>
     44 
     45 #ifndef NOPAM
     46 #include <security/pam_appl.h>
     47 #ifdef OPENPAM
     48 #include <security/openpam.h>
     49 #endif
     50 #endif /* !NOPAM */
     51 
     52 #include "layer.h"
     53 #include "mbuf.h"
     54 #include "defs.h"
     55 #include "log.h"
     56 #include "timer.h"
     57 #include "fsm.h"
     58 #include "iplist.h"
     59 #include "throughput.h"
     60 #include "slcompress.h"
     61 #include "lqr.h"
     62 #include "hdlc.h"
     63 #include "ncpaddr.h"
     64 #include "ipcp.h"
     65 #include "auth.h"
     66 #include "systems.h"
     67 #include "lcp.h"
     68 #include "ccp.h"
     69 #include "link.h"
     70 #include "descriptor.h"
     71 #include "chat.h"
     72 #include "proto.h"
     73 #include "filter.h"
     74 #include "mp.h"
     75 #ifndef NORADIUS
     76 #include "radius.h"
     77 #endif
     78 #include "cbcp.h"
     79 #include "chap.h"
     80 #include "async.h"
     81 #include "physical.h"
     82 #include "datalink.h"
     83 #include "ipv6cp.h"
     84 #include "ncp.h"
     85 #include "bundle.h"
     86 
     87 const char *
     88 Auth2Nam(u_short auth, u_char type)
     89 {
     90   static char chap[10];
     91 
     92   switch (auth) {
     93   case PROTO_PAP:
     94     return "PAP";
     95   case PROTO_CHAP:
     96     snprintf(chap, sizeof chap, "CHAP 0x%02x", type);
     97     return chap;
     98   case 0:
     99     return "none";
    100   }
    101   return "unknown";
    102 }
    103 
    104 #if !defined(NOPAM) && !defined(OPENPAM)
    105 static int
    106 pam_conv(int n, const struct pam_message **msg, struct pam_response **resp,
    107   void *data)
    108 {
    109 
    110   if (n != 1 || msg[0]->msg_style != PAM_PROMPT_ECHO_OFF)
    111     return (PAM_CONV_ERR);
    112   if ((*resp = malloc(sizeof(struct pam_response))) == NULL)
    113     return (PAM_CONV_ERR);
    114   (*resp)[0].resp = strdup((const char *)data);
    115   (*resp)[0].resp_retcode = 0;
    116 
    117   return ((*resp)[0].resp != NULL ? PAM_SUCCESS : PAM_CONV_ERR);
    118 }
    119 #endif /* !defined(NOPAM) && !defined(OPENPAM) */
    120 
    121 static int
    122 auth_CheckPasswd(const char *name, const char *data, const char *key)
    123 {
    124   if (!strcmp(data, "*")) {
    125 #ifdef NOPAM
    126     /* Then look up the real password database */
    127     struct passwd *pw;
    128     int result;
    129 
    130     result = (pw = getpwnam(name)) &&
    131              !strcmp(crypt(key, pw->pw_passwd), pw->pw_passwd);
    132     endpwent();
    133     return result;
    134 #else /* !NOPAM */
    135     /* Then consult with PAM. */
    136     pam_handle_t *pamh;
    137     int status;
    138 
    139     struct pam_conv pamc = {
    140 #ifdef OPENPAM
    141       &openpam_nullconv, NULL
    142 #else
    143       &pam_conv, key
    144 #endif
    145     };
    146 
    147     if (pam_start("ppp", name, &pamc, &pamh) != PAM_SUCCESS)
    148       return (0);
    149 #ifdef OPENPAM
    150     if ((status = pam_set_item(pamh, PAM_AUTHTOK, key)) == PAM_SUCCESS)
    151 #endif
    152       status = pam_authenticate(pamh, 0);
    153     pam_end(pamh, status);
    154     return (status == PAM_SUCCESS);
    155 #endif /* !NOPAM */
    156   }
    157 
    158   return !strcmp(data, key);
    159 }
    160 
    161 int
    162 auth_SetPhoneList(const char *name, char *phone, int phonelen)
    163 {
    164   FILE *fp;
    165   int n, lineno;
    166   char *vector[6], buff[LINE_LEN];
    167   const char *slash;
    168 
    169   fp = OpenSecret(SECRETFILE);
    170   if (fp != NULL) {
    171 again:
    172     lineno = 0;
    173     while (fgets(buff, sizeof buff, fp)) {
    174       lineno++;
    175       if (buff[0] == '#')
    176         continue;
    177       buff[strlen(buff) - 1] = '\0';
    178       memset(vector, '\0', sizeof vector);
    179       if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0)
    180         log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno);
    181       if (n < 5)
    182         continue;
    183       if (strcmp(vector[0], name) == 0) {
    184         CloseSecret(fp);
    185         if (*vector[4] == '\0')
    186           return 0;
    187         strncpy(phone, vector[4], phonelen - 1);
    188         phone[phonelen - 1] = '\0';
    189         return 1;		/* Valid */
    190       }
    191     }
    192 
    193     if ((slash = strrchr(name, '\\')) != NULL && slash[1]) {
    194       /* Look for the name without the leading domain */
    195       name = slash + 1;
    196       rewind(fp);
    197       goto again;
    198     }
    199 
    200     CloseSecret(fp);
    201   }
    202   *phone = '\0';
    203   return 0;
    204 }
    205 
    206 int
    207 auth_Select(struct bundle *bundle, const char *name)
    208 {
    209   FILE *fp;
    210   int n, lineno;
    211   char *vector[5], buff[LINE_LEN];
    212   const char *slash;
    213 
    214   if (*name == '\0') {
    215     ipcp_Setup(&bundle->ncp.ipcp, INADDR_NONE);
    216     return 1;
    217   }
    218 
    219 #ifndef NORADIUS
    220   if (bundle->radius.valid && bundle->radius.ip.s_addr != INADDR_NONE &&
    221 	bundle->radius.ip.s_addr != RADIUS_INADDR_POOL) {
    222     /* We've got a radius IP - it overrides everything */
    223     if (!ipcp_UseHisIPaddr(bundle, bundle->radius.ip))
    224       return 0;
    225     ipcp_Setup(&bundle->ncp.ipcp, bundle->radius.mask.s_addr);
    226     /* Continue with ppp.secret in case we've got a new label */
    227   }
    228 #endif
    229 
    230   fp = OpenSecret(SECRETFILE);
    231   if (fp != NULL) {
    232 again:
    233     lineno = 0;
    234     while (fgets(buff, sizeof buff, fp)) {
    235       lineno++;
    236       if (buff[0] == '#')
    237         continue;
    238       buff[strlen(buff) - 1] = '\0';
    239       memset(vector, '\0', sizeof vector);
    240       if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0)
    241         log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno);
    242       if (n < 2)
    243         continue;
    244       if (strcmp(vector[0], name) == 0) {
    245         CloseSecret(fp);
    246 #ifndef NORADIUS
    247         if (!bundle->radius.valid || bundle->radius.ip.s_addr == INADDR_NONE) {
    248 #endif
    249           if (n > 2 && *vector[2] && strcmp(vector[2], "*") &&
    250               !ipcp_UseHisaddr(bundle, vector[2], 1))
    251             return 0;
    252           ipcp_Setup(&bundle->ncp.ipcp, INADDR_NONE);
    253 #ifndef NORADIUS
    254         }
    255 #endif
    256         if (n > 3 && *vector[3] && strcmp(vector[3], "*"))
    257           bundle_SetLabel(bundle, vector[3]);
    258         return 1;		/* Valid */
    259       }
    260     }
    261 
    262     if ((slash = strrchr(name, '\\')) != NULL && slash[1]) {
    263       /* Look for the name without the leading domain */
    264       name = slash + 1;
    265       rewind(fp);
    266       goto again;
    267     }
    268 
    269     CloseSecret(fp);
    270   }
    271 
    272 #ifndef NOPASSWDAUTH
    273   /* Let 'em in anyway - they must have been in the passwd file */
    274   ipcp_Setup(&bundle->ncp.ipcp, INADDR_NONE);
    275   return 1;
    276 #else
    277 #ifndef NORADIUS
    278   if (bundle->radius.valid)
    279     return 1;
    280 #endif
    281 
    282   /* Disappeared from ppp.secret ??? */
    283   return 0;
    284 #endif
    285 }
    286 
    287 int
    288 auth_Validate(struct bundle *bundle, const char *name, const char *key)
    289 {
    290   /* Used by PAP routines */
    291 
    292   FILE *fp;
    293   int n, lineno;
    294   char *vector[5], buff[LINE_LEN];
    295   const char *slash;
    296 
    297   fp = OpenSecret(SECRETFILE);
    298 again:
    299   lineno = 0;
    300   if (fp != NULL) {
    301     while (fgets(buff, sizeof buff, fp)) {
    302       lineno++;
    303       if (buff[0] == '#')
    304         continue;
    305       buff[strlen(buff) - 1] = 0;
    306       memset(vector, '\0', sizeof vector);
    307       if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0)
    308         log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno);
    309       if (n < 2)
    310         continue;
    311       if (strcmp(vector[0], name) == 0) {
    312         CloseSecret(fp);
    313         return auth_CheckPasswd(name, vector[1], key);
    314       }
    315     }
    316   }
    317 
    318   if ((slash = strrchr(name, '\\')) != NULL && slash[1]) {
    319     /* Look for the name without the leading domain */
    320     name = slash + 1;
    321     if (fp != NULL) {
    322       rewind(fp);
    323       goto again;
    324     }
    325   }
    326 
    327   if (fp != NULL)
    328     CloseSecret(fp);
    329 
    330 #ifndef NOPASSWDAUTH
    331   if (Enabled(bundle, OPT_PASSWDAUTH))
    332     return auth_CheckPasswd(name, "*", key);
    333 #endif
    334 
    335   return 0;			/* Invalid */
    336 }
    337 
    338 char *
    339 auth_GetSecret(const char *name, size_t len)
    340 {
    341   /* Used by CHAP routines */
    342 
    343   FILE *fp;
    344   int n, lineno;
    345   char *vector[5];
    346   const char *slash;
    347   static char buff[LINE_LEN];	/* vector[] will point here when returned */
    348 
    349   fp = OpenSecret(SECRETFILE);
    350   if (fp == NULL)
    351     return (NULL);
    352 
    353 again:
    354   lineno = 0;
    355   while (fgets(buff, sizeof buff, fp)) {
    356     lineno++;
    357     if (buff[0] == '#')
    358       continue;
    359     n = strlen(buff) - 1;
    360     if (buff[n] == '\n')
    361       buff[n] = '\0';	/* Trim the '\n' */
    362     memset(vector, '\0', sizeof vector);
    363     if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0)
    364       log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno);
    365     if (n < 2)
    366       continue;
    367     if (strlen(vector[0]) == len && strncmp(vector[0], name, len) == 0) {
    368       CloseSecret(fp);
    369       return vector[1];
    370     }
    371   }
    372 
    373   if ((slash = strrchr(name, '\\')) != NULL && slash[1]) {
    374     /* Go back and look for the name without the leading domain */
    375     len -= slash - name + 1;
    376     name = slash + 1;
    377     rewind(fp);
    378     goto again;
    379   }
    380 
    381   CloseSecret(fp);
    382   return (NULL);		/* Invalid */
    383 }
    384 
    385 static void
    386 AuthTimeout(void *vauthp)
    387 {
    388   struct authinfo *authp = (struct authinfo *)vauthp;
    389 
    390   timer_Stop(&authp->authtimer);
    391   if (--authp->retry > 0) {
    392     authp->id++;
    393     (*authp->fn.req)(authp);
    394     timer_Start(&authp->authtimer);
    395   } else {
    396     log_Printf(LogPHASE, "Auth: No response from server\n");
    397     datalink_AuthNotOk(authp->physical->dl);
    398   }
    399 }
    400 
    401 void
    402 auth_Init(struct authinfo *authp, struct physical *p, auth_func req,
    403           auth_func success, auth_func failure)
    404 {
    405   memset(authp, '\0', sizeof(struct authinfo));
    406   authp->cfg.fsm.timeout = DEF_FSMRETRY;
    407   authp->cfg.fsm.maxreq = DEF_FSMAUTHTRIES;
    408   authp->cfg.fsm.maxtrm = 0;	/* not used */
    409   authp->fn.req = req;
    410   authp->fn.success = success;
    411   authp->fn.failure = failure;
    412   authp->physical = p;
    413 }
    414 
    415 void
    416 auth_StartReq(struct authinfo *authp)
    417 {
    418   timer_Stop(&authp->authtimer);
    419   authp->authtimer.func = AuthTimeout;
    420   authp->authtimer.name = "auth";
    421   authp->authtimer.load = authp->cfg.fsm.timeout * SECTICKS;
    422   authp->authtimer.arg = (void *)authp;
    423   authp->retry = authp->cfg.fsm.maxreq;
    424   authp->id = 1;
    425   (*authp->fn.req)(authp);
    426   timer_Start(&authp->authtimer);
    427 }
    428 
    429 void
    430 auth_StopTimer(struct authinfo *authp)
    431 {
    432   timer_Stop(&authp->authtimer);
    433 }
    434 
    435 struct mbuf *
    436 auth_ReadHeader(struct authinfo *authp, struct mbuf *bp)
    437 {
    438   size_t len;
    439 
    440   len = m_length(bp);
    441   if (len >= sizeof authp->in.hdr) {
    442     bp = mbuf_Read(bp, (u_char *)&authp->in.hdr, sizeof authp->in.hdr);
    443     if (len >= ntohs(authp->in.hdr.length))
    444       return bp;
    445     authp->in.hdr.length = htons(0);
    446     log_Printf(LogWARN, "auth_ReadHeader: Short packet (%u > %zu) !\n",
    447                ntohs(authp->in.hdr.length), len);
    448   } else {
    449     authp->in.hdr.length = htons(0);
    450     log_Printf(LogWARN, "auth_ReadHeader: Short packet header (%u > %zu) !\n",
    451                (int)(sizeof authp->in.hdr), len);
    452   }
    453 
    454   m_freem(bp);
    455   return NULL;
    456 }
    457 
    458 struct mbuf *
    459 auth_ReadName(struct authinfo *authp, struct mbuf *bp, size_t len)
    460 {
    461   if (len > sizeof authp->in.name - 1)
    462     log_Printf(LogWARN, "auth_ReadName: Name too long (%zu) !\n", len);
    463   else {
    464     size_t mlen = m_length(bp);
    465 
    466     if (len > mlen)
    467       log_Printf(LogWARN, "auth_ReadName: Short packet (%zu > %zu) !\n",
    468                  len, mlen);
    469     else {
    470       bp = mbuf_Read(bp, (u_char *)authp->in.name, len);
    471       authp->in.name[len] = '\0';
    472       return bp;
    473     }
    474   }
    475 
    476   *authp->in.name = '\0';
    477   m_freem(bp);
    478   return NULL;
    479 }
    480