mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-02-10 00:37:00 +08:00
Separated accounting from authentication.
This commit is contained in:
@@ -40,6 +40,17 @@ auth = "plain[./sample.passwd]"
|
||||
#enable-auth = gssapi
|
||||
#enable-auth = "gssapi[keytab:/etc/key.tab]"
|
||||
|
||||
# Accounting methods available:
|
||||
# pam: can only be combined with PAM authentication method, it provides
|
||||
# a session opened using PAM.
|
||||
#
|
||||
# radius: can be combined with any authentication method, it provides
|
||||
# radius accounting to available users (see also stats-report-time).
|
||||
#
|
||||
# Only one accounting method can be specified.
|
||||
#acct = "pam"
|
||||
#acct = "radius[/etc/radiusclient/radiusclient.conf]"
|
||||
|
||||
# Whether to enable seccomp/Linux namespaces worker isolation. That restricts the number of
|
||||
# system calls allowed to a worker process, in order to reduce damage from a
|
||||
# bug in the worker process. It is available on Linux systems at a performance cost.
|
||||
|
||||
@@ -66,6 +66,8 @@ COMMON_SOURCES=common.c common.h system.c system.h setproctitle.c setproctitle.h
|
||||
AUTH_SOURCES=auth/pam.c auth/pam.h auth/plain.c auth/plain.h auth/radius.c auth/radius.h \
|
||||
auth/common.c auth/common.h auth/gssapi.h auth/gssapi.c
|
||||
|
||||
ACCT_SOURCES=acct/pam.c acct/pam.h acct/radius.c acct/radius.h
|
||||
|
||||
ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \
|
||||
cookies.c main-misc.c ip-lease.c ip-lease.h \
|
||||
vpn.h cookies.h tlslib.h log.c tun.c tun.h \
|
||||
@@ -73,7 +75,7 @@ ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \
|
||||
worker-extras.c html.c html.h worker-http.c \
|
||||
main-user.c worker-misc.c route-add.c route-add.h worker-privs.c \
|
||||
sec-mod.c sec-mod-db.c sec-mod-auth.c sec-mod-auth.h sec-mod.h sec-mod-ban.c \
|
||||
script-list.h $(COMMON_SOURCES) $(AUTH_SOURCES) \
|
||||
script-list.h $(COMMON_SOURCES) $(AUTH_SOURCES) $(ACCT_SOURCES) \
|
||||
icmp-ping.c icmp-ping.h worker-kkdcp.c \
|
||||
sec-mod-sup-config.c sec-mod-sup-config.h \
|
||||
sup-config/file.c sup-config/file.h \
|
||||
@@ -82,7 +84,7 @@ ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \
|
||||
vasprintf.c vasprintf.h lzs.c lzs.h \
|
||||
proc-search.c proc-search.h http-heads.h \
|
||||
str.c str.h gettime.h $(CCAN_SOURCES) $(HTTP_PARSER_SOURCES) \
|
||||
$(PROTOBUF_SOURCES) kkdcp.asn kkdcp_asn1_tab.c
|
||||
$(PROTOBUF_SOURCES) kkdcp.asn kkdcp_asn1_tab.c sec-mod-acct.h
|
||||
|
||||
|
||||
ocserv_SOURCES += ipc.pb-c.h ipc.pb-c.c ctl.pb-c.c ctl.pb-c.h
|
||||
|
||||
83
src/acct/pam.c
Normal file
83
src/acct/pam.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Nikos Mavrogiannopoulos
|
||||
*
|
||||
* This file is part of ocserv.
|
||||
*
|
||||
* ocserv is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ocserv is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <vpn.h>
|
||||
#include "pam.h"
|
||||
#include <sec-mod-acct.h>
|
||||
|
||||
#ifdef HAVE_PAM
|
||||
|
||||
#include <security/pam_appl.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <pcl.h>
|
||||
#include <str.h>
|
||||
#include "auth/pam.h"
|
||||
|
||||
static int pam_acct_open_session(unsigned auth_method, void *ctx, const struct common_auth_info_st *ai, const void *sid, unsigned sid_size)
|
||||
{
|
||||
struct pam_ctx_st * pctx = ctx;
|
||||
int pret;
|
||||
|
||||
if (auth_method != AUTH_TYPE_PAM) {
|
||||
syslog(LOG_AUTH, "PAM-acct: pam_open_session cannot be combined with this authentication method (%x)", auth_method);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pctx->cr != NULL) {
|
||||
co_delete(pctx->cr);
|
||||
pctx->cr = NULL;
|
||||
}
|
||||
|
||||
pret = pam_open_session(pctx->ph, PAM_SILENT);
|
||||
if (pret != PAM_SUCCESS) {
|
||||
syslog(LOG_AUTH, "PAM-acct: pam_open_session: %s", pam_strerror(pctx->ph, pret));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pam_acct_close_session(unsigned auth_method, void *ctx, const struct common_auth_info_st *ai, stats_st *stats)
|
||||
{
|
||||
struct pam_ctx_st * pctx = ctx;
|
||||
int pret;
|
||||
|
||||
pret = pam_close_session(pctx->ph, PAM_SILENT);
|
||||
if (pret != PAM_SUCCESS) {
|
||||
syslog(LOG_AUTH, "PAM-acct: pam_close_session: %s", pam_strerror(pctx->ph, pret));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const struct acct_mod_st pam_acct_funcs = {
|
||||
.type = ACCT_TYPE_PAM,
|
||||
.auth_types = AUTH_TYPE_PAM & (~VIRTUAL_AUTH_TYPES),
|
||||
.open_session = pam_acct_open_session,
|
||||
.close_session = pam_acct_close_session,
|
||||
};
|
||||
|
||||
#endif
|
||||
28
src/acct/pam.h
Normal file
28
src/acct/pam.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Red Hat, Inc.
|
||||
*
|
||||
* Author: Nikos Mavrogiannopoulos
|
||||
*
|
||||
* This file is part of ocserv.
|
||||
*
|
||||
* The GnuTLS is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
#ifndef ACCT_PAM_H
|
||||
#define ACCT_PAM_H
|
||||
|
||||
#include <sec-mod-acct.h>
|
||||
|
||||
extern const struct acct_mod_st pam_acct_funcs;
|
||||
|
||||
#endif
|
||||
282
src/acct/radius.c
Normal file
282
src/acct/radius.c
Normal file
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Red Hat, Inc.
|
||||
*
|
||||
* This file is part of ocserv.
|
||||
*
|
||||
* ocserv is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ocserv is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
#include <vpn.h>
|
||||
#include <c-ctype.h>
|
||||
#include <arpa/inet.h> /* inet_ntop */
|
||||
#include "radius.h"
|
||||
#include "auth/common.h"
|
||||
|
||||
#ifdef HAVE_RADIUS
|
||||
|
||||
#include <freeradius-client.h>
|
||||
#include <sec-mod-acct.h>
|
||||
#include "auth/radius.h"
|
||||
#include "acct/radius.h"
|
||||
|
||||
static rc_handle *rh = NULL;
|
||||
static char nas_identifier[64];
|
||||
|
||||
static void acct_radius_global_init(void *pool, const char *server_name, void *additional)
|
||||
{
|
||||
rh = rc_read_config(additional);
|
||||
if (rh == NULL) {
|
||||
fprintf(stderr, "radius initialization error\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (server_name)
|
||||
strlcpy(nas_identifier, server_name, sizeof(nas_identifier));
|
||||
else
|
||||
nas_identifier[0] = 0;
|
||||
|
||||
if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary")) != 0) {
|
||||
fprintf(stderr, "error reading the radius dictionary\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void acct_radius_global_deinit(void)
|
||||
{
|
||||
if (rh != NULL)
|
||||
rc_destroy(rh);
|
||||
}
|
||||
|
||||
static void append_stats(rc_handle *rh, VALUE_PAIR **send, stats_st *stats)
|
||||
{
|
||||
uint32_t uin, uout;
|
||||
|
||||
if (stats->uptime) {
|
||||
uin = stats->uptime;
|
||||
if (rc_avpair_add(rh, send, PW_ACCT_SESSION_TIME, &uin, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uin = stats->bytes_in;
|
||||
uout = stats->bytes_out;
|
||||
|
||||
if (rc_avpair_add(rh, send, PW_ACCT_INPUT_OCTETS, &uin, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rc_avpair_add(rh, send, PW_ACCT_OUTPUT_OCTETS, &uout, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
uin = stats->bytes_in / 4294967296;
|
||||
if (rc_avpair_add(rh, send, PW_ACCT_INPUT_GIGAWORDS, &uin, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
uout = stats->bytes_in / 4294967296;
|
||||
if (rc_avpair_add(rh, send, PW_ACCT_OUTPUT_GIGAWORDS, &uout, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void append_acct_standard(rc_handle *rh, const common_auth_info_st *ai, VALUE_PAIR **send)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (nas_identifier[0] != 0) {
|
||||
if (rc_avpair_add(rh, send, PW_NAS_IDENTIFIER, nas_identifier, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc_avpair_add(rh, send, PW_USER_NAME, ai->username, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
i = PW_FRAMED;
|
||||
if (rc_avpair_add(rh, send, PW_SERVICE_TYPE, &i, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
i = PW_PPP;
|
||||
if (rc_avpair_add(rh, send, PW_FRAMED_PROTOCOL, &i, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ai->ipv4[0] != 0) {
|
||||
struct in_addr in;
|
||||
inet_pton(AF_INET, ai->ipv4, &in);
|
||||
in.s_addr = ntohl(in.s_addr);
|
||||
if (rc_avpair_add(rh, send, PW_FRAMED_IP_ADDRESS, &in, sizeof(in), 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ai->ipv6[0] != 0) {
|
||||
struct in6_addr in;
|
||||
inet_pton(AF_INET6, ai->ipv6, &in);
|
||||
if (rc_avpair_add(rh, send, PW_FRAMED_IPV6_ADDRESS, &in, sizeof(in), 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc_avpair_add(rh, send, PW_CALLING_STATION_ID, ai->remote_ip, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rc_avpair_add(rh, send, PW_ACCT_SESSION_ID, ai->psid, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
i = PW_RADIUS;
|
||||
if (rc_avpair_add(rh, send, PW_ACCT_AUTHENTIC, &i, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
i = PW_ASYNC;
|
||||
if (rc_avpair_add(rh, send, PW_NAS_PORT_TYPE, &i, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void radius_acct_session_stats(unsigned auth_method, void *ctx, const common_auth_info_st *ai, stats_st *stats)
|
||||
{
|
||||
int ret;
|
||||
uint32_t status_type;
|
||||
VALUE_PAIR *send = NULL, *recvd = NULL;
|
||||
|
||||
status_type = PW_STATUS_ALIVE;
|
||||
|
||||
syslog(LOG_DEBUG, "radius-auth: sending session interim update");
|
||||
|
||||
if (rc_avpair_add(rh, &send, PW_ACCT_STATUS_TYPE, &status_type, -1, 0) == NULL) {
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
append_acct_standard(rh, ai, &send);
|
||||
append_stats(rh, &send, stats);
|
||||
|
||||
ret = rc_aaa(rh, 0, send, &recvd, NULL, 1, PW_ACCOUNTING_REQUEST);
|
||||
|
||||
if (recvd != NULL)
|
||||
rc_avpair_free(recvd);
|
||||
|
||||
if (ret != OK_RC) {
|
||||
syslog(LOG_AUTH, "radius-auth: radius_open_session: %d", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
rc_avpair_free(send);
|
||||
return;
|
||||
}
|
||||
|
||||
static int radius_acct_open_session(unsigned auth_method, void *ctx, const common_auth_info_st *ai, const void *sid, unsigned sid_size)
|
||||
{
|
||||
int ret;
|
||||
uint32_t status_type;
|
||||
VALUE_PAIR *send = NULL, *recvd = NULL;
|
||||
|
||||
status_type = PW_STATUS_START;
|
||||
|
||||
if (sid_size != SID_SIZE) {
|
||||
syslog(LOG_DEBUG, "radius-auth: incorrect sid size");
|
||||
return -1;
|
||||
}
|
||||
|
||||
syslog(LOG_DEBUG, "radius-auth: opening session %s", ai->psid);
|
||||
|
||||
if (rc_avpair_add(rh, &send, PW_ACCT_STATUS_TYPE, &status_type, -1, 0) == NULL) {
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
append_acct_standard(rh, ai, &send);
|
||||
|
||||
ret = rc_aaa(rh, 0, send, &recvd, NULL, 1, PW_ACCOUNTING_REQUEST);
|
||||
|
||||
if (recvd != NULL)
|
||||
rc_avpair_free(recvd);
|
||||
|
||||
if (ret != OK_RC) {
|
||||
syslog(LOG_AUTH, "radius-auth: radius_open_session: %d", ret);
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
cleanup:
|
||||
rc_avpair_free(send);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void radius_acct_close_session(unsigned auth_method, void *ctx, const common_auth_info_st *ai, stats_st *stats)
|
||||
{
|
||||
int ret;
|
||||
uint32_t status_type;
|
||||
VALUE_PAIR *send = NULL, *recvd = NULL;
|
||||
|
||||
status_type = PW_STATUS_STOP;
|
||||
|
||||
syslog(LOG_DEBUG, "radius-auth: closing session");
|
||||
if (rc_avpair_add(rh, &send, PW_ACCT_STATUS_TYPE, &status_type, -1, 0) == NULL)
|
||||
return;
|
||||
|
||||
ret = PW_USER_REQUEST;
|
||||
if (rc_avpair_add(rh, &send, PW_ACCT_TERMINATE_CAUSE, &ret, -1, 0) == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
append_acct_standard(rh, ai, &send);
|
||||
append_stats(rh, &send, stats);
|
||||
|
||||
ret = rc_aaa(rh, 0, send, &recvd, NULL, 1, PW_ACCOUNTING_REQUEST);
|
||||
if (recvd != NULL)
|
||||
rc_avpair_free(recvd);
|
||||
|
||||
if (ret != OK_RC) {
|
||||
syslog(LOG_INFO, "radius-auth: radius_close_session: %d", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
rc_avpair_free(send);
|
||||
return;
|
||||
}
|
||||
|
||||
const struct acct_mod_st radius_acct_funcs = {
|
||||
.type = ACCT_TYPE_RADIUS,
|
||||
.auth_types = ALL_AUTH_TYPES,
|
||||
.global_init = acct_radius_global_init,
|
||||
.global_deinit = acct_radius_global_deinit,
|
||||
.open_session = radius_acct_open_session,
|
||||
.close_session = radius_acct_close_session,
|
||||
.session_stats = radius_acct_session_stats
|
||||
};
|
||||
|
||||
#endif
|
||||
28
src/acct/radius.h
Normal file
28
src/acct/radius.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Red Hat, Inc.
|
||||
*
|
||||
* Author: Nikos Mavrogiannopoulos
|
||||
*
|
||||
* This file is part of ocserv.
|
||||
*
|
||||
* The GnuTLS is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
#ifndef ACCT_RADIUS_H
|
||||
#define ACCT_RADIUS_H
|
||||
|
||||
#include <sec-mod-auth.h>
|
||||
|
||||
extern const struct acct_mod_st radius_acct_funcs;
|
||||
|
||||
#endif
|
||||
@@ -42,8 +42,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <pcl.h>
|
||||
#include <str.h>
|
||||
#include "auth/pam.h"
|
||||
|
||||
#define PAM_STACK_SIZE (96*1024)
|
||||
|
||||
@@ -55,20 +54,6 @@ enum {
|
||||
PAM_S_COMPLETE,
|
||||
};
|
||||
|
||||
struct pam_ctx_st {
|
||||
char password[MAX_PASSWORD_SIZE];
|
||||
char username[MAX_USERNAME_SIZE];
|
||||
pam_handle_t * ph;
|
||||
struct pam_conv dc;
|
||||
coroutine_t cr;
|
||||
int cr_ret;
|
||||
unsigned changing; /* whether we are entering a new password */
|
||||
str_st msg;
|
||||
unsigned sent_msg;
|
||||
struct pam_response *replies; /* for safety */
|
||||
unsigned state; /* PAM_S_ */
|
||||
};
|
||||
|
||||
static int ocserv_conv(int msg_size, const struct pam_message **msg,
|
||||
struct pam_response **resp, void *uptr)
|
||||
{
|
||||
@@ -353,38 +338,6 @@ struct pam_ctx_st * pctx = ctx;
|
||||
talloc_free(pctx);
|
||||
}
|
||||
|
||||
static int pam_auth_open_session(void* ctx, const void *sid, unsigned sid_size)
|
||||
{
|
||||
struct pam_ctx_st * pctx = ctx;
|
||||
int pret;
|
||||
|
||||
if (pctx->cr != NULL) {
|
||||
co_delete(pctx->cr);
|
||||
pctx->cr = NULL;
|
||||
}
|
||||
|
||||
pret = pam_open_session(pctx->ph, PAM_SILENT);
|
||||
if (pret != PAM_SUCCESS) {
|
||||
syslog(LOG_AUTH, "PAM-auth: pam_open_session: %s", pam_strerror(pctx->ph, pret));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pam_auth_close_session(void* ctx, stats_st *stats)
|
||||
{
|
||||
struct pam_ctx_st * pctx = ctx;
|
||||
int pret;
|
||||
|
||||
pret = pam_close_session(pctx->ph, PAM_SILENT);
|
||||
if (pret != PAM_SUCCESS) {
|
||||
syslog(LOG_AUTH, "PAM-auth: pam_close_session: %s", pam_strerror(pctx->ph, pret));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void pam_group_list(void *pool, void *_additional, char ***groupname, unsigned *groupname_size)
|
||||
{
|
||||
struct group *grp;
|
||||
@@ -430,8 +383,6 @@ const struct auth_mod_st pam_auth_funcs = {
|
||||
.auth_pass = pam_auth_pass,
|
||||
.auth_group = pam_auth_group,
|
||||
.auth_user = pam_auth_user,
|
||||
.open_session = pam_auth_open_session,
|
||||
.close_session = pam_auth_close_session,
|
||||
.group_list = pam_group_list
|
||||
};
|
||||
|
||||
|
||||
@@ -22,7 +22,25 @@
|
||||
#define PAM_H
|
||||
|
||||
#include <sec-mod-auth.h>
|
||||
#include <security/pam_appl.h>
|
||||
#include <str.h>
|
||||
#include <pcl.h>
|
||||
|
||||
extern const struct auth_mod_st pam_auth_funcs;
|
||||
|
||||
struct pam_ctx_st {
|
||||
char password[MAX_PASSWORD_SIZE];
|
||||
char username[MAX_USERNAME_SIZE];
|
||||
pam_handle_t * ph;
|
||||
struct pam_conv dc;
|
||||
coroutine_t cr;
|
||||
int cr_ret;
|
||||
unsigned changing; /* whether we are entering a new password */
|
||||
str_st msg;
|
||||
unsigned sent_msg;
|
||||
struct pam_response *replies; /* for safety */
|
||||
unsigned state; /* PAM_S_ */
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -323,218 +323,6 @@ static void radius_auth_deinit(void *ctx)
|
||||
talloc_free(pctx);
|
||||
}
|
||||
|
||||
static void append_stats(rc_handle *rh, VALUE_PAIR **send, stats_st *stats)
|
||||
{
|
||||
uint32_t uin, uout;
|
||||
|
||||
if (stats->uptime) {
|
||||
uin = stats->uptime;
|
||||
if (rc_avpair_add(rh, send, PW_ACCT_SESSION_TIME, &uin, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uin = stats->bytes_in;
|
||||
uout = stats->bytes_out;
|
||||
|
||||
if (rc_avpair_add(rh, send, PW_ACCT_INPUT_OCTETS, &uin, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rc_avpair_add(rh, send, PW_ACCT_OUTPUT_OCTETS, &uout, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
uin = stats->bytes_in / 4294967296;
|
||||
if (rc_avpair_add(rh, send, PW_ACCT_INPUT_GIGAWORDS, &uin, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
uout = stats->bytes_in / 4294967296;
|
||||
if (rc_avpair_add(rh, send, PW_ACCT_OUTPUT_GIGAWORDS, &uout, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void append_acct_standard(struct radius_ctx_st * pctx, rc_handle *rh,
|
||||
VALUE_PAIR **send)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (nas_identifier[0] != 0) {
|
||||
if (rc_avpair_add(rh, send, PW_NAS_IDENTIFIER, nas_identifier, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc_avpair_add(rh, send, PW_USER_NAME, pctx->username, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
i = PW_FRAMED;
|
||||
if (rc_avpair_add(rh, send, PW_SERVICE_TYPE, &i, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
i = PW_PPP;
|
||||
if (rc_avpair_add(rh, send, PW_FRAMED_PROTOCOL, &i, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pctx->ipv4[0] != 0) {
|
||||
struct in_addr in;
|
||||
inet_pton(AF_INET, pctx->ipv4, &in);
|
||||
in.s_addr = ntohl(in.s_addr);
|
||||
if (rc_avpair_add(rh, send, PW_FRAMED_IP_ADDRESS, &in, sizeof(in), 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (pctx->ipv6[0] != 0) {
|
||||
struct in6_addr in;
|
||||
inet_pton(AF_INET6, pctx->ipv6, &in);
|
||||
if (rc_avpair_add(rh, send, PW_FRAMED_IPV6_ADDRESS, &in, sizeof(in), 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc_avpair_add(rh, send, PW_CALLING_STATION_ID, pctx->remote_ip, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rc_avpair_add(rh, send, PW_ACCT_SESSION_ID, pctx->sid, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
i = PW_RADIUS;
|
||||
if (rc_avpair_add(rh, send, PW_ACCT_AUTHENTIC, &i, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
i = PW_ASYNC;
|
||||
if (rc_avpair_add(rh, send, PW_NAS_PORT_TYPE, &i, -1, 0) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void radius_auth_session_stats(void* ctx, stats_st *stats, const char *ip)
|
||||
{
|
||||
struct radius_ctx_st * pctx = ctx;
|
||||
int ret;
|
||||
uint32_t status_type;
|
||||
VALUE_PAIR *send = NULL, *recvd = NULL;
|
||||
|
||||
if (ip)
|
||||
strlcpy(pctx->remote_ip, ip, sizeof(pctx->remote_ip));
|
||||
|
||||
status_type = PW_STATUS_ALIVE;
|
||||
|
||||
syslog(LOG_DEBUG, "radius-auth: sending session interim update");
|
||||
|
||||
if (rc_avpair_add(rh, &send, PW_ACCT_STATUS_TYPE, &status_type, -1, 0) == NULL) {
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
append_acct_standard(pctx, rh, &send);
|
||||
append_stats(rh, &send, stats);
|
||||
|
||||
ret = rc_aaa(rh, 0, send, &recvd, NULL, 1, PW_ACCOUNTING_REQUEST);
|
||||
|
||||
if (recvd != NULL)
|
||||
rc_avpair_free(recvd);
|
||||
|
||||
if (ret != OK_RC) {
|
||||
syslog(LOG_AUTH, "radius-auth: radius_open_session: %d", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
rc_avpair_free(send);
|
||||
return;
|
||||
}
|
||||
|
||||
static int radius_auth_open_session(void* ctx, const void *sid, unsigned sid_size)
|
||||
{
|
||||
struct radius_ctx_st * pctx = ctx;
|
||||
int ret;
|
||||
uint32_t status_type;
|
||||
VALUE_PAIR *send = NULL, *recvd = NULL;
|
||||
|
||||
status_type = PW_STATUS_START;
|
||||
|
||||
if (sid_size != SID_SIZE) {
|
||||
syslog(LOG_DEBUG, "radius-auth: incorrect sid size");
|
||||
return -1;
|
||||
}
|
||||
|
||||
base64_encode((char *)sid, sid_size, (char *)pctx->sid, sizeof(pctx->sid));
|
||||
|
||||
syslog(LOG_DEBUG, "radius-auth: opening session %s", pctx->sid);
|
||||
|
||||
if (rc_avpair_add(rh, &send, PW_ACCT_STATUS_TYPE, &status_type, -1, 0) == NULL) {
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
append_acct_standard(pctx, rh, &send);
|
||||
|
||||
ret = rc_aaa(rh, 0, send, &recvd, NULL, 1, PW_ACCOUNTING_REQUEST);
|
||||
|
||||
if (recvd != NULL)
|
||||
rc_avpair_free(recvd);
|
||||
|
||||
if (ret != OK_RC) {
|
||||
syslog(LOG_AUTH, "radius-auth: radius_open_session: %d", ret);
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
cleanup:
|
||||
rc_avpair_free(send);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void radius_auth_close_session(void* ctx, stats_st *stats)
|
||||
{
|
||||
struct radius_ctx_st * pctx = ctx;
|
||||
int ret;
|
||||
uint32_t status_type;
|
||||
VALUE_PAIR *send = NULL, *recvd = NULL;
|
||||
|
||||
status_type = PW_STATUS_STOP;
|
||||
|
||||
syslog(LOG_DEBUG, "radius-auth: closing session");
|
||||
if (rc_avpair_add(rh, &send, PW_ACCT_STATUS_TYPE, &status_type, -1, 0) == NULL)
|
||||
return;
|
||||
|
||||
ret = PW_USER_REQUEST;
|
||||
if (rc_avpair_add(rh, &send, PW_ACCT_TERMINATE_CAUSE, &ret, -1, 0) == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
append_acct_standard(pctx, rh, &send);
|
||||
append_stats(rh, &send, stats);
|
||||
|
||||
ret = rc_aaa(rh, 0, send, &recvd, NULL, 1, PW_ACCOUNTING_REQUEST);
|
||||
if (recvd != NULL)
|
||||
rc_avpair_free(recvd);
|
||||
|
||||
if (ret != OK_RC) {
|
||||
syslog(LOG_INFO, "radius-auth: radius_close_session: %d", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
rc_avpair_free(send);
|
||||
return;
|
||||
}
|
||||
|
||||
const struct auth_mod_st radius_auth_funcs = {
|
||||
.type = AUTH_TYPE_RADIUS | AUTH_TYPE_USERNAME_PASS,
|
||||
.allows_retries = 1,
|
||||
@@ -546,9 +334,6 @@ const struct auth_mod_st radius_auth_funcs = {
|
||||
.auth_pass = radius_auth_pass,
|
||||
.auth_user = radius_auth_user,
|
||||
.auth_group = radius_auth_group,
|
||||
.open_session = radius_auth_open_session,
|
||||
.close_session = radius_auth_close_session,
|
||||
.session_stats = radius_auth_session_stats,
|
||||
.group_list = NULL
|
||||
};
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
struct radius_ctx_st {
|
||||
char username[MAX_USERNAME_SIZE*2];
|
||||
char groupname[MAX_GROUPNAME_SIZE];
|
||||
char sid[BASE64_LENGTH(SID_SIZE) + 1];
|
||||
|
||||
char remote_ip[MAX_IP_STR];
|
||||
|
||||
|
||||
56
src/config.c
56
src/config.c
@@ -33,10 +33,13 @@
|
||||
#include <c-ctype.h>
|
||||
#include <auth/pam.h>
|
||||
#include <auth/radius.h>
|
||||
#include <acct/pam.h>
|
||||
#include <acct/radius.h>
|
||||
#include <auth/plain.h>
|
||||
#include <auth/gssapi.h>
|
||||
#include <auth/common.h>
|
||||
#include <sec-mod-sup-config.h>
|
||||
#include <sec-mod-acct.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
@@ -69,6 +72,7 @@ static struct cfg_options available_options[] = {
|
||||
{ .name = "select-group", .type = OPTION_MULTI_LINE, .mandatory = 0 },
|
||||
{ .name = "custom-header", .type = OPTION_MULTI_LINE, .mandatory = 0 },
|
||||
{ .name = "split-dns", .type = OPTION_MULTI_LINE, .mandatory = 0 },
|
||||
{ .name = "acct", .type = OPTION_STRING, .mandatory = 0 },
|
||||
{ .name = "server-name", .type = OPTION_STRING, .mandatory = 0 },
|
||||
{ .name = "listen-host", .type = OPTION_STRING, .mandatory = 0 },
|
||||
{ .name = "listen-host-is-dyndns", .type = OPTION_BOOLEAN, .mandatory = 0 },
|
||||
@@ -533,6 +537,51 @@ static void figure_auth_funcs(struct cfg_st *config, char **auth, unsigned auth_
|
||||
talloc_free(auth);
|
||||
}
|
||||
|
||||
typedef struct acct_types_st {
|
||||
const char *name;
|
||||
unsigned name_size;
|
||||
const struct acct_mod_st *mod;
|
||||
char *(*get_brackets_string)(struct cfg_st *config, const char *);
|
||||
} acct_types_st;
|
||||
|
||||
static acct_types_st avail_acct_types[] =
|
||||
{
|
||||
{NAME("pam"), &pam_acct_funcs, NULL},
|
||||
#ifdef HAVE_RADIUS
|
||||
{NAME("radius"), &radius_acct_funcs, get_brackets_string1},
|
||||
#endif
|
||||
};
|
||||
|
||||
static void figure_acct_funcs(struct cfg_st *config, const char *acct)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned found = 0;
|
||||
|
||||
/* Set the accounting method */
|
||||
for (i=0;i<sizeof(avail_acct_types)/sizeof(avail_acct_types[0]);i++) {
|
||||
if (c_strncasecmp(acct, avail_acct_types[i].name, avail_acct_types[i].name_size) == 0) {
|
||||
if (avail_acct_types[i].get_brackets_string)
|
||||
config->acct.additional = avail_acct_types[i].get_brackets_string(config, acct+avail_acct_types[i].name_size);
|
||||
|
||||
if ((avail_acct_types[i].mod->auth_types & config->auth[0].type) == 0) {
|
||||
fprintf(stderr, "You cannot mix the '%s' accounting method with the '%s' authentication method\n", acct, config->auth[0].name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
config->acct.amod = avail_acct_types[i].mod;
|
||||
config->acct.name = avail_acct_types[i].name;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found == 0) {
|
||||
fprintf(stderr, "Unknown or unsupported accounting method: %s\n", acct);
|
||||
exit(1);
|
||||
}
|
||||
fprintf(stderr, "Setting '%s' as accounting method\n", config->acct.name);
|
||||
}
|
||||
|
||||
#ifdef HAVE_GSSAPI
|
||||
static void parse_kkdcp(struct cfg_st *config, char **urlfw, unsigned urlfw_size)
|
||||
{
|
||||
@@ -692,6 +741,13 @@ unsigned urlfw_size = 0;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
tmp = NULL;
|
||||
READ_STRING("acct", tmp);
|
||||
if (tmp != NULL) {
|
||||
figure_acct_funcs(config, tmp);
|
||||
talloc_free(tmp);
|
||||
}
|
||||
|
||||
/* When adding allocated data, remember to modify
|
||||
* reload_cfg_file();
|
||||
*/
|
||||
|
||||
@@ -115,7 +115,9 @@ message cli_stats_msg
|
||||
required uint64 bytes_out = 2;
|
||||
optional bytes sid = 3; /* only required by sec-mod */
|
||||
required uint32 uptime = 4; /* sec-mod */
|
||||
optional string ip = 5; /* only required by sec-mod */
|
||||
optional string remote_ip = 5; /* only required by sec-mod */
|
||||
optional string ipv4 = 6; /* only required by sec-mod */
|
||||
optional string ipv6 = 7; /* only required by sec-mod */
|
||||
}
|
||||
|
||||
/* UDP_FD */
|
||||
|
||||
@@ -115,6 +115,17 @@ An example configuration file follows.
|
||||
#enable-auth = gssapi
|
||||
#enable-auth = "gssapi[keytab:/etc/key.tab]"
|
||||
|
||||
# Accounting methods available:
|
||||
# pam: can only be combined with PAM authentication method, it provides
|
||||
# a session opened using PAM.
|
||||
#
|
||||
# radius: can be combined with any authentication method, it provides
|
||||
# radius accounting to available users (see also stats-report-time).
|
||||
#
|
||||
# Only one accounting method can be specified.
|
||||
#acct = "pam"
|
||||
#acct = "radius[/etc/radiusclient/radiusclient.conf]"
|
||||
|
||||
# Whether to enable seccomp/Linux namespaces worker isolation. That restricts the number of
|
||||
# system calls allowed to a worker process, in order to reduce damage from a
|
||||
# bug in the worker process. It is available on Linux systems at a performance cost.
|
||||
|
||||
41
src/sec-mod-acct.h
Normal file
41
src/sec-mod-acct.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Red Hat, Inc.
|
||||
*
|
||||
* Author: Nikos Mavrogiannopoulos
|
||||
*
|
||||
* This file is part of ocserv.
|
||||
*
|
||||
* The GnuTLS is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
#ifndef ACCT_H
|
||||
# define ACCT_H
|
||||
|
||||
#include <main.h>
|
||||
#include <sec-mod-auth.h>
|
||||
|
||||
typedef struct acct_mod_st {
|
||||
unsigned int type; /* ACCT_TYPE_ */
|
||||
unsigned int auth_types; /* or of the AUTH_TYPEs which are compatible with this */
|
||||
void (*global_init)(void *pool, const char *server_name, void* additional);
|
||||
void (*global_deinit)(void);
|
||||
|
||||
/* The context provided below is of the authentication method */
|
||||
int (*open_session)(unsigned auth_method, void *ctx, const common_auth_info_st *ai, const void *sid, unsigned sid_size); /* optional, may be null */
|
||||
void (*session_stats)(unsigned auth_method, void *ctx, const common_auth_info_st *ai, struct stats_st *stats); /* optional, may be null */
|
||||
void (*close_session)(unsigned auth_method, void *ctx, const common_auth_info_st *ai, struct stats_st *stats); /* optional may be null */
|
||||
} acct_mod_st;
|
||||
|
||||
/* The accounting messages exchanged with the worker thread are shown in ipc.proto.
|
||||
*/
|
||||
#endif
|
||||
@@ -50,6 +50,7 @@
|
||||
#include <sec-mod.h>
|
||||
#include <vpn.h>
|
||||
#include <sec-mod-sup-config.h>
|
||||
#include <sec-mod-acct.h>
|
||||
|
||||
#ifdef HAVE_GSSAPI
|
||||
# include <gssapi/gssapi.h>
|
||||
@@ -64,6 +65,9 @@ void sec_auth_init(sec_mod_st * sec, struct cfg_st *config)
|
||||
if (config->auth[i].enabled && config->auth[i].amod && config->auth[i].amod->global_init)
|
||||
config->auth[i].amod->global_init(sec, config->server_name, config->auth[i].additional);
|
||||
}
|
||||
|
||||
if (config->acct.amod && config->acct.amod->global_init)
|
||||
config->acct.amod->global_init(sec, config->server_name, config->acct.additional);
|
||||
}
|
||||
|
||||
static int generate_cookie(sec_mod_st * sec, client_entry_st * entry)
|
||||
@@ -71,15 +75,15 @@ static int generate_cookie(sec_mod_st * sec, client_entry_st * entry)
|
||||
int ret;
|
||||
Cookie msg = COOKIE__INIT;
|
||||
|
||||
msg.username = entry->username;
|
||||
msg.groupname = entry->groupname;
|
||||
msg.username = entry->auth_info.username;
|
||||
msg.groupname = entry->auth_info.groupname;
|
||||
msg.hostname = entry->hostname;
|
||||
msg.ip = entry->ip;
|
||||
msg.ip = entry->auth_info.remote_ip;
|
||||
msg.tls_auth_ok = entry->tls_auth_ok;
|
||||
|
||||
/* Fixme: possibly we should allow for completely random seeds */
|
||||
if (sec->config->predictable_ips != 0) {
|
||||
msg.ipv4_seed = hash_any(entry->username, strlen(entry->username), 0);
|
||||
msg.ipv4_seed = hash_any(entry->auth_info.username, strlen(entry->auth_info.username), 0);
|
||||
} else {
|
||||
ret = gnutls_rnd(GNUTLS_RND_NONCE, &msg.ipv4_seed, sizeof(msg.ipv4_seed));
|
||||
if (ret < 0)
|
||||
@@ -121,7 +125,7 @@ int send_sec_auth_reply(int cfd, sec_mod_st * sec, client_entry_st * entry, AUTH
|
||||
msg.cookie.data = entry->cookie;
|
||||
msg.cookie.len = entry->cookie_size;
|
||||
|
||||
msg.user_name = entry->username;
|
||||
msg.user_name = entry->auth_info.username;
|
||||
|
||||
if (entry->msg_str != NULL) {
|
||||
msg.msg = entry->msg_str;
|
||||
@@ -199,33 +203,33 @@ static int check_user_group_status(sec_mod_st * sec, client_entry_st * e,
|
||||
if (e->auth_type & AUTH_TYPE_CERTIFICATE) {
|
||||
if (tls_auth_ok == 0) {
|
||||
seclog(sec, LOG_INFO, "user %s (session: %s) presented no certificate",
|
||||
e->username, e->printable_sid);
|
||||
e->auth_info.username, e->auth_info.psid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
e->tls_auth_ok = tls_auth_ok;
|
||||
if (tls_auth_ok != 0) {
|
||||
if (e->username[0] == 0 && sec->config->cert_user_oid != NULL) {
|
||||
if (e->auth_info.username[0] == 0 && sec->config->cert_user_oid != NULL) {
|
||||
if (cert_user == NULL) {
|
||||
seclog(sec, LOG_INFO, "no username in the certificate!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
strlcpy(e->username, cert_user, sizeof(e->username));
|
||||
if (cert_groups_size > 0 && sec->config->cert_group_oid != NULL && e->groupname[0] == 0)
|
||||
strlcpy(e->groupname, cert_groups[0], sizeof(e->groupname));
|
||||
strlcpy(e->auth_info.username, cert_user, sizeof(e->auth_info.username));
|
||||
if (cert_groups_size > 0 && sec->config->cert_group_oid != NULL && e->auth_info.groupname[0] == 0)
|
||||
strlcpy(e->auth_info.groupname, cert_groups[0], sizeof(e->auth_info.groupname));
|
||||
} else {
|
||||
if (sec->config->cert_user_oid != NULL && cert_user && strcmp(e->username, cert_user) != 0) {
|
||||
if (sec->config->cert_user_oid != NULL && cert_user && strcmp(e->auth_info.username, cert_user) != 0) {
|
||||
seclog(sec, LOG_INFO,
|
||||
"user '%s' (session: %s) presented a certificate from user '%s'",
|
||||
e->username, e->printable_sid, cert_user);
|
||||
e->auth_info.username, e->auth_info.psid, cert_user);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sec->config->cert_group_oid != NULL) {
|
||||
found = 0;
|
||||
for (i=0;i<cert_groups_size;i++) {
|
||||
if (strcmp(e->groupname, cert_groups[i]) == 0) {
|
||||
if (strcmp(e->auth_info.groupname, cert_groups[i]) == 0) {
|
||||
found++;
|
||||
break;
|
||||
}
|
||||
@@ -233,7 +237,7 @@ static int check_user_group_status(sec_mod_st * sec, client_entry_st * e,
|
||||
if (found == 0) {
|
||||
seclog(sec, LOG_INFO,
|
||||
"user '%s' (session: %s) presented a certificate from group '%s' but he isn't a member of it",
|
||||
e->username, e->printable_sid, e->groupname);
|
||||
e->auth_info.username, e->auth_info.psid, e->auth_info.groupname);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -267,7 +271,7 @@ int handle_sec_auth_res(int cfd, sec_mod_st * sec, client_entry_st * e, int resu
|
||||
if (result == ERR_AUTH_CONTINUE) {
|
||||
/* if the module allows multiple retries for the password */
|
||||
if (e->status != PS_AUTH_INIT && e->module && e->module->allows_retries) {
|
||||
add_ip_to_ban_list(sec, e->ip, 1, time(0) + sec->config->min_reauth_time);
|
||||
add_ip_to_ban_list(sec, e->auth_info.remote_ip, 1, time(0) + sec->config->min_reauth_time);
|
||||
}
|
||||
|
||||
ret = send_sec_auth_reply_msg(cfd, sec, e);
|
||||
@@ -281,8 +285,8 @@ int handle_sec_auth_res(int cfd, sec_mod_st * sec, client_entry_st * e, int resu
|
||||
e->status = PS_AUTH_COMPLETED;
|
||||
|
||||
if (e->module) {
|
||||
e->module->auth_user(e->auth_ctx, e->username,
|
||||
sizeof(e->username));
|
||||
e->module->auth_user(e->auth_ctx, e->auth_info.username,
|
||||
sizeof(e->auth_info.username));
|
||||
}
|
||||
|
||||
ret = send_sec_auth_reply(cfd, sec, e, AUTH__REP__OK);
|
||||
@@ -291,13 +295,13 @@ int handle_sec_auth_res(int cfd, sec_mod_st * sec, client_entry_st * e, int resu
|
||||
seclog(sec, LOG_ERR, "could not send reply auth cmd.");
|
||||
return ret;
|
||||
}
|
||||
remove_ip_from_ban_list(sec, e->ip);
|
||||
remove_ip_from_ban_list(sec, e->auth_info.remote_ip);
|
||||
|
||||
ret = 0;
|
||||
} else {
|
||||
e->status = PS_AUTH_FAILED;
|
||||
|
||||
add_ip_to_ban_list(sec, e->ip, 1, time(0) + sec->config->min_reauth_time);
|
||||
add_ip_to_ban_list(sec, e->auth_info.remote_ip, 1, time(0) + sec->config->min_reauth_time);
|
||||
|
||||
ret = send_sec_auth_reply(cfd, sec, e, AUTH__REP__FAILED);
|
||||
if (ret < 0) {
|
||||
@@ -345,7 +349,7 @@ int handle_sec_auth_session_cmd(int cfd, sec_mod_st *sec, const SecAuthSessionMs
|
||||
}
|
||||
|
||||
if (e->status != PS_AUTH_COMPLETED) {
|
||||
seclog(sec, LOG_ERR, "session cmd received in unauthenticated client %s (session: %s)!", e->username, e->printable_sid);
|
||||
seclog(sec, LOG_ERR, "session cmd received in unauthenticated client %s (session: %s)!", e->auth_info.username, e->auth_info.psid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -363,8 +367,8 @@ int handle_sec_auth_session_cmd(int cfd, sec_mod_st *sec, const SecAuthSessionMs
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (e->module != NULL && e->module->open_session != NULL && e->session_is_open == 0) {
|
||||
ret = e->module->open_session(e->auth_ctx, req->sid.data, req->sid.len);
|
||||
if (sec->config->acct.amod != NULL && sec->config->acct.amod->open_session != NULL && e->session_is_open == 0) {
|
||||
ret = sec->config->acct.amod->open_session(e->module->type, e->auth_ctx, &e->auth_info, req->sid.data, req->sid.len);
|
||||
if (ret < 0) {
|
||||
e->status = PS_AUTH_FAILED;
|
||||
seclog(sec, LOG_ERR, "could not open session.");
|
||||
@@ -385,7 +389,7 @@ int handle_sec_auth_session_cmd(int cfd, sec_mod_st *sec, const SecAuthSessionMs
|
||||
if (rep.reply == AUTH__REP__OK && sec->config_module && sec->config_module->get_sup_config) {
|
||||
ret = sec->config_module->get_sup_config(sec->config, e, &rep, lpool);
|
||||
if (ret < 0) {
|
||||
seclog(sec, LOG_ERR, "error reading additional configuration for '%s' (session: %s)", e->username, e->printable_sid);
|
||||
seclog(sec, LOG_ERR, "error reading additional configuration for '%s' (session: %s)", e->auth_info.username, e->auth_info.psid);
|
||||
talloc_free(lpool);
|
||||
return ERR_READ_CONFIG;
|
||||
}
|
||||
@@ -400,16 +404,16 @@ int handle_sec_auth_session_cmd(int cfd, sec_mod_st *sec, const SecAuthSessionMs
|
||||
talloc_free(lpool);
|
||||
|
||||
if (rep.reply != AUTH__REP__OK) {
|
||||
seclog(sec, LOG_INFO, "denied open session for user '%s' (session: %s)", e->username, e->printable_sid);
|
||||
seclog(sec, LOG_INFO, "denied open session for user '%s' (session: %s)", e->auth_info.username, e->auth_info.psid);
|
||||
del_client_entry(sec, e);
|
||||
} else { /* set expiration time to unlimited (until someone closes the session) */
|
||||
seclog(sec, LOG_INFO, "initiating session for user '%s' (session: %s)", e->username, e->printable_sid);
|
||||
seclog(sec, LOG_INFO, "initiating session for user '%s' (session: %s)", e->auth_info.username, e->auth_info.psid);
|
||||
e->time = -1;
|
||||
e->in_use++;
|
||||
}
|
||||
|
||||
} else { /* CLOSE */
|
||||
seclog(sec, LOG_INFO, "temporarily closing session for %s (session: %s)", e->username, e->printable_sid);
|
||||
seclog(sec, LOG_INFO, "temporarily closing session for %s (session: %s)", e->auth_info.username, e->auth_info.psid);
|
||||
|
||||
if (req->has_uptime && req->uptime > e->stats.uptime) {
|
||||
e->stats.uptime = req->uptime;
|
||||
@@ -447,7 +451,7 @@ int handle_sec_auth_stats_cmd(sec_mod_st * sec, const CliStatsMsg * req)
|
||||
}
|
||||
|
||||
if (e->status != PS_AUTH_COMPLETED) {
|
||||
seclog(sec, LOG_ERR, "session stats received in unauthenticated client %s (session: %s)!", e->username, e->printable_sid);
|
||||
seclog(sec, LOG_ERR, "session stats received in unauthenticated client %s (session: %s)!", e->auth_info.username, e->auth_info.psid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -459,11 +463,18 @@ int handle_sec_auth_stats_cmd(sec_mod_st * sec, const CliStatsMsg * req)
|
||||
if (req->uptime > e->stats.uptime)
|
||||
e->stats.uptime = req->uptime;
|
||||
|
||||
if (e->module == NULL || e->module->session_stats == NULL)
|
||||
if (sec->config->acct.amod == NULL || sec->config->acct.amod->session_stats == NULL)
|
||||
return 0;
|
||||
|
||||
stats_add_to(&totals, &e->stats, &e->saved_stats);
|
||||
e->module->session_stats(e->auth_ctx, &totals, req->ip);
|
||||
if (req->remote_ip)
|
||||
strlcpy(e->auth_info.remote_ip, req->remote_ip, sizeof(e->auth_info.remote_ip));
|
||||
if (req->ipv4)
|
||||
strlcpy(e->auth_info.ipv4, req->ipv4, sizeof(e->auth_info.ipv4));
|
||||
if (req->ipv6)
|
||||
strlcpy(e->auth_info.ipv6, req->ipv6, sizeof(e->auth_info.ipv6));
|
||||
|
||||
sec->config->acct.amod->session_stats(e->module->type, e->auth_ctx, &e->auth_info, &totals);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -492,16 +503,16 @@ int handle_sec_auth_cont(int cfd, sec_mod_st * sec, const SecAuthContMsg * req)
|
||||
|
||||
if (e->status != PS_AUTH_INIT && e->status != PS_AUTH_CONT) {
|
||||
seclog(sec, LOG_ERR, "auth cont received for %s (session: %s) but we are on state %u!",
|
||||
e->username, e->printable_sid, e->status);
|
||||
e->auth_info.username, e->auth_info.psid, e->status);
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
seclog(sec, LOG_DEBUG, "auth cont for user '%s' (session: %s)", e->username, e->printable_sid);
|
||||
seclog(sec, LOG_DEBUG, "auth cont for user '%s' (session: %s)", e->auth_info.username, e->auth_info.psid);
|
||||
|
||||
if (req->password == NULL) {
|
||||
seclog(sec, LOG_ERR, "no password given in auth cont for user '%s' (session: %s)",
|
||||
e->username, e->printable_sid);
|
||||
e->auth_info.username, e->auth_info.psid);
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
@@ -520,7 +531,7 @@ int handle_sec_auth_cont(int cfd, sec_mod_st * sec, const SecAuthContMsg * req)
|
||||
if (ret < 0) {
|
||||
seclog(sec, LOG_DEBUG,
|
||||
"error in password given in auth cont for user '%s' (session: %s)",
|
||||
e->username, e->printable_sid);
|
||||
e->auth_info.username, e->auth_info.psid);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -543,7 +554,7 @@ int set_module(sec_mod_st * sec, client_entry_st *e, unsigned auth_type)
|
||||
e->module = sec->config->auth[i].amod;
|
||||
e->auth_type = sec->config->auth[i].type;
|
||||
|
||||
seclog(sec, LOG_INFO, "using '%s' authentication to authenticate user (session: %s)", sec->config->auth[i].name, e->printable_sid);
|
||||
seclog(sec, LOG_INFO, "using '%s' authentication to authenticate user (session: %s)", sec->config->auth[i].name, e->auth_info.psid);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -589,26 +600,26 @@ int handle_sec_auth_init(int cfd, sec_mod_st * sec, const SecAuthInitMsg * req)
|
||||
}
|
||||
|
||||
ret =
|
||||
e->module->auth_group(e->auth_ctx, req->group_name, e->groupname,
|
||||
sizeof(e->groupname));
|
||||
e->module->auth_group(e->auth_ctx, req->group_name, e->auth_info.groupname,
|
||||
sizeof(e->auth_info.groupname));
|
||||
if (ret != 0) {
|
||||
ret = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
e->groupname[sizeof(e->groupname) - 1] = 0;
|
||||
e->auth_info.groupname[sizeof(e->auth_info.groupname) - 1] = 0;
|
||||
|
||||
if (req->user_name != NULL) {
|
||||
strlcpy(e->username, req->user_name, sizeof(e->username));
|
||||
strlcpy(e->auth_info.username, req->user_name, sizeof(e->auth_info.username));
|
||||
}
|
||||
}
|
||||
|
||||
if (e->auth_type & AUTH_TYPE_CERTIFICATE) {
|
||||
if (e->groupname[0] == 0 && req->group_name != NULL && sec->config->cert_group_oid != NULL) {
|
||||
if (e->auth_info.groupname[0] == 0 && req->group_name != NULL && sec->config->cert_group_oid != NULL) {
|
||||
unsigned i, found = 0;
|
||||
|
||||
for (i=0;i<req->n_cert_group_names;i++) {
|
||||
if (strcmp(req->group_name, req->cert_group_names[i]) == 0) {
|
||||
strlcpy(e->groupname, req->cert_group_names[i], sizeof(e->groupname));
|
||||
strlcpy(e->auth_info.groupname, req->cert_group_names[i], sizeof(e->auth_info.groupname));
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
@@ -634,7 +645,7 @@ int handle_sec_auth_init(int cfd, sec_mod_st * sec, const SecAuthInitMsg * req)
|
||||
e->status = PS_AUTH_INIT;
|
||||
seclog(sec, LOG_DEBUG, "auth init %sfor user '%s' (session: %s) of group: '%s' from '%s'",
|
||||
req->tls_auth_ok?"(with cert) ":"",
|
||||
e->username, e->printable_sid, e->groupname, req->ip);
|
||||
e->auth_info.username, e->auth_info.psid, e->auth_info.groupname, req->ip);
|
||||
|
||||
if (need_continue != 0) {
|
||||
ret = ERR_AUTH_CONTINUE;
|
||||
@@ -651,10 +662,10 @@ void sec_auth_user_deinit(sec_mod_st * sec, client_entry_st * e)
|
||||
if (e->module == NULL)
|
||||
return;
|
||||
|
||||
seclog(sec, LOG_DEBUG, "permamently closing session of user '%s' (session: %s)", e->username, e->printable_sid);
|
||||
seclog(sec, LOG_DEBUG, "permamently closing session of user '%s' (session: %s)", e->auth_info.username, e->auth_info.psid);
|
||||
if (e->auth_ctx != NULL) {
|
||||
if (e->module->close_session) {
|
||||
e->module->close_session(e->auth_ctx, &e->saved_stats);
|
||||
if (sec->config->acct.amod != NULL && sec->config->acct.amod->close_session != NULL && e->session_is_open != 0) {
|
||||
sec->config->acct.amod->close_session(e->module->type, e->auth_ctx, &e->auth_info, &e->saved_stats);
|
||||
}
|
||||
e->module->auth_deinit(e->auth_ctx);
|
||||
e->auth_ctx = NULL;
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#define MAX_AUTH_REQS 8
|
||||
#define MAX_GROUPS 32
|
||||
|
||||
struct auth_mod_st {
|
||||
typedef struct auth_mod_st {
|
||||
unsigned int type;
|
||||
unsigned int allows_retries; /* whether the module allows retries of the same password */
|
||||
void (*global_init)(void *pool, const char *server_name, void* additional);
|
||||
@@ -38,13 +38,9 @@ struct auth_mod_st {
|
||||
int (*auth_group)(void* ctx, const char *suggested, char *groupname, int groupname_size);
|
||||
int (*auth_user)(void* ctx, char *groupname, int groupname_size);
|
||||
|
||||
int (*open_session)(void *ctx, const void *sid, unsigned sid_size); /* optional, may be null */
|
||||
void (*session_stats)(void *ctx, struct stats_st *stats, const char *ip); /* optional, may be null */
|
||||
void (*close_session)(void *ctx, struct stats_st *stats); /* optional may be null */
|
||||
|
||||
void (*auth_deinit)(void* ctx);
|
||||
void (*group_list)(void *pool, void *additional, char ***groupname, unsigned *groupname_size);
|
||||
};
|
||||
} auth_mod_st;
|
||||
|
||||
void main_auth_init(main_server_st *s);
|
||||
void proc_auth_deinit(main_server_st* s, struct proc_st* proc);
|
||||
|
||||
@@ -95,7 +95,7 @@ client_entry_st *new_client_entry(sec_mod_st *sec, const char *ip)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strlcpy(e->ip, ip, sizeof(e->ip));
|
||||
strlcpy(e->auth_info.remote_ip, ip, sizeof(e->auth_info.remote_ip));
|
||||
|
||||
do {
|
||||
ret = gnutls_rnd(GNUTLS_RND_RANDOM, e->sid, sizeof(e->sid));
|
||||
@@ -114,8 +114,7 @@ client_entry_st *new_client_entry(sec_mod_st *sec, const char *ip)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
snprintf(e->printable_sid, sizeof(e->printable_sid), "%.2x%.2x%.2x",
|
||||
(unsigned) e->sid[0], (unsigned) e->sid[1], (unsigned) e->sid[2]);
|
||||
base64_encode((char *)e->sid, SID_SIZE, (char *)e->auth_info.psid, sizeof(e->auth_info.psid));
|
||||
e->time = time(0);
|
||||
|
||||
if (htable_add(db, rehash(e, NULL), e) == 0) {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <cookies.h>
|
||||
#include <gnutls/abstract.h>
|
||||
#include <ccan/htable/htable.h>
|
||||
#include <base64.h>
|
||||
|
||||
typedef struct sec_mod_st {
|
||||
gnutls_datum_t dcookie_key; /* the key to generate cookies */
|
||||
@@ -44,6 +45,15 @@ typedef struct stats_st {
|
||||
time_t uptime;
|
||||
} stats_st;
|
||||
|
||||
typedef struct common_auth_info_st {
|
||||
char username[MAX_USERNAME_SIZE*2];
|
||||
char groupname[MAX_GROUPNAME_SIZE]; /* the owner's group */
|
||||
char psid[BASE64_LENGTH(SID_SIZE) + 1]; /* printable */
|
||||
char remote_ip[MAX_IP_STR];
|
||||
char ipv4[MAX_IP_STR];
|
||||
char ipv6[MAX_IP_STR];
|
||||
} common_auth_info_st;
|
||||
|
||||
typedef struct client_entry_st {
|
||||
/* A unique session identifier used to distinguish sessions
|
||||
* prior to authentication. It is sent as cookie to the client
|
||||
@@ -52,9 +62,6 @@ typedef struct client_entry_st {
|
||||
*/
|
||||
uint8_t sid[SID_SIZE];
|
||||
|
||||
/* a part of sid used in the logs to differentiate the session */
|
||||
char printable_sid[7];
|
||||
|
||||
void * auth_ctx; /* the context of authentication */
|
||||
unsigned session_is_open; /* whether open_session was done */
|
||||
unsigned in_use; /* counter of users of this structure */
|
||||
@@ -67,10 +74,7 @@ typedef struct client_entry_st {
|
||||
|
||||
unsigned status; /* PS_AUTH_ */
|
||||
|
||||
char ip[MAX_IP_STR]; /* the user's IP */
|
||||
char hostname[MAX_HOSTNAME_SIZE]; /* the requested hostname */
|
||||
char username[MAX_USERNAME_SIZE]; /* the owner */
|
||||
char groupname[MAX_GROUPNAME_SIZE]; /* the owner's group */
|
||||
uint8_t *cookie; /* the cookie associated with the session */
|
||||
unsigned cookie_size;
|
||||
|
||||
@@ -81,6 +85,9 @@ typedef struct client_entry_st {
|
||||
|
||||
/* the auth type associated with the user */
|
||||
unsigned auth_type;
|
||||
|
||||
struct common_auth_info_st auth_info;
|
||||
|
||||
/* the module this entry is using */
|
||||
const struct auth_mod_st *module;
|
||||
} client_entry_st;
|
||||
|
||||
@@ -269,9 +269,9 @@ static int get_sup_config(struct cfg_st *cfg, client_entry_st *entry,
|
||||
char file[_POSIX_PATH_MAX];
|
||||
int ret;
|
||||
|
||||
if (cfg->per_group_dir != NULL && entry->groupname[0] != 0) {
|
||||
if (cfg->per_group_dir != NULL && entry->auth_info.groupname[0] != 0) {
|
||||
snprintf(file, sizeof(file), "%s/%s", cfg->per_group_dir,
|
||||
entry->groupname);
|
||||
entry->auth_info.groupname);
|
||||
|
||||
ret = read_sup_config_file(cfg, msg, pool, file, cfg->default_group_conf, "group");
|
||||
if (ret < 0)
|
||||
@@ -280,7 +280,7 @@ static int get_sup_config(struct cfg_st *cfg, client_entry_st *entry,
|
||||
|
||||
if (cfg->per_user_dir != NULL) {
|
||||
snprintf(file, sizeof(file), "%s/%s", cfg->per_user_dir,
|
||||
entry->username);
|
||||
entry->auth_info.username);
|
||||
ret = read_sup_config_file(cfg, msg, pool, file, cfg->default_user_conf, "user");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
13
src/vpn.h
13
src/vpn.h
@@ -87,6 +87,12 @@ extern int syslog_open;
|
||||
#define AUTH_TYPE_RADIUS (1<<5 | AUTH_TYPE_USERNAME_PASS)
|
||||
#define AUTH_TYPE_GSSAPI (1<<6)
|
||||
|
||||
#define ALL_AUTH_TYPES ((AUTH_TYPE_PAM|AUTH_TYPE_PLAIN|AUTH_TYPE_CERTIFICATE|AUTH_TYPE_RADIUS|AUTH_TYPE_GSSAPI) & (~AUTH_TYPE_USERNAME_PASS))
|
||||
#define VIRTUAL_AUTH_TYPES (AUTH_TYPE_USERNAME_PASS)
|
||||
|
||||
#define ACCT_TYPE_PAM (1<<1)
|
||||
#define ACCT_TYPE_RADIUS (1<<2)
|
||||
|
||||
#define ERR_SUCCESS 0
|
||||
#define ERR_BAD_COMMAND -2
|
||||
#define ERR_AUTH_FAIL -3
|
||||
@@ -218,6 +224,12 @@ typedef struct auth_struct_st {
|
||||
bool enabled;
|
||||
} auth_struct_st;
|
||||
|
||||
typedef struct acct_struct_st {
|
||||
const char *name;
|
||||
char *additional;
|
||||
const struct acct_mod_st *amod;
|
||||
} acct_struct_st;
|
||||
|
||||
typedef struct kkdcp_realm_st {
|
||||
char *realm;
|
||||
struct sockaddr_storage addr;
|
||||
@@ -262,6 +274,7 @@ struct cfg_st {
|
||||
|
||||
auth_struct_st auth[MAX_AUTH_METHODS];
|
||||
unsigned auth_methods;
|
||||
acct_struct_st acct;
|
||||
|
||||
gnutls_certificate_request_t cert_req;
|
||||
char *priorities;
|
||||
|
||||
@@ -618,9 +618,12 @@ int periodic_check(worker_st * ws, unsigned mtu_overhead, time_t now,
|
||||
msg.sid.data = ws->sid;
|
||||
msg.has_sid = 1;
|
||||
|
||||
msg.ip = human_addr2((void *)&ws->remote_addr, ws->remote_addr_len,
|
||||
msg.remote_ip = human_addr2((void *)&ws->remote_addr, ws->remote_addr_len,
|
||||
buf, sizeof(buf), 0);
|
||||
|
||||
msg.ipv4 = ws->vinfo.ipv4;
|
||||
msg.ipv4 = ws->vinfo.ipv6;
|
||||
|
||||
send_msg_to_secmod(ws, sd, SM_CMD_CLI_STATS, &msg,
|
||||
(pack_size_func)cli_stats_msg__get_packed_size,
|
||||
(pack_func) cli_stats_msg__pack);
|
||||
|
||||
@@ -20,6 +20,8 @@ use-occtl = true
|
||||
# to generate password entries.
|
||||
#auth = "plain[/etc/ocserv/ocpasswd]"
|
||||
|
||||
acct = pam
|
||||
|
||||
# A banner to be displayed on clients
|
||||
#banner = "Welcome"
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ use-occtl = true
|
||||
# to generate password entries.
|
||||
#auth = "plain[/etc/ocserv/ocpasswd]"
|
||||
|
||||
acct = "radius[/etc/radiusclient/radiusclient.conf]"
|
||||
|
||||
# A banner to be displayed on clients
|
||||
#banner = "Welcome"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user