aboutsummaryrefslogtreecommitdiff
path: root/appl/popper/auth_gssapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'appl/popper/auth_gssapi.c')
-rw-r--r--appl/popper/auth_gssapi.c253
1 files changed, 253 insertions, 0 deletions
diff --git a/appl/popper/auth_gssapi.c b/appl/popper/auth_gssapi.c
new file mode 100644
index 000000000000..032efe7ee3c8
--- /dev/null
+++ b/appl/popper/auth_gssapi.c
@@ -0,0 +1,253 @@
+/*
+ * 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. 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 <popper.h>
+#include <base64.h>
+#include <pop_auth.h>
+RCSID("$Id$");
+
+
+#if defined(SASL) && defined(KRB5)
+#include <gssapi.h>
+
+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 {
+ char * cstr;
+
+ ret = gss_display_status (&new_stat,
+ min_stat,
+ GSS_C_MECH_CODE,
+ gs->mech_oid,
+ &msg_ctx,
+ &status_string);
+ if (asprintf(&cstr, "%.*s", (int)status_string.length,
+ (const char *)status_string.value) >= 0) {
+ pop_auth_set_error(cstr);
+ free(cstr);
+ } else {
+ pop_auth_set_error("unknown error");
+ }
+ 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 */