thisconfigdir=.
myfulldir=.
mydir=.
-# Don't build sample by default: plugins/locate/python plugins/preauth/wpse plugins/preauth/cksum_body
+# Don't build sample by default, and definitely don't install them
+# for production use:
+# plugins/locate/python
+# plugins/preauth/wpse
+# plugins/preauth/cksum_body
+# plugins/authdata/greet
SUBDIRS=util include lib @krb524@ kdc kadmin @ldap_plugin_dir@ slave clients \
plugins/kdb/db2 \
plugins/preauth/pkinit \
$(ADMIN_MANDIR) $(SERVER_MANDIR) $(CLIENT_MANDIR) \
$(FILE_MANDIR) $(KRB5_LIBDIR) $(KRB5_INCDIR) \
$(KRB5_DB_MODULE_DIR) $(KRB5_PA_MODULE_DIR) \
+ $(KRB5_AD_MODULE_DIR) \
$(KRB5_LIBKRB5_MODULE_DIR) \
@localstatedir@ @localstatedir@/krb5kdc \
$(KRB5_INCSUBDIRS) $(datadir) $(EXAMPLEDIR)
MODULE_DIR = @libdir@/krb5/plugins
KRB5_DB_MODULE_DIR = $(MODULE_DIR)/kdb
KRB5_PA_MODULE_DIR = $(MODULE_DIR)/preauth
+KRB5_AD_MODULE_DIR = $(MODULE_DIR)/authdata
KRB5_LIBKRB5_MODULE_DIR = $(MODULE_DIR)/libkrb5
KRB5_INCSUBDIRS = \
$(KRB5_INCDIR)/krb5 \
plugins/kdb/db2/libdb2/test
plugins/preauth/cksum_body
plugins/preauth/wpse
+ plugins/authdata/greet
clients clients/klist clients/kinit clients/kvno
clients/kdestroy clients/kpasswd clients/ksu
--- /dev/null
+/*
+ * krb5/authdata_plugin.h
+ *
+ * Copyright (C) 2007 Apple Inc. All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * AuthorizationData plugin definitions for Kerberos 5.
+ */
+
+/*
+ * This is considered an INTERNAL interface at this time.
+ *
+ * Some work is needed before exporting it:
+ *
+ * + Documentation.
+ * + Sample code.
+ * + Test cases (preferably automated testing under "make check").
+ * + Hook into TGS exchange too; will change API.
+ * + Examine memory management issues, especially for Windows; may
+ * change API.
+ *
+ * Other changes that would be nice to have, but not necessarily
+ * before making this interface public:
+ *
+ * + Library support for AD-IF-RELEVANT and similar wrappers. (We can
+ * make the plugin construct them if it wants them.)
+ * + KDC could combine/optimize wrapped AD elements provided by
+ * multiple plugins, e.g., two IF-RELEVANT sequences could be
+ * merged. (The preauth plugin API also has this bug, we're going
+ * to need a general fix.)
+ */
+
+#ifndef KRB5_AUTHDATA_PLUGIN_H_INCLUDED
+#define KRB5_AUTHDATA_PLUGIN_H_INCLUDED
+#include <krb5/krb5.h>
+
+/*
+ * While arguments of these types are passed-in, for the most part a
+ * authorization data module can treat them as opaque. If we need
+ * keying data, we can ask for it directly.
+ */
+struct _krb5_db_entry_new;
+
+/*
+ * The function table / structure which an authdata server module must export as
+ * "authdata_server_0". NOTE: replace "0" with "1" for the type and
+ * variable names if this gets picked up by upstream. If the interfaces work
+ * correctly, future versions of the table will add either more callbacks or
+ * more arguments to callbacks, and in both cases we'll be able to wrap the v0
+ * functions.
+ */
+/* extern krb5plugin_authdata_ftable_v0 authdata_server_0; */
+typedef struct krb5plugin_authdata_ftable_v0 {
+ /* Not-usually-visible name. */
+ char *name;
+
+ /*
+ * Per-plugin initialization/cleanup. The init function is called
+ * by the KDC when the plugin is loaded, and the fini function is
+ * called before the plugin is unloaded. Both are optional.
+ */
+ krb5_error_code (*init_proc)(krb5_context, void **);
+ void (*fini_proc)(krb5_context, void *);
+ /*
+ * Actual authorization data handling function. If this field
+ * holds a null pointer, this mechanism will be skipped, and the
+ * init/fini functions will not be run.
+ *
+ * This function should only modify the field
+ * enc_tkt_reply->authorization_data. All other values should be
+ * considered inputs only. And, it should *modify* the field, not
+ * overwrite it and assume that there are no other authdata
+ * plugins in use.
+ *
+ * Memory management: authorization_data is a malloc-allocated,
+ * null-terminated sequence of malloc-allocated pointers to
+ * authorization data structures. This plugin code currently
+ * assumes the libraries, KDC, and plugin all use the same malloc
+ * pool, which may be a problem if/when we get the KDC code
+ * running on Windows.
+ *
+ * If this function returns a non-zero error code, a message
+ * is logged, but no other action is taken. Other authdata
+ * plugins will be called, and a response will be sent to the
+ * client (barring other problems).
+ */
+ krb5_error_code (*authdata_proc)(krb5_context,
+ struct _krb5_db_entry_new *client,
+ krb5_data *req_pkt,
+ krb5_kdc_req *request,
+ krb5_enc_tkt_part *enc_tkt_reply);
+} krb5plugin_authdata_ftable_v0;
+#endif /* KRB5_AUTHDATA_PLUGIN_H_INCLUDED */
#define DEFAULT_PROFILE_PATH ("~/Library/Preferences/edu.mit.Kerberos" ":" DEFAULT_SECURE_PROFILE_PATH)
#define KRB5_PLUGIN_BUNDLE_DIR "/System/Library/KerberosPlugins/KerberosFrameworkPlugins"
#define KDB5_PLUGIN_BUNDLE_DIR "/System/Library/KerberosPlugins/KerberosDatabasePlugins"
+#define KRB5_AUTHDATA_PLUGIN_BUNDLE_DIR "/System/Library/KerberosPlugins/KerberosAuthDataPlugins"
#else
#define DEFAULT_SECURE_PROFILE_PATH "/etc/krb5.conf:@SYSCONFDIR/krb5.conf"
#define DEFAULT_PROFILE_PATH DEFAULT_SECURE_PROFILE_PATH
$(srcdir)/policy.c \
$(srcdir)/extern.c \
$(srcdir)/replay.c \
+ $(srcdir)/kdc_authdata.c \
$(srcdir)/kerberos_v4.c
OBJS= \
policy.o \
extern.o \
replay.o \
+ kdc_authdata.o \
kerberos_v4.o
RT_OBJS= rtest.o \
/*
* kdc/do_as_req.c
*
+ * Portions Copyright (C) 2007 Apple Inc.
* Copyright 1990,1991,2007 by the Massachusetts Institute of Technology.
* All Rights Reserved.
*
goto errout;
}
+ errcode = handle_authdata(kdc_context, &client, req_pkt, request, &enc_tkt_reply);
+ if (errcode) {
+ krb5_klog_syslog(LOG_INFO, "AS_REQ : handle_authdata (%d)", errcode);
+ }
+
ticket_reply.enc_part2 = &enc_tkt_reply;
/*
--- /dev/null
+/*
+ * kdc/kdc_authdata.c
+ *
+ * Copyright (C) 2007 Apple Inc. All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * AuthorizationData routines for the KDC.
+ */
+
+#include "k5-int.h"
+#include "kdc_util.h"
+#include "extern.h"
+#include <stdio.h>
+#include "adm_proto.h"
+
+#include <syslog.h>
+
+#include <assert.h>
+#include "../include/krb5/authdata_plugin.h"
+
+#if TARGET_OS_MAC
+static const char *objdirs[] = { KRB5_AUTHDATA_PLUGIN_BUNDLE_DIR, LIBDIR "/krb5/plugins/authdata", NULL }; /* should be a list */
+#else
+static const char *objdirs[] = { LIBDIR "/krb5/plugins/authdata", NULL };
+#endif
+
+typedef krb5_error_code (*authdata_proc)
+ (krb5_context, krb5_db_entry *client,
+ krb5_data *req_pkt,
+ krb5_kdc_req *request,
+ krb5_enc_tkt_part * enc_tkt_reply);
+
+typedef krb5_error_code (*init_proc)
+ (krb5_context, void **);
+typedef void (*fini_proc)
+ (krb5_context, void *);
+
+typedef struct _krb5_authdata_systems {
+ const char *name;
+ int type;
+ int flags;
+ void *plugin_context;
+ init_proc init;
+ fini_proc fini;
+ authdata_proc handle_authdata;
+} krb5_authdata_systems;
+
+#undef GREET_PREAUTH
+
+#ifdef GREET_PREAUTH
+static krb5_error_code
+greet_init(krb5_context ctx, void **blob)
+{
+ *blob = "hello";
+ return 0;
+}
+
+static void
+greet_fini(krb5_context ctx, void *blob)
+{
+}
+
+static krb5_error_code
+greet_authdata(krb5_context ctx, krb5_db_entry *client,
+ krb5_data *req_pkt,
+ krb5_kdc_req *request,
+ krb5_enc_tkt_part * enc_tkt_reply)
+{
+#define GREET_SIZE (20)
+
+ char *p;
+ krb5_authdata *a;
+ size_t count;
+ krb5_authdata **new_ad;
+
+ krb5_klog_syslog (LOG_DEBUG, "in greet_authdata");
+
+ p = calloc(1, GREET_SIZE);
+ a = calloc(1, sizeof(*a));
+
+ if (p == NULL || a == NULL) {
+ free(p);
+ free(a);
+ return ENOMEM;
+ }
+ strcpy(p, "hello");
+ a->magic = KV5M_AUTHDATA;
+ a->ad_type = -42;
+ a->length = GREET_SIZE;
+ a->contents = p;
+ if (enc_tkt_reply->authorization_data == 0) {
+ count = 0;
+ } else {
+ for (count = 0; enc_tkt_reply->authorization_data[count] != 0; count++)
+ ;
+ }
+ new_ad = realloc(enc_tkt_reply->authorization_data,
+ (count+2) * sizeof(krb5_authdata *));
+ if (new_ad == NULL) {
+ free(p);
+ free(a);
+ return ENOMEM;
+ }
+ enc_tkt_reply->authorization_data = new_ad;
+ new_ad[count] = a;
+ new_ad[count+1] = NULL;
+ return 0;
+}
+#endif
+
+static krb5_authdata_systems static_authdata_systems[] = {
+#ifdef GREET_PREAUTH
+ { "greeting", 0, 0, 0, greet_init, greet_fini, greet_authdata },
+#endif
+ { "[end]", -1,}
+};
+
+static krb5_authdata_systems *authdata_systems;
+static int n_authdata_systems;
+static struct plugin_dir_handle authdata_plugins;
+
+krb5_error_code
+load_authdata_plugins(krb5_context context)
+{
+ struct errinfo err;
+ void **authdata_plugins_ftables = NULL;
+ struct krb5plugin_authdata_ftable_v0 *ftable = NULL;
+ size_t module_count;
+ int i, k;
+ init_proc server_init_proc = NULL;
+
+ memset(&err, 0, sizeof(err));
+
+ /* Attempt to load all of the authdata plugins we can find. */
+ PLUGIN_DIR_INIT(&authdata_plugins);
+ if (PLUGIN_DIR_OPEN(&authdata_plugins) == 0) {
+ if (krb5int_open_plugin_dirs(objdirs, NULL,
+ &authdata_plugins, &err) != 0) {
+ return KRB5_PLUGIN_NO_HANDLE;
+ }
+ }
+
+ /* Get the method tables provided by the loaded plugins. */
+ authdata_plugins_ftables = NULL;
+ n_authdata_systems = 0;
+ if (krb5int_get_plugin_dir_data(&authdata_plugins,
+ "authdata_server_0",
+ &authdata_plugins_ftables, &err) != 0) {
+ return KRB5_PLUGIN_NO_HANDLE;
+ }
+
+ /* Count the valid modules. */
+ module_count = sizeof(static_authdata_systems)
+ / sizeof(static_authdata_systems[0]);
+ if (authdata_plugins_ftables != NULL) {
+ for (i = 0; authdata_plugins_ftables[i] != NULL; i++) {
+ ftable = authdata_plugins_ftables[i];
+ if ((ftable->authdata_proc != NULL)) {
+ module_count++;
+ }
+ }
+ }
+
+ /* Build the complete list of supported authdata options, and
+ * leave room for a terminator entry. */
+ authdata_systems = calloc(module_count + 1, sizeof(krb5_authdata_systems));
+ if (authdata_systems == NULL) {
+ krb5int_free_plugin_dir_data(authdata_plugins_ftables);
+ return ENOMEM;
+ }
+
+ /* Add the locally-supplied mechanisms to the dynamic list first. */
+ for (i = 0, k = 0;
+ i < sizeof(static_authdata_systems) / sizeof(static_authdata_systems[0]);
+ i++) {
+ if (static_authdata_systems[i].type == -1)
+ break;
+ authdata_systems[k] = static_authdata_systems[i];
+ /* Try to initialize the authdata system. If it fails, we'll remove it
+ * from the list of systems we'll be using. */
+ server_init_proc = static_authdata_systems[i].init;
+ if ((server_init_proc != NULL) &&
+ ((*server_init_proc)(context, &authdata_systems[k].plugin_context) != 0)) {
+ memset(&authdata_systems[k], 0, sizeof(authdata_systems[k]));
+ continue;
+ }
+ k++;
+ }
+
+ /* Now add the dynamically-loaded mechanisms to the list. */
+ if (authdata_plugins_ftables != NULL) {
+ for (i = 0; authdata_plugins_ftables[i] != NULL; i++) {
+ krb5_error_code initerr;
+ void *pctx = NULL;
+
+ ftable = authdata_plugins_ftables[i];
+ if ((ftable->authdata_proc == NULL)) {
+ continue;
+ }
+ server_init_proc = ftable->init_proc;
+ if ((server_init_proc != NULL) &&
+ ((initerr = (*server_init_proc)(context, &pctx)) != 0)) {
+ const char *emsg;
+ emsg = krb5_get_error_message(context, initerr);
+ if (emsg) {
+ krb5_klog_syslog(LOG_ERR,
+ "authdata %s failed to initialize: %s",
+ ftable->name, emsg);
+ krb5_free_error_message(context, emsg);
+ }
+ memset(&authdata_systems[k], 0, sizeof(authdata_systems[k]));
+
+ continue;
+ }
+
+ authdata_systems[k].name = ftable->name;
+ authdata_systems[k].init = server_init_proc;
+ authdata_systems[k].fini = ftable->fini_proc;
+ authdata_systems[k].handle_authdata = ftable->authdata_proc;
+ authdata_systems[k].plugin_context = pctx;
+ k++;
+ }
+ }
+ n_authdata_systems = k;
+ /* Add the end-of-list marker. */
+ authdata_systems[k].name = "[end]";
+ authdata_systems[k].type = -1;
+ return 0;
+}
+
+krb5_error_code
+unload_authdata_plugins(krb5_context context)
+{
+ int i;
+ if (authdata_systems != NULL) {
+ for (i = 0; i < n_authdata_systems; i++) {
+ if (authdata_systems[i].fini != NULL) {
+ (*authdata_systems[i].fini)(context,
+ authdata_systems[i].plugin_context);
+ }
+ memset(&authdata_systems[i], 0, sizeof(authdata_systems[i]));
+ }
+ free(authdata_systems);
+ authdata_systems = NULL;
+ n_authdata_systems = 0;
+ krb5int_close_plugin_dirs(&authdata_plugins);
+ }
+ return 0;
+}
+
+krb5_error_code
+handle_authdata (krb5_context context, krb5_db_entry *client,
+ krb5_data *req_pkt, krb5_kdc_req *request,
+ krb5_enc_tkt_part *enc_tkt_reply)
+{
+ krb5_error_code retval = 0;
+ int i;
+ const char *emsg;
+
+ krb5_klog_syslog (LOG_DEBUG, "handling authdata");
+
+ for (i = 0; i < n_authdata_systems; i++) {
+ const krb5_authdata_systems *asys = &authdata_systems[i];
+ if (asys->handle_authdata && asys->type != -1) {
+ retval = asys->handle_authdata(context, client, req_pkt,
+ request, enc_tkt_reply);
+ if (retval) {
+ emsg = krb5_get_error_message (context, retval);
+ krb5_klog_syslog (LOG_INFO,
+ "authdata (%s) handling failure: %s",
+ asys->name, emsg);
+ krb5_free_error_message (context, emsg);
+ } else {
+ krb5_klog_syslog (LOG_DEBUG, ".. .. ok");
+ }
+ }
+ }
+
+ return 0;
+}
/*
* kdc/kdc_util.h
*
+ * Portions Copyright (C) 2007 Apple Inc.
* Copyright 1990, 2007 by the Massachusetts Institute of Technology.
*
* Export of this software from the United States of America may
krb5_error_code free_padata_context
(krb5_context context, void **padata_context);
+/* kdc_authdata.c */
+krb5_error_code load_authdata_plugins(krb5_context context);
+krb5_error_code unload_authdata_plugins(krb5_context context);
+
+krb5_error_code handle_authdata (krb5_context context, krb5_db_entry *client,
+ krb5_data *req_pkt, krb5_kdc_req *request,
+ krb5_enc_tkt_part *enc_tkt_reply);
+
/* replay.c */
krb5_boolean kdc_check_lookaside (krb5_data *, krb5_data **);
void kdc_insert_lookaside (krb5_data *, krb5_data *);
/*
* kdc/main.c
*
+ * Portions Copyright (C) 2007 Apple Inc.
* Copyright 1990,2001,2008 by the Massachusetts Institute of Technology.
*
* Export of this software from the United States of America may
setup_signal_handlers();
load_preauth_plugins(kcontext);
+ load_authdata_plugins(kcontext);
retval = setup_sam();
if (retval) {
}
krb5_klog_syslog(LOG_INFO, "shutting down");
unload_preauth_plugins(kcontext);
+ unload_authdata_plugins(kcontext);
krb5_klog_close(kdc_context);
finish_realms(argv[0]);
if (kdc_realmlist)
return retval;
}
+#if 0
+#include <syslog.h>
+static void
+debug_log_authz_data(const char *which, krb5_authdata **a)
+{
+ if (a) {
+ syslog(LOG_ERR|LOG_DAEMON, "%s authz data:", which);
+ while (*a) {
+ syslog(LOG_ERR|LOG_DAEMON, " ad_type:%d length:%d '%.*s'",
+ (*a)->ad_type, (*a)->length, (*a)->length,
+ (char *) (*a)->contents);
+ a++;
+ }
+ syslog(LOG_ERR|LOG_DAEMON, " [end]");
+ } else
+ syslog(LOG_ERR|LOG_DAEMON, "no %s authz data", which);
+}
+#else
+static void
+debug_log_authz_data(const char *which, krb5_authdata **a)
+{
+}
+#endif
+
static krb5_error_code
krb5_rd_req_decoded_opt(krb5_context context, krb5_auth_context *auth_context,
const krb5_ap_req *req, krb5_const_principal server,
if ((*auth_context)->keyblock) { /* User to User authentication */
if ((retval = krb5_decrypt_tkt_part(context, (*auth_context)->keyblock,
req->ticket)))
-goto cleanup;
+ goto cleanup;
krb5_free_keyblock(context, (*auth_context)->keyblock);
(*auth_context)->keyblock = NULL;
} else {
&((*auth_context)->keyblock))))
goto cleanup;
+ debug_log_authz_data("ticket", req->ticket->enc_part2->authorization_data);
+
/*
* If not AP_OPTS_MUTUAL_REQUIRED then and sequence numbers are used
* then the default sequence number is the one's complement of the
/* now decode the decrypted stuff */
if (!(retval = decode_krb5_authenticator(&scratch, &local_auth))) {
*authpp = local_auth;
+ debug_log_authz_data("authenticator", local_auth->authorization_data);
}
clean_scratch();
return retval;
--- /dev/null
+thisconfigdir=../../..
+myfulldir=plugins/authdata/greet
+mydir=plugins/authdata/greet
+BUILDTOP=$(REL)..$(S)..$(S)..
+KRB5_RUN_ENV = @KRB5_RUN_ENV@
+KRB5_CONFIG_SETUP = KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf ; export KRB5_CONFIG ;
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+MODULE_INSTALL_DIR = $(KRB5_AD_MODULE_DIR)
+DEFS=@DEFS@
+
+LOCALINCLUDES = -I../../../include/krb5
+
+LIBBASE=greet
+LIBMAJOR=0
+LIBMINOR=0
+SO_EXT=.so
+#RELDIR=../plugins/preauth/wpse
+# Depends on nothing
+SHLIB_EXPDEPS =
+SHLIB_EXPLIBS=
+
+SHLIB_DIRS=-L$(TOPLIBD)
+SHLIB_RDIRS=$(KRB5_LIBDIR)
+STOBJLISTS=OBJS.ST
+STLIBOBJS= greet_auth.o
+
+SRCS= greet_auth.c
+
+all-unix:: $(LIBBASE)$(SO_EXT)
+install-unix:: install-libs
+clean-unix:: clean-libs clean-libobjs
+
+clean::
+ $(RM) lib$(LIBBASE)$(SO_EXT)
+
+@libnover_frag@
+@libobj_frag@
+
+# +++ Dependency line eater +++
+#
+# Makefile dependencies follow. This must be the last section in
+# the Makefile.in file
+#
+greet_auth.so greet_auth.po $(OUTPRE)greet_auth.$(OBJEXT): \
+ $(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(SRCTOP)/include/krb5/authdata_plugin.h \
+ greet_auth.c
--- /dev/null
+authdata_server_0
--- /dev/null
+/*
+ * plugins/authdata/greet/
+ *
+ * Copyright 2008 by the Massachusetts Institute of Technology.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * Sample authorization data plugin
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <krb5/authdata_plugin.h>
+
+typedef struct krb5_db_entry krb5_db_entry;
+
+static krb5_error_code
+greet_init(krb5_context ctx, void **blob)
+{
+ *blob = "hello";
+ return 0;
+}
+
+static void
+greet_fini(krb5_context ctx, void *blob)
+{
+}
+
+static krb5_error_code
+greet_authdata(krb5_context ctx, krb5_db_entry *client,
+ krb5_data *req_pkt,
+ krb5_kdc_req *request,
+ krb5_enc_tkt_part * enc_tkt_reply)
+{
+#define GREET_SIZE (20)
+
+ char *p;
+ krb5_authdata *a;
+ size_t count;
+ krb5_authdata **new_ad;
+
+ p = calloc(1, GREET_SIZE);
+ a = calloc(1, sizeof(*a));
+
+ if (p == NULL || a == NULL) {
+ free(p);
+ free(a);
+ return ENOMEM;
+ }
+ strcpy(p, "hello there");
+ a->magic = KV5M_AUTHDATA;
+ a->ad_type = -42;
+ a->length = GREET_SIZE;
+ a->contents = p;
+ if (enc_tkt_reply->authorization_data == 0) {
+ count = 0;
+ } else {
+ for (count = 0; enc_tkt_reply->authorization_data[count] != 0; count++)
+ ;
+ }
+ new_ad = realloc(enc_tkt_reply->authorization_data,
+ (count+2) * sizeof(krb5_authdata *));
+ if (new_ad == NULL) {
+ free(p);
+ free(a);
+ return ENOMEM;
+ }
+ enc_tkt_reply->authorization_data = new_ad;
+ new_ad[count] = a;
+ new_ad[count+1] = NULL;
+ return 0;
+}
+
+krb5plugin_authdata_ftable_v0 authdata_server_0 = {
+ "greet",
+ greet_init,
+ greet_fini,
+ greet_authdata,
+};