#include <string.h>

#include <glib.h>
#include <stdio.h>
#include "ca_configFns.h"
#include "ca_defs.h"
#include "ca_dictionary.h"
#include "ca_macros.h"


#include "cr.h"
#include "au_util.h"
#include "lu.h"

#undef MIN
#undef MAX
#include "memwrap.h"

void
au_override (AU_ret_t *ret_val, gboolean *override, au_plugin_callback_info_t *info)
{
  char *override_pwd;

  LG_log(au_context, LG_FUNC, ">au_override: entering");

  LG_log(au_context, LG_DEBUG, "au_override: ret_val start [%s]", 
         AU_ret2str(*ret_val));

  /* only allow override if we do not have an error */
  if (*ret_val != AU_ERROR)
  {
    override_pwd = ca_get_overridecryptedpw;
    /* chop off any trailing newline */
    if ( override_pwd[strlen(override_pwd)-1] == '\n' )
      override_pwd[strlen(override_pwd)-1] = '\0' ;

    if (CR_credential_list_check(info->cred, CR_OVERRIDE, override_pwd, TRUE))
    {
      *ret_val = AU_AUTHORISED;
      *override = TRUE;
    }
    else
    {
      *override = FALSE;
    }
    UT_free(override_pwd);
  }

  LG_log(au_context, LG_DEBUG, "au_override: ret_val final [%s]",
         AU_ret2str(*ret_val));
  LG_log(au_context, LG_FUNC, "<au_override: exiting");
}

AU_ret_t
au_check_authentications (GList *auth_attrs, GList *cred)
{
  AU_ret_t ret_val;
  GList *p;
  const gchar *auth;
  gboolean known_auth;
  CR_type auth_type;
  const gchar *auth_val;

  LG_log(au_context, LG_FUNC, ">au_check_authentications: entering");

  /* default to unauthenticated, and set to authenticated if any match */
  ret_val = AU_UNAUTHORISED_CONT;

  /* loop through our attributes */
  for (p=auth_attrs; p != NULL; p = g_list_next(p))
  {
    auth = rpsl_attr_get_value(p->data);

    /* NONE is a special case and always succeeds */
    if (strcasecmp(auth, "NONE") == 0) 
    {
      ret_val = AU_AUTHORISED;
      LG_log(au_context, LG_DEBUG,
             "au_check_authentications: NONE authenticated");
    }
    else 
    {
      /* flag to verify we have a good authentication type */
      known_auth = TRUE;

      /* determine the authentication type and data from the attribute */
      if (strncasecmp(auth, "PGPKEY-", 7) == 0)
      {
        auth_type = CR_PGP;
        auth_val = auth+7;
      }
      else if (strncasecmp(auth, "MAIL-FROM ", 10) == 0)
      {
        auth_type = CR_FROM;
        auth_val = auth+10;
      }
      else if (strncasecmp(auth, "CRYPT-PW ", 9) == 0)
      {
        auth_type = CR_PASSWORD;
        auth_val = auth+9;
      }
      else if (strncasecmp(auth, "MD5-PW ", 7) == 0)
      {
        auth_type = CR_PASSWORD;
        auth_val = auth+7;
      }
      else
      {
        known_auth = FALSE;
        LG_log(au_context, LG_WARN, 
               "au_check_authentications: unrecognised authentication %s",
               auth);
      }

      LG_log(au_context, LG_DEBUG, 
               "au_check_authentications: auth_val %s", auth_val);
      LG_log(au_context, LG_DEBUG, 
               "au_check_authentications: auth_type %s", CR_type2str(auth_type));

      /* check the credential list for this authentication */
      if (known_auth &&
          CR_credential_list_check(cred, auth_type, auth_val, FALSE))
      { 
        ret_val = AU_AUTHORISED;
        LG_log(au_context, LG_DEBUG,
               "au_check_authentications: %s authenticated", auth);
      }
      else
      {
        LG_log(au_context, LG_DEBUG,
               "au_check_authentications: %s NOT authenticated", auth);
      }
    }
  }

  /* log result */
  LG_log(au_context, LG_FUNC, 
         "<au_check_authentications: exiting with value [%s]",
         AU_ret2str(ret_val));

  /* return result */
  return ret_val;
}

AU_ret_t
au_mntner_authenticate (RT_context_t *ctx, const gchar *mntner_name, LU_server_t *lu, 
                        const gchar *source_name, GList *cred, 
                        rpsl_object_t **mntner)
{
  AU_ret_t ret_val;
  GList *auth_attrs;

  LG_log(au_context, LG_FUNC, ">au_mntner_authenticate: entering");

  LG_log(au_context, LG_DEBUG, 
         "au_mntner_authenticate: checking maintainer %s", mntner_name);

  /* try looking up the maintainer */
  if (LU_lookup(lu, mntner, "mntner", mntner_name, source_name) == LU_ERROR)
  {
    /* lookup failed */
    *mntner = NULL;
    LG_log(au_context, LG_WARN, 
           "au_mntner_authenticate: error looking up mntner %s", mntner_name);
    ret_val = AU_ERROR;
  }
  else
  {
    /* lookup worked */
    if (*mntner == NULL)
    {
      /* no such maintainer (how did this get here?!?!?) */
      LG_log(au_context, LG_WARN,
             "au_mntner_authenticate: non-existant mntner %s", mntner_name);
      RT_non_exist_mntner(ctx, mntner_name);
      ret_val = AU_UNAUTHORISED_CONT;
    }
    else
    {
      /* mntner exists - check the "auth:" attributes */
      auth_attrs = rpsl_object_get_attr(*mntner, "auth");
      rpsl_attr_split_multiple(&auth_attrs);
      ret_val = au_check_authentications(auth_attrs, cred);
    }
  }

  LG_log(au_context, LG_FUNC, 
         "<au_mntner_authenticate: exiting with value [%s]",
         AU_ret2str(ret_val));

  return ret_val;
}
