It is useful in some applications to get a snapshot of the stream
management state for storage outside the process, in order to recover
from crashes and other things. The get_sm_state already present is not
suitable for this because it returns a live object tied in to the
current context and such, and containing much unneeded internal-api
data.
Introduce xmpp_sm_state_set_callback which is called every time the
state changes with a serialized state, and a dual xmpp_sm_state_restore
which takes in this serialized state and sets up a new sm_state based on
that.
The serialization is considered opaque from the PoV of the API, but is
based on CBOR to facilitate easy debugging.
The code-path which checks whether the server requires an "xmpp-session"
was untested and therefore the connection-callback handler was triggered
twice with the state `XMPP_CONN_CONNECT`. This happened if the server
supports stream-management and requires a session.
Reported via https://github.com/profanity-im/profanity/issues/1954
Fixup of c7d410f38b
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
Introduce a `conn_interface` to simplify the decision logic which API
we must call.
This also fixes some bugs of the previous commit.
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
* Delay the notification of the library user that the connection was
successful, until SM is reported by the server as enabled.
* Clear the SM queue in case resumption failed.
* Improve some debug statements & comments.
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
In case a connection is established, but the stream negotiation has not
completed yet, a user may think that they can start sending data,
but this is not the case.
All of the following quotes originate in RFC6120.
As of Ch. 8:
> After a client and a server (or two servers) have completed stream
> negotiation, either party can send XML stanzas.
As of Ch. 7.3.1:
> The parties to a stream MUST consider resource binding as
> mandatory-to-negotiate.
As of Ch. 6.3.1:
> The parties to a stream MUST consider SASL as mandatory-to-negotiate.
As of Ch. 4.3.5:
> The initiating entity MUST NOT attempt to send XML stanzas to entities
> other than itself (i.e., the client's connected resource or any other
> authenticated resource of the client's account) or the server to which
> it is connected until stream negotiation has been completed.
> Even if the initiating entity does attempt to do so, the receiving
> entity MUST NOT accept such stanzas and MUST close the stream with a
> <not-authorized/> stream error [...]
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
It has been pointed out that the wording of the license of this library is
not entirely clear.
The term "dual licensing" usually refers to a licence choice of two
licenses "LICENSE1 _or_ LICENSE2.
Instead the license of this library claimed "LICENSE1 _and_ LICENSE2".
After an internal discussion with @metajack and @pasis it was made clear
that the initial idea was to dual license the library in the usual way.
This was also made clear by jack on the ML in the past [0].
As of jack, these licensing terms originated from jquery, which also used
the 'and' version in the past and has since been corrected [1].
This patch changes the license terms to 'MIT or GPLv3' and also adds SPDX
headers [2].
[0] https://groups.google.com/g/libstrophe/c/JkFgr601JQc
[1] https://stackoverflow.com/q/2758409
[2] https://spdx.org
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
This patch handles the case where the server sends its list of features,
but the `<bind>` feature is missing.
A server doing so is violating RFC6120 (c.f. [0]), but it happened in [1].
Previously we ended up in a segfault, now we terminate the connection.
Reproducing this was done with netcat and profanity:
```
shell1 $ nc -l -p 5222
profanity $ /connect foo@127.0.0.1 tls disable
-> nc receives: '<?xml version="1.0"?><stream:stream to="127.0.0.1" xml:lang="en" version="1.0" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams">'
nc send: <?xml version="1.0"?>
<stream:stream from="127.0.0.1" id="foobarbaz" lang="en" version="1.0" xmlns:stream="http://etherx.jabber.org/streams">
<features xmlns="http://etherx.jabber.org/streams"><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism></mechanisms></features>
-> nc receives: '<auth mechanism="PLAIN" xmlns="urn:ietf:params:xml:ns:xmpp-sasl">XXXXXXXXXX</auth>'
nc send: <success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>
-> nc receives: '<?xml version="1.0"?><stream:stream to="127.0.0.1" xml:lang="en" version="1.0" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams"><stream:stream from="127.0.0.1" id="foobarbaz" lang="en" version="1.0" xmlns:stream="http://etherx.jabber.org/streams">'
nc send: <?xml version="1.0"?>
<stream:stream from="127.0.0.1" id="foobarbaz" lang="en" version="1.0" xmlns:stream="http://etherx.jabber.org/streams">
<features xmlns="http://etherx.jabber.org/streams"/>
-> pre-patch this lead to a segfault of profanity, now the stream gets closed.
```
[0] https://datatracker.ietf.org/doc/html/rfc6120#section-7.2
[1] https://github.com/profanity-im/profanity/issues/1849
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
Instead of using the "cloning version" `xmpp_stanza_add_child()` use the
version that takes ownership, so we don't have to release directly
afterwards.
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
Instead of always releasing the stanza after calling `send_stanza()`, this
is done inside the function now.
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
... and forgetting to 1. clear the password cache and 2. print a message
of what exactly happened ...
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
In order to be able to distinguish between user-created entries and
library-internal entries, we mark each entry who it belongs to.
This allows then later to let the user manage only the queue entries
that were created by them.
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
The cache is stored per connection object and is cleared on
* entry of wrong password
* release of connection object
* successful connection
It can be configured that libstrophe retries the password entry in case
the user entered a wrong password.
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
In order to be able to load password-protected key files a password
callback was added.
This also adds support for PKCS#12 containers instead of certificate+key.
Signed-off-by: Steffen Jaeckel <jaeckel-floss@eyet-services.de>
Const variables in prototypes don't add much value, but make the code
larger and redundant. Remove these const keywords.
Note, this doesn't apply to pointers to const memory.
Make it possible to reset password to NULL. It is not required for
ANONYMOUS authentication. Also, report an error and disconnect if
password is not set and libstrophe should try authentication mechanisms
other than ANONYMOUS.
Introduced UNUSED macro with cast to void in commoh.h for internal
use. Used cast to void directly in those files which do not
include common.h. Although this change doesn't fix semantic issues
with unused function parameters, it does explicitly mark all those
places, which might require attention in future.
* Add SCRAM_DIGEST_SIZE macro for maximum possible digest size. It will
avoid new buffer overflow errors when new digests are added.
* Fix buffer overflow in sasl_scram(). Buffers were allocated for SHA1
digest size.
* Fix bug with handler re-registration when a SASL SCRAM mechanism
fails.
@sjaeckel integrated clang-format with formal coding style. Run his
script and commit changes.
There are pros and cons of this commit.
Mixed coding style is a "broken window". A good single style simplifies
reading and writing code.
On the other hand, this is a big change which will lead to conflicts.
PLAIN mechanism sends password in BASE64 encoding which everyone can
read. As result, debug logs expose password and users often don't remove
it when post the logs in the Internet.
Usually, both a secure mechanism and PLAIN are used in the scenario when
username or password is incorrect. PLAIN fails in this scenario anyway.
Legacy authentication can expose password in plaintext. Since this is
not widely used mechanism, disable it by default. It can be enabled back
with connection option XMPP_CONN_FLAG_LEGACY_AUTH.
There are places where code relies on well-formed stanzas and expects
that ns attribute is always present. Check whether ns NULL or not before
passing it to strcmp().
Fixes#121.
RFC6121 removes the precondition of establishing a session before a client
may exchange XML stanzas on an XMPP network.
This PR allows libstrophe to not request session where it is indicated
as optional by the server, saving a round trip.
https://tools.ietf.org/html/rfc6121#section-1.4
Instead, keep the same handler until connection is disconnected. Stream
is opened 3 times during usual workflow. Deleting/restoring the handler
every time brings more places for possible mistakes.
Default opening tag doesn't allow to implement XEP-0174. In this case
client needs to send specific attributes. As solution user passes
attributes that are sent inside opening tag. Previous variant of this
function is renamed to xmpp_conn_open_stream_default().
The way to pass attributes is not the best one, but it's used to conform
existent interface of xmpp_stanza_get_attributes().
Remove "raw" suffix from functions that work with a raw connection.
This function is similar to xmpp_connect_client(), but doesn't perform
authentication. Instead, it calls user's connection handler immediately
after establishing the connection. Hence, user can implement own
authendication or registration procedures.
Such a "raw" connection can be useful when user interaction is required
(e.g. Data Forms in XEP-0077, OAuth2).
* Removed dependency from internal headers in rand.h. xmpp_rand
interface can be public in the future;
* xmpp_rand functions accept xmpp_rand_t object instead of xmpp_ctx_t.
If interface function returns char* the result must be freed with
xmpp_free().
In case of const char* the result must not be changed by user. Also, the
result is valid only during stanza lifetime.