UA_FileTransferDriver_openHandle creates a Session handle with the checks of
Open, e.g. for OpenWithMasks of a TrustList (Part 12). Its openContext reaches
the backend open.
The backend open gets the caller as a context: the Session of Open, CreateFile
and the copies of MoveOrCopy, NULL for direct calls. Its result reaches the
client.
Replace pathname-based chmod calls in localWriteOnlyFile with fchmod on a retained descriptor, addressing the three CodeQL TOCTOU comments. Close the descriptor before removing the scratch directory.
Restore application contexts before subtree deletion and keep original ownership separate from explicit Delete/move operations. Preserve contexts allocated by constructors for driver-created Objects as well.
Propagate entry metadata errors so a cross-driver move cannot delete an uncopied source file. Add lifecycle and local filesystem regressions covering both findings.
Size, LastModifiedTime, Writable and UserWritable returned the scalar for an
IndexRange (Part 4 7.27). Writable and UserWritable ignored a denied Traverse
on a managed ancestor that Open enforces (Part 20 4.2.1).
The Delete and MoveOrCopy Methods kept application Objects of the removed
storage entries; teardown and refresh still only release them. The subtree
release iterates the children instead of re-reading the child index.
A readdir() error ended the listing early, so a move to another driver could
delete source files that were never copied. Writing a file needs no read
access anymore (Part 20 4.2.2).
UA_GDSReceiver_start did not start when initGDSRolePermissions failed,
but left the push method callbacks installed. The RolePermissions are
one way to restrict the methods to SecurityAdmin (Part 12, 7.10). RBAC
is optional, and the AccessControl plugin can restrict the methods as
well. So a failed role setup is now logged as a warning and the receiver
starts.
UA_Server_run_startup ignored the driver results and ran without
listening. It now fails if a transport cannot open its socket and
neither another transport nor a reverse connect reaches the server.
Avoid comparing an unset optional endpoint override with strncmp. Use an exact UA_String comparison against the configured connection URL for all three discovery helpers, and initialize result outputs before early errors.
Cover matching URLs with session and channel-only connections, and reject different hosts and URL prefixes. Validated discovery, server node services, server lifecycle and event loop suites under ASan/UBSan.
Allow PubSub connections to be configured and enabled while the event loop and connection
managers are still fresh. Defer transport validation and socket creation until the server
starts. Enabled connections remain paused during configuration and automatically transition to
operational once the PubSub manager becomes active.
Add lifecycle coverage for creating and enabling a UDP PubSub connection before server startup.
Handles survive a vanished file or a replaced parent, Read at the end returns an
empty ByteString, the root is queried with the complete backend, failed starts
are logged and the analyzer accepts releaseSubtree.
refresh-interval 0 disables the timer, UA_FileTransferDriver_refresh() reconciles
on demand. The directory Methods respect max-scan-depth; skipped entries and cut
trees are logged at start and when they change.
Add the file transfer tutorial, a custom in-memory backend example, and
build and feature documentation. Wire the public API and tutorial into
the generated driver documentation.
Co-authored-by: Julius Pfrommer <julius.pfrommer@o6-automation.com>
Exercise backend contracts, access rights, session isolation, handle limits,
reconciliation, partial failures, reused-node restoration, shared Methods,
and independent driver lifecycles. Include client/server transfers and
zip-tree cleanup regressions. Build the suites when Method calls and the
required Namespace Zero types are available.
Co-authored-by: Julius Pfrommer <julius.pfrommer@o6-automation.com>
Serve a single file or a directory using the shared file backend operations.
Validate relative paths, create entries exclusively, and avoid replacing an
existing rename destination. Support Windows UTF-16 paths and filter links
to directories and special files during enumeration.
Co-authored-by: Julius Pfrommer <julius.pfrommer@o6-automation.com>
Expose one file or directory backend through FileType and FileDirectoryType
Objects. Bind Objects to the driver lifetime, preserve reused application
nodes, and close session handles on stop or session cleanup.
Enforce file and directory access rights in Properties and Methods. Index
entries and handles with zip trees, reconcile storage changes, and retain
removed entries while their handles remain open. Include the reduced
namespace model and compile the driver with Method-call support in every
Namespace Zero configuration. Export the API unconditionally.
Co-authored-by: Julius Pfrommer <julius.pfrommer@o6-automation.com>
Reject registering the same driver twice, which would create a cycle in the
server's driver list. Permit multiple generic drivers and enforce a single
instance for each specialized driver type.
Return the start callback's error when a driver is added to a running server.
Unlink a failed registration, retain its server pointer for cleanup, and leave
ownership with the caller. Cover failure, retry, and shutdown in server tests.
ActivateSession decrypts the UserIdentityToken in place (decryptUserToken). Afterwards
auditActivateSessionEvent put that token unchanged into the audit payload, so the
payload carried the plaintext password of a UserNameIdentityToken (also when it was
sent RSA-OAEP encrypted on a SignAndEncrypt channel) or the plaintext tokenData of an
IssuedIdentityToken.
The payload is used in two places, and both leaked the secret:
- the auditNotificationCallback / globalNotificationCallback of the application;
- the event fields of the AuditActivateSessionEventType event that is generated on
the Server object. A MonitoredItem selecting /UserIdentityToken receives the
password of every user who logs in. Audit events are meant to be collected by
audit/SIEM clients, so the secret leaves the server and ends up in logs.
This affects master only (the auditing code is not in a release branch) and only
servers with auditingEnabled.
Put a shallow copy of the token without password / tokenData into the payload. The
copy lives on the stack of auditActivateSessionEvent and outlives the synchronous
auditSessionEvent call; no allocation. PolicyId, UserName and EncryptionAlgorithm
are kept for the audit trail. Other token types are unchanged.
The test logs in as user1 and checks both the audit notification and the
AuditActivateSessionEventType event received by a local event MonitoredItem on the
Server object: they name user1 and carry no password. Without the fix both carried
the password.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Part 6 6.8.1 excludes the encrypting key and IV from L for ECC policies
without AEAD in SecurityMode Sign. We derived the full length, so Sign
with nistP256/384 and brainpool failed with other stacks. Adds a test.
Without encryption support, the #None endpoint offered x509 and password
tokens that ActivateSession always rejects. The endpoint check now runs in
every build. It removes x509 tokens without the password warning.
UA_Node_insertOrUpdateLocale told a null locale from an empty one, so a
DisplayName or Description written with one could not be updated or removed
with the other. Part 3, 8.4 treats both as the unknown locale.
readRaw_service_default parsed the IndexRange of each node to read, but
never freed the dimensions of the parsed range. Every raw history read with
an IndexRange leaked them. They are now freed after the backend call.
The services call six AccessControl callbacks without a NULL check, so a
plugin without one of them crashed the server on the first request.
UA_Server_run_startup now refuses such a plugin with BadConfigurationError.
UA_Server_removeReverseConnect unlinked a connected entry and its CLOSING
callback unlinked it again, which corrupted the list. The entry now stays
linked until its connection has closed.
Read and Write took onRead/onWrite of an external value source from
valueSource.internal, but the setter stores them in valueSource.external at
a different offset of the union. So they never fired.