1 /* $OpenBSD: npppd_auth.c,v 1.23 2024/02/26 10:42:05 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 /**@file authentication realm */
29 /* $Id: npppd_auth.c,v 1.23 2024/02/26 10:42:05 yasuoka Exp $ */
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <net/if_dl.h>
35 #include <arpa/inet.h>
36 #include <stdio.h>
37 #include <syslog.h>
38 #include <string.h>
39 #include <time.h>
40 #include <event.h>
41 #include <stdarg.h>
42 #include <stdlib.h>
43 #include <netdb.h>
44 #include <errno.h>
45
46 #include "debugutil.h"
47 #include "npppd_local.h"
48 #include "npppd_auth.h"
49 #include "net_utils.h"
50
51 #include "npppd_auth_local.h"
52 #include "npppd_radius.h"
53
54 /**
55 * Create a npppd_auth_base object.
56 * @param auth_type the authentication type.
57 * specify {@link ::NPPPD_AUTH_TYPE_LOCAL} to authenticate by the local
58 * file, or specify {@link ::NPPPD_AUTH_TYPE_RADIUS} for RADIUS
59 * authentication.
60 * @param name the configuration name
61 * @param _npppd the parent {@link ::npppd} object
62 * @see ::NPPPD_AUTH_TYPE_LOCAL
63 * @see ::NPPPD_AUTH_TYPE_RADIUS
64 * @return The pointer to the {@link ::npppd_auth_base} object will be returned
65 * in case success otherwise NULL will be returned.
66 */
67 npppd_auth_base *
npppd_auth_create(int auth_type,const char * name,void * _npppd)68 npppd_auth_create(int auth_type, const char *name, void *_npppd)
69 {
70 npppd_auth_base *base;
71
72 NPPPD_AUTH_ASSERT(name != NULL);
73
74 switch (auth_type) {
75 case NPPPD_AUTH_TYPE_LOCAL:
76 if ((base = calloc(1, sizeof(npppd_auth_local))) != NULL) {
77 base->type = NPPPD_AUTH_TYPE_LOCAL;
78 strlcpy(base->name, name, sizeof(base->name));
79 base->npppd = _npppd;
80
81 return base;
82 }
83 break;
84
85 #ifdef USE_NPPPD_RADIUS
86 case NPPPD_AUTH_TYPE_RADIUS:
87 if ((base = calloc(1, sizeof(npppd_auth_radius))) != NULL) {
88 npppd_auth_radius *_this = (npppd_auth_radius *)base;
89 base->type = NPPPD_AUTH_TYPE_RADIUS;
90 strlcpy(base->name, name, sizeof(base->name));
91 base->npppd = _npppd;
92 if ((_this->rad_auth_setting =
93 radius_req_setting_create()) == NULL)
94 goto radius_fail;
95 if ((_this->rad_acct_setting =
96 radius_req_setting_create()) == NULL)
97 goto radius_fail;
98
99 return base;
100 radius_fail:
101 if (_this->rad_auth_setting != NULL)
102 radius_req_setting_destroy(
103 _this->rad_auth_setting);
104 if (_this->rad_acct_setting != NULL)
105 radius_req_setting_destroy(
106 _this->rad_acct_setting);
107 free(base);
108 return NULL;
109 }
110
111 break;
112 #endif
113
114 default:
115 NPPPD_AUTH_ASSERT(0);
116 break;
117 }
118
119 return NULL;
120 }
121
122 /**
123 * Call this function to make the object unusable.
124 * <p>
125 * {@link ::npppd_auth_base} objects is referred by the {@link ::npppd_ppp}
126 * object. After this function is called, npppd will disconnect the PPP
127 * links that refers the object, it will call {@link ::npppd_auth_destroy()}
128 * when all the references to the object are released.</p>
129 */
130 void
npppd_auth_dispose(npppd_auth_base * base)131 npppd_auth_dispose(npppd_auth_base *base)
132 {
133
134 base->disposing = 1;
135
136 return;
137 }
138
139 /** Destroy the {@link ::npppd_auth_base} object. */
140 void
npppd_auth_destroy(npppd_auth_base * base)141 npppd_auth_destroy(npppd_auth_base *base)
142 {
143
144 if (base->disposing == 0)
145 npppd_auth_dispose(base);
146
147 npppd_auth_base_log(base, LOG_INFO, "Finalized");
148
149 switch(base->type) {
150 case NPPPD_AUTH_TYPE_LOCAL:
151 memset(base, 0, sizeof(npppd_auth_local));
152 break;
153
154 #ifdef USE_NPPPD_RADIUS
155 case NPPPD_AUTH_TYPE_RADIUS:
156 {
157 npppd_auth_radius *_this = (npppd_auth_radius *)base;
158 if (_this->rad_auth_setting != NULL)
159 radius_req_setting_destroy(_this->rad_auth_setting);
160 _this->rad_auth_setting = NULL;
161 if (_this->rad_acct_setting != NULL)
162 radius_req_setting_destroy(_this->rad_acct_setting);
163 _this->rad_acct_setting = NULL;
164 memset(base, 0, sizeof(npppd_auth_local));
165 break;
166 }
167 #endif
168 }
169 free(base);
170
171 return;
172 }
173
174 /** Reload the configuration */
175 int
npppd_auth_reload(npppd_auth_base * base)176 npppd_auth_reload(npppd_auth_base *base)
177 {
178 struct authconf *auth;
179
180 TAILQ_FOREACH(auth, &base->npppd->conf.authconfs, entry) {
181 if (strcmp(auth->name, base->name) == 0)
182 break;
183 }
184 if (auth == NULL)
185 return 1;
186
187 base->pppsuffix[0] = '\0';
188 if (auth->username_suffix != NULL)
189 strlcpy(base->pppsuffix, auth->username_suffix,
190 sizeof(base->pppsuffix));
191 base->eap_capable = auth->eap_capable;
192 base->strip_nt_domain = auth->strip_nt_domain;
193 base->strip_atmark_realm = auth->strip_atmark_realm;
194 base->has_users_file = 0;
195 base->radius_ready = 0;
196 base->user_max_session = auth->user_max_session;
197
198 if (strlen(auth->users_file_path) > 0) {
199 strlcpy(base->users_file_path, auth->users_file_path,
200 sizeof(base->users_file_path));
201 base->has_users_file = 1;
202 } else {
203 if (base->type == NPPPD_AUTH_TYPE_LOCAL) {
204 npppd_auth_base_log(base,
205 LOG_WARNING, "missing users_file property.");
206 goto fail;
207 }
208 }
209
210 switch (base->type) {
211 #ifdef USE_NPPPD_RADIUS
212 case NPPPD_AUTH_TYPE_RADIUS:
213 if (npppd_auth_radius_reload(base, auth) != 0)
214 goto fail;
215 break;
216 #endif
217 }
218 base->initialized = 1;
219
220 return 0;
221
222 fail:
223 base->initialized = 0;
224 base->has_users_file = 0;
225 base->radius_ready = 0;
226
227 return 1;
228 }
229
230 /**
231 * This function gets specified user's password. The value 0 is returned
232 * if the call succeeds.
233 *
234 * @param username username which gets the password
235 * @param password buffers which stores the password
236 * Specify NULL if you want to known the length of
237 * the password only.
238 * @param lppassword pointer which indicates the length of
239 * the buffer which stores the password.
240 * @return A value 1 is returned if user is unknown. A value 2 is returned
241 * if password buffer is sufficient. A negative value is
242 * returned if other error occurred.
243 */
244 int
npppd_auth_get_user_password(npppd_auth_base * base,const char * username,char * password,int * plpassword)245 npppd_auth_get_user_password(npppd_auth_base *base,
246 const char *username, char *password, int *plpassword)
247 {
248 int retval, sz, lpassword;
249 npppd_auth_user *user;
250
251 NPPPD_AUTH_ASSERT(base != NULL);
252 NPPPD_AUTH_DBG((base, LOG_DEBUG, "%s(%s)", __func__, username));
253
254 user = NULL;
255 retval = 0;
256 if (base->has_users_file == 0) {
257 retval = -1;
258 goto out;
259 }
260 if ((user = npppd_auth_get_user(base, username)) == NULL) {
261 retval = 1;
262 goto out;
263 }
264 if (password == NULL && plpassword == NULL) {
265 retval = 0;
266 goto out;
267 }
268 if (plpassword == NULL) {
269 retval = -1;
270 goto out;
271 }
272 lpassword = strlen(user->password) + 1;
273 sz = *plpassword;
274 *plpassword = lpassword;
275 if (password == NULL) {
276 retval = 0;
277 goto out;
278 }
279 if (sz < lpassword) {
280 retval = 2;
281 goto out;
282 }
283 strlcpy(password, user->password, sz);
284 out:
285 free(user);
286
287 return retval;
288 }
289
290 /**
291 * This function gets specified users' Framed-IP-{Address,Netmask}.
292 * The value 0 is returned if the call succeeds.
293 * <p>
294 * Because authentication database is updated at any time, the password is
295 * possible to be inconsistent if this function is not called immediately
296 * after authentication. So this function is called immediately after
297 * authentication. </p>
298 * @param username username which gets the password
299 * @param ip4address pointer which indicates struct in_addr which
300 * stores the Framed-IP-Address
301 * @param ip4netmask pointer which indicates struct in_addr which
302 * stores Framed-IP-Netmask
303 */
304 int
npppd_auth_get_framed_ip(npppd_auth_base * base,const char * username,struct in_addr * ip4address,struct in_addr * ip4netmask)305 npppd_auth_get_framed_ip(npppd_auth_base *base, const char *username,
306 struct in_addr *ip4address, struct in_addr *ip4netmask)
307 {
308 npppd_auth_user *user;
309
310 NPPPD_AUTH_ASSERT(base != NULL);
311 NPPPD_AUTH_DBG((base, LOG_DEBUG, "%s(%s)", __func__, username));
312 if (base->has_users_file == 0)
313 return -1;
314
315 if ((user = npppd_auth_get_user(base, username)) == NULL)
316 return 1;
317
318 if (user->framed_ip_address.s_addr != 0) {
319 *ip4address = user->framed_ip_address;
320 if (ip4netmask != NULL)
321 *ip4netmask = user->framed_ip_netmask;
322
323 free(user);
324 return 0;
325 }
326 free(user);
327
328 return 1;
329 }
330
331 /**
332 * Retribute "Calling-Number" attribute of the user from the realm.
333 *
334 * @param username Username.
335 * @param number Pointer to the space for the Calling-Number. This
336 * can be NULL in case retributing the Calling-Number only.
337 * @param plnumber Pointer to the length of the space for the
338 * Calling-Number.
339 * @return 0 if the Calling-Number attribute is successfully retributed.
340 * 1 if the user has no Calling-Number attribute. return -1 if the realm
341 * doesn't have user attributes or other errors. return 2 if the space
342 * is not enough.
343 */
344 int
npppd_auth_get_calling_number(npppd_auth_base * base,const char * username,char * number,int * plnumber)345 npppd_auth_get_calling_number(npppd_auth_base *base, const char *username,
346 char *number, int *plnumber)
347 {
348 int retval, lcallnum, sz;
349 npppd_auth_user *user;
350
351 user = NULL;
352 retval = 0;
353 if (base->has_users_file == 0)
354 return -1;
355
356 if ((user = npppd_auth_get_user(base, username)) == NULL)
357 return 1;
358
359 if (number == NULL && plnumber == NULL) {
360 retval = 0;
361 goto out;
362 }
363 if (plnumber == NULL) {
364 retval = -1;
365 goto out;
366 }
367 lcallnum = strlen(user->calling_number) + 1;
368 sz = *plnumber;
369 *plnumber = lcallnum;
370 if (sz < lcallnum) {
371 retval = 2;
372 goto out;
373 }
374 strlcpy(number, user->calling_number, sz);
375
376 out:
377 free(user);
378
379 return retval;
380 }
381
382 int
npppd_auth_get_type(npppd_auth_base * base)383 npppd_auth_get_type(npppd_auth_base *base)
384 {
385 return base->type;
386 }
387
388 int
npppd_auth_is_usable(npppd_auth_base * base)389 npppd_auth_is_usable(npppd_auth_base *base)
390 {
391 return (base->initialized != 0 && base->disposing == 0)? 1 : 0;
392 }
393
394 int
npppd_auth_is_ready(npppd_auth_base * base)395 npppd_auth_is_ready(npppd_auth_base *base)
396 {
397 if (!npppd_auth_is_usable(base))
398 return 0;
399
400 switch(base->type) {
401 case NPPPD_AUTH_TYPE_LOCAL:
402 return (base->has_users_file)? 1 : 0;
403 /* NOTREACHED */
404
405 case NPPPD_AUTH_TYPE_RADIUS:
406 return (base->has_users_file != 0 ||
407 base->radius_ready != 0)? 1 : 0;
408 /* NOTREACHED */
409 }
410 NPPPD_AUTH_ASSERT(0);
411
412 return 0;
413 }
414
415 int
npppd_auth_is_disposing(npppd_auth_base * base)416 npppd_auth_is_disposing(npppd_auth_base *base)
417 {
418 return (base->disposing != 0)? 1 : 0;
419 }
420
421 int
npppd_auth_is_eap_capable(npppd_auth_base * base)422 npppd_auth_is_eap_capable(npppd_auth_base *base)
423 {
424 return (base->eap_capable != 0)? 1 : 0;
425 }
426
427 const char *
npppd_auth_get_name(npppd_auth_base * base)428 npppd_auth_get_name(npppd_auth_base *base)
429 {
430 return base->name;
431 }
432
433 const char *
npppd_auth_get_suffix(npppd_auth_base * base)434 npppd_auth_get_suffix(npppd_auth_base *base)
435 {
436 return base->pppsuffix;
437 }
438
439 const char *
npppd_auth_username_for_auth(npppd_auth_base * base,const char * username,char * username_buffer)440 npppd_auth_username_for_auth(npppd_auth_base *base, const char *username,
441 char *username_buffer)
442 {
443 const char *u0;
444 char *atmark, *u1;
445
446 u0 = NULL;
447 if (base->strip_nt_domain != 0) {
448 if ((u0 = strchr(username, '\\')) != NULL)
449 u0++;
450 }
451 if (u0 == NULL)
452 u0 = username;
453 u1 = username_buffer;
454 if (username_buffer != u0)
455 memmove(username_buffer, u0, MINIMUM(strlen(u0) + 1,
456 MAX_USERNAME_LENGTH));
457 if (base->strip_atmark_realm != 0) {
458 if ((atmark = strrchr(u1, '@')) != NULL)
459 *atmark = '\0';
460 }
461
462 return username_buffer;
463 }
464
465 int
npppd_auth_user_session_unlimited(npppd_auth_base * _this)466 npppd_auth_user_session_unlimited(npppd_auth_base *_this)
467 {
468 return (_this->user_max_session == 0) ? 1 : 0;
469 }
470
471 int
npppd_check_auth_user_max_session(npppd_auth_base * _this,int count)472 npppd_check_auth_user_max_session(npppd_auth_base *_this, int count)
473 {
474 if (!npppd_auth_user_session_unlimited(_this) &&
475 _this->user_max_session <= count)
476 return 1;
477 else
478 return 0;
479 }
480
481 /***********************************************************************
482 * Account list related functions
483 ***********************************************************************/
484 static npppd_auth_user *
npppd_auth_get_user(npppd_auth_base * base,const char * username)485 npppd_auth_get_user(npppd_auth_base *base, const char *username)
486 {
487 int lsuffix, lusername;
488 const char *un;
489 char buf[MAX_USERNAME_LENGTH];
490 npppd_auth_user *u;
491
492 un = username;
493 lsuffix = strlen(base->pppsuffix);
494 lusername = strlen(username);
495 if (lsuffix > 0 && lusername > lsuffix &&
496 strcmp(username + lusername - lsuffix, base->pppsuffix) == 0 &&
497 lusername - lsuffix < sizeof(buf)) {
498 memcpy(buf, username, lusername - lsuffix);
499 buf[lusername - lsuffix] = '\0';
500 un = buf;
501 }
502
503 if (priv_get_user_info(base->users_file_path, un, &u) == 0)
504 return u;
505
506 return NULL;
507 }
508
509 #ifdef USE_NPPPD_RADIUS
510 /***********************************************************************
511 * RADIUS
512 ***********************************************************************/
513 /** reload the configuration of RADIUS authentication realm */
514 static int
npppd_auth_radius_reload(npppd_auth_base * base,struct authconf * auth)515 npppd_auth_radius_reload(npppd_auth_base *base, struct authconf *auth)
516 {
517 npppd_auth_radius *_this = (npppd_auth_radius *)base;
518 radius_req_setting *rad;
519 struct radserver *server;
520 int i, nauth, nacct;
521
522 _this->rad_auth_setting->timeout =
523 (auth->data.radius.auth.timeout == 0)
524 ? DEFAULT_RADIUS_TIMEOUT : auth->data.radius.auth.timeout;
525 _this->rad_acct_setting->timeout =
526 (auth->data.radius.acct.timeout == 0)
527 ? DEFAULT_RADIUS_TIMEOUT : auth->data.radius.acct.timeout;
528
529
530 _this->rad_auth_setting->max_tries =
531 (auth->data.radius.auth.max_tries == 0)
532 ? DEFAULT_RADIUS_MAX_TRIES : auth->data.radius.auth.max_tries;
533 _this->rad_acct_setting->max_tries =
534 (auth->data.radius.acct.max_tries == 0)
535 ? DEFAULT_RADIUS_MAX_TRIES : auth->data.radius.acct.max_tries;
536
537 _this->rad_auth_setting->max_failovers =
538 (auth->data.radius.auth.max_failovers == 0)
539 ? DEFAULT_RADIUS_MAX_FAILOVERS
540 : auth->data.radius.auth.max_failovers;
541 _this->rad_acct_setting->max_failovers =
542 (auth->data.radius.acct.max_failovers == 0)
543 ? DEFAULT_RADIUS_MAX_FAILOVERS
544 : auth->data.radius.acct.max_failovers;
545
546 _this->rad_acct_setting->curr_server =
547 _this->rad_auth_setting->curr_server = 0;
548
549 /* load configs for authentication server */
550 rad = _this->rad_auth_setting;
551 for (i = 0; i < countof(rad->server); i++)
552 memset(&rad->server[i], 0, sizeof(rad->server[0]));
553 i = 0;
554 TAILQ_FOREACH(server, &auth->data.radius.auth.servers, entry) {
555 if (i >= countof(rad->server))
556 break;
557 memcpy(&rad->server[i].peer, &server->address,
558 server->address.ss_len);
559 if (((struct sockaddr_in *)&rad->server[i].peer)->sin_port
560 == 0)
561 ((struct sockaddr_in *)&rad->server[i].peer)->sin_port
562 = htons(DEFAULT_RADIUS_AUTH_PORT);
563 strlcpy(rad->server[i].secret, server->secret,
564 sizeof(rad->server[i].secret));
565 rad->server[i].enabled = 1;
566 i++;
567 }
568 nauth = i;
569
570 /* load configs for accounting server */
571 rad = _this->rad_acct_setting;
572 for (i = 0; i < countof(rad->server); i++)
573 memset(&rad->server[i], 0, sizeof(rad->server[0]));
574 i = 0;
575 TAILQ_FOREACH(server, &auth->data.radius.acct.servers, entry) {
576 if (i >= countof(rad->server))
577 break;
578 memcpy(&rad->server[i].peer, &server->address,
579 server->address.ss_len);
580 if (((struct sockaddr_in *)&rad->server[i].peer)->sin_port
581 == 0)
582 ((struct sockaddr_in *)&rad->server[i].peer)->sin_port
583 = htons(DEFAULT_RADIUS_ACCT_PORT);
584 strlcpy(rad->server[i].secret, server->secret,
585 sizeof(rad->server[i].secret));
586 rad->server[i].enabled = 1;
587 i++;
588 }
589 nacct = i;
590
591 for (i = 0; i < countof(_this->rad_auth_setting->server); i++) {
592 if (_this->rad_auth_setting->server[i].enabled)
593 base->radius_ready = 1;
594 }
595
596 npppd_auth_base_log(&_this->nar_base, LOG_INFO,
597 "Loaded configuration. %d authentication server%s, %d accounting "
598 "server%s.",
599 nauth, (nauth > 1)? "s" : "", nacct, (nacct > 1)? "s" : "");
600
601 if (nacct > 0 && _this->rad_acct_on == 0) {
602 radius_acct_on(base->npppd, _this->rad_acct_setting);
603 _this->rad_acct_on = 1;
604 }
605
606 return 0;
607 }
608
609 /**
610 * Get {@link ::radius_req_setting} for RADIUS authentication of specified
611 * {@link ::npppd_auth_base} object.
612 */
613 void *
npppd_auth_radius_get_radius_auth_setting(npppd_auth_radius * _this)614 npppd_auth_radius_get_radius_auth_setting(npppd_auth_radius *_this)
615 {
616 return _this->rad_auth_setting;
617 }
618
619 /**
620 * Get {@link ::radius_req_setting} for RADIUS accounting of specified
621 * {@link ::npppd_auth_base} object.
622 */
623 void *
npppd_auth_radius_get_radius_acct_setting(npppd_auth_radius * _this)624 npppd_auth_radius_get_radius_acct_setting(npppd_auth_radius *_this)
625 {
626 return _this->rad_acct_setting;
627 }
628
629 #endif
630
631 /***********************************************************************
632 * Helper functions
633 ***********************************************************************/
634 /** Log it which starts the label based on this instance. */
635 static int
npppd_auth_base_log(npppd_auth_base * _this,int prio,const char * fmt,...)636 npppd_auth_base_log(npppd_auth_base *_this, int prio, const char *fmt, ...)
637 {
638 int status;
639 char logbuf[BUFSIZ];
640 va_list ap;
641
642 NPPPD_AUTH_ASSERT(_this != NULL);
643 va_start(ap, fmt);
644 snprintf(logbuf, sizeof(logbuf), "realm name=%s %s",
645 _this->name, fmt);
646 status = vlog_printf(prio, logbuf, ap);
647 va_end(ap);
648
649 return status;
650 }
651