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