AUTH_SASL(3)

πŸ’– AUTH_SASL(3) β€” SASL implementation πŸ’–

okay bestie, gather round, because this is the AUTH_SASL(3) page and it's literally the moment where your app learns how to do SASL. no cap. this whole thing was written by S. Varshavchik, an absolute legend, and we're about to go through it together, top to bottom, every last flag and return code, because ✨ details ✨ are the whole vibe.


🌸 NAME 🌸

auth_sasl, auth_sasl_ex β€” SASL implementation

so yeah, you've got two functions here, not one. one of them is the main character, and the other one is the main character's slightly more sophisticated sibling who went to the EXTERNAL of it all. iykyk.


πŸŽ€ SYNOPSIS πŸŽ€

#include <courierauthsasl.h>

int rc=auth_sasl(const char *method, const char *initialresponse,
                 char *(*conversation_func)(const char *, void *)),
                 void *callback_arg, char **authtype_ret,
                 char **authdata_ret);

int rc=auth_sasl_ex(const char *method, const char *initialresponse,
                    const char *externalauth,
                    char *(*conversation_func)(const char *, void *)),
                    void *callback_arg, char **authtype_ret,
                    char **authdata_ret);

okay so first things first, you gotta #include <courierauthsasl.h>. that's the vibe check you have to pass before anything else works. πŸ’… then you pick your function, and honestly? auth_sasl_ex is just auth_sasl with one extra argument in the middle, so don't let it intimidate you. look at those signatures, babes, they're literally the same shape otherwise. πŸ¦‹


✨ DESCRIPTION ✨

auth_sasl is a generic SASL server implementation. that's the headline. remember it, because it's doing a LOT of heavy lifting for you behind the scenes. 🫢

method is the requested SASL method β€” aka, the client walks up and says "hey, i'd like to authenticate using this" and you hand that request straight to method. at this time, auth_sasl knows how to handle the following SASL methods:

  • LOGIN
  • PLAIN
  • CRAM-MD5
  • CRAM-SHA1

that's the roster. those are the four icons it currently serves. no more, no less, periodt. πŸ‘‘

initialresponse is a base64-encoded initial response provided in the client's SASL request. and listen, this is important: initialresponse must be NULL if an initial response was not included in the client's SASL request. don't be out here passing garbage when the client gave you nothing. NULL it is. πŸ’€

conversation_func is the application-implemented SASL conversation callback function β€” yes, you write this one, bestie, it's your homework. here's how the whole back-and-forth goes:

  • conversation_func receives a base64-encoded SASL prompt, plus the callback_arg argument that you passed to auth_sasl.
  • conversation_func must return a buffer containing the base64-encoded reply from the client.
  • auth_sasl will free(3) this buffer when it's done with it. so do not free it yourself, okay? let the function handle its own business. πŸ™ˆ
  • conversation_func should return NULL to abort the SASL conversation. that's your escape hatch, the "nope, we're done here" button.

auth_sasl_ex is a version of auth_sasl that recognizes the EXTERNAL SASL method. so it's the glow-up edition. πŸ’– it takes an extra parameter, externalauth, and this one should be set to indicate a login that was authenticated via some other means β€” such as, perhaps, an SSL certificate β€” or NULL if no externally-authenticated identity was established.

now for the plot twist, and this is the part where auth_sasl_ex behaves exactly like its sibling:

  • If method is not EXTERNAL, auth_sasl_ex is identical to auth_sasl, and externalauth is ignored. like, literally just vibing in the corner, doing nothing.
  • Otherwise, if method is EXTERNAL and externalauth is not NULL, auth_sasl_ex returns AUTHSASL_OK, and sets *authtype_ret and *authdata_ret accordingly.

and why do we care about those two? because of this: the subsequent invocation of auth_generic() returns authentication information for the login ID specified by externalauth. so it all chains together, a whole relay race of auth. πŸƒβ€β™€οΈπŸ’¨


πŸ”₯ RETURNS πŸ”₯

If the SASL conversation successfully completes, auth_sasl or auth_sasl_ex initializes *authtype_ret and *authdata_ret. they'll be set to malloc(3)-ed buffers that can be directly passed as arguments to auth_generic_meta(3)[1].

and girly, listen to me: it is the application's responsibility to free(3) these buffers when it's done with them. the library is NOT going to clean up after you. that's your mess, you own it. 🧹✨

auth_sasl or auth_sasl_ex returns AUTHSASL_OK when the SASL conversation successfully completes, and *authtype_ret and *authdata_ret are successfully assembled. any other return indicates an error condition. and right now, two error conditions are defined:

  • AUTHSASL_ABORTED β€” the SASL conversation was aborted by the client. they hung up on you mid-conversation, iconic of them, but also rude. 😭
  • AUTHSASL_ERROR β€” general error (insufficient memory, or some other reason). check errno for any clues. yeah, that's the "idk what happened bestie, go read errno" error. πŸ•΅οΈβ€β™€οΈ
⚠️ real talk: anything that isn't AUTHSASL_OK means something went wrong. don't be out here treating random return values as success. that's not the move.

🌈 SEE ALSO 🌈

authlib(3)[2], auth_generic_meta(3)[1].

go read these next, they're the supporting cast and they absolutely understood the assignment.


πŸ’œ NOTES πŸ’œ

  1. auth_generic_meta(3) https://www.courier-mta.org/authlib/auth_generic.html
  2. authlib(3) https://www.courier-mta.org/authlib/authlib.html

and that's the whole page, bestie!! you made it to the end, which is honestly main character energy. πŸŽ€

this was brought to you by S. Varshavchik, dated 06/18/2026 β€” so go forth, implement your conversation_func, free your buffers, and slay those SASL conversations. AUTHSASL_OK or it didn't happen. πŸ’…βœ¨ bye!!

πŸ“¦ where this page comes from