#line 1 "/export/aphraelraid/home/peter/hack/Pike/7.6/src/modules/Kerberos/kerberos.cmod"
/*
 * $Id: kerberos.cmod,v 1.1 2004/05/13 08:57:08 grubba Exp $
 *
 * Kerberos support for Pike.
 *
 * 2004-05-12 Henrik Grubbström
 *
 * FIXME: Currently only minimal support, and only for Kerberos 5 (not 4).
 */

#include "global.h"
#include "config.h"

#include "svalue.h"
#include "module.h"
#include "interpret.h"

#if defined(HAVE_KRB5_H) && defined(HAVE_LIBKRB5)
#define HAVE_KRB5
#endif

#line 24 "/export/aphraelraid/home/peter/hack/Pike/7.6/src/modules/Kerberos/kerberos.cmod"
/* #define KRB_DEBUG */

#ifdef KRB_DEBUG
#define KRB_FPRINTF(X)	fprintf X
#else /* !KRB_DEBUG */
#define KRB_FPRINTF(X)
#endif /* KRB_DEBUG */

#ifdef HAVE_KRB5

#ifdef HAVE_KRB5_H
#include <krb5.h>
#endif


#undef class_Context_defined
#define class_Context_defined
struct program *Context_program=0;
int Context_program_fun_num=-1;

#undef var_ctx_Context_defined
#define var_ctx_Context_defined

#undef THIS
#define THIS ((struct Context_struct *)(Pike_interpreter.frame_pointer->current_storage))

#undef THIS_CONTEXT
#define THIS_CONTEXT ((struct Context_struct *)(Pike_interpreter.frame_pointer->current_storage))

#undef OBJ2_CONTEXT
#define OBJ2_CONTEXT(o) ((struct Context_struct *)(o->storage+Context_storage_offset))

#undef GET_CONTEXT_STORAGE
#define GET_CONTEXT_STORAGE ((struct Context_struct *)(o->storage+Context_storage_offset)
static ptrdiff_t Context_storage_offset;
struct Context_struct {

#ifdef var_ctx_Context_defined
#line 40 "/export/aphraelraid/home/peter/hack/Pike/7.6/src/modules/Kerberos/kerberos.cmod"
krb5_context ctx;
#endif /* var_ctx_Context_defined */
};

#undef internal_init_Context_defined
#define internal_init_Context_defined

#undef Context_event_handler_defined
#define Context_event_handler_defined
static void init_Context_struct(void)
#line 43 "/export/aphraelraid/home/peter/hack/Pike/7.6/src/modules/Kerberos/kerberos.cmod"
{
    krb5_error_code err_code;
    if ((err_code = krb5_init_context(&THIS->ctx))) {
      Pike_error("Failed to initialize context: %d\n", err_code);
    }
  }

  
#undef internal_exit_Context_defined
#define internal_exit_Context_defined

#undef Context_event_handler_defined
#define Context_event_handler_defined
static void exit_Context_struct(void)
#line 51 "/export/aphraelraid/home/peter/hack/Pike/7.6/src/modules/Kerberos/kerberos.cmod"
{
    if (THIS->ctx) {
      krb5_free_context(THIS->ctx);
    }
  }

  #define f_Context_authenticate_defined
ptrdiff_t f_Context_authenticate_fun_num = 0;
void f_Context_authenticate(INT32 args) {
#line 57 "/export/aphraelraid/home/peter/hack/Pike/7.6/src/modules/Kerberos/kerberos.cmod"
struct pike_string * user;
#line 57 "/export/aphraelraid/home/peter/hack/Pike/7.6/src/modules/Kerberos/kerberos.cmod"
struct pike_string * password;
#line 57 "/export/aphraelraid/home/peter/hack/Pike/7.6/src/modules/Kerberos/kerberos.cmod"
if(args != 2) wrong_number_of_args_error("authenticate",args,2);
#line 57 "/export/aphraelraid/home/peter/hack/Pike/7.6/src/modules/Kerberos/kerberos.cmod"
if(Pike_sp[0-2].type != PIKE_T_STRING) SIMPLE_BAD_ARG_ERROR("authenticate",1,"string");
#line 57 "/export/aphraelraid/home/peter/hack/Pike/7.6/src/modules/Kerberos/kerberos.cmod"
debug_malloc_pass(user=Pike_sp[0-2].u.string);
#line 57 "/export/aphraelraid/home/peter/hack/Pike/7.6/src/modules/Kerberos/kerberos.cmod"
if(Pike_sp[1-2].type != PIKE_T_STRING) SIMPLE_BAD_ARG_ERROR("authenticate",2,"string");
#line 57 "/export/aphraelraid/home/peter/hack/Pike/7.6/src/modules/Kerberos/kerberos.cmod"
debug_malloc_pass(password=Pike_sp[1-2].u.string);
#line 59 "/export/aphraelraid/home/peter/hack/Pike/7.6/src/modules/Kerberos/kerberos.cmod"
{
    krb5_error_code err_code;
    krb5_principal principal;
    krb5_get_init_creds_opt get_creds_opt;
    krb5_verify_init_creds_opt verify_creds_opt;
    krb5_creds creds;
    ONERROR err;

    /* Hide the password from backtraces. */
    Pike_sp[0] = Pike_sp[1-args];
    Pike_sp[1-args].type = PIKE_T_INT;
    Pike_sp[1-args].subtype = NUMBER_UNDEFINED;
    Pike_sp[1-args].u.integer = 0;
    Pike_sp++;
    args++;

    if (user->size_shift || password->size_shift) {
      KRB_FPRINTF((stderr, "Wide password or user name.\n"));
      pop_n_elems(args);
      push_int(0);
      return;
    }

    if ((err_code = krb5_parse_name(THIS->ctx, STR0(user), &principal))) {
      KRB_FPRINTF((stderr, "Failed to parse user name: %d\n", err_code));
      pop_n_elems(args);
      push_int(0);
      return;
    }

    krb5_get_init_creds_opt_init(&get_creds_opt);
    krb5_verify_init_creds_opt_init(&verify_creds_opt);

    if ((err_code = krb5_get_init_creds_password(THIS->ctx, &creds,
						 principal, STR0(password),
						 krb5_prompter_posix,
						 NULL, 0, NULL,
						 &get_creds_opt))) {
      KRB_FPRINTF((stderr, "Failed to get password credentials: %d.\n",
		   err_code));
      pop_n_elems(args);
      push_int(0);
      return;
    }

    if ((err_code = krb5_verify_init_creds(THIS->ctx, &creds,
					   NULL, NULL, NULL,
					   &verify_creds_opt))) {
      krb5_free_cred_contents(THIS->ctx, &creds);
      KRB_FPRINTF((stderr, "Failed to verify credentials: %d.\n", err_code));
      pop_n_elems(args);
      push_int(0);
      return;
    }

    krb5_free_cred_contents(THIS->ctx, &creds);
    KRB_FPRINTF((stderr, "Credentials ok."));

    pop_n_elems(args);
    push_int(1);
    return;
  }
}

#ifdef Context_event_handler_defined
static void Context_event_handler(int ev) {
  switch(ev) {

#ifdef internal_init_Context_defined
  case PROG_EVENT_INIT: init_Context_struct(); break;

#endif /* internal_init_Context_defined */

#ifdef internal_exit_Context_defined
  case PROG_EVENT_EXIT: exit_Context_struct(); break;

#endif /* internal_exit_Context_defined */
  default: break; 
  }
}

#endif /* Context_event_handler_defined */
#line 124 "/export/aphraelraid/home/peter/hack/Pike/7.6/src/modules/Kerberos/kerberos.cmod"
#endif /* HAVE_KRB5 */

PIKE_MODULE_INIT
{
  
#ifdef class_Context_defined

#ifdef PROG_CONTEXT_ID
  START_NEW_PROGRAM_ID(CONTEXT);
#else
  start_new_program();

#endif /* PROG_CONTEXT_ID */

#ifndef tObjImpl_CONTEXT

#undef tObjImpl_CONTEXT
#define tObjImpl_CONTEXT tObj

#endif /* tObjImpl_CONTEXT */

#ifdef THIS_CONTEXT

  Context_storage_offset=ADD_STORAGE(struct Context_struct);

#endif /* THIS_CONTEXT */

#ifdef Context_event_handler_defined
  pike_set_prog_event_callback(Context_event_handler);

#endif /* Context_event_handler_defined */

#ifdef f_Context_authenticate_defined
#line 57 "/export/aphraelraid/home/peter/hack/Pike/7.6/src/modules/Kerberos/kerberos.cmod"
  f_Context_authenticate_fun_num =
    ADD_FUNCTION2("authenticate", f_Context_authenticate, tFunc(tString tString,"\10\0\0\0\0\0\0\0\1"), 0, OPT_EXTERNAL_DEPEND);

#endif /* f_Context_authenticate_defined */
  Context_program=end_program();
  Context_program_fun_num=add_program_constant("Context",Context_program,0);

#endif /* class_Context_defined */
#line 128 "/export/aphraelraid/home/peter/hack/Pike/7.6/src/modules/Kerberos/kerberos.cmod"
;
}

PIKE_MODULE_EXIT
{
  
#ifdef class_Context_defined
  if(Context_program) {
    free_program(Context_program);
    Context_program=0;
  }

#endif /* class_Context_defined */
#line 133 "/export/aphraelraid/home/peter/hack/Pike/7.6/src/modules/Kerberos/kerberos.cmod"
;
}

