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