File: | src/usr.sbin/npppd/npppd/pap.c |
Warning: | line 479, column 2 Value stored to 'radctx' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: pap.c,v 1.12 2021/03/29 03:54:39 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.12 2021/03/29 03:54:39 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(*__errno()).h> |
47 | #include <vis.h> |
48 | |
49 | #include "npppd.h" |
50 | #include "ppp.h" |
51 | |
52 | #ifdef USE_NPPPD_RADIUS1 |
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 AUTHREQ0x01 0x01 |
61 | #define AUTHACK0x02 0x02 |
62 | #define AUTHNAK0x03 0x03 |
63 | |
64 | #define PAP_STATE_INITIAL0 0 |
65 | #define PAP_STATE_STARTING1 1 |
66 | #define PAP_STATE_AUTHENTICATING2 2 |
67 | #define PAP_STATE_SENT_RESPONSE3 3 |
68 | #define PAP_STATE_STOPPED4 4 |
69 | #define PAP_STATE_PROXY_AUTHENTICATION5 5 |
70 | |
71 | #define DEFAULT_SUCCESS_MESSAGE"OK" "OK" |
72 | #define DEFAULT_FAILURE_MESSAGE"Unknown username or password" "Unknown username or password" |
73 | #define DEFAULT_ERROR_MESSAGE"Unknown failure" "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(&__sF[2]), \ |
80 | "\nASSERT(" #cond ") failed on %s() at %s:%d.\n"\ |
81 | , __func__, __FILE__"/usr/src/usr.sbin/npppd/npppd/pap.c", __LINE__81); \ |
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)__attribute__((__format__ (__printf__, 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_RADIUS1 |
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 |
112 | pap_init(pap *_this, npppd_ppp *ppp) |
113 | { |
114 | _this->ppp = ppp; |
115 | _this->state = PAP_STATE_INITIAL0; |
116 | _this->auth_id = -1; |
117 | } |
118 | |
119 | int |
120 | pap_start(pap *_this) |
121 | { |
122 | pap_log(_this, LOG_DEBUG7, "%s", __func__); |
123 | |
124 | if (_this->state == PAP_STATE_PROXY_AUTHENTICATION5) { |
125 | _this->state = PAP_STATE_AUTHENTICATING2; |
126 | pap_authenticate(_this, _this->ppp->proxy_authen_resp); |
127 | return 0; |
128 | } |
129 | |
130 | _this->state = PAP_STATE_STARTING1; |
131 | return 0; |
132 | } |
133 | |
134 | int |
135 | pap_stop(pap *_this) |
136 | { |
137 | _this->state = PAP_STATE_STOPPED4; |
138 | _this->auth_id = -1; |
139 | |
140 | #ifdef USE_NPPPD_RADIUS1 |
141 | if (_this->radctx != NULL((void *)0)) { |
142 | radius_cancel_request(_this->radctx); |
143 | _this->radctx = NULL((void *)0); |
144 | } |
145 | #endif |
146 | return 0; |
147 | } |
148 | |
149 | /** Receiving PAP packet */ |
150 | int |
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_LENGTH256], password[MAX_PASSWORD_LENGTH256]; |
156 | |
157 | if (_this->state == PAP_STATE_STOPPED4 || |
158 | _this->state == PAP_STATE_INITIAL0) { |
159 | pap_log(_this, LOG_ERR3, "Received pap packet. But pap is " |
160 | "not started."); |
161 | return -1; |
162 | } |
163 | pktp1 = pktp; |
164 | |
165 | GETCHAR(code, pktp1){ (code) = *(pktp1)++; }; |
166 | GETCHAR(id, pktp1){ (id) = *(pktp1)++; }; |
167 | GETSHORT(length, pktp1){ (length) = *(pktp1)++ << 8; (length) |= *(pktp1)++; }; |
168 | |
169 | if (code != AUTHREQ0x01) { |
170 | pap_log(_this, LOG_ERR3, "%s: Received unknown code=%d", |
171 | __func__, code); |
172 | return -1; |
173 | } |
174 | if (lpktp < length) { |
175 | pap_log(_this, LOG_ERR3, "%s: Received broken packet.", |
176 | __func__); |
177 | return -1; |
178 | } |
179 | |
180 | /* retribute the username */ |
181 | #define remlen(lpktp - (pktp1 - pktp)) (lpktp - (pktp1 - pktp)) |
182 | if (remlen(lpktp - (pktp1 - pktp)) < 1) |
183 | goto fail; |
184 | GETCHAR(len, pktp1){ (len) = *(pktp1)++; }; |
185 | if (len <= 0) |
186 | goto fail; |
187 | if (remlen(lpktp - (pktp1 - pktp)) < 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_STARTING1) { |
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_AUTHENTICATING2 || |
200 | _this->state == PAP_STATE_SENT_RESPONSE3) && |
201 | strcmp(_this->name, name) == 0) { |
202 | /* continue */ |
203 | } else { |
204 | pap_log(_this, LOG_ERR3, |
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_AUTHENTICATING2) |
213 | return 0; |
214 | _this->auth_id = id; |
215 | strlcpy(_this->name, name, sizeof(_this->name)); |
216 | |
217 | _this->state = PAP_STATE_AUTHENTICATING2; |
218 | |
219 | /* retribute the password */ |
220 | if (remlen(lpktp - (pktp1 - pktp)) < 1) |
221 | goto fail; |
222 | GETCHAR(len, pktp1){ (len) = *(pktp1)++; }; |
223 | if (remlen(lpktp - (pktp1 - pktp)) < 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"Unknown username or password"); |
234 | return -1; |
235 | } |
236 | |
237 | static void |
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_INFO6, |
244 | "username=\"%s\" realm is not ready.", _this->name); |
245 | goto fail; |
246 | /* NOTREACHED */ |
247 | } |
248 | #if USE_NPPPD_RADIUS1 |
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"Unknown username or password"); |
263 | } |
264 | |
265 | static void |
266 | pap_log(pap *_this, uint32_t prio, const char *fmt, ...) |
267 | { |
268 | char logbuf[BUFSIZ1024]; |
269 | va_list ap; |
270 | |
271 | va_start(ap, fmt)__builtin_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)__builtin_va_end(ap); |
276 | } |
277 | |
278 | static void |
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_PAP0xC023) + HEADERLEN4; |
286 | lpktp = _this->ppp->mru - HEADERLEN4; |
287 | realm = npppd_ppp_get_realm_name(_this->ppp->pppd, _this->ppp); |
288 | |
289 | pktp1 = pktp; |
290 | if (mes == NULL((void *)0)) |
291 | lmes = 0; |
292 | else |
293 | lmes = strlen(mes); |
294 | lmes = MINIMUM(lmes, lpktp - 1)(((lmes) < (lpktp - 1)) ? (lmes) : (lpktp - 1)); |
295 | |
296 | PUTCHAR(lmes, pktp1){ *(pktp1)++ = (u_char) (lmes); }; |
297 | if (lmes > 0) |
298 | memcpy(pktp1, mes, lmes); |
299 | lpktp = lmes + 1; |
300 | |
301 | if (authok) |
302 | ppp_output(_this->ppp, PPP_PROTO_PAP0xC023, AUTHACK0x02, _this->auth_id, |
303 | pktp, lpktp); |
304 | else |
305 | ppp_output(_this->ppp, PPP_PROTO_PAP0xC023, AUTHNAK0x03, _this->auth_id, |
306 | pktp, lpktp); |
307 | |
308 | if (!authok) { |
309 | pap_log(_this, LOG_ALERT1, |
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_PAP0xC023, 1 /* peer */, NULL((void *)0)); |
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_INFO6, |
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_RESPONSE3; |
326 | } |
327 | } |
328 | |
329 | static void |
330 | pap_local_authenticate(pap *_this, const char *username, const char *password) |
331 | { |
332 | int lpassword0; |
333 | char password0[MAX_PASSWORD_LENGTH256]; |
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"OK"); |
341 | return; |
342 | } |
343 | } |
344 | pap_response(_this, 0, DEFAULT_FAILURE_MESSAGE"Unknown username or password"); |
345 | } |
346 | |
347 | /*********************************************************************** |
348 | * Proxy Authentication |
349 | ***********************************************************************/ |
350 | int |
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_NOTICE5, |
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((void *)0)) { |
368 | pap_log(_this, LOG_ERR3, "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_AUTHENTICATION5; |
378 | |
379 | return 0; |
380 | } |
381 | |
382 | #ifdef USE_NPPPD_RADIUS1 |
383 | static void |
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((void *)0); |
393 | char buf0[MAX_USERNAME_LENGTH256]; |
394 | |
395 | if ((rad_setting = npppd_get_radius_auth_setting(_this->ppp->pppd, |
396 | _this->ppp)) == NULL((void *)0)) |
397 | goto fail; |
398 | |
399 | if ((radpkt = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST1)) |
400 | == NULL((void *)0)) |
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_NAME1, |
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((void *)0)) |
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))(((strlen(password)) < (sizeof(pass))) ? (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_PASSWORD2, pass, |
454 | passlen) != 0) |
455 | goto fail; |
456 | |
457 | radius_request(_this->radctx, radpkt); |
458 | |
459 | return; |
460 | fail: |
461 | if (_this->radctx != NULL((void *)0)) |
462 | radius_cancel_request(_this->radctx); |
463 | pap_log(_this, LOG_ERR3, "%s() failed: %m", __func__); |
464 | pap_response(_this, 0, DEFAULT_ERROR_MESSAGE"Unknown failure"); |
465 | |
466 | return; |
467 | } |
468 | |
469 | static void |
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((void *)0); |
475 | RADIUS_REQUEST_CTX radctx; |
476 | pap *_this; |
477 | |
478 | _this = context; |
479 | radctx = _this->radctx; |
Value stored to 'radctx' is never read | |
480 | _this->radctx = NULL((void *)0); /* important */ |
481 | |
482 | if (pkt == NULL((void *)0)) { |
483 | if (flags & RADIUS_REQUEST_TIMEOUT0x0002) |
484 | reason = "timeout"; |
485 | else if (flags & RADIUS_REQUEST_ERROR0x0001) |
486 | reason = strerror(errno(*__errno())); |
487 | else |
488 | reason = "error"; |
489 | goto auth_failed; |
490 | } |
491 | code = radius_get_code(pkt); |
492 | if (code == RADIUS_CODE_ACCESS_REJECT3) { |
493 | reason="reject"; |
494 | goto auth_failed; |
495 | } else if (code != RADIUS_CODE_ACCESS_ACCEPT2) { |
496 | reason="error"; |
497 | goto auth_failed; |
498 | } |
499 | if ((flags & RADIUS_REQUEST_CHECK_AUTHENTICATOR_OK0x0010) == 0 && |
500 | (flags & RADIUS_REQUEST_CHECK_AUTHENTICATOR_NO_CHECK0x0020) == 0) { |
501 | reason="bad_authenticator"; |
502 | goto auth_failed; |
503 | } |
504 | /* Authentication succeeded */ |
505 | pap_response(_this, 1, DEFAULT_SUCCESS_MESSAGE"OK"); |
506 | ppp_process_radius_framed_ip(_this->ppp, pkt); |
507 | |
508 | return; |
509 | auth_failed: |
510 | /* Authentication failure */ |
511 | pap_log(_this, LOG_WARNING4, "Radius authentication request failed: %s", |
512 | reason); |
513 | /* log reply messages from radius server */ |
514 | if (pkt != NULL((void *)0)) { |
515 | char radmsg[255], vissed[1024]; |
516 | size_t rmlen = 0; |
517 | if ((radius_get_raw_attr(pkt, RADIUS_TYPE_REPLY_MESSAGE18, |
518 | radmsg, &rmlen)) == 0) { |
519 | if (rmlen != 0) { |
520 | strvisx(vissed, radmsg, rmlen, VIS_WHITE(0x04 | 0x08 | 0x10)); |
521 | pap_log(_this, LOG_WARNING4, |
522 | "Radius reply message: %s", vissed); |
523 | } |
524 | } |
525 | } |
526 | |
527 | pap_response(_this, 0, DEFAULT_FAILURE_MESSAGE"Unknown username or password"); |
528 | } |
529 | #endif |