From a0d8310e75e8007e18939980b0ae8064ac55212a Mon Sep 17 00:00:00 2001 From: Johan Danielsson Date: Mon, 14 Jun 2004 08:19:05 +0000 Subject: [PATCH] improved SASL support git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@13929 ec53bebd-3082-4978-b11e-865c3cabbd6b --- appl/popper/auth_gssapi.c | 250 ++++++++++++++++++++++++++++++++ appl/popper/auth_krb4.c | 208 +++++++++++++++++++++++++++ appl/popper/pop_auth.c | 293 +++++++++++++++++--------------------- appl/popper/pop_auth.h | 25 ++++ 4 files changed, 613 insertions(+), 163 deletions(-) create mode 100644 appl/popper/auth_gssapi.c create mode 100644 appl/popper/auth_krb4.c create mode 100644 appl/popper/pop_auth.h diff --git a/appl/popper/auth_gssapi.c b/appl/popper/auth_gssapi.c new file mode 100644 index 000000000..15780fbb5 --- /dev/null +++ b/appl/popper/auth_gssapi.c @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Kungliga Tekniska + * Högskolan and its contributors. + * + * 4. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +RCSID("$Id$"); + + +#if defined(SASL) && defined(KRB5) +#include + +extern krb5_context gssapi_krb5_context; + +struct gss_state { + gss_ctx_id_t context_hdl; + gss_OID mech_oid; + gss_name_t client_name; + int stage; +}; + +static void +gss_set_error (struct gss_state *gs, int min_stat) +{ + OM_uint32 new_stat; + OM_uint32 msg_ctx = 0; + gss_buffer_desc status_string; + OM_uint32 ret; + + do { + ret = gss_display_status (&new_stat, + min_stat, + GSS_C_MECH_CODE, + gs->mech_oid, + &msg_ctx, + &status_string); + pop_auth_set_error(status_string.value); + gss_release_buffer (&new_stat, &status_string); + } while (!GSS_ERROR(ret) && msg_ctx != 0); +} + +static int +gss_loop(POP *p, void *state, + /* const */ void *input, size_t input_length, + void **output, size_t *output_length) +{ + struct gss_state *gs = state; + gss_buffer_desc real_input_token, real_output_token; + gss_buffer_t input_token = &real_input_token, + output_token = &real_output_token; + OM_uint32 maj_stat, min_stat; + gss_channel_bindings_t bindings = GSS_C_NO_CHANNEL_BINDINGS; + + if(gs->stage == 0) { + /* we require an initial response, so ask for one if not + present */ + gs->stage++; + if(input == NULL && input_length == 0) { + /* XXX this could be done better */ + fputs("+ \r\n", p->output); + fflush(p->output); + return POP_AUTH_CONTINUE; + } + } + if(gs->stage == 1) { + input_token->value = input; + input_token->length = input_length; + maj_stat = + gss_accept_sec_context (&min_stat, + &gs->context_hdl, + GSS_C_NO_CREDENTIAL, + input_token, + bindings, + &gs->client_name, + &gs->mech_oid, + output_token, + NULL, + NULL, + NULL); + if (GSS_ERROR(maj_stat)) { + gss_set_error(gs, min_stat); + return POP_AUTH_FAILURE; + } + if (output_token->length != 0) { + *output = output_token->value; + *output_length = output_token->length; + } + if(maj_stat == GSS_S_COMPLETE) + gs->stage++; + + return POP_AUTH_CONTINUE; + } + + if(gs->stage == 2) { + /* send wanted protection levels */ + unsigned char x[4] = { 1, 0, 0, 0 }; + + input_token->value = x; + input_token->length = 4; + + maj_stat = gss_wrap(&min_stat, + gs->context_hdl, + FALSE, + GSS_C_QOP_DEFAULT, + input_token, + NULL, + output_token); + if (GSS_ERROR(maj_stat)) { + gss_set_error(gs, min_stat); + return POP_AUTH_FAILURE; + } + *output = output_token->value; + *output_length = output_token->length; + gs->stage++; + return POP_AUTH_CONTINUE; + } + if(gs->stage == 3) { + /* receive protection levels and username */ + char *name; + krb5_principal principal; + gss_buffer_desc export_name; + gss_OID oid; + unsigned char *ptr; + + input_token->value = input; + input_token->length = input_length; + + maj_stat = gss_unwrap (&min_stat, + gs->context_hdl, + input_token, + output_token, + NULL, + NULL); + if (GSS_ERROR(maj_stat)) { + gss_set_error(gs, min_stat); + return POP_AUTH_FAILURE; + } + if(output_token->length < 5) { + pop_auth_set_error("response too short"); + return POP_AUTH_FAILURE; + } + ptr = output_token->value; + if(ptr[0] != 1) { + pop_auth_set_error("must use clear text"); + return POP_AUTH_FAILURE; + } + memmove(output_token->value, ptr + 4, output_token->length - 4); + ptr[output_token->length - 4] = '\0'; + + maj_stat = gss_display_name(&min_stat, gs->client_name, + &export_name, &oid); + if(maj_stat != GSS_S_COMPLETE) { + gss_set_error(gs, min_stat); + return POP_AUTH_FAILURE; + } + /* XXX kerberos */ + if(oid != GSS_KRB5_NT_PRINCIPAL_NAME) { + pop_auth_set_error("unexpected gss name type"); + gss_release_buffer(&min_stat, &export_name); + return POP_AUTH_FAILURE; + } + name = malloc(export_name.length + 1); + if(name == NULL) { + pop_auth_set_error("out of memory"); + gss_release_buffer(&min_stat, &export_name); + return POP_AUTH_FAILURE; + } + memcpy(name, export_name.value, export_name.length); + name[export_name.length] = '\0'; + gss_release_buffer(&min_stat, &export_name); + krb5_parse_name(gssapi_krb5_context, name, &principal); + + if(!krb5_kuserok(gssapi_krb5_context, principal, ptr)) { + pop_auth_set_error("Permission denied"); + return POP_AUTH_FAILURE; + } + + + strlcpy(p->user, ptr, sizeof(p->user)); + return POP_AUTH_COMPLETE; + } + return POP_AUTH_FAILURE; +} + + +static int +gss_init(POP *p, void **state) +{ + struct gss_state *gs = malloc(sizeof(*gs)); + if(gs == NULL) { + pop_auth_set_error("out of memory"); + return POP_AUTH_FAILURE; + } + gs->context_hdl = GSS_C_NO_CONTEXT; + gs->stage = 0; + *state = gs; + return POP_AUTH_CONTINUE; +} + +static int +gss_cleanup(POP *p, void *state) +{ + OM_uint32 min_stat; + struct gss_state *gs = state; + if(gs->context_hdl != GSS_C_NO_CONTEXT) + gss_delete_sec_context(&min_stat, &gs->context_hdl, GSS_C_NO_BUFFER); + free(state); + return POP_AUTH_CONTINUE; +} + +struct auth_mech gssapi_mech = { + "GSSAPI", gss_init, gss_loop, gss_cleanup +}; + +#endif /* KRB5 */ diff --git a/appl/popper/auth_krb4.c b/appl/popper/auth_krb4.c new file mode 100644 index 000000000..bb564cbe6 --- /dev/null +++ b/appl/popper/auth_krb4.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Kungliga Tekniska + * Högskolan and its contributors. + * + * 4. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +RCSID("$Id$"); + + +#if defined(SASL) && defined(KRB4) +#include +#include + +struct krb4_state { + int stage; + u_int32_t nonce; +}; + +static int +krb4_loop(POP *p, void *state, + /* const */ void *input, size_t input_length, + void **output, size_t *output_length) +{ + struct krb4_state *ks = state; + + int ret; + des_cblock key; + unsigned char *data; + char instance[INST_SZ]; + des_key_schedule schedule; + + if(ks->stage == 0) { + if(input_length > 0) + return POP_AUTH_FAILURE; + /* S -> C: 32 bit nonce in MSB base64 */ +#ifdef HAVE_OPENSSL +#define des_new_random_key des_random_key +#endif + des_new_random_key(key); + ks->nonce = (key[0] | (key[1] << 8) | (key[2] << 16) | (key[3] << 24) + | key[4] | (key[5] << 8) | (key[6] << 16) | (key[7] << 24)); + *output = malloc(4); + if(*output == NULL) { + pop_auth_set_error("out of memory"); + return POP_AUTH_FAILURE; + } + krb_put_int(ks->nonce, *output, 4, 4); + *output_length = 4; + ks->stage++; + return POP_AUTH_CONTINUE; + } + + if(ks->stage == 1) { + KTEXT_ST authent; + /* C -> S: ticket and authenticator */ + + if (input_length > sizeof(authent.dat)) { + pop_auth_set_error("data packet too long"); + return POP_AUTH_FAILURE; + } + memcpy(authent.dat, input, input_length); + authent.length = input_length; + + k_getsockinst (0, instance, sizeof(instance)); + ret = krb_rd_req(&authent, "pop", instance, + 0 /* XXX p->in_addr.sin_addr.s_addr */, + &p->kdata, NULL); + if (ret != 0) { + pop_auth_set_error(krb_get_err_text(ret)); + return POP_AUTH_FAILURE; + } + if (p->kdata.checksum != ks->nonce) { + pop_auth_set_error("data stream modified"); + return POP_AUTH_FAILURE; + } + /* S -> C: nonce + 1 | bit | max segment */ + + *output = malloc(8); + if(*output == NULL) { + pop_auth_set_error("out of memory"); + return POP_AUTH_FAILURE; + } + data = *output; + krb_put_int(ks->nonce + 1, data, 8, 4); + data[4] = 1; + data[5] = 0; + data[6] = 0; + data[7] = 0; + des_key_sched(&p->kdata.session, schedule); + des_pcbc_encrypt((des_cblock*)data, + (des_cblock*)data, 8, + schedule, + &p->kdata.session, + DES_ENCRYPT); + *output_length = 8; + ks->stage++; + return POP_AUTH_CONTINUE; + } + + if(ks->stage == 2) { + u_int32_t nonce_reply; + /* C -> S: nonce | bit | max segment | username */ + + if (input_length % 8 != 0) { + pop_auth_set_error("reply is not a multiple of 8 bytes"); + return POP_AUTH_FAILURE; + } + + des_key_sched(&p->kdata.session, schedule); + des_pcbc_encrypt((des_cblock*)input, + (des_cblock*)input, + input_length, + schedule, + &p->kdata.session, + DES_DECRYPT); + + data = input; + krb_get_int(data, &nonce_reply, 4, 0); + if (nonce_reply != ks->nonce) { + pop_auth_set_error("data stream modified"); + return POP_AUTH_FAILURE; + } + if(data[4] != 1) { + + } + if(data[input_length - 1] != '\0') { + pop_auth_set_error("bad format of username"); + return POP_AUTH_FAILURE; + } + strlcpy(p->user, data + 8, sizeof(p->user)); + if (kuserok(&p->kdata, p->user)) { + pop_log(p, POP_PRIORITY, + "%s: (%s.%s@%s) tried to retrieve mail for %s.", + p->client, p->kdata.pname, p->kdata.pinst, + p->kdata.prealm, p->user); + pop_auth_set_error("Permission denied"); + return POP_AUTH_FAILURE; + } + pop_log(p, POP_INFO, "%s: %s.%s@%s -> %s", + p->ipaddr, + p->kdata.pname, p->kdata.pinst, p->kdata.prealm, + p->user); + return POP_AUTH_COMPLETE; + } + return POP_AUTH_FAILURE; +} + + +static int +krb4_init(POP *p, void **state) +{ + struct krb4_state *ks = malloc(sizeof(*ks)); + if(ks == NULL) { + pop_auth_set_error("out of memory"); + return POP_AUTH_FAILURE; + } + ks->stage = 0; + *state = ks; + return POP_AUTH_CONTINUE; +} + +static int +krb4_cleanup(POP *p, void *state) +{ + free(state); + return POP_AUTH_CONTINUE; +} + +struct auth_mech krb4_mech = { + "KERBEROS_V4", krb4_init, krb4_loop, krb4_cleanup +}; + +#endif /* KRB5 */ diff --git a/appl/popper/pop_auth.c b/appl/popper/pop_auth.c index 333253752..c2f8fbea0 100644 --- a/appl/popper/pop_auth.c +++ b/appl/popper/pop_auth.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan + * Copyright (c) 2004 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -37,184 +37,151 @@ */ #include +#ifdef SASL #include +#include RCSID("$Id$"); -#ifdef KRB4 - -enum { - NO_PROT = 1, - INT_PROT = 2, - PRIV_PROT = 4 -}; - -static int -auth_krb4(POP *p) -{ - int ret; - des_cblock key; - u_int32_t nonce, nonce_reply; - u_int32_t max_client_packet; - int protocols = NO_PROT | INT_PROT | PRIV_PROT; - char data[8]; - int len; - char *s; - char instance[INST_SZ]; - KTEXT_ST authent; - des_key_schedule schedule; - struct passwd *pw; - - /* S -> C: 32 bit nonce in MSB base64 */ - - des_new_random_key(&key); - nonce = (key[0] | (key[1] << 8) | (key[2] << 16) | (key[3] << 24) - | key[4] | (key[5] << 8) | (key[6] << 16) | (key[7] << 24)); - krb_put_int(nonce, data, 4, 8); - len = base64_encode(data, 4, &s); - - pop_msg(p, POP_CONTINUE, "%s", s); - free(s); - - /* C -> S: ticket and authenticator */ - - ret = sch_readline(p->input, &s); - if (ret <= 0 || strcmp (s, "*") == 0) - return pop_msg(p, POP_FAILURE, - "authentication aborted by client"); - len = strlen(s); - if (len > sizeof(authent.dat)) { - return pop_msg(p, POP_FAILURE, "data packet too long"); - } - - authent.length = base64_decode(s, authent.dat); - - k_getsockinst (0, instance, sizeof(instance)); - ret = krb_rd_req(&authent, "pop", instance, - p->in_addr.sin_addr.s_addr, - &p->kdata, NULL); - if (ret != 0) { - return pop_msg(p, POP_FAILURE, "rd_req: %s", - krb_get_err_text(ret)); - } - if (p->kdata.checksum != nonce) { - return pop_msg(p, POP_FAILURE, "data stream modified"); - } - - /* S -> C: nonce + 1 | bit | max segment */ - - krb_put_int(nonce + 1, data, 4, 7); - data[4] = protocols; - krb_put_int(1024, data + 5, 3, 3); /* XXX */ - des_key_sched(&p->kdata.session, schedule); - des_pcbc_encrypt((des_cblock*)data, - (des_cblock*)data, 8, - schedule, - &p->kdata.session, - DES_ENCRYPT); - len = base64_encode(data, 8, &s); - pop_msg(p, POP_CONTINUE, "%s", s); - - free(s); - - /* C -> S: nonce | bit | max segment | username */ - - ret = sch_readline(p->input, &s); - if (ret <= 0 || strcmp (s, "*") == 0) - return pop_msg(p, POP_FAILURE, - "authentication aborted"); - len = strlen(s); - if (len > sizeof(authent.dat)) { - return pop_msg(p, POP_FAILURE, "data packet too long"); - } - - authent.length = base64_decode(s, authent.dat); - - if (authent.length % 8 != 0) { - return pop_msg(p, POP_FAILURE, "reply is not a multiple of 8 bytes"); - } - - des_key_sched(&p->kdata.session, schedule); - des_pcbc_encrypt((des_cblock*)authent.dat, - (des_cblock*)authent.dat, - authent.length, - schedule, - &p->kdata.session, - DES_DECRYPT); - - krb_get_int(authent.dat, &nonce_reply, 4, 0); - if (nonce_reply != nonce) { - return pop_msg(p, POP_FAILURE, "data stream modified"); - } - protocols &= authent.dat[4]; - krb_get_int(authent.dat + 5, &max_client_packet, 3, 0); - if(authent.dat[authent.length - 1] != '\0') { - return pop_msg(p, POP_FAILURE, "bad format of username"); - } - strncpy (p->user, authent.dat + 8, sizeof(p->user)); - pw = k_getpwnam(p->user); - if (pw == NULL) { - return (pop_msg(p,POP_FAILURE, - "Password supplied for \"%s\" is incorrect.", - p->user)); - } - - if (kuserok(&p->kdata, p->user)) { - pop_log(p, POP_PRIORITY, - "%s: (%s.%s@%s) tried to retrieve mail for %s.", - p->client, p->kdata.pname, p->kdata.pinst, - p->kdata.prealm, p->user); - return(pop_msg(p,POP_FAILURE, - "Popping not authorized")); - } - pop_log(p, POP_INFO, "%s: %s.%s@%s -> %s", - p->ipaddr, - p->kdata.pname, p->kdata.pinst, p->kdata.prealm, - p->user); - ret = pop_login(p, pw); - if (protocols & PRIV_PROT) - ; - else if (protocols & INT_PROT) - ; - else - ; - - return ret; -} -#endif /* KRB4 */ - -#ifdef KRB5 -static int -auth_gssapi(POP *p) -{ - -} -#endif /* KRB5 */ - /* * auth: RFC1734 */ -static struct { - const char *name; - int (*func)(POP *); -} methods[] = { -#ifdef KRB4 - {"KERBEROS_V4", auth_krb4}, -#endif +static char * +getline(POP *p) +{ + char *buf = NULL; + size_t size = 1024; + buf = malloc(size); + if(buf == NULL) + return NULL; + *buf = '\0'; + while(fgets(buf + strlen(buf), size - strlen(buf), p->input) != NULL) { + char *p; + if((p = strchr(buf, '\n')) != NULL) { + while(p > buf && p[-1] == '\r') + p--; + *p = '\0'; + return buf; + } + /* just assume we ran out of buffer space, we'll catch eof + next round */ + size += 1024; + p = realloc(buf, size); + if(p == NULL) + break; + buf = p; + } + free(buf); + return NULL; +} + +static char auth_msg[128]; +void +pop_auth_set_error(const char *message) +{ + strlcpy(auth_msg, message, sizeof(auth_msg)); +} + +static struct auth_mech *methods[] = { #ifdef KRB5 - {"GSSAPI", auth_gssapi}, + &gssapi_mech, #endif - {NULL, NULL} +#ifdef KRB4 + &krb4_mech, +#endif + NULL }; +static int +auth_execute(POP *p, struct auth_mech *m, void *state, const char *line) +{ + void *input, *output; + size_t input_length, output_length; + int status; + + if(line == NULL) { + input = NULL; + input_length = 0; + } else { + input = strdup(line); + if(input == NULL) { + pop_auth_set_error("out of memory"); + return POP_AUTH_FAILURE; + } + input_length = base64_decode(line, input); + if(input_length == (size_t)-1) { + pop_auth_set_error("base64 decode error"); + return POP_AUTH_FAILURE; + } + } + output = NULL; output_length = 0; + status = (*m->loop)(p, state, input, input_length, &output, &output_length); + if(output_length > 0) { + char *s; + base64_encode(output, output_length, &s); + fprintf(p->output, "+ %s\r\n", s); + fflush(p->output); + free(output); + free(s); + } + return status; +} + +static int +auth_loop(POP *p, struct auth_mech *m) +{ + int status; + void *state = NULL; + char *line; + + status = (*m->init)(p, &state); + + status = auth_execute(p, m, state, p->pop_parm[2]); + + while(status == POP_AUTH_CONTINUE) { + line = getline(p); + if(line == NULL) { + (*m->cleanup)(p, state); + return pop_msg(p, POP_FAILURE, "error reading data"); + } + if(strcmp(line, "*") == 0) { + (*m->cleanup)(p, state); + return pop_msg(p, POP_FAILURE, "terminated by client"); + } + status = auth_execute(p, m, state, line); + free(line); + } + + + (*m->cleanup)(p, state); + if(status == POP_AUTH_FAILURE) + return pop_msg(p, POP_FAILURE, "%s", auth_msg); + return pop_msg(p, POP_SUCCESS, "authentication complete"); +} + int pop_auth (POP *p) { int i; - for (i = 0; methods[i].name != NULL; ++i) - if (strcasecmp(p->pop_parm[1], methods[i].name) == 0) - return (*methods[i].func)(p); + for (i = 0; methods[i] != NULL; ++i) + if (strcasecmp(p->pop_parm[1], methods[i]->name) == 0) + return auth_loop(p, methods[i]); return pop_msg(p, POP_FAILURE, "Authentication method %s unknown", p->pop_parm[1]); } + +void +pop_capa_sasl(POP *p) +{ + int i; + + if(methods[0] == NULL) + return; + + fprintf(p->output, "SASL"); + for (i = 0; methods[i] != NULL; ++i) + fprintf(p->output, " %s", methods[i]->name); + fprintf(p->output, "\r\n"); +} +#endif diff --git a/appl/popper/pop_auth.h b/appl/popper/pop_auth.h new file mode 100644 index 000000000..4a2eb4776 --- /dev/null +++ b/appl/popper/pop_auth.h @@ -0,0 +1,25 @@ +#ifndef __pop_auth_h__ +#define __pop_auth_h__ + +struct auth_mech { + const char *name; + int (*init)(POP*, void**); + int (*loop)(POP*, void*, void*, size_t, void**, size_t*); + int (*cleanup)(POP*, void*); +}; + +#define POP_AUTH_CONTINUE 0 +#define POP_AUTH_FAILURE 1 +#define POP_AUTH_COMPLETE 2 + +void pop_auth_set_error(const char *message); + +#ifdef KRB5 +extern struct auth_mech gssapi_mech; +#endif +#ifdef KRB4 +extern struct auth_mech krb4_mech; +#endif + + +#endif /* __pop_auth_h__ */