Files
ocserv/src/main-auth.c
T
Dimitri Papadopoulos a2ec3bba9c Consistent include files and directives
* Import system headers as `#include <...>`.
* Import local headers as `#include "..."`.
* Use consistent header guards (starting with `OC_`).

Signed-off-by: Dimitri Papadopoulos <3350651-DimitriPapadopoulos@users.noreply.gitlab.com>
2026-06-06 15:23:54 +02:00

238 lines
6.2 KiB
C

/*
* Copyright (C) 2013-2020 Nikos Mavrogiannopoulos
* Copyright (C) 2014, 2015 Red Hat, Inc.
*
* This program 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.
*
* This program 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 <unistd.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netdb.h>
#include <signal.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#include "tlslib.h"
#include "script-list.h"
#include "ip-lease.h"
#include "proc-search.h"
#include "str.h"
#include "vpn.h"
#include "tun.h"
#include "main.h"
#include "ccan/list/list.h"
#include "common/common.h"
int send_cookie_auth_reply(main_server_st *s, struct proc_st *proc, AUTHREP r)
{
AuthCookieReplyMsg msg = AUTH_COOKIE_REPLY_MSG__INIT;
int ret;
if (r == AUTH__REP__OK && proc->tun_lease.name[0] != 0) {
char ipv6[MAX_IP_STR];
char ipv4[MAX_IP_STR];
char ipv6_local[MAX_IP_STR];
char ipv4_local[MAX_IP_STR];
/* fill message */
msg.reply = AUTH__REP__OK;
msg.has_session_id = 1;
msg.session_id.data = proc->dtls_session_id;
msg.session_id.len = sizeof(proc->dtls_session_id);
msg.sid.data = proc->sid;
msg.sid.len = sizeof(proc->sid);
msg.session_start_time = proc->session_start_time;
msg.vname = proc->tun_lease.name;
msg.user_name = proc->username;
msg.group_name = proc->groupname;
if (proc->ipv4 && proc->ipv4->rip_len > 0) {
msg.ipv4 = human_addr2(
(struct sockaddr *)&proc->ipv4->rip,
proc->ipv4->rip_len, ipv4, sizeof(ipv4), 0);
msg.ipv4_local =
human_addr2((struct sockaddr *)&proc->ipv4->lip,
proc->ipv4->lip_len, ipv4_local,
sizeof(ipv4_local), 0);
}
if (proc->ipv6 && proc->ipv6->rip_len > 0) {
msg.ipv6 = human_addr2(
(struct sockaddr *)&proc->ipv6->rip,
proc->ipv6->rip_len, ipv6, sizeof(ipv6), 0);
msg.ipv6_local =
human_addr2((struct sockaddr *)&proc->ipv6->lip,
proc->ipv6->lip_len, ipv6_local,
sizeof(ipv6_local), 0);
}
msg.config = proc->config;
msg.secmod_addr.data =
(uint8_t *)&s
->sec_mod_instances[proc->sec_mod_instance_index]
.secmod_addr;
msg.secmod_addr.len =
s->sec_mod_instances[proc->sec_mod_instance_index]
.secmod_addr_len;
ret = send_socket_msg_to_worker(
s, proc, AUTH_COOKIE_REP, proc->tun_lease.fd, &msg,
(pack_size_func)auth_cookie_reply_msg__get_packed_size,
(pack_func)auth_cookie_reply_msg__pack);
} else {
msg.reply = AUTH__REP__FAILED;
ret = send_msg_to_worker(
s, proc, AUTH_COOKIE_REP, &msg,
(pack_size_func)auth_cookie_reply_msg__get_packed_size,
(pack_func)auth_cookie_reply_msg__pack);
}
if (ret < 0) {
int e = errno;
mslog(s, proc, LOG_ERR, "send_msg: %s", strerror(e));
return ret;
}
return 0;
}
int handle_auth_cookie_req(sec_mod_instance_st *sec_mod_instance,
struct proc_st *proc,
const AuthCookieRequestMsg *req)
{
main_server_st *s = sec_mod_instance->server;
int ret;
struct proc_st *old_proc;
if (req->cookie.data == NULL || req->cookie.len != sizeof(proc->sid))
return -1;
/* generate a new DTLS session ID for each connection, to allow
* openconnect of distinguishing when the DTLS key has switched. */
ret = gnutls_rnd(GNUTLS_RND_NONCE, proc->dtls_session_id,
sizeof(proc->dtls_session_id));
if (ret < 0)
return -1;
proc->dtls_session_id_size = sizeof(proc->dtls_session_id);
/* check for a user with the same sid as in the cookie */
old_proc = proc_search_sid(s, req->cookie.data);
if (old_proc != NULL) {
if (old_proc->invalidated != 0) {
mslog(s, proc, LOG_ERR,
"the reused session has been invalidated");
return -1;
}
}
/* loads sup config and basic proc info (e.g., username) */
ret = session_open(sec_mod_instance, proc, req->cookie.data,
req->cookie.len);
if (ret < 0) {
mslog(s, proc, LOG_INFO, "could not open session");
return -1;
}
/* disconnect and reuse previous session's IPs*/
if (old_proc != NULL) {
if (strcmp(proc->username, old_proc->username) != 0) {
mslog(s, old_proc, LOG_ERR,
"the user of the new session doesn't match the old (new: %s)",
proc->username);
return -1;
}
mslog(s, old_proc, LOG_INFO,
"disconnecting previous user session due to session reuse");
/* steal its leases */
steal_ip_leases(old_proc, proc);
if (old_proc->pid > 0) {
kill_proc(old_proc);
}
mslog(s, proc, LOG_DEBUG, "reusing session");
} else {
mslog(s, proc, LOG_INFO, "new user session");
}
/* update the SID */
memcpy(proc->sid, req->cookie.data, req->cookie.len);
/* this also hints to call session_close() */
proc->active_sid = 1;
if (req->hostname != NULL)
strlcpy(proc->hostname, req->hostname, sizeof(proc->hostname));
/* add the links to proc hash */
if (proc_table_add(s, proc) < 0) {
mslog(s, proc, LOG_ERR, "failed to add proc hashes");
return -1;
}
return 0;
}
/* Checks for multiple users.
*
* It returns a negative error code if more than the maximum allowed
* users are found.
*
* In addition this function will also check whether the cookie
* used had been reused before, and then disconnect the old session
* (cookies are unique).
*/
int check_multiple_users(main_server_st *s, struct proc_st *proc)
{
struct proc_st *ctmp = NULL, *cpos;
unsigned int entries = 1; /* that one */
unsigned int max;
max = proc->config->max_same_clients;
if (max == 0)
return 0;
list_for_each_safe(&s->proc_list.head, ctmp, cpos, list)
{
if (ctmp != proc && ctmp->pid != -1) {
if (!ctmp->pid_killed &&
strcmp(proc->username, ctmp->username) == 0) {
entries++;
if (entries > max)
return -1;
}
}
}
return 0;
}