#ifndef PUTTY_SSHGSS_H
#define PUTTY_SSHGSS_H
#include "putty.h"
#include "pgssapi.h"

#ifndef NO_GSSAPI

#define SSH2_GSS_OIDTYPE 0x06
typedef void *Ssh_gss_ctx;

typedef enum Ssh_gss_stat {
    SSH_GSS_OK = 0,
    SSH_GSS_S_CONTINUE_NEEDED,
    SSH_GSS_NO_MEM,
    SSH_GSS_BAD_HOST_NAME,
    SSH_GSS_FAILURE
} Ssh_gss_stat;

#define SSH_GSS_S_COMPLETE SSH_GSS_OK

#define SSH_GSS_CLEAR_BUF(buf) do {		\
    (*buf).length = 0;				\
    (*buf).value = NULL;				\
} while (0)

typedef gss_buffer_desc Ssh_gss_buf;
typedef gss_name_t Ssh_gss_name;

/* Functions, provided by either wingss.c or sshgssc.c */

struct ssh_gss_library;

/*
 * Prepare a collection of GSSAPI libraries for use in a single SSH
 * connection. Returns a structure containing a list of libraries,
 * with their ids (see struct ssh_gss_library below) filled in so
 * that the client can go through them in the SSH user's preferred
 * order.
 *
 * Must always return non-NULL. (Even if no libraries are available,
 * it must return an empty structure.)
 *
 * The free function cleans up the structure, and its associated
 * libraries (if any).
 */
struct ssh_gss_liblist {
    struct ssh_gss_library *libraries;
    int nlibraries;
};
struct ssh_gss_liblist *ssh_gss_setup(const Config *cfg);
void ssh_gss_cleanup(struct ssh_gss_liblist *list);

/*
 * Fills in buf with a string describing the GSSAPI mechanism in
 * use. buf->data is not dynamically allocated.
 */
typedef Ssh_gss_stat (*t_ssh_gss_indicate_mech)(struct ssh_gss_library *lib,
						Ssh_gss_buf *buf);

/*
 * Converts a name such as a hostname into a GSSAPI internal form,
 * which is placed in "out". The result should be freed by
 * ssh_gss_release_name().
 */
typedef Ssh_gss_stat (*t_ssh_gss_import_name)(struct ssh_gss_library *lib,
					      char *in, Ssh_gss_name *out);

/*
 * Frees the contents of an Ssh_gss_name structure filled in by
 * ssh_gss_import_name().
 */
typedef Ssh_gss_stat (*t_ssh_gss_release_name)(struct ssh_gss_library *lib,
					       Ssh_gss_name *name);

/*
 * The main GSSAPI security context setup function. The "out"
 * parameter will need to be freed by ssh_gss_free_tok.
 */
typedef Ssh_gss_stat (*t_ssh_gss_init_sec_context)
    (struct ssh_gss_library *lib,
     Ssh_gss_ctx *ctx, Ssh_gss_name name, int delegate,
     Ssh_gss_buf *in, Ssh_gss_buf *out);

/*
 * Frees the contents of an Ssh_gss_buf filled in by
 * ssh_gss_init_sec_context(). Do not accidentally call this on
 * something filled in by ssh_gss_get_mic() (which requires a
 * different free function) or something filled in by any other
 * way.
 */
typedef Ssh_gss_stat (*t_ssh_gss_free_tok)(struct ssh_gss_library *lib,
					   Ssh_gss_buf *);

/*
 * Acquires the credentials to perform authentication in the first
 * place. Needs to be freed by ssh_gss_release_cred().
 */
typedef Ssh_gss_stat (*t_ssh_gss_acquire_cred)(struct ssh_gss_library *lib,
					       Ssh_gss_ctx *);

/*
 * Frees the contents of an Ssh_gss_ctx filled in by
 * ssh_gss_acquire_cred().
 */
typedef Ssh_gss_stat (*t_ssh_gss_release_cred)(struct ssh_gss_library *lib,
					       Ssh_gss_ctx *);

/*
 * Gets a MIC for some input data. "out" needs to be freed by
 * ssh_gss_free_mic().
 */
typedef Ssh_gss_stat (*t_ssh_gss_get_mic)(struct ssh_gss_library *lib,
					  Ssh_gss_ctx ctx, Ssh_gss_buf *in,
                 Ssh_gss_buf *out);

/*
 * Frees the contents of an Ssh_gss_buf filled in by
 * ssh_gss_get_mic(). Do not accidentally call this on something
 * filled in by ssh_gss_init_sec_context() (which requires a
 * different free function) or something filled in by any other
 * way.
 */
typedef Ssh_gss_stat (*t_ssh_gss_free_mic)(struct ssh_gss_library *lib,
					   Ssh_gss_buf *);

/*
 * Return an error message after authentication failed. The
 * message string is returned in "buf", with buf->len giving the
 * number of characters of printable message text and buf->data
 * containing one more character which is a trailing NUL.
 * buf->data should be manually freed by the caller. 
 */
typedef Ssh_gss_stat (*t_ssh_gss_display_status)(struct ssh_gss_library *lib,
						 Ssh_gss_ctx, Ssh_gss_buf *buf);

struct ssh_gss_library {
    /*
     * Identifying number in the enumeration used by the
     * configuration code to specify a preference order.
     */
    int id;

    /*
     * Filled in at initialisation time, if there's anything
     * interesting to say about how GSSAPI was initialised (e.g.
     * which of a number of alternative libraries was used).
     */
    const char *gsslogmsg;

    /*
     * Function pointers implementing the SSH wrapper layer on top
     * of GSSAPI. (Defined in sshgssc, typically, though Windows
     * provides an alternative layer to sit on top of the annoyingly
     * different SSPI.)
     */
    t_ssh_gss_indicate_mech indicate_mech;
    t_ssh_gss_import_name import_name;
    t_ssh_gss_release_name release_name;
    t_ssh_gss_init_sec_context init_sec_context;
    t_ssh_gss_free_tok free_tok;
    t_ssh_gss_acquire_cred acquire_cred;
    t_ssh_gss_release_cred release_cred;
    t_ssh_gss_get_mic get_mic;
    t_ssh_gss_free_mic free_mic;
    t_ssh_gss_display_status display_status;

    /*
     * Additional data for the wrapper layers.
     */
    union {
	struct gssapi_functions gssapi;
	/*
	 * The SSPI wrappers don't need to store their Windows API
	 * function pointers in this structure, because there can't
	 * be more than one set of them available.
	 */
    } u;

    /*
     * Wrapper layers will often also need to store a library handle
     * of some sort for cleanup time.
     */
    void *handle;
};

#endif /* NO_GSSAPI */

#endif /*PUTTY_SSHGSS_H*/
