1 /* $OpenBSD: pap.c,v 1.14 2024/07/01 07:09:07 yasuoka Exp $ */
2
3 /*-
4 * Copyright (c) 2009 Internet Initiative Japan Inc.
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 /* $Id: pap.c,v 1.14 2024/07/01 07:09:07 yasuoka Exp $ */
29 /**@file
30 * This file provides Password Authentication Protocol (PAP) handlers.
31 * @author Yasuoka Masahiko
32 */
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/time.h>
36 #include <net/if_dl.h>
37 #include <netinet/in.h>
38
39 #include <event.h>
40 #include <md5.h>
41 #include <stdarg.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <syslog.h>
46 #include <errno.h>
47 #include <vis.h>
48
49 #include "npppd.h"
50 #include "ppp.h"
51
52 #ifdef USE_NPPPD_RADIUS
53 #include <radius.h>
54 #include "radius_chap_const.h"
55 #include "npppd_radius.h"
56 #endif
57
58 #include "debugutil.h"
59
60 #define AUTHREQ 0x01
61 #define AUTHACK 0x02
62 #define AUTHNAK 0x03
63
64 #define PAP_STATE_INITIAL 0
65 #define PAP_STATE_STARTING 1
66 #define PAP_STATE_AUTHENTICATING 2
67 #define PAP_STATE_SENT_RESPONSE 3
68 #define PAP_STATE_STOPPED 4
69 #define PAP_STATE_PROXY_AUTHENTICATION 5
70
71 #define DEFAULT_SUCCESS_MESSAGE "OK"
72 #define DEFAULT_FAILURE_MESSAGE "Unknown username or password"
73 #define DEFAULT_ERROR_MESSAGE "Unknown failure"
74
75 #ifdef PAP_DEBUG
76 #define PAP_DBG(x) pap_log x
77 #define PAP_ASSERT(cond) \
78 if (!(cond)) { \
79 fprintf(stderr, \
80 "\nASSERT(" #cond ") failed on %s() at %s:%d.\n"\
81 , __func__, __FILE__, __LINE__); \
82 abort(); \
83 }
84 #else
85 #define PAP_ASSERT(cond)
86 #define PAP_DBG(x)
87 #endif
88
89 static void pap_log (pap *, uint32_t, const char *, ...) __printflike(3,4);
90 static void pap_response (pap *, int, const char *);
91 static void pap_authenticate(pap *, const char *);
92 static void pap_local_authenticate (pap *, const char *, const char *);
93 #ifdef USE_NPPPD_RADIUS
94 static void pap_radius_authenticate (pap *, const char *, const char *);
95 static void pap_radius_response (void *, RADIUS_PACKET *, int, RADIUS_REQUEST_CTX);
96 #endif
97
98 #ifdef __cplusplus
99 extern "C" {
100 #endif
101
102 void pap_init (pap *, npppd_ppp *);
103 int pap_start (pap *);
104 int pap_stop (pap *);
105 int pap_input (pap *, u_char *, int);
106
107 #ifdef __cplusplus
108 }
109 #endif
110
111 void
pap_init(pap * _this,npppd_ppp * ppp)112 pap_init(pap *_this, npppd_ppp *ppp)
113 {
114 _this->ppp = ppp;
115 _this->state = PAP_STATE_INITIAL;
116 _this->auth_id = -1;
117 }
118
119 int
pap_start(pap * _this)120 pap_start(pap *_this)
121 {
122 pap_log(_this, LOG_DEBUG, "%s", __func__);
123
124 if (_this->state == PAP_STATE_PROXY_AUTHENTICATION) {
125 _this->state = PAP_STATE_AUTHENTICATING;
126 pap_authenticate(_this, _this->ppp->proxy_authen_resp);
127 return 0;
128 }
129
130 _this->state = PAP_STATE_STARTING;
131 return 0;
132 }
133
134 int
pap_stop(pap * _this)135 pap_stop(pap *_this)
136 {
137 _this->state = PAP_STATE_STOPPED;
138 _this->auth_id = -1;
139
140 #ifdef USE_NPPPD_RADIUS
141 if (_this->radctx != NULL) {
142 radius_cancel_request(_this->radctx);
143 _this->radctx = NULL;
144 }
145 #endif
146 return 0;
147 }
148
149 /** Receiving PAP packet */
150 int
pap_input(pap * _this,u_char * pktp,int lpktp)151 pap_input(pap *_this, u_char *pktp, int lpktp)
152 {
153 int code, id, length, len;
154 u_char *pktp1;
155 char name[MAX_USERNAME_LENGTH], password[MAX_PASSWORD_LENGTH];
156
157 if (_this->state == PAP_STATE_STOPPED ||
158 _this->state == PAP_STATE_INITIAL) {
159 pap_log(_this, LOG_ERR, "Received pap packet. But pap is "
160 "not started.");
161 return -1;
162 }
163 pktp1 = pktp;
164
165 GETCHAR(code, pktp1);
166 GETCHAR(id, pktp1);
167 GETSHORT(length, pktp1);
168
169 if (code != AUTHREQ) {
170 pap_log(_this, LOG_ERR, "%s: Received unknown code=%d",
171 __func__, code);
172 return -1;
173 }
174 if (lpktp < length) {
175 pap_log(_this, LOG_ERR, "%s: Received broken packet.",
176 __func__);
177 return -1;
178 }
179
180 /* retribute the username */
181 #define remlen (lpktp - (pktp1 - pktp))
182 if (remlen < 1)
183 goto fail;
184 GETCHAR(len, pktp1);
185 if (len <= 0)
186 goto fail;
187 if (remlen < len)
188 goto fail;
189 if (len > 0)
190 memcpy(name, pktp1, len);
191 name[len] = '\0';
192 pktp1 += len;
193
194 if (_this->state != PAP_STATE_STARTING) {
195 /*
196 * Receiving identical message again, it must be the message
197 * retransmit by the peer. Continue if the username is same.
198 */
199 if ((_this->state == PAP_STATE_AUTHENTICATING ||
200 _this->state == PAP_STATE_SENT_RESPONSE) &&
201 strcmp(_this->name, name) == 0) {
202 /* continue */
203 } else {
204 pap_log(_this, LOG_ERR,
205 "Received AuthReq is not same as before. "
206 "(%d,%s) != (%d,%s)", id, name, _this->auth_id,
207 _this->name);
208 _this->auth_id = id;
209 goto fail;
210 }
211 }
212 if (_this->state == PAP_STATE_AUTHENTICATING)
213 return 0;
214 _this->auth_id = id;
215 strlcpy(_this->name, name, sizeof(_this->name));
216
217 _this->state = PAP_STATE_AUTHENTICATING;
218
219 /* retribute the password */
220 if (remlen < 1)
221 goto fail;
222 GETCHAR(len, pktp1);
223 if (remlen < len)
224 goto fail;
225 if (len > 0)
226 memcpy(password, pktp1, len);
227
228 password[len] = '\0';
229 pap_authenticate(_this, password);
230
231 return 0;
232 fail:
233 pap_response(_this, 0, DEFAULT_FAILURE_MESSAGE);
234 return -1;
235 }
236
237 static void
pap_authenticate(pap * _this,const char * password)238 pap_authenticate(pap *_this, const char *password)
239 {
240 if (npppd_ppp_bind_realm(_this->ppp->pppd, _this->ppp, _this->name, 0)
241 == 0) {
242 if (!npppd_ppp_is_realm_ready(_this->ppp->pppd, _this->ppp)) {
243 pap_log(_this, LOG_INFO,
244 "username=\"%s\" realm is not ready.", _this->name);
245 goto fail;
246 /* NOTREACHED */
247 }
248 #if USE_NPPPD_RADIUS
249 if (npppd_ppp_is_realm_radius(_this->ppp->pppd, _this->ppp)) {
250 pap_radius_authenticate(_this, _this->name, password);
251 return;
252 /* NOTREACHED */
253 } else
254 #endif
255 if (npppd_ppp_is_realm_local(_this->ppp->pppd, _this->ppp)) {
256 pap_local_authenticate(_this, _this->name, password);
257 return;
258 /* NOTREACHED */
259 }
260 }
261 fail:
262 pap_response(_this, 0, DEFAULT_FAILURE_MESSAGE);
263 }
264
265 static void
pap_log(pap * _this,uint32_t prio,const char * fmt,...)266 pap_log(pap *_this, uint32_t prio, const char *fmt, ...)
267 {
268 char logbuf[BUFSIZ];
269 va_list ap;
270
271 va_start(ap, fmt);
272 snprintf(logbuf, sizeof(logbuf), "ppp id=%u layer=pap %s",
273 _this->ppp->id, fmt);
274 vlog_printf(prio, logbuf, ap);
275 va_end(ap);
276 }
277
278 static void
pap_response(pap * _this,int authok,const char * mes)279 pap_response(pap *_this, int authok, const char *mes)
280 {
281 int lpktp, lmes;
282 u_char *pktp, *pktp1;
283 const char *realm;
284
285 pktp = ppp_packetbuf(_this->ppp, PPP_PROTO_PAP) + HEADERLEN;
286 lpktp = _this->ppp->mru - HEADERLEN;
287 realm = npppd_ppp_get_realm_name(_this->ppp->pppd, _this->ppp);
288
289 pktp1 = pktp;
290 if (mes == NULL)
291 lmes = 0;
292 else
293 lmes = strlen(mes);
294 lmes = MINIMUM(lmes, lpktp - 1);
295
296 PUTCHAR(lmes, pktp1);
297 if (lmes > 0)
298 memcpy(pktp1, mes, lmes);
299 lpktp = lmes + 1;
300
301 if (authok)
302 ppp_output(_this->ppp, PPP_PROTO_PAP, AUTHACK, _this->auth_id,
303 pktp, lpktp);
304 else
305 ppp_output(_this->ppp, PPP_PROTO_PAP, AUTHNAK, _this->auth_id,
306 pktp, lpktp);
307
308 if (!authok) {
309 pap_log(_this, LOG_ALERT,
310 "logtype=Failure username=\"%s\" realm=%s", _this->name,
311 realm);
312 pap_stop(_this);
313 ppp_set_disconnect_cause(_this->ppp,
314 PPP_DISCON_AUTH_FAILED, PPP_PROTO_PAP, 1 /* peer */, NULL);
315 ppp_stop(_this->ppp, "Authentication Required");
316 } else {
317 strlcpy(_this->ppp->username, _this->name,
318 sizeof(_this->ppp->username));
319 pap_log(_this, LOG_INFO,
320 "logtype=Success username=\"%s\" realm=%s", _this->name,
321 realm);
322 pap_stop(_this);
323 ppp_auth_ok(_this->ppp);
324 /* reset the state to response request of retransmision. */
325 _this->state = PAP_STATE_SENT_RESPONSE;
326 }
327 }
328
329 static void
pap_local_authenticate(pap * _this,const char * username,const char * password)330 pap_local_authenticate(pap *_this, const char *username, const char *password)
331 {
332 int lpassword0;
333 char password0[MAX_PASSWORD_LENGTH];
334
335 lpassword0 = sizeof(password0);
336
337 if (npppd_get_user_password(_this->ppp->pppd, _this->ppp, username,
338 password0, &lpassword0) == 0) {
339 if (!strcmp(password0, password)) {
340 pap_response(_this, 1, DEFAULT_SUCCESS_MESSAGE);
341 return;
342 }
343 }
344 pap_response(_this, 0, DEFAULT_FAILURE_MESSAGE);
345 }
346
347 /***********************************************************************
348 * Proxy Authentication
349 ***********************************************************************/
350 int
pap_proxy_authen_prepare(pap * _this,dialin_proxy_info * dpi)351 pap_proxy_authen_prepare(pap *_this, dialin_proxy_info *dpi)
352 {
353
354 PAP_ASSERT(dpi->auth_type == PPP_AUTH_PAP);
355 PAP_ASSERT(_this->state == PAP_STATE_INITIAL);
356
357 _this->auth_id = dpi->auth_id;
358 if (strlen(dpi->username) >= sizeof(_this->name)) {
359 pap_log(_this, LOG_NOTICE,
360 "\"Proxy Authen Name\" is too long.");
361 return -1;
362 }
363
364 /* copy the authentication properties */
365 PAP_ASSERT(_this->ppp->proxy_authen_resp == NULL);
366 if ((_this->ppp->proxy_authen_resp = malloc(dpi->lauth_resp + 1)) ==
367 NULL) {
368 pap_log(_this, LOG_ERR, "malloc() failed in %s(): %m",
369 __func__);
370 return -1;
371 }
372 memcpy(_this->ppp->proxy_authen_resp, dpi->auth_resp,
373 dpi->lauth_resp);
374 _this->ppp->proxy_authen_resp[dpi->lauth_resp] = '\0';
375 strlcpy(_this->name, dpi->username, sizeof(_this->name));
376
377 _this->state = PAP_STATE_PROXY_AUTHENTICATION;
378
379 return 0;
380 }
381
382 #ifdef USE_NPPPD_RADIUS
383 static void
pap_radius_authenticate(pap * _this,const char * username,const char * password)384 pap_radius_authenticate(pap *_this, const char *username, const char *password)
385 {
386 void *radctx;
387 RADIUS_PACKET *radpkt;
388 MD5_CTX md5ctx;
389 int i, j, s_len, passlen;
390 u_char ra[16], digest[16], pass[128];
391 const char *s;
392 radius_req_setting *rad_setting = NULL;
393 char buf0[MAX_USERNAME_LENGTH];
394
395 if ((rad_setting = npppd_get_radius_auth_setting(_this->ppp->pppd,
396 _this->ppp)) == NULL)
397 goto fail;
398
399 if ((radpkt = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST))
400 == NULL)
401 goto fail;
402
403 if (radius_prepare(rad_setting, _this, &radctx, pap_radius_response)
404 != 0) {
405 radius_delete_packet(radpkt);
406 goto fail;
407 }
408
409 if (ppp_set_radius_attrs_for_authreq(_this->ppp, rad_setting, radpkt)
410 != 0)
411 goto fail;
412
413 if (radius_put_string_attr(radpkt, RADIUS_TYPE_USER_NAME,
414 npppd_ppp_get_username_for_auth(_this->ppp->pppd, _this->ppp,
415 username, buf0)) != 0)
416 goto fail;
417
418 if (_this->radctx != NULL)
419 radius_cancel_request(_this->radctx);
420
421 _this->radctx = radctx;
422
423 /* Create RADIUS User-Password Attribute (RFC 2865, 5.2.) */
424 s = radius_get_server_secret(_this->radctx);
425 s_len = strlen(s);
426
427 memset(pass, 0, sizeof(pass)); /* null padding */
428 passlen = MINIMUM(strlen(password), sizeof(pass));
429 memcpy(pass, password, passlen);
430 if ((passlen % 16) != 0)
431 passlen += 16 - (passlen % 16);
432
433 radius_get_authenticator(radpkt, ra);
434
435 MD5Init(&md5ctx);
436 MD5Update(&md5ctx, s, s_len);
437 MD5Update(&md5ctx, ra, 16);
438 MD5Final(digest, &md5ctx);
439
440 for (i = 0; i < 16; i++)
441 pass[i] ^= digest[i];
442
443 while (i < passlen) {
444 MD5Init(&md5ctx);
445 MD5Update(&md5ctx, s, s_len);
446 MD5Update(&md5ctx, &pass[i - 16], 16);
447 MD5Final(digest, &md5ctx);
448
449 for (j = 0; j < 16; j++, i++)
450 pass[i] ^= digest[j];
451 }
452
453 if (radius_put_raw_attr(radpkt, RADIUS_TYPE_USER_PASSWORD, pass,
454 passlen) != 0)
455 goto fail;
456
457 radius_request(_this->radctx, radpkt);
458
459 return;
460 fail:
461 if (_this->radctx != NULL)
462 radius_cancel_request(_this->radctx);
463 pap_log(_this, LOG_ERR, "%s() failed: %m", __func__);
464 pap_response(_this, 0, DEFAULT_ERROR_MESSAGE);
465
466 return;
467 }
468
469 static void
pap_radius_response(void * context,RADIUS_PACKET * pkt,int flags,RADIUS_REQUEST_CTX reqctx)470 pap_radius_response(void *context, RADIUS_PACKET *pkt, int flags,
471 RADIUS_REQUEST_CTX reqctx)
472 {
473 int code = -1;
474 const char *reason = NULL;
475 RADIUS_REQUEST_CTX radctx;
476 pap *_this;
477
478 _this = context;
479 radctx = _this->radctx;
480 _this->radctx = NULL; /* important */
481
482 if (pkt == NULL) {
483 if (flags & RADIUS_REQUEST_TIMEOUT)
484 reason = "timeout";
485 else if (flags & RADIUS_REQUEST_ERROR)
486 reason = strerror(errno);
487 else
488 reason = "error";
489 goto auth_failed;
490 }
491 code = radius_get_code(pkt);
492 if (code == RADIUS_CODE_ACCESS_REJECT) {
493 reason="reject";
494 goto auth_failed;
495 } else if (code != RADIUS_CODE_ACCESS_ACCEPT) {
496 reason="error";
497 goto auth_failed;
498 }
499 if ((flags & RADIUS_REQUEST_CHECK_AUTHENTICATOR_OK) == 0 &&
500 (flags & RADIUS_REQUEST_CHECK_AUTHENTICATOR_NO_CHECK) == 0) {
501 reason="bad_authenticator";
502 goto auth_failed;
503 }
504 if ((flags & RADIUS_REQUEST_CHECK_MSG_AUTHENTICATOR_OK) == 0 &&
505 (flags & RADIUS_REQUEST_CHECK_NO_MSG_AUTHENTICATOR) == 0) {
506 reason="bad_authenticator";
507 goto auth_failed;
508 }
509 /* Authentication succeeded */
510 pap_response(_this, 1, DEFAULT_SUCCESS_MESSAGE);
511 ppp_process_radius_attrs(_this->ppp, pkt);
512
513 return;
514 auth_failed:
515 /* Authentication failure */
516 pap_log(_this, LOG_WARNING, "Radius authentication request failed: %s",
517 reason);
518 /* log reply messages from radius server */
519 if (pkt != NULL) {
520 char radmsg[255], vissed[1024];
521 size_t rmlen = 0;
522 if ((radius_get_raw_attr(pkt, RADIUS_TYPE_REPLY_MESSAGE,
523 radmsg, &rmlen)) == 0) {
524 if (rmlen != 0) {
525 strvisx(vissed, radmsg, rmlen, VIS_WHITE);
526 pap_log(_this, LOG_WARNING,
527 "Radius reply message: %s", vissed);
528 }
529 }
530 }
531
532 pap_response(_this, 0, DEFAULT_FAILURE_MESSAGE);
533 }
534 #endif
535