SASL client library - draft --------------------------- Version: $NetBSD: library.txt,v 1.3 2011/02/11 23:44:42 christos Exp $ 1. Typedefs Moved to src/*.h 2. Public API saslc_t *saslc_init(const char *appname); - Function takes appname as an argument, function allocates and initializes new saslc_t structure, parses configuration files if available (/etc/saslc/appname.d/sasl.conf and then /etc/saslc/appname.d/mechanism.conf for machanisms which are listed in sasl.conf) Function returns pointer to the saslc_t on success and NULL on failure. const char *saslc_strerror(saslc_t *saslc); - function maps last error number in saslc to the message string. Returns pointer to the message string on success and pointer to the "unknown error" string on failure. int saslc_end(saslc_t *saslc); - function destroys SASL library context and deallocates any resources used. If any sessions are assigned to the context then function closes them. It returns 0 on success and -1 on failure. saslc_sess_t *saslc_sess_init(saslc_t *saslc, const char *mechs); - Function creates a new sasl session. If saslc is NULL then default configuration settings are used. Mechs is the string which consists of a comma separated list of mechanism names. Mechanism used for the authentication is selected basing on the configuration. Function allocates saslc_sess_t and performs initialization of saslc_sess_t, pointer to it is returned on success and NULL is returned on failure. In case of a failure saslc errno is set. int saslc_sess_setprop(saslc_sess_t *sess, const char *name, const char *value); - Functions sets a property in the session. This function is used for setting i.e. callbacks. It returns 0 on success and -1 on failure. In case of a failure sess errno is set. NOTE: Property is added to the sess->prop dictionary. NOTE: All properties' names should match to [A-Za-z0-9_]+. const char *saslc_sess_getprop(saslc_sess_t *sess, const char *name); - Function gets property from the session. It return pointer to the property value on success and NULL on failure. In case of a failure sess errno is set. NOTE: Property is taken from the sess->prop dictionary, if property not exist then sess->context->prop is used with added sess->mech->name."-" prefix. int saslc_sess_cont(saslc_sess_t *sess, const char *in, size_t inlen, char **out, size_t *outlen); - Function performs one step of the SASL authentication. Input data of length inlen is passed in the "in" argument. Function stores output of length outlen in the out argument and returns 0 on success, 1 if more steps of the SASL authentication is needed and -1 on failure. In case of a failure sess errno is set. NOTE: user is responsible for deallocate the output data. IMPLEMENTATION: sess->mech->cont(sess, in, inlen, out, outlen) const char *saslc_sess_strerror(saslc_sess_t *sess); - function maps last error number in sess to message string. Returns pointer to the message string on success and pointer to the "unknown error" string on failure. const char *saslc_sess_strmech(saslc_sess_t *sess); - function returns pointer to the string contains name of the mechanism used in session. On failure function returns pointer to "unknown". int saslc_sess_encode(saslc_sess_t *sess, const char *in, size_t inlen, char **out, size_t *outlen); - function encodes data using security layer negotiated during the authentication. Returns 0 on success, -1 on failure. In case of a failure sess errno is set. IMPLEMENTATION: sess->mech->encode(sess, in, inlen, out, outlen) int saslc_sess_decode(saslc_sess_t *sess, const char *in, size_t inlen, char **out, size_t *outlen); - function decodes data using security layer negotiated during the authentication. Returns 0 on success, -1 on failure. In case of a failure sess errno is set. IMPLEMENTATION: sess->mech->decode(sess, in, inlen, out, outlen) void saslc_sess_end(saslc_sess_t *sess); - function destroys SASL session and deallocates any resources used. 3. Mechanisms 3.1. Global mechanisms table saslc_mech_list_t *mechanisms; List of mechanisms, initialized during first call of saslc_start(...); 3.3. Mechanisms implementation Each mechanism will provide const saslc_mech_t structure describing its implementation. Mechanisms state is described by saslc_mech_sess_t, using this type by mechanism is not mandatory and different struct can be defined by a mechanism if necessary. This structure is used only for representing internal state of the mechanism session, and wouldn't be used outside of mechanism implementation. 3.2. Mechanisms which are going to be implemented * ANONYMOUS (create, destroy, cont) * EXTERNAL (create, destroy, cont) * PLAIN (create, destroy, cont) * LOGIN (create, destroy, cont) * CRAM-MD5 (create, destroy, cont) * DIGEST-MD5 (create, destroy, cont, encode, decode) * GSSAPI (create, destroy, cont, encode, decode) 3.3. Example Consider ANONYMOUS mechanism as example, its pseudo implementation looks as follows: generic_create(...) { // create mech_sess structure // mech_sess->status = AUTHENTICATION } anon_cont(...) { char *token; if ( mech_sess->status != AUTHENTICATION ) { // error handler } // get token from session if present, if not use default from // configuration // output = token, outlen = lenght(token) // mech_sess->status = AUTHENTICATED... // return 0; } generic_destroy(...) { // destroy mech_sess structure // return } saslc_mech_t anon_mech = { "ANONYMOUS", // const char *name; FLAG_ANONYMOUS, /* mechanism flags */ mech_generic_create; /* create function - creates mechanism instance */ mech_anonymous_cont; /* step function - performs one step of authentication */ NULL; /* encoding function - encodes input according to negotiated security layer */ NULL; /* decoding function - decodes input according to negotiated security layer */ mech_generic_destroy; /* destroy function - destroys mechanism instance */ } mech_anonymous; 4. Expected usage Below is presented example and expected usage of the library. /* creating context */ ... ctx = saslc_init("example"); if ( ctx == NULL ) { //error handler } ... /* session */ sess = saslc_sess_init(ctx, "PLAIN,ANONYMOUS"); if ( sess == NULL ) { //error handler } if ( strcmp(saslc_sess_strmech(sess),"PLAIN") == 0 ) { saslc_sess_setprop(sess, "USERID", "foo"); saslc_sess_setprop(sess, "PASSWORD", "bar"); } else if ( strcmp(saslc_sess_strmech(sess),"ANONYMOUS") == 0 ) { saslc_sess_setprop(sess, "TOKEN", "foo@bar.com"); } // sending auth // proto read // parse while ( (last = sasl_sess_cont(sess, in, inlen, out, outlen)) >= 0 ) { // proto send // proto read // parse if ( last == 0 ) break; } if ( last == 0 ) { // yay! } else { // error handler } ... /* destroying session and context */ saslc_sess_end(sess); saslc_end(ctx); ... vim:tw=79:spell:spelllang=en