diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2010-09-03 12:49:33 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2010-09-03 12:59:44 +0300 |
commit | 607f57384987efc9f08a1febff4c6ab00e61e2ab (patch) | |
tree | 54df99489423c38460ab61ce9c0277ff65d5e782 | |
parent | 64c8eabf83ec6f1a7b1050a1929b4387f78b7ccc (diff) | |
download | mailutils-607f57384987efc9f08a1febff4c6ab00e61e2ab.tar.gz mailutils-607f57384987efc9f08a1febff4c6ab00e61e2ab.tar.bz2 |
Re-implement GSASL support.
* libmu_auth/lbuf.c: Removed.
* libmu_auth/lbuf.h: Removed.
* libmu_auth/Makefile.am : Remove lbuf stuff.
* include/mailutils/sys/gsasl-stream.h: New file.
* include/mailutils/sys/Makefile.am: Add gsasl-stream.h.
* include/mailutils/gsasl.h (mu_gsasl_stream_create): Remove.
(gsasl_encoder_stream, gsasl_decoder_stream): New prototypes.
* libmu_auth/gsasl.c: Rewrite.
* imap4d/authenticate.c (auth_data): Remove.
Use struct imap4d_auth instead.
(_auth_try): Use new authentication API.
(imap4d_authenticate): Likewise.
* imap4d/imap4d.h (util_register_event, util_event_remove)
(util_run_events): Remove.
(imap4d_auth_handler_fp): Change prototype.
(imap4d_auth): New struct.
(imap4d_auth_result): New enum.
* imap4d/io.c (io_format_completion_response)
(io_stream_completion_response): New functions.
(io_completion_response): Rewrite using io_format_completion_response.
* imap4d/util.c (sc2string): Remove leftover prototype.
(util_register_event, util_event_remove)
(util_run_events): Remove.
* imap4d/auth_gsasl.c: Revamp using new streams and the new
authentication interface.
* imap4d/auth_gss.c: Likewise (though yet untested).
* mailbox/xscript-stream.c (_xscript_ctl): Remove unused variables.
-rw-r--r-- | imap4d/auth_gsasl.c | 141 | ||||
-rw-r--r-- | imap4d/auth_gss.c | 58 | ||||
-rw-r--r-- | imap4d/authenticate.c | 65 | ||||
-rw-r--r-- | imap4d/imap4d.h | 31 | ||||
-rw-r--r-- | imap4d/io.c | 46 | ||||
-rw-r--r-- | imap4d/util.c | 69 | ||||
-rw-r--r-- | include/mailutils/gsasl.h | 6 | ||||
-rw-r--r-- | include/mailutils/sys/Makefile.am | 1 | ||||
-rw-r--r-- | include/mailutils/sys/gsasl-stream.h | 38 | ||||
-rw-r--r-- | libmu_auth/Makefile.am | 2 | ||||
-rw-r--r-- | libmu_auth/gsasl.c | 316 | ||||
-rw-r--r-- | libmu_auth/lbuf.c | 167 | ||||
-rw-r--r-- | libmu_auth/lbuf.h | 37 | ||||
-rw-r--r-- | mailbox/xscript-stream.c | 1 |
14 files changed, 376 insertions, 602 deletions
diff --git a/imap4d/auth_gsasl.c b/imap4d/auth_gsasl.c index 036063db4..b16cd380f 100644 --- a/imap4d/auth_gsasl.c +++ b/imap4d/auth_gsasl.c @@ -29,43 +29,6 @@ static Gsasl_session *sess_ctx; static void auth_gsasl_capa_init (int disable); -static int -create_gsasl_stream (mu_stream_t *newstr, mu_stream_t transport, int flags) -{ - int rc; - - rc = mu_gsasl_stream_create (newstr, transport, sess_ctx, flags); - if (rc) - { - mu_diag_output (MU_DIAG_ERROR, _("cannot create SASL stream: %s"), - mu_strerror (rc)); - return RESP_NO; - } - - if ((rc = mu_stream_open (*newstr)) != 0) - { - mu_diag_output (MU_DIAG_ERROR, - _("cannot open SASL input stream: %s"), - mu_stream_strerror (*newstr, rc)); - return RESP_NO; - } - - return RESP_OK; -} - -int -gsasl_replace_streams (void *self, void *data) -{ - mu_stream_t *s = data; - - util_set_input (s[0]); - util_set_output (s[1]); - free (s); - util_event_remove (self); - free (self); - return 0; -} - static void finish_session (void) { @@ -73,7 +36,21 @@ finish_session (void) } static int -auth_gsasl (struct imap4d_command *command, char *auth_type, char **username) +restore_and_return (struct imap4d_auth *ap, mu_stream_t *str, int resp) +{ + int rc = mu_stream_ioctl (iostream, MU_IOCTL_SWAP_STREAM, str); + if (rc) + { + mu_error (_("%s failed when it should not: %s"), "MU_IOCTL_SWAP_STREAM", + mu_stream_strerror (iostream, rc)); + abort (); + } + ap->response = resp; + return imap4d_auth_resp; +} + +static enum imap4d_auth_result +auth_gsasl (struct imap4d_auth *ap) { char *input_str = NULL; size_t input_size = 0; @@ -81,15 +58,15 @@ auth_gsasl (struct imap4d_command *command, char *auth_type, char **username) char *output; int rc; - rc = gsasl_server_start (ctx, auth_type, &sess_ctx); + rc = gsasl_server_start (ctx, ap->auth_type, &sess_ctx); if (rc != GSASL_OK) { mu_diag_output (MU_DIAG_NOTICE, _("SASL gsasl_server_start: %s"), gsasl_strerror (rc)); - return 0; + return imap4d_auth_fail; } - gsasl_callback_hook_set (ctx, username); + gsasl_callback_hook_set (ctx, &ap->username); output = NULL; while ((rc = gsasl_step64 (sess_ctx, input_str, &output)) @@ -105,7 +82,8 @@ auth_gsasl (struct imap4d_command *command, char *auth_type, char **username) gsasl_strerror (rc)); free (input_str); free (output); - return RESP_NO; + ap->response = RESP_NO; + return imap4d_auth_resp; } /* Some SASL mechanisms output additional data when GSASL_OK is @@ -119,44 +97,81 @@ auth_gsasl (struct imap4d_command *command, char *auth_type, char **username) mu_diag_output (MU_DIAG_NOTICE, _("non-empty client response")); free (input_str); free (output); - return RESP_NO; + ap->response = RESP_NO; + return imap4d_auth_resp; } } free (input_str); free (output); - if (*username == NULL) + if (ap->username == NULL) { - mu_diag_output (MU_DIAG_NOTICE, _("GSASL %s: cannot get username"), auth_type); - return RESP_NO; + mu_diag_output (MU_DIAG_NOTICE, _("GSASL %s: cannot get username"), + ap->auth_type); + ap->response = RESP_NO; + return imap4d_auth_resp; } + auth_gsasl_capa_init (1); if (sess_ctx) { - mu_stream_t tmp, new_in, new_out; - mu_stream_t *s; - - util_get_input (&tmp); - if (create_gsasl_stream (&new_in, tmp, MU_STREAM_READ)) - return RESP_NO; - util_get_output (&tmp); - if (create_gsasl_stream (&new_out, tmp, MU_STREAM_WRITE)) + mu_stream_t stream[2], newstream[2]; + + stream[0] = stream[1] = NULL; + rc = mu_stream_ioctl (iostream, MU_IOCTL_SWAP_STREAM, stream); + if (rc) + { + mu_error (_("%s failed: %s"), "MU_IOCTL_SWAP_STREAM", + mu_stream_strerror (iostream, rc)); + ap->response = RESP_NO; + return imap4d_auth_resp; + } + rc = gsasl_encoder_stream (&newstream[0], stream[0], sess_ctx, + MU_STREAM_READ); + if (rc) + { + mu_error (_("%s failed: %s"), "gsasl_encoder_stream", + mu_strerror (rc)); + return restore_and_return (ap, stream, RESP_NO); + } + + rc = gsasl_decoder_stream (&newstream[1], stream[1], sess_ctx, + MU_STREAM_WRITE); + if (rc) + { + mu_error (_("%s failed: %s"), "gsasl_decoder_stream", + mu_strerror (rc)); + mu_stream_destroy (&newstream[0]); + return restore_and_return (ap, stream, RESP_NO); + } + + if (ap->username) { - mu_stream_destroy (&new_in); - return RESP_NO; + if (imap4d_session_setup (ap->username)) + return restore_and_return (ap, stream, RESP_NO); } - s = calloc (2, sizeof (mu_stream_t)); - s[0] = new_in; - s[1] = new_out; - util_register_event (STATE_NONAUTH, STATE_AUTH, - gsasl_replace_streams, s); + /* FIXME: This is not reflected in the transcript. */ + io_stream_completion_response (stream[1], ap->command, RESP_OK, + "%s authentication successful", + ap->auth_type); + mu_stream_flush (stream[1]); + + rc = mu_stream_ioctl (iostream, MU_IOCTL_SWAP_STREAM, newstream); + if (rc) + { + mu_error (_("%s failed when it should not: %s"), + "MU_IOCTL_SWAP_STREAM", + mu_stream_strerror (iostream, rc)); + abort (); + } util_atexit (finish_session); + return imap4d_auth_ok; } - auth_gsasl_capa_init (1); - return RESP_OK; + ap->response = RESP_OK; + return imap4d_auth_resp; } static void diff --git a/imap4d/auth_gss.c b/imap4d/auth_gss.c index 300936245..28ce74a4f 100644 --- a/imap4d/auth_gss.c +++ b/imap4d/auth_gss.c @@ -108,9 +108,8 @@ imap4d_gss_userok (gss_buffer_t client_name, char *name) } #endif -static int -auth_gssapi (struct imap4d_command *command, - char *auth_type_unused, char **username) +static enum imap4d_auth_result +auth_gssapi (struct imap4d_auth *ap) { gss_buffer_desc tokbuf, outbuf; OM_uint32 maj_stat, min_stat, min_stat2; @@ -147,7 +146,8 @@ auth_gssapi (struct imap4d_command *command, if (maj_stat != GSS_S_COMPLETE) { display_status ("import name", maj_stat, min_stat); - return RESP_NO; + ap->response = RESP_NO; + return imap4d_auth_resp; } maj_stat = gss_acquire_cred (&min_stat, server_name, 0, @@ -158,7 +158,8 @@ auth_gssapi (struct imap4d_command *command, if (maj_stat != GSS_S_COMPLETE) { display_status ("acquire credentials", maj_stat, min_stat); - return RESP_NO; + ap->response = RESP_NO; + return imap4d_auth_resp; } /* Start the dialogue */ @@ -206,7 +207,8 @@ auth_gssapi (struct imap4d_command *command, maj_stat = gss_delete_sec_context (&min_stat, &context, &outbuf); gss_release_buffer (&min_stat, &outbuf); free (token_str); - return RESP_NO; + ap->response = RESP_NO; + return imap4d_auth_resp; } if (outbuf.length) @@ -228,7 +230,8 @@ auth_gssapi (struct imap4d_command *command, { display_status ("wrap", maj_stat, min_stat); free (token_str); - return RESP_NO; + ap->response = RESP_NO; + return imap4d_auth_resp; } mu_base64_encode (outbuf.value, outbuf.length, &tmp, &size); @@ -246,7 +249,8 @@ auth_gssapi (struct imap4d_command *command, if (maj_stat != GSS_S_COMPLETE) { display_status ("unwrap", maj_stat, min_stat); - return RESP_NO; + ap->response = RESP_NO; + return imap4d_auth_resp; } sec_level = ntohl (*(OM_uint32 *) outbuf.value); @@ -261,23 +265,25 @@ auth_gssapi (struct imap4d_command *command, gss_release_buffer (&min_stat, &outbuf); maj_stat = gss_delete_sec_context (&min_stat, &context, &outbuf); gss_release_buffer (&min_stat, &outbuf); - return RESP_NO; + ap->response = RESP_NO; + return imap4d_auth_resp; } protection_mech = mech; client_buffer_size = sec_level & 0x00ffffffff; - *username = malloc (outbuf.length - 4 + 1); - if (!*username) + ap->username = malloc (outbuf.length - 4 + 1); + if (!ap->username) { mu_diag_output (MU_DIAG_NOTICE, _("not enough memory")); gss_release_buffer (&min_stat, &outbuf); maj_stat = gss_delete_sec_context (&min_stat, &context, &outbuf); gss_release_buffer (&min_stat, &outbuf); - return RESP_NO; + ap->response = RESP_NO; + return imap4d_auth_resp; } - memcpy (*username, (char *) outbuf.value + 4, outbuf.length - 4); - (*username)[outbuf.length - 4] = '\0'; + memcpy (ap->username, (char *) outbuf.value + 4, outbuf.length - 4); + ap->username[outbuf.length - 4] = '\0'; gss_release_buffer (&min_stat, &outbuf); maj_stat = gss_display_name (&min_stat, client, &client_name, &mech_type); @@ -286,36 +292,40 @@ auth_gssapi (struct imap4d_command *command, display_status ("get client name", maj_stat, min_stat); maj_stat = gss_delete_sec_context (&min_stat, &context, &outbuf); gss_release_buffer (&min_stat, &outbuf); - free (*username); - return RESP_NO; + free (ap->username); + ap->response = RESP_NO; + return imap4d_auth_resp; } #ifdef WITH_GSS - baduser = !gss_userok (client, *username); + baduser = !gss_userok (client, ap->username); #else - baduser = imap4d_gss_userok (&client_name, *username); + baduser = imap4d_gss_userok (&client_name, ap->username); #endif if (baduser) { - mu_diag_output (MU_DIAG_NOTICE, _("GSSAPI user %s is NOT authorized as %s"), - (char *) client_name.value, *username); + mu_diag_output (MU_DIAG_NOTICE, + _("GSSAPI user %s is NOT authorized as %s"), + (char *) client_name.value, ap->username); maj_stat = gss_delete_sec_context (&min_stat, &context, &outbuf); gss_release_buffer (&min_stat, &outbuf); gss_release_buffer (&min_stat, &client_name); - free (*username); - return RESP_NO; + free (ap->username); + ap->response = RESP_NO; + return imap4d_auth_resp; } else { mu_diag_output (MU_DIAG_NOTICE, _("GSSAPI user %s is authorized as %s"), - (char *) client_name.value, *username); + (char *) client_name.value, ap->username); } gss_release_buffer (&min_stat, &client_name); maj_stat = gss_delete_sec_context (&min_stat, &context, &outbuf); gss_release_buffer (&min_stat, &outbuf); - return RESP_OK; + ap->response = RESP_OK; + return imap4d_auth_resp; } void diff --git a/imap4d/authenticate.c b/imap4d/authenticate.c index 08ffa146c..166294cdc 100644 --- a/imap4d/authenticate.c +++ b/imap4d/authenticate.c @@ -19,7 +19,8 @@ #include "imap4d.h" -struct imap_auth { +struct imap_auth +{ char *name; imap4d_auth_handler_fp handler; }; @@ -66,24 +67,17 @@ _auth_capa (void *item, void *usused) return 0; } -struct auth_data { - struct imap4d_command *command; - char *auth_type; - char *arg; - char *username; - int result; -}; - static int _auth_try (void *item, void *data) { struct imap_auth *p = item; - struct auth_data *ap = data; + struct imap4d_auth *ap = data; if (strcmp (p->name, ap->auth_type) == 0) { - ap->result = p->handler (ap->command, ap->auth_type, &ap->username); - return 1; + int res = p->handler (ap); + if (res) + return res; } return 0; } @@ -104,8 +98,9 @@ int imap4d_authenticate (struct imap4d_command *command, imap4d_tokbuf_t tok) { char *auth_type; - struct auth_data adata; - + struct imap4d_auth adata; + enum imap4d_auth_result res; + if (imap4d_tokbuf_argc (tok) != 3) return io_completion_response (command, RESP_BAD, "Invalid arguments"); @@ -117,25 +112,35 @@ imap4d_authenticate (struct imap4d_command *command, imap4d_tokbuf_t tok) adata.command = command; adata.auth_type = auth_type; - adata.arg = NULL; adata.username = NULL; - if (mu_list_do (imap_auth_list, _auth_try, &adata) == 0) - return io_completion_response (command, RESP_NO, - "Authentication mechanism not supported"); - - if (adata.result == RESP_OK && adata.username) + res = mu_list_do (imap_auth_list, _auth_try, &adata); + + switch (res) { - if (imap4d_session_setup (adata.username)) - return io_completion_response (command, RESP_NO, - "User name or passwd rejected"); - else - return io_completion_response (command, RESP_OK, - "%s authentication successful", - auth_type); + case imap4d_auth_nosup: + return io_completion_response (command, RESP_NO, + "Authentication mechanism not supported"); + case imap4d_auth_ok: + return 0; + + case imap4d_auth_resp: + if (adata.response == RESP_OK && adata.username) + { + if (imap4d_session_setup (adata.username)) + return io_completion_response (command, RESP_NO, + "User name or passwd rejected"); + else + return io_completion_response (command, RESP_OK, + "%s authentication successful", + auth_type); + } + /* fall through */ + case imap4d_auth_fail: + adata.response = RESP_NO; + break; } - - return io_completion_response (command, adata.result, - "%s authentication failed", auth_type); + return io_completion_response (command, adata.response, + "%s authentication failed", auth_type); } diff --git a/imap4d/imap4d.h b/imap4d/imap4d.h index b8348a599..ba6ef6516 100644 --- a/imap4d/imap4d.h +++ b/imap4d/imap4d.h @@ -218,6 +218,11 @@ extern int io_send_literal (const char *); extern int io_copy_out (mu_stream_t str, size_t size); extern int io_completion_response (struct imap4d_command *, int, const char *, ...) MU_PRINTFLIKE(3,4); +extern int io_stream_completion_response (mu_stream_t str, + struct imap4d_command *command, + int rc, + const char *format, ...) + MU_PRINTFLIKE(4,5); int io_getline (char **pbuf, size_t *psize, size_t *pnbytes); void io_setio (FILE*, FILE*); void io_flush (void); @@ -368,10 +373,6 @@ int util_type_to_attribute (int type, char **attr_str); int util_attribute_matches_flag (mu_attribute_t attr, const char *item); int util_uidvalidity (mu_mailbox_t smbox, unsigned long *uidvp); -void util_register_event (int old_state, int new_state, - mu_list_action_t *action, void *data); -void util_event_remove (void *id); -void util_run_events (int old_state, int new_state); int util_is_master (void); void util_bye (void); @@ -385,8 +386,26 @@ int util_trim_nl (char *s, size_t len); int imap4d_init_tls_server (void); #endif /* WITH_TLS */ -typedef int (*imap4d_auth_handler_fp) (struct imap4d_command *, - char *, char **); +struct imap4d_auth +{ + /* input */ + struct imap4d_command *command; + char *auth_type; + /* output */ + char *username; + int response; +}; + +enum imap4d_auth_result + { + imap4d_auth_nosup, + imap4d_auth_ok, + imap4d_auth_resp, + imap4d_auth_fail + }; + +typedef enum imap4d_auth_result + (*imap4d_auth_handler_fp) (struct imap4d_auth *); extern void auth_add (char *name, imap4d_auth_handler_fp handler); extern void auth_remove (char *name); diff --git a/imap4d/io.c b/imap4d/io.c index b3cee483a..05645ae62 100644 --- a/imap4d/io.c +++ b/imap4d/io.c @@ -219,20 +219,18 @@ io_untagged_response (int rc, const char *format, ...) /* Send the completion response and reset the state. */ int -io_completion_response (struct imap4d_command *command, int rc, - const char *format, ...) +io_format_completion_response (mu_stream_t str, + struct imap4d_command *command, int rc, + const char *format, va_list ap) { int new_state; int status = 0; - va_list ap; const char *sc = sc2string (rc); - mu_stream_printf (iostream, "%s %s%s ", + mu_stream_printf (str, "%s %s%s ", command->tag, sc, command->name); - va_start (ap, format); - mu_stream_vprintf (iostream, format, ap); - va_end (ap); - mu_stream_write (iostream, "\n", 1, NULL); + mu_stream_vprintf (str, format, ap); + mu_stream_write (str, "\n", 1, NULL); /* Reset the state. */ if (rc == RESP_OK) @@ -243,11 +241,35 @@ io_completion_response (struct imap4d_command *command, int rc, new_state = STATE_NONE; if (new_state != STATE_NONE) - { - util_run_events (state, new_state); - state = new_state; - } + state = new_state; + + return status; +} + +int +io_completion_response (struct imap4d_command *command, int rc, + const char *format, ...) +{ + va_list ap; + int status; + + va_start (ap, format); + status = io_format_completion_response (iostream, command, rc, format, ap); + va_end (ap); + return status; +} + +int +io_stream_completion_response (mu_stream_t str, + struct imap4d_command *command, int rc, + const char *format, ...) +{ + va_list ap; + int status; + va_start (ap, format); + status = io_format_completion_response (str, command, rc, format, ap); + va_end (ap); return status; } diff --git a/imap4d/util.c b/imap4d/util.c index 80cfc6e7a..a4c504331 100644 --- a/imap4d/util.c +++ b/imap4d/util.c @@ -20,7 +20,6 @@ #include "imap4d.h" static int add2set (size_t **, int *, unsigned long); -static const char *sc2string (int); /* NOTE: Allocates Memory. */ /* Expand: ~ --> /home/user and to ~guest --> /home/guest. */ @@ -651,74 +650,6 @@ util_bye () mu_list_do (atexit_list, atexit_run, 0); } -struct state_event -{ - int old_state; - int new_state; - mu_list_action_t *action; - void *data; -}; - -static mu_list_t event_list; - -void -util_register_event (int old_state, int new_state, - mu_list_action_t *action, void *data) -{ - struct state_event *evp = malloc (sizeof (*evp)); - if (!evp) - imap4d_bye (ERR_NO_MEM); - evp->old_state = old_state; - evp->new_state = new_state; - evp->action = action; - evp->data = data; - if (!event_list) - { - mu_list_create (&event_list); - mu_list_set_destroy_item (event_list, mu_list_free_item); - } - mu_list_append (event_list, (void*)evp); -} - -void -util_event_remove (void *id) -{ - mu_list_remove (event_list, id); -} - -static int -event_exec (void *item, void *data) -{ - struct state_event *ev = data, *elem = item; - - if (ev->old_state == elem->old_state && ev->new_state == elem->new_state) - return elem->action (item, elem->data); - return 0; -} - -void -util_run_events (int old_state, int new_state) -{ - if (event_list) - { - struct state_event ev; - mu_iterator_t itr; - ev.old_state = old_state; - ev.new_state = new_state; - - mu_list_get_iterator (event_list, &itr); - for (mu_iterator_first (itr); - !mu_iterator_is_done (itr); mu_iterator_next (itr)) - { - struct state_event *p; - mu_iterator_current (itr, (void **)&p); - if (event_exec (p, &ev)) - break; - } - mu_iterator_destroy (&itr); - } -} - void util_chdir (const char *dir) { diff --git a/include/mailutils/gsasl.h b/include/mailutils/gsasl.h index 583b356db..be5f2bb26 100644 --- a/include/mailutils/gsasl.h +++ b/include/mailutils/gsasl.h @@ -36,8 +36,10 @@ extern struct mu_gsasl_module_data mu_gsasl_module_data; #ifdef WITH_GSASL #include <gsasl.h> -int mu_gsasl_stream_create (mu_stream_t *stream, mu_stream_t transport, - Gsasl_session *ctx, int flags); +int gsasl_encoder_stream (mu_stream_t *pstr, mu_stream_t transport, + Gsasl_session *ctx, int flags); +int gsasl_decoder_stream (mu_stream_t *pstr, mu_stream_t transport, + Gsasl_session *ctx, int flags); #endif diff --git a/include/mailutils/sys/Makefile.am b/include/mailutils/sys/Makefile.am index ce37112b0..bc813e9f1 100644 --- a/include/mailutils/sys/Makefile.am +++ b/include/mailutils/sys/Makefile.am @@ -22,6 +22,7 @@ sysinclude_HEADERS = \ dbgstream.h\ file_stream.h\ filter.h\ + gsasl-stream.h\ header_stream.h\ header.h\ iostream.h\ diff --git a/include/mailutils/sys/gsasl-stream.h b/include/mailutils/sys/gsasl-stream.h new file mode 100644 index 000000000..c93176790 --- /dev/null +++ b/include/mailutils/sys/gsasl-stream.h @@ -0,0 +1,38 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2010 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _MAILUTILS_SYS_TLS_STREAM_H +# define _MAILUTILS_SYS_GSASL_STREAM_H + +# include <mailutils/types.h> +# include <mailutils/stream.h> +# include <mailutils/sys/stream.h> + +struct _mu_gsasl_filter +{ + Gsasl_session *sess_ctx; /* Context */ + int gsasl_err; /* Last Gsasl error code */ + char *bufptr; + size_t bufsize; +}; + +struct _mu_gsasl_stream +{ + struct _mu_stream stream; + mu_stream_t transport; +}; + +#endif diff --git a/libmu_auth/Makefile.am b/libmu_auth/Makefile.am index 0f97e5521..2533ffbb1 100644 --- a/libmu_auth/Makefile.am +++ b/libmu_auth/Makefile.am @@ -26,8 +26,6 @@ lib_LTLIBRARIES = libmu_auth.la libmu_auth_la_SOURCES = \ gsasl.c\ - lbuf.c\ - lbuf.h\ ldap.c\ pam.c\ radius.c\ diff --git a/libmu_auth/gsasl.c b/libmu_auth/gsasl.c index bdaa1174b..d03f3e211 100644 --- a/libmu_auth/gsasl.c +++ b/libmu_auth/gsasl.c @@ -33,9 +33,10 @@ #include <mailutils/nls.h> #include <mailutils/stream.h> #include <mailutils/gsasl.h> +#include <mailutils/sys/gsasl-stream.h> +#include <mailutils/filter.h> #include <gsasl.h> -#include <lbuf.h> struct mu_gsasl_module_data mu_gsasl_module_data = { SITE_CRAM_MD5_PWD @@ -49,235 +50,172 @@ mu_gsasl_module_init (enum mu_gocs_op op, void *data) return 0; } -struct _gsasl_stream { - Gsasl_session *sess_ctx; /* Context */ - int last_err; /* Last Gsasl error code */ - - mu_stream_t stream; /* I/O stream */ - struct _line_buffer *lb; -}; - -static void -_gsasl_destroy (mu_stream_t stream) -{ - int flags; - struct _gsasl_stream *s = mu_stream_get_owner (stream); - mu_stream_get_flags (stream, &flags); - if (!(flags & MU_STREAM_NO_CLOSE)) - mu_stream_destroy (&s->stream, mu_stream_get_owner (s->stream)); - _auth_lb_destroy (&s->lb); -} - -static int -_gsasl_readline (mu_stream_t stream, char *optr, size_t osize, - off_t offset, size_t *nbytes) + +static enum mu_filter_result +_gsasl_encoder (void *xdata, + enum mu_filter_command cmd, + struct mu_filter_io *iobuf) { - struct _gsasl_stream *s = mu_stream_get_owner (stream); - int rc; - size_t len, sz; - char *bufp = NULL; + struct _mu_gsasl_filter *flt = xdata; - if (_auth_lb_level (s->lb)) + switch (cmd) { - len = _auth_lb_readline (s->lb, optr, osize-1); - optr[len] = 0; - if (nbytes) - *nbytes = len; - return 0; + case mu_filter_init: + flt->bufptr = NULL; + flt->bufsize = 0; + flt->gsasl_err = 0; + return mu_filter_ok; + + case mu_filter_done: + if (flt->bufptr) + free (flt->bufptr); + free (flt); + return mu_filter_ok; + + default: + break; } - do + if (flt->bufptr == NULL) { - char c; - size_t sz; - int status; - - status = mu_stream_sequential_read (s->stream, &c, 1, &sz); - if (status == EINTR) - continue; - else if (status) + int status = gsasl_encode (flt->sess_ctx, iobuf->input, iobuf->isize, + &flt->bufptr, &flt->bufsize); + /* FIXME: Can it require more input? */ + if (status) { - free (bufp); - return status; + flt->gsasl_err = status; + return mu_filter_falure; } - rc = _auth_lb_grow (s->lb, &c, sz); - if (rc) - return rc; - - rc = gsasl_decode (s->sess_ctx, - _auth_lb_data (s->lb), - _auth_lb_level (s->lb), - &bufp, &len); } - while (rc == GSASL_NEEDS_MORE); + + iobuf->osize = flt->bufsize; - if (rc != GSASL_OK) - { - s->last_err = rc; - free (bufp); - return EIO; - } - - sz = len > osize ? osize : len; - - if (len > osize) - { - memcpy (optr, bufp, osize); - _auth_lb_drop (s->lb); - _auth_lb_grow (s->lb, bufp + osize, len - osize); - len = osize; - } - else - { - _auth_lb_drop (s->lb); - memcpy (optr, bufp, len); - } + if (flt->bufsize > iobuf->osize) + return mu_filter_moreoutput; - if (len < osize) - optr[len] = 0; - - if (nbytes) - *nbytes = len; - - free (bufp); + memcpy (iobuf->output, flt->bufptr, flt->bufsize); - return 0; + free (flt->bufptr); + flt->bufptr = NULL; + flt->bufsize = 0; + + return mu_filter_ok; } - -int -write_chunk (void *data, char *start, char *end) + + +static enum mu_filter_result +_gsasl_decoder (void *xdata, + enum mu_filter_command cmd, + struct mu_filter_io *iobuf) { - struct _gsasl_stream *s = data; - size_t chunk_size = end - start + 1; - size_t len = 0; - char *buf = NULL; + struct _mu_gsasl_filter *flt = xdata; int status; - - gsasl_encode (s->sess_ctx, start, chunk_size, &buf, &len); - - status = mu_stream_sequential_write (s->stream, buf, len); - free (buf); + switch (cmd) + { + case mu_filter_init: + flt->bufptr = NULL; + flt->bufsize = 0; + flt->gsasl_err = 0; + return mu_filter_ok; + + case mu_filter_done: + if (flt->bufptr) + free (flt->bufptr); + free (flt); + return mu_filter_ok; + + default: + break; + } - return status; -} + if (flt->bufptr == NULL) + { + status = gsasl_decode (flt->sess_ctx, iobuf->input, iobuf->isize, + &flt->bufptr, &flt->bufsize); + switch (status) + { + case GSASL_OK: + break; + + case GSASL_NEEDS_MORE: + iobuf->isize++; + return mu_filter_moreinput; + + default: + flt->gsasl_err = status; + return mu_filter_falure; + } + } + iobuf->osize = flt->bufsize; -static int -_gsasl_write (mu_stream_t stream, const char *iptr, size_t isize, - off_t offset, size_t *nbytes) -{ - int rc; - struct _gsasl_stream *s = mu_stream_get_owner (stream); + if (flt->bufsize > iobuf->osize) + return mu_filter_moreoutput; - rc = _auth_lb_grow (s->lb, iptr, isize); - if (rc) - return rc; - - return _auth_lb_writelines (s->lb, iptr, isize, offset, - write_chunk, s, nbytes); -} - -static int -_gsasl_flush (mu_stream_t stream) -{< |