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_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.
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.
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>
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>
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.
Links to a deleted MonitoredItem were only removed when the triggering item reported. If it never reports (Disabled mode, or a value that does not change), they stay forever, and since MonitoredItem ids are never reused a client can grow the link array of one item without bound by creating, linking and deleting items in a loop. Every addLink scans that array, so SetTriggering gets slower with each round.
Part 4, 5.13.1.6 says that the link goes away with the triggered item. SetTriggering now prunes the links of the triggering item to MonitoredItems that no longer exist before applying the request, which keeps the array bounded by the items of the Subscription.
CreateMonitoredItems, ModifyMonitoredItems, SetMonitoringMode and DeleteMonitoredItems all check maxMonitoredItemsPerCall, but SetTriggering accepted any number of links. Apply the same limit there, counting the links to add and the links to remove together, and return Bad_TooManyOperations above it (Part 4, 5.13.5).
Also free removeResults with its own size in the out-of-memory path, it was using linksToAddSize.
Match the server loop atomic reads when starting and stopping the test server. This fixes the ThreadSanitizer race introduced by the 1.5 merge.
Validation: reproduced the race locally before the fix; check_accesscontrol passes with ThreadSanitizer after the fix.
Port keyless certificate validation into the GDS receiver driver instead
of restoring the removed server implementation. Preserve master's timer
batching, PubSub lifecycle and client HTTP configuration handling.
Adapt Publish cancellation to response tokens and the HEL/fuzz harnesses
to the explicit TCP driver. Keep SKS policy history and custom datatype
ownership intact, including failed replacement configuration cleanup.
Retain TPM error cleanup while enforcing key-handle and nonce lengths.
Validation:
- Full mbedTLS unit-test build with full namespace, GDS, SKS and Query.
- 21 affected suites passed with ASan/UBSan, plus 9 isolated SKS ownership
and lifecycle checks.
- OpenSSL certificate update, GDS information model and client encryption
suites passed with sanitizers.
- OPN, MSG and binary-message fuzzers each completed 100 sanitizer runs.
- Both TPM PubSub policy sources passed compilation checks.
The full SKS client suite timed out after multicast UDP sends reported
"No route to host" on this machine; its affected ownership and lifecycle
cases passed separately. No live TPM hardware validation was performed.
Adapt the incoming fixes and regressions to the 1.5 encoding options,
nodestore, connection-manager, PubSub and session APIs. Preserve the
strict HEL EndpointUrl limit of less than 4096 bytes.
Cover cancellation of interleaved queued Publish requests, including
response handles, cancellation counts and a successful CancelResponse.
Extend the nodestore mask regression to 1.5's derived attributes and
invalid attribute identifiers.
Validation: full OpenSSL test build; 252 checks passed across the builtin
types, server, attribute services, client subscriptions and mbedTLS PubSub
decryption suites, with sanitizers enabled.
Require decoding the HEL body to consume the entire message. Add handshake regressions for one-byte and eight-byte suffixes, checking BadDecodingError and connection closure.
Reject EndpointUrls longer than 4096 bytes with BadTcpEndpointUrlInvalid and propagate allocation errors when copying the accepted URL. Add handshake tests for the boundary, oversized URLs, connection closure, and negotiation of a higher requested protocol version down to zero.
attr2mask is indexed by the AttributeId, but the table starts at index
0 while AttributeIds start at 1. Each Read therefore asks the
Nodestore for the attribute that follows the requested one, for
example DataType instead of Value.
Fix misspellings found with codespell across headers, sources, examples,
tests and the documentation, including "propably" in the nodeset
compiler docs. Identifiers, companion spec names and generated code are
left untouched.
The AUDIT_UPDATE_WRITE application notification carries the AttributeId,
IndexRange, NewValue and OldValue of a write, but not the NodeId of the written
node. That NodeId is only set as the SourceNode of the generated
AuditWriteUpdateEvent, so an auditNotificationCallback cannot tell which node
was written without additionally subscribing to the events.
Add /SourceNode (the BaseEventType field name) to the payload. The generated
events are unchanged: the event-field lookup already resolves /SourceNode to
the same NodeId by default, and the RBAC check uses the EventDescription.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Namespace 0 is now restricted to the predefined set of SecureChannel
attributes, for both read and write; other namespaces stay free-form.
The built-in read-only keys are no longer cached in channel->attributes. UA_SecureChannel_getBuiltinAttribute computes them fresh from the
live channel on every access, and notifySecureChannel now reuses it
instead of duplicating the field mappings.
notifySecureChannel now merges the same data it sends in the
SECURECHANNEL_OPENED notification into channel->attributes, so it's
readable via UA_Server_getSecureChannelAttribute and friends. These
keys are rejected by set/delete with BADNOTWRITABLE, only
maxMessageSize stays writable. Also fixes a null-pointer read on
connectionManager in notifySecureChannel and a misleading doc comment
on getSecureChannelAttribute_scalar.