Commit Graph
100 Commits
Author SHA1 Message Date
Nikos Mavrogiannopoulos 9e46c9714e Merge branch 'tmp-LICENSE' into 'master'
Add LICENSE files of bundled sotware

See merge request openconnect/ocserv!562
2026-05-30 21:36:22 +00:00
Nikos Mavrogiannopoulos ce350a17e5 Merge branch 'tmp-llhttp' into 'master'
llhttp: updated to latest version 9.4.1

Closes #736

See merge request openconnect/ocserv!564
2026-05-30 21:28:00 +00:00
Nikos Mavrogiannopoulos bcc9d3bff7 .triage-policies.yml: close stale and unassigned issues
Automatically close issues that have been open for more than 6 months
without an assignee and without a linked merge request. Security-labeled
issues are excluded.

The motivation:

- Issues tend to stay open indefinitely under the implicit assumption that
  someone will eventually pick them up. In practice this rarely happens.
- The backlog keeps growing, making it harder to see what is actually
  being worked on.
- The number of contributors who turn an issue into a merge request is
  very small relative to the number of issues filed.
- The goal is to keep the issue tracker focused on work that is actively
  in progress, not as a wishlist.
- Hopefully this encourages a more active contribution culture: instead
  of "I have reported it, someone will pick it up", reporters are nudged
  to either own the fix or accept that it may not happen.

Resolves: #740
Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-05-30 22:51:16 +02:00
Nikos Mavrogiannopoulos 0727bdbe1f worker: detect and handle errors in socket from main
Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-05-30 22:49:07 +02:00
Nikos Mavrogiannopoulos 30f33ac9d1 tun_write/read were made macros in linux for write and read
This avoids an unnecessary function call.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-05-30 22:49:07 +02:00
Nikos Mavrogiannopoulos 2be9af605b tlslib: simplified by requiring gnutls 3.3.5
This removes the (unconditional) ZERO_COPY conditional.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-05-30 22:49:07 +02:00
Nikos Mavrogiannopoulos d3372cbcb4 worker: drain TUN in a burst loop to avoid per-packet epoll_wait()
Previously tun_watcher_cb() called tun_mainloop() exactly once per
libev wakeup and then returned, causing ev_run() to call epoll_wait()
again before the next packet.  At high packet rates the TUN device
stays continuously readable, so this wastes one epoll_wait() syscall
per packet (~20-30 µs each in the report) and keeps the worker nearly
idle while the TUN queue grows.  The result is severe packet loss on the
TUN→client path (74% loss reported at 900 Mbps in issue #423).

Fix by looping in tun_watcher_cb() up to TUN_BURST_MAX iterations before
yielding back to the event loop and making the tun fd non-blocking. That
resulted to a reorganization of tls_mainloop() / dtls_mainloop() via
parse_data() to queue packet when the tunfd isn't writeable.

Resolves: #423

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-05-30 22:49:07 +02:00
Nikos Mavrogiannopoulos f5231eab10 CONTRIBUTING.md: added rule on patches
Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-05-26 13:06:55 +02:00
Nikos MavrogiannopoulosandDimitri Papadopoulos 8faa35d67a Merge branch 'tmp-736' into 'master'
Fix calculation of avg_auth_time acros sec-mod instances

Closes #736

See merge request openconnect/ocserv!560
2026-05-24 16:09:20 +02:00
Nikos Mavrogiannopoulos 0eb7313bca Merge branch 'tmp-736' into 'master'
Fix calculation of avg_auth_time acros sec-mod instances

Closes #736

See merge request openconnect/ocserv!560
2026-05-24 11:24:14 +00:00
Nikos Mavrogiannopoulos efd41d300f Merge branch 'tmp-711' into 'master'
Set `sa` before attempting to set `sa->sin6_family`

Closes #711

See merge request openconnect/ocserv!554
2026-05-24 09:22:08 +00:00
Nikos Mavrogiannopoulos 6b74546a1b Merge branch 'tmp-pcl' into 'master'
Always use the bundled PCL library

Closes #663

See merge request openconnect/ocserv!565
2026-05-24 09:21:42 +00:00
Nikos Mavrogiannopoulos 1b6e22246d Test proxy protocol parser with IPv6 packet
Relates: #711

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-05-23 14:52:01 +00:00
Nikos Mavrogiannopoulos ae021ecf58 Merge branch 'anyconnect-bye-packet' into 'master'
Handle AnyConnect BYE packet with reconnect intention (0x91)

Closes #732

See merge request openconnect/ocserv!555
2026-05-23 14:25:22 +00:00
Nikos Mavrogiannopoulos e5894dba7d NEWS: doc update
Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-05-23 07:43:46 +02:00
Nikos Mavrogiannopoulos 2dd5956317 dtls_send: fix hang and buffer overread on persistent GNUTLS_E_AGAIN
Same two bugs as cstp_send (issue #638): the retry passed the original
data_size instead of the remaining byte count, and GNUTLS_E_AGAIN caused
an unbounded sleep loop.  Apply the same poll()-based fix bounded by
DEFAULT_SOCKET_TIMEOUT.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-05-23 07:39:51 +02:00
Nikos Mavrogiannopoulos d2b78d48ca tests: add live reproducer for cstp_send() hang on frozen peer (issue #638)
Connects an openconnect client, floods ICMP traffic so the server
accumulates ICMP replies in cstp_send(), then freezes the client with
SIGSTOP to prevent the TCP receive buffer from draining.  Asserts that
the worker session disappears from occtl within DEFAULT_SOCKET_TIMEOUT
plus margin, which would never happen with the old infinite retry loop.

Relates: #638

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-05-23 07:39:51 +02:00
Nikos Mavrogiannopoulos 35e3d15a11 cstp_send: fix worker hang and buffer overread on TLS send
A worker could get permanently stuck when a client disappeared silently
(e.g. iOS roaming between WiFi and cellular): the TLS send loop retried
indefinitely on GNUTLS_E_AGAIN with no deadline, requiring SIGKILL to
recover.

A separate bug caused a buffer overread on partial sends: the retry used
the original data_size instead of the remaining byte count, so the send
pointer advanced past the end of the caller's buffer.

Resolves: #638

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-05-23 07:39:51 +02:00
Nikos Mavrogiannopoulos bb9bcd7461 main: remove cgroup support in favour of systemd resource controls
Native cgroup placement is removed. Delegating resource enforcement
to systemd eliminates the privileged /sys/fs/cgroup writes from
the main process and simplifies the code.

Administrators who previously relied on the 'cgroup' option should use
the [Service] section of the ocserv unit file instead; see
systemd.resource-control(5) for details.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-05-23 07:09:23 +02:00
Nikos Mavrogiannopoulos 25861ab602 Merge branch 'tmp-nettle4' into 'master'
Build against GNU Nettle 4

Closes #697

See merge request openconnect/ocserv!553
2026-05-21 06:35:54 +00:00
Nikos Mavrogiannopoulos 788b1a2b30 Merge branch 'tmp-fix-716' into 'master'
worker: stop HTTP parser at message boundary to prevent request pipelining confusion

Closes #716

See merge request openconnect/ocserv!549
2026-05-21 06:34:06 +00:00
Nikos Mavrogiannopoulos 583f0c0be5 worker: fix ICMPv6 misclassification as data traffic affecting idle-timeout
ICMPv6 was never excluded from idle-timeout accounting because is_data()
inspected data[9] for both IPv4 and IPv6.  Offset 9 is the Protocol field
in the IPv4 fixed header (RFC 791), but the Next Header field in the IPv6
fixed header sits at offset 6 (RFC 8200 §3).  As a result, the idle timer
was reset on every ICMPv6 packet, preventing the server from disconnecting
clients that were sending only control traffic.

Resolves: #724
Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-05-19 20:14:21 +02:00
Nikos Mavrogiannopoulos bf23e0d549 /svc handler: add the owasp headers for consistency
Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-05-19 20:11:33 +02:00
Nikos Mavrogiannopoulos e567f92e64 Removed unnecessary CA and certificate handlers
This removes certificate and CA handlers not used by the openconnect
client. This is a hardening measure to further reduce the attack surface
of the worker process.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-05-19 20:11:33 +02:00
Nikos Mavrogiannopoulos 2dfb9acec5 Updated instructions for AI agents reporting vulnerabilities
Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-05-19 16:57:44 +02:00
Nikos Mavrogiannopoulos 0b47ea457d Merge branch 'tmp-uninitialised-handle' into 'master'
Do not use uninitialised PAM/GnuTLS handles

Closes #722

See merge request openconnect/ocserv!547
2026-05-17 19:56:55 +00:00
Nikos Mavrogiannopoulos 6e658f00ae Merge branch 'tmp-NULL-dereference' into 'master'
Avoid NULL dereference in case of memory exhaustion

Closes #721

See merge request openconnect/ocserv!545
2026-05-16 20:20:49 +00:00
Nikos Mavrogiannopoulos 01f2787ab6 worker: reject HTTP pipelining to prevent request confusion
When two HTTP requests arrived in the same TLS read buffer, a single
llhttp_execute() call would fire callbacks for both requests inline.
Because http_req_reset() is not called between them, ws->req ended up
reflecting the second request's URL and headers, silently discarding
the first.  In the worst case, body bytes from the first request
accumulated alongside the second request's body.

Fix this by registering an on_message_begin callback that returns
HPE_PAUSED when an existing message is detected.

Resolves: #716

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-05-15 06:42:24 +02:00
Nikos Mavrogiannopoulos aeaf5a0896 Merge branch 'tmp-seclog-trailing-newline' into 'master'
Avoid trailing `\n` in messages passed to logging

See merge request openconnect/ocserv!544
2026-05-12 18:02:45 +00:00
Nikos Mavrogiannopoulos 6c4a0aca93 Merge branch 'tmp-talloc_array' into 'master'
talloc_size() → talloc_array()

Closes #725

See merge request openconnect/ocserv!541
2026-05-12 05:21:44 +00:00
Nikos Mavrogiannopoulos 923187aa4c Merge branch 'tmp-strerror' into 'master'
Use strerror() and pass proper errno to it

Closes #723

See merge request openconnect/ocserv!542
2026-05-12 05:14:54 +00:00
Nikos Mavrogiannopoulos 93c08b5c83 Merge branch 'pam-service' into 'master'
Add service sub-option to PAM auth

Closes #718

See merge request openconnect/ocserv!539
2026-05-11 17:06:56 +00:00
Nikos Mavrogiannopoulos 2548a27b51 Merge branch 'tmp-AF_INET' into 'master'
Build on FreeBSD

See merge request openconnect/ocserv!514
2026-05-07 01:56:53 +00:00
Nikos Mavrogiannopoulos 22bbad4eb5 worker: add per-worker memory limit via RLIMIT_DATA
Introduce a per-worker heap cap as defense-in-depth against
memory-exhaustion DoS attacks. The limit uses RLIMIT_DATA rather
than RLIMIT_AS: since Linux 4.7 RLIMIT_DATA covers brk and private
anonymous mmap regions, i.e, the paths used by malloc and talloc, while
ignoring shared-library file mappings that inflate RLIMIT_AS without
reflecting actual allocation.

This aligns with haproxy's handling. See also:
https://github.com/torvalds/linux/commit/84638335900f1995495838fe1bd4870c43ec1f67
https://sources.debian.org/src/haproxy/3.2.17-1/src/limits.c?hl=486#L486
https://www.kernel.org/doc/html/latest/mm/overcommit-accounting.html

The cap is computed at worker startup by reading the data+stack field
from /proc/self/statm.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-05-06 13:54:40 +02:00
Nikos Mavrogiannopoulos 4303a12f60 worker: harden HTTP request header size limits
Bound memory growth in the worker for unauthenticated connections by
enforcing HTTP headers limit in addition to HTTP body limit.

Resolves: #712

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-05-06 13:54:21 +02:00
Nikos Mavrogiannopoulos 7efa74f8e8 protobuf files were removed from the repository
This is a follow-up to a65f2c22a2
which did not actually remove the files.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-05-03 19:15:55 +02:00
Nikos Mavrogiannopoulos 8e0f7f460a Merge branch 'tmp-llhttp_cb' into 'master'
llhttp callbacks should return -1 on error

See merge request openconnect/ocserv!537
2026-05-03 17:05:13 +00:00
Nikos Mavrogiannopoulos 8913ffadff doc: updated for nft/iptables dependencies
Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-05-02 18:49:43 +02:00
Nikos Mavrogiannopoulos 4c85218f41 .gitignore: removed leftovers from autotools
Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-05-02 17:21:42 +02:00
Nikos Mavrogiannopoulos 9c44e09356 ocserv-fw-nftables: replace ipcalc with pure-shell mask_to_prefix
ipcalc was used only to convert dotted-decimal subnet masks to CIDR
prefix lengths (e.g. 255.255.0.0 -> 16), replaced with a POSIX shell
script.

Relates: #709

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-05-02 17:21:38 +02:00
Nikos Mavrogiannopoulos dcb1b8d24e Merge branch 'tmp-prefer-nft' into 'master'
meson: nftables is preferred unless only iptables is found

See merge request openconnect/ocserv!531
2026-05-02 15:09:43 +00:00
Nikos Mavrogiannopoulos 465d3ce383 Merge branch 'tmp-framed-ipv6' into 'master'
radius-auth: fix Framed-IPv6-Prefix routes being silently dropped

Closes #710

See merge request openconnect/ocserv!532
2026-05-01 20:21:09 +00:00
Nikos Mavrogiannopoulos dda2015aa4 meson: nftables is preferred unless iptables is explicitly requested
Relates: #709

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-05-01 22:17:04 +02:00
Nikos Mavrogiannopoulos c41b6d52de Merge branch 'tmp-CID-645850' into 'master'
Fix new Coverity Scan defect

See merge request openconnect/ocserv!530
2026-05-01 19:26:45 +00:00
Nikos Mavrogiannopoulos e7d79e232d radius-auth: fix Framed-IPv6-Prefix routes being silently dropped
When processing a RADIUS Access-Accept with Framed-IPv6-Prefix, the code
passed the wrong value for it. Corrected by passing the actual prefix.

Fixes: #710

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-05-01 16:31:38 +02:00
Nikos Mavrogiannopoulos ac5ee6a10b Merge branch 'type-limits-warning' into 'master'
Fix compiler warning when PAM/RADIUS are disabled

See merge request openconnect/ocserv!529
2026-05-01 14:12:10 +00:00
Nikos Mavrogiannopoulos 4334978fd6 Merge branch 'tunnel-all-dns' into 'master'
Fix tunnel-all-dns ignored in user config

Closes #708

See merge request openconnect/ocserv!527
2026-04-27 03:54:29 +00:00
Nikos Mavrogiannopoulos 54e3244b45 tests: fix radius failures with radcli 1.5.0
radcli 1.5.0 validates Message-Authenticator in RADIUS responses
CVE-2024-3596 (BlastRADIUS) and silently discards responses that lack
it.  Make sure that the Message-Authenticator message is known to
the client via the dictionary.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-25 19:40:56 +02:00
Nikos Mavrogiannopoulos 5148c723cb tests: fix flaky radius tests by waiting for server readiness
All six radius tests used a fixed sleep 4 after starting radiusd and
ocserv.  On slow or ASAN-instrumented hosts (CentOS 10 CI) this is
insufficient: freeradius with -xx debug logging takes longer than 4
seconds to load its modules, and even after binding UDP 1812 it continues
initializing its user database before it can process auth requests.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-25 17:20:38 +02:00
Nikos Mavrogiannopoulos 5137ba4309 ai: add AI policy
CONTRIBUTING.md: new AI Assistance Policy section stating that AI use is
assumed and requires no disclosure, that human accountability is what
matters, and that reviewers may request additional explanation for
submissions showing signs of unchecked generation.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-25 12:08:32 +02:00
Nikos Mavrogiannopoulos 855966cd95 ai: add AI guidance, personas
Introduce a structured AI assistance framework for the project:

- AGENTS.md: single, comprehensive AI guidance file for all tools
  (Claude Code, Codex, Copilot, Cursor). Covers the privilege-separation
  architecture invariant, build/test instructions, code style (including
  a rule against deep preprocessor conditionals), memory allocator policy,
  IPC modification procedure, module-specific doc pointers, and a
  contribution checklist split into agent-runnable and human-judgment items.
  Includes a security disclosure gate that redirects potential vulnerability
  reports to the confidential issue tracker before any public MR is opened.

- contrib/ai/personas/ocserv-core-dev.md: maintainer-facing persona with
  project-specific protocols for anti-hallucination (GnuTLS/protobuf/seccomp
  APIs), memory safety (talloc-first, gnutls_malloc exception), a taxonomy
  of ocserv-specific vulnerability classes, and a self-verification protocol
  that distinguishes what an agent can check automatically from what requires
  human judgment.

- contrib/ai/personas/ocserv-contributor.md: external-contributor-facing
  persona with mandatory architecture orientation, a prominent security
  disclosure gate, five hard guardrails (privilege boundary, syscall
  portability, GnuTLS-only, protobuf regeneration, talloc), and a
  step-by-step workflow for features, bug fixes, and security fixes.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-25 12:08:32 +02:00
Nikos Mavrogiannopoulos a65f2c22a2 protobuf source files are generated during release
Protobuf files are removed from the repository and are only
auto-generated during dist.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-23 19:21:27 +02:00
Nikos Mavrogiannopoulos 58a67f14f3 config: extend vhost_inherit_static_config to cover vhost-scoped fields
All [scope: vhost (non-reloadable)] fields in static_cfg_st now inherit
from the default vhost when not explicitly set in a named-vhost section,
consistent with how ReloadableConfig fields already behave.  This means
a named vhost that shares the same TLS cert, CA, auth method, or PKCS#11
pins as the default no longer has to repeat them.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-23 10:51:26 +02:00
Nikos Mavrogiannopoulos 112afa683c config: treat expose-iroutes as a normal configuration option
That is store it in VhostConfig and avoid manual clearing of it.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-22 20:29:26 +02:00
Nikos Mavrogiannopoulos 836e6f0785 config: fix scope annotation and vhost guards for global-only options
NetworkConfig.name ('device' key) is global-only: the parser calls
error_on_vhost() and tun.c always reads it from the default vhost.
Annotate it as [scope: global] in cfg.proto to match the implementation.

Also add missing error_on_vhost() guards to the deprecated aliases
'use-seccomp' (for isolate-workers), 'use-dbus' (for use-occtl) and
'min-reauth-time' (for ban-time). Their canonical replacements already
reject vhost use; the aliases did not.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-22 20:29:24 +02:00
Nikos Mavrogiannopoulos 139ff827d9 config: restructure per-vhost configuration for clarity and maintainability
Introduce a protobuf-generated ReloadableConfig (cfg.proto) to hold all
fields that reload on SIGHUP, and separate them from static_cfg_st, which
holds fields that require a server restart.  Named vhosts inherit from the
default vhost via a pack/unpack round-trip. Adding a new config field
only requires editing cfg.proto.  Struct and accessor names (ReloadableConfig,
static_cfg_st, GETRCONFIG, GETSCONFIG) now reflect each field's lifetime.
A new unit test covers the full inheritance path.

Resolves: #705

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-22 20:29:15 +02:00
Nikos Mavrogiannopoulos 1228688fb2 Merge branch 'tmp-rfc1123' into 'master'
valid_hostname: enhance to cover RFC 1123 requirements

See merge request openconnect/ocserv!525
2026-04-22 11:20:05 +00:00
Nikos Mavrogiannopoulos caacc92c28 Merge branch 'doc-user-config' into 'master'
doc: clarify reload behavior for per-user/group configs

See merge request openconnect/ocserv!526
2026-04-21 18:58:01 +00:00
Nikos Mavrogiannopoulos 745d7883be design.md: include auth state in the diagram
Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-21 19:19:32 +02:00
Nikos Mavrogiannopoulos 56055a2ed0 Merge branch 'udp-desync' into 'master'
Do not forward UDP until client is authenticated

Closes #706

See merge request openconnect/ocserv!522
2026-04-21 16:42:35 +00:00
Nikos Mavrogiannopoulos a9f42c892c valid_hostname: enhance to cover RFC 1123 requirements
Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-18 15:51:20 +02:00
Nikos Mavrogiannopoulos 0f7640bcea Merge branch 'tmp-claude' into 'master'
RFC 952 prohibits trailing hyphen

See merge request openconnect/ocserv!523
2026-04-18 13:43:36 +00:00
Nikos Mavrogiannopoulos c0e3aa6c5c Merge branch 'tmp-disable-adaptive-rate-limit' into 'master'
Add check to disable adaptive rate limiting

Closes #493

See merge request openconnect/ocserv!476
2026-04-18 13:32:07 +00:00
Nikos Mavrogiannopoulos da90b76b07 bumped versions
Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-17 00:08:27 +02:00
Nikos Mavrogiannopoulos c520accb84 Released 1.4.2
Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-16 23:27:59 +02:00
Nikos Mavrogiannopoulos 537e171664 worker-auth: require exact session_id length in cookie auth reply
recv_cookie_auth_reply() used > instead of != when validating
msg->session_id.len, allowing a shorter-than-expected length to
pass. ws->session_id is always consumed at full sizeof() by the
DTLS session setup; a short fill would leave stale tail bytes.
Align with the stricter != check used in recv_auth_reply().

proxy-proto: abort on zero-length unknown TLV in parse_ssl_tlvs()

An unknown TLV with length == 0 caused an infinite loop: the
AVAIL_HEADER_SIZE macro subtracted nothing and data did not
advance. Detect this and return early, consistent with how
AVAIL_HEADER_SIZE handles other malformed headers.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-16 23:05:34 +02:00
Nikos Mavrogiannopoulos 5d0a4dadc4 NEWS: documented updates
Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-16 22:53:37 +02:00
Nikos Mavrogiannopoulos bc961061d1 worker: fix PP2_SUBTYPE_SSL_CN parsed as top-level TLV instead of sub-TLV
Per proxy protocol v2 spec §2.2.6, PP2_SUBTYPE_SSL_CN (0x22) is a
sub-TLV inside the PP2_TYPE_SSL body, not a top-level TLV in the TLV
stream.  The previous code looked for 0x22 at the top level, where
haproxy never sends it, so client certificate CN was never extracted
via proxy protocol.

Fix parse_ssl_tlvs() to scan the bytes after the fixed pp2_tlv_ssl
header as a nested sub-TLV loop when cert_auth_ok is set.

Also fix htons() -> ntohs() for the TLV length byte-swap (functionally
identical but semantically correct for a network-to-host conversion),
and update the misleading comment that claimed the field was
little-endian.

Add tests/proxyproto-v2.c, a unit test that feeds a binary proxy
protocol v2 packet with PP2_TYPE_SSL + PP2_SUBTYPE_SSL_CN sub-TLV
through parse_proxy_proto_header() and verifies that cert_auth_ok and
cert_username are populated correctly.  Also covers verify!=0, missing
CERT_SESS flag, no CN sub-TLV, and TCP conn_type (TLV parsing skipped).

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-16 22:46:41 +02:00
Nikos Mavrogiannopoulos a0504dd5a7 main: bound-check sec-mod message length before allocation
handle_sec_mod_commands() lacked an upper-bound check on the `length`
field received from the sec-mod socket before passing it to talloc_size().
The worker command handler already applies a MAX_MSG_SIZE guard.

Replace the redundant (int)length < 0 cast (impossible for uint32_t) with
a length > MAX_MSG_SIZE check, matching the pattern in handle_worker_commands().
Also fix the format specifier from %d to %u for the uint32_t length.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-16 22:46:41 +02:00
Nikos Mavrogiannopoulos 8355aa080e sec-mod: call sec_auth_user_deinit on all entries at teardown
On sec-mod exit, sec_mod_client_db_deinit() freed client entries via
talloc_free without first calling sec_auth_user_deinit(), leaving open
accounting sessions (RADIUS, PAM) and auth module state uncleaned.

Iterate over all entries and call sec_auth_user_deinit() before the
htable_clear/talloc_free teardown, matching the behaviour of the normal
del_client_entry -> clean_entry path.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-16 22:46:41 +02:00
Nikos Mavrogiannopoulos b37a2dd0de sec-mod: guard against NULL orig_remote_ip in auth init HMAC
protobuf-c sets absent string fields to NULL at runtime even when
marked required in the schema, contrary to the in-code comment.
Calling strlen(NULL) is undefined behaviour and crashes sec-mod.
A compromised worker could exploit this to deny authentication for
all connected clients.

Add an explicit NULL check before the strlen call, consistent with
the existing guard on the our_ip field.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-16 22:46:41 +02:00
Nikos Mavrogiannopoulos 22a0c2d54c sec-mod: bound-check cli_addr.len before memcpy in TLS session store
A compromised worker could supply a cli_addr.len value larger than
sizeof(struct sockaddr_storage) (128 bytes), overflowing the fixed-size
remote_addr field in tls_cache_st and corrupting adjacent talloc heap
metadata inside the privileged sec-mod process.

Add the missing upper-bound check, consistent with the existing checks
on session_id.len and session_data.len in the same function.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-16 22:46:41 +02:00
Nikos Mavrogiannopoulos 0db69e24f9 worker-tun: eliminate strict-aliasing UB in tun_write()
Accessing iph->ip_v via a struct ip* cast from void* is undefined
behaviour under C99/C11 strict-aliasing rules.  Replace the cast with a
direct byte read from the existing uint8_t pointer; the IP version is in
the high nibble of the first byte (finding 4.2).

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-16 22:46:41 +02:00
Nikos Mavrogiannopoulos 175867ce71 worker-http: fix unsigned comparison with <= 0 in header_value_check()
req->value.length is size_t (unsigned); comparing it with <= 0 is
equivalent to == 0 but misleading.  Use == 0 to accurately reflect
the intent (finding 4.1).

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-16 22:46:41 +02:00
Nikos Mavrogiannopoulos f2795a10a9 worker-auth: guard against NULL msg->msg in recv_auth_reply()
msg->msg is a protobuf optional field and may be NULL.  Guard the
talloc_strdup call so a missing message field does not silently
propagate NULL to the caller (finding 2.2).

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-16 22:46:41 +02:00
Nikos Mavrogiannopoulos 4c9e97fe2d worker-auth: document intentional protobuf message lifetime for user_config
ws->user_config borrows a pointer into the unpacked auth_cookie_reply
protobuf message.  The message must therefore stay alive for the entire
worker session and is only freed on the error path.  Clarify this
non-obvious ownership invariant with a comment so future readers do not
accidentally free msg on success (finding 1.2).

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-16 22:46:41 +02:00
Nikos Mavrogiannopoulos 1acf13f0bd proxy-proto: fix TLV parsing loop skipping data pointer advance
Two continue statements in parse_ssl_tlvs() bypassed the
data += tlv.length update at the bottom of the loop:

- PP2_TYPE_SSL with tlv.length < sizeof(pp2_tlv_ssl): the body bytes
  were re-parsed as a new TLV header on the next iteration.
- PP2_TYPE_SSL_CN with an oversized length: same misbehaviour, and
  could allow a crafted proxy header to cause ws->cert_auth_ok to be
  set without a real client certificate being present.

Fix by advancing data and decrementing data_size within each branch
before continuing, and moving data += tlv.length into each branch so
the loop has no shared trailing update to be skipped. Also preserve
the full original TLV length for PP2_TYPE_SSL to consume the entire
body rather than only sizeof(pp2_tlv_ssl) bytes.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-16 22:46:41 +02:00
Nikos Mavrogiannopoulos 071762674e proxy-proto: fix our_addr_len set to IPv4 size for IPv6 connections
When parsing a proxy protocol v2 header with AF_INET6, our_addr_len
was set to sizeof(struct sockaddr_in) (16) instead of
sizeof(struct sockaddr_in6) (28). Any socket API call passing
(our_addr, our_addr_len) for an IPv6 address would use a truncated
length, potentially reading uninitialised memory.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-16 22:46:41 +02:00
Nikos Mavrogiannopoulos 8e6d81a83a worker: validate session_id length from IPC reply before memcpy
recv_cookie_auth_reply() copied msg->session_id into the fixed-size
ws->session_id buffer without checking that msg->session_id.len fits.
A malformed IPC message could overflow the buffer. Add the same length
guard that recv_auth_reply() already applies to dtls_session_id.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-16 22:46:41 +02:00
Nikos Mavrogiannopoulos 464463c594 worker: limit HTTP request body to 256 KB to prevent memory exhaustion
An unauthenticated client could stream an arbitrarily large POST body,
causing the worker process to grow its heap without bound via repeated
talloc_realloc_size() calls in http_body_cb(). Add a 256 KB cap that
covers the largest legitimate payload (KKDCP Kerberos messages) while
rejecting oversized bodies early by returning an llhttp error code.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-16 22:46:41 +02:00
Nikos Mavrogiannopoulos 76a17dadac Merge branch 'del_build-aux' into 'master'
build: remove obsolete build-aux directory

See merge request openconnect/ocserv!519
2026-04-15 06:48:04 +00:00
Nikos Mavrogiannopoulos d3eceef085 Merge branch '64bit-timestamps' into 'master'
protobuf: use 64-bit signed integers for timestamp fields

See merge request openconnect/ocserv!506
2026-04-14 19:03:05 +00:00
Nikos Mavrogiannopoulos 468335a7cf Merge branch 'vhosts-no-udp' into 'master'
Allow using no-udp option in vhosts

Closes #680

See merge request openconnect/ocserv!516
2026-04-14 19:02:03 +00:00
Nikos Mavrogiannopoulos 4a0a087996 config: align default values with sample.config
Several options had hardcoded or named defaults in apply_default_conf()
that diverged from the values documented in doc/sample.config, leading
to silent behaviour differences for servers running without explicit
configuration.

Relates: #680

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-14 18:57:45 +02:00
Nikos Mavrogiannopoulos 611eb00527 config: add scope annotations and validation script
Add machine-readable [scope: X] annotations to doc/sample.config and
src/vpn.h struct fields to document which config options are permanent,
global-only, per-vhost, or per-user/group overridable.

Scope vocabulary:
  global (non-reloadable)  -- in perm_cfg_st; requires restart; cannot differ per vhost
  vhost (non-reloadable)   -- in perm_cfg_st; requires restart; can differ per vhost
  global            -- in cfg_st; reloadable; cannot be set in [vhost:] sections
  vhost             -- in cfg_st; reloadable; can differ per vhost
  vhost user        -- in cfg_st; reloadable; also overridable per user/group

Add tests/check-config-scope.py: a script that cross-checks the annotations
against the actual code:
  (a) every option in sample.config has a [scope:] annotation
  (b-c) [global] options match error_on_vhost() calls in config.c
  (d-e) [vhost user] options match handlers in src/sup-config/file.c
  (f) every field in cfg_st and perm_cfg_st has a [scope:] comment

Also fix a pre-existing bug in src/sup-config/file.c: the tunnel-all-dns
option was compared using an underscore ("tunnel_all_dns") instead of
the correct dash ("tunnel-all-dns"), silently ignoring the per-user
setting.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-14 18:57:45 +02:00
Nikos Mavrogiannopoulos 62a5f72864 DPD time: corrected duplicate assignment and set value for mobile-dpd
Resolves: #680

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-14 18:57:45 +02:00
Nikos Mavrogiannopoulos 0096ebcc2b config: convert warn_on_vhost to error_on_vhost
Setting a global-only option (e.g. rate-limit-ms, device, ban-time)
inside a [vhost:X] section previously produced a warning and silently
discarded the value, leaving administrators wondering why the setting
had no effect.

Replace warn_on_vhost() with error_on_vhost() which emits an ERRSTR
diagnostic and returns 0 from the ini handler.  Returning 0 causes
ini_parse() to record a parse error, which in turn causes
parse_cfg_file() to call exit(EXIT_FAILURE), aborting startup or a
SIGHUP reload.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-14 18:57:44 +02:00
Nikos Mavrogiannopoulos 05cf33adb7 tests: added tests for multiple ocpasswd options
Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-13 22:43:52 +02:00
Nikos Mavrogiannopoulos 24d924f65c Merge branch 'tmp-typos' into 'master'
Fix typos

See merge request openconnect/ocserv!515
2026-04-10 04:31:08 +00:00
Nikos Mavrogiannopoulos db50c02cbd Merge branch 'tmp-radius-group-separator' into 'master'
radius: add group-separator option for OU= Class attributes

Closes #428

See merge request openconnect/ocserv!513
2026-04-10 04:29:39 +00:00
Nikos Mavrogiannopoulos 78e6a28ff5 Merge branch 'bugfix/vhosts' into 'master'
Fix virtual host global option inheritance

Closes #698

See merge request openconnect/ocserv!505
2026-04-10 04:28:52 +00:00
Nikos Mavrogiannopoulos 89a40dde31 tests: add radius-multi-group-comma test for group-separator=comma
Regression test for the group-separator=comma option: verifies that
OU= Class attributes with comma-separated group names (as sent by
Freeradius) are correctly parsed when group-separator=comma is set.

Relates: #428

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-06 21:27:28 +02:00
Nikos Mavrogiannopoulos 828fca691e radius: add group-separator option for OU= Class attributes
Freeradius deployments may send groups in the Class attribute using a
comma as separator (e.g. "OU=group1,group2") rather than the semicolon
that ocserv expects by default. Add a group-separator option to the
radius auth configuration to allow this to be changed:

  auth = "radius[config=...,group-separator=comma]"

Accepted values are 'semicolon' (default) and 'comma'. The literal
character is not accepted in the config syntax as it conflicts with the
key=value pair delimiter.

Resolves: #428

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-06 21:27:28 +02:00
Nikos Mavrogiannopoulos ab23290899 .gitignore: added .cache
Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-06 21:26:58 +02:00
Nikos Mavrogiannopoulos 95c8207e07 auth/plain: use real passwd salt for timing normalisation and clear on deinit
Instead of always using a hardcoded $5$fakesalt$ when the requested user
is not found, read_auth_pass() now captures the salt from the first entry
in the passwd file whose password field starts with '$'. This ensures the
crypt() call in plain_auth_pass() uses the same algorithm as real entries,
preventing observable timing differences that could leak username existence.
Falls back to $5$fakesalt$ when no usable entry is found.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-06 21:12:38 +02:00
Nikos Mavrogiannopoulos 2e81af318e strsep: removed conditional code for strsep
strsep() was used conditionally in plain authentication with fallback
code, whereas radius code used it unconditionally. Rely on strsep()
unconditionally to simplify the code.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-06 21:02:06 +02:00
Nikos Mavrogiannopoulos 85b4d19f0a tests: check that empty password with correct OTP fails when password is set
Regression test: a user with both a password and OTP configured must not
be able to authenticate by supplying an empty password (even with the
correct OTP).

Relates: #323
Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-03 13:58:18 +02:00
Nikos Mavrogiannopoulos ebb34f6787 auth/plain: fix password retry and prevent username enumeration via timing
Corrected bugs that prevented a correct password from being accepted after
a wrong one in the same session:

- worker-auth.c: a stale webvpncontext SID cookie caused a reconnecting
  client to skip SEC_AUTH_INIT and jump directly to SEC_AUTH_CONT with
  a PS_AUTH_FAILED session, which sec-mod rejects.

- auth/plain.c: the 'failed' flag was sticky across retry attempts, so a
  correct password following a wrong one was still treated as failure.
  Refactored into 'unknown_user' (sticky, for timing protection) and a
  local 'wrong_pass' (fresh each call). crypt() is now always called
  regardless of whether the user exists to normalise response timing and
  prevent username enumeration.

Resolves: #323

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-03 13:55:07 +02:00
Nikos Mavrogiannopoulos c45e3467bb tests: check for the case where a password is incorrectly entered
This is a reproducer for the issue reported in #323

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-03 12:29:01 +02:00
Nikos Mavrogiannopoulos 9840050511 .gitlab-ci.yml: increased jobs
Several tests run longer without taking any resources, allow
more parallelization to finish faster.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
2026-04-02 23:15:56 +02:00