From b5a541c640dfedda7480332f4838e30f0a9e1770 Mon Sep 17 00:00:00 2001 From: Ken Raeburn Date: Sun, 26 Mar 2006 20:55:59 +0000 Subject: [PATCH] Initial enhanced error message support, similar to what I sent to krbdev except for some function renaming (krb5_free_error was already in use, so added _message to everything), and the context is allowed to be NULL (in which case we fall back to error_message() and storing no strings) to simplify some code. Low-level routines in the support library, using a private data structure; higher-level routines in libkrb5, using a krb5_context. Added error info strings to the KRB_ERR_GENERIC case in gc_via_tkt.c and the python sample service location plugin. Added code to kinit and kvno to look up and display the strings. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@17776 dc483132-0cff-0310-8789-dd5450dbe970 --- src/clients/kinit/ChangeLog | 8 ++ src/clients/kinit/kinit.c | 16 +++ src/clients/kvno/ChangeLog | 8 ++ src/clients/kvno/kvno.c | 34 ++++-- src/include/ChangeLog | 9 ++ src/include/k5-err.h | 23 ++++ src/include/k5-int.h | 6 ++ src/include/krb5.hin | 15 +++ src/lib/krb5/ChangeLog | 7 ++ src/lib/krb5/krb/ChangeLog | 8 ++ src/lib/krb5/krb/Makefile.in | 5 +- src/lib/krb5/krb/gc_via_tkt.c | 27 +++++ src/lib/krb5/krb/kerrs.c | 48 +++++++++ src/lib/krb5/krb5_libinit.c | 4 + src/lib/krb5/libkrb5.exports | 5 + src/plugins/locate/python/ChangeLog | 8 ++ src/plugins/locate/python/Makefile.in | 11 +- src/plugins/locate/python/py-locate.c | 58 +++++++--- src/util/support/ChangeLog | 8 ++ src/util/support/Makefile.in | 3 + src/util/support/errors.c | 134 ++++++++++++++++++++++++ src/util/support/libkrb5support.exports | 6 ++ src/util/support/threads.c | 4 + 23 files changed, 423 insertions(+), 32 deletions(-) create mode 100644 src/include/k5-err.h create mode 100644 src/lib/krb5/krb/kerrs.c create mode 100644 src/util/support/errors.c diff --git a/src/clients/kinit/ChangeLog b/src/clients/kinit/ChangeLog index 63d53ffa9..6b97d7a2b 100644 --- a/src/clients/kinit/ChangeLog +++ b/src/clients/kinit/ChangeLog @@ -1,3 +1,11 @@ +2006-03-26 Ken Raeburn + + * kinit.c (extended_com_err_fn): New function. + (errctx): New variable. + (k5_begin): Set errctx. + (k5_end): Clear it. + (main): Call set_com_err_hook. + 2004-07-01 Ken Raeburn * kinit.c (k5_kinit): Don't free addresses after calling diff --git a/src/clients/kinit/kinit.c b/src/clients/kinit/kinit.c index 6ffebadd4..8160822da 100644 --- a/src/clients/kinit/kinit.c +++ b/src/clients/kinit/kinit.c @@ -268,6 +268,18 @@ fprintf(stderr, USAGE_OPT_FMT, indent, col1) exit(2); } +static krb5_context errctx; +static void extended_com_err_fn (const char *myprog, errcode_t code, + const char *fmt, va_list args) +{ + const char *emsg; + emsg = krb5_get_error_message (errctx, code); + fprintf (stderr, "%s: %s ", myprog, emsg); + krb5_free_error_message (errctx, emsg); + vfprintf (stderr, fmt, args); + fprintf (stderr, "\n"); +} + static char * parse_options(argc, argv, opts, progname) int argc; @@ -494,6 +506,7 @@ struct k4_data* k4; com_err(progname, code, "while initializing Kerberos 5 library"); return 0; } + errctx = k5->ctx; if (opts->k5_cache_name) { code = krb5_cc_resolve(k5->ctx, opts->k5_cache_name, &k5->cc); @@ -591,6 +604,7 @@ k5_end(k5) krb5_cc_close(k5->ctx, k5->cc); if (k5->ctx) krb5_free_context(k5->ctx); + errctx = NULL; memset(k5, 0, sizeof(*k5)); } @@ -1098,6 +1112,8 @@ main(argc, argv) memset(&k5, 0, sizeof(k5)); memset(&k4, 0, sizeof(k4)); + set_com_err_hook (extended_com_err_fn); + parse_options(argc, argv, &opts, progname); got_k5 = k5_begin(&opts, &k5, &k4); diff --git a/src/clients/kvno/ChangeLog b/src/clients/kvno/ChangeLog index 0a81427ff..0982dd036 100644 --- a/src/clients/kvno/ChangeLog +++ b/src/clients/kvno/ChangeLog @@ -1,3 +1,11 @@ +2006-03-26 Ken Raeburn + + * kvno.c: Include com_err.h. + (extended_com_err_fn): New function. + (context): New variable. + (main): Call set_com_err_hook. + (do_v5_kvno): Call com_err instead of fprintf+error_message. + 2004-08-31 Tom Yu * kvno.M: Update usage. diff --git a/src/clients/kvno/kvno.c b/src/clients/kvno/kvno.c index c860eb7d4..4accdb4a9 100644 --- a/src/clients/kvno/kvno.c +++ b/src/clients/kvno/kvno.c @@ -55,12 +55,18 @@ static void do_v4_kvno (int argc, char *argv[]); static void do_v5_kvno (int argc, char *argv[], char *ccachestr, char *etypestr); +#include +static void extended_com_err_fn (const char *, errcode_t, const char *, + va_list); + int main(int argc, char *argv[]) { int option; char *etypestr = 0, *ccachestr = 0; int v4 = 0; + set_com_err_hook (extended_com_err_fn); + prog = strrchr(argv[0], '/'); prog = prog ? (prog + 1) : argv[0]; @@ -149,10 +155,21 @@ static void do_v4_kvno (int count, char *names[]) } #include +static krb5_context context; +static void extended_com_err_fn (const char *myprog, errcode_t code, + const char *fmt, va_list args) +{ + const char *emsg; + emsg = krb5_get_error_message (context, code); + fprintf (stderr, "%s: %s ", myprog, emsg); + krb5_free_error_message (context, emsg); + vfprintf (stderr, fmt, args); + fprintf (stderr, "\n"); +} + static void do_v5_kvno (int count, char *names[], char * ccachestr, char *etypestr) { - krb5_context context; krb5_error_code ret; int i, errors; krb5_enctype etype; @@ -203,16 +220,16 @@ static void do_v5_kvno (int count, char *names[], ret = krb5_parse_name(context, names[i], &in_creds.server); if (ret) { if (!quiet) - fprintf(stderr, "%s: %s while parsing principal name\n", - names[i], error_message(ret)); + com_err(prog, ret, "while parsing principal name %s", names[i]); errors++; continue; } ret = krb5_unparse_name(context, in_creds.server, &princ); if (ret) { - fprintf(stderr, "%s: %s while printing principal name\n", - names[i], error_message(ret)); + com_err(prog, ret, + "while formatting parsed principal name for '%s'", + names[i]); errors++; continue; } @@ -224,8 +241,7 @@ static void do_v5_kvno (int count, char *names[], krb5_free_principal(context, in_creds.server); if (ret) { - fprintf(stderr, "%s: %s while getting credentials\n", - princ, error_message(ret)); + com_err(prog, ret, "while getting credentials for %s", princ); krb5_free_unparsed_name(context, princ); @@ -236,9 +252,7 @@ static void do_v5_kvno (int count, char *names[], /* we need a native ticket */ ret = krb5_decode_ticket(&out_creds->ticket, &ticket); if (ret) { - fprintf(stderr, "%s: %s while decoding ticket\n", - princ, error_message(ret)); - + com_err(prog, ret, "while decoding ticket for %s", princ); krb5_free_creds(context, out_creds); krb5_free_unparsed_name(context, princ); diff --git a/src/include/ChangeLog b/src/include/ChangeLog index cf62126c9..b5c4654a4 100644 --- a/src/include/ChangeLog +++ b/src/include/ChangeLog @@ -1,3 +1,12 @@ +2006-03-26 Ken Raeburn + + * krb5.hin (krb5_set_error_message, krb5_vset_error_message, + krb5_get_error_message, krb5_free_error_message, + krb5_clear_error_message): Declare. + * k5-err.h: New file. + * k5-int.h: Include it. + (struct _krb5_context): Add new field ERR. + 2006-03-11 Ken Raeburn * adm.h, adm_defs.h, adm_proto.h, copyright.h, kdb.h, kdb_dbc.h, diff --git a/src/include/k5-err.h b/src/include/k5-err.h new file mode 100644 index 000000000..0ac20802b --- /dev/null +++ b/src/include/k5-err.h @@ -0,0 +1,23 @@ +#define _(X) (X) +#define KRB5_CALLCONV +struct errinfo { + long code; + const char *msg; + char scratch_buf[1024]; +}; + +void +krb5int_set_error (struct errinfo *ep, + long code, + const char *fmt, ...); +void +krb5int_vset_error (struct errinfo *ep, long code, + const char *fmt, va_list args); +char * +krb5int_get_error (struct errinfo *ep, long code); +void +krb5int_free_error (struct errinfo *ep, char *msg); +void +krb5int_clear_error (struct errinfo *ep); +void +krb5int_set_error_info_callout_fn (const char *(KRB5_CALLCONV *f)(long)); diff --git a/src/include/k5-int.h b/src/include/k5-int.h index ff8b34205..4b455f9fb 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -169,6 +169,9 @@ typedef INT64_TYPE krb5_int64; /* Get mutex support; currently used only for the replay cache. */ #include "k5-thread.h" +/* Get error info support. */ +#include "k5-err.h" + /* krb5/krb5.h includes many other .h files in the krb5 subdirectory. The ones that it doesn't include, we include below. */ @@ -1067,6 +1070,9 @@ struct _krb5_context { struct plugin_dir_handle libkrb5_plugins; struct krb5plugin_service_locate_ftable *vtbl; void (**locate_fptrs)(void); + + /* error detail info */ + struct errinfo err; }; /* could be used in a table to find an etype and initialize a block */ diff --git a/src/include/krb5.hin b/src/include/krb5.hin index eaaedec8f..d786e6770 100644 --- a/src/include/krb5.hin +++ b/src/include/krb5.hin @@ -2536,6 +2536,21 @@ typedef krb5_int32 krb5_prompt_type; krb5_prompt_type* KRB5_CALLCONV krb5_get_prompt_types (krb5_context context); +/* Error reporting */ +void +krb5_set_error_message (krb5_context, krb5_error_code, const char *, ...); +#ifdef va_start +void +krb5_vset_error_message (krb5_context, krb5_error_code, const char *, va_list); +#endif +char * +krb5_get_error_message (krb5_context, krb5_error_code); +void +krb5_free_error_message (krb5_context, char *); +void +krb5_clear_error_message (krb5_context); + + #if TARGET_OS_MAC # pragma options align=reset #endif diff --git a/src/lib/krb5/ChangeLog b/src/lib/krb5/ChangeLog index f7849aea5..6cfd3e644 100644 --- a/src/lib/krb5/ChangeLog +++ b/src/lib/krb5/ChangeLog @@ -1,3 +1,10 @@ +2006-03-26 Ken Raeburn + + * krb5_libinit.c (krb5int_lib_init): Register callback function + for lower-level error-info support routines. + (krb5int_lib_fini): Clear the callback function. + * libkrb5.exports: Export new error-message functions. + 2005-11-14 Jeffrey Altman * krb5_libinit.c: include k5-int.h instead of krb5.h diff --git a/src/lib/krb5/krb/ChangeLog b/src/lib/krb5/krb/ChangeLog index ba3211c4c..4b5062d95 100644 --- a/src/lib/krb5/krb/ChangeLog +++ b/src/lib/krb5/krb/ChangeLog @@ -1,3 +1,11 @@ +2006-03-26 Ken Raeburn + + * kerrs.c: New file. + * Makefile.in (SRCS, OBJS, STLIBOBJS): Add it. + + * gc_via_tkt.c (krb5_get_cred_via_tkt): If the KDC returns + KRB_ERR_GENERIC, store the e-text field as the error message. + 2006-03-13 Ken Raeburn * Makefile.in (check-unix): Use RUN_SETUP for t_deltat. diff --git a/src/lib/krb5/krb/Makefile.in b/src/lib/krb5/krb/Makefile.in index 05249cabb..2a3d09de6 100644 --- a/src/lib/krb5/krb/Makefile.in +++ b/src/lib/krb5/krb/Makefile.in @@ -55,6 +55,7 @@ STLIBOBJS= \ init_ctx.o \ init_keyblock.o \ kdc_rep_dc.o \ + kerrs.o \ kfree.o \ mk_cred.o \ mk_error.o \ @@ -140,7 +141,8 @@ OBJS= $(OUTPRE)addr_comp.$(OBJEXT) \ $(OUTPRE)init_ctx.$(OBJEXT) \ $(OUTPRE)init_keyblock.$(OBJEXT) \ $(OUTPRE)kdc_rep_dc.$(OBJEXT) \ - $(OUTPRE)kfree.$(OBJEXT) \ + $(OUTPRE)kerrs.$(OBJEXT) \ + $(OUTPRE)kfree.$(OBJEXT) \ $(OUTPRE)mk_cred.$(OBJEXT) \ $(OUTPRE)mk_error.$(OBJEXT) \ $(OUTPRE)mk_priv.$(OBJEXT) \ @@ -226,6 +228,7 @@ SRCS= $(srcdir)/addr_comp.c \ $(srcdir)/init_ctx.c \ $(srcdir)/init_keyblock.c \ $(srcdir)/kdc_rep_dc.c \ + $(srcdir)/kerrs.c \ $(srcdir)/kfree.c \ $(srcdir)/mk_cred.c \ $(srcdir)/mk_error.c \ diff --git a/src/lib/krb5/krb/gc_via_tkt.c b/src/lib/krb5/krb/gc_via_tkt.c index 1008d1f92..a1ed6e90d 100644 --- a/src/lib/krb5/krb/gc_via_tkt.c +++ b/src/lib/krb5/krb/gc_via_tkt.c @@ -171,6 +171,33 @@ krb5_get_cred_via_tkt (krb5_context context, krb5_creds *tkt, goto error_4; retval = (krb5_error_code) err_reply->error + ERROR_TABLE_BASE_krb5; + if (err_reply->text.length > 0) { + const char *m; + switch (err_reply->error) { + case KRB_ERR_GENERIC: + krb5_set_error_message(context, retval, + "KDC returned error string: %s", + err_reply->text.data); + break; + default: +#if 0 /* We should stop the KDC from sending back this text, because + if the local language doesn't match the KDC's language, we'd + just wind up printing out the error message in two languages. + Well, when we get some localization. Which is already + happening in KfM. */ + m = error_message(retval); + /* Special case: MIT KDC may return this same string + in the e-text field. */ + if (strlen (m) == err_reply->text.length-1 + && !strcmp(m, err_reply->text.data)) + break; + krb5_set_error_message(context, retval, + "%s (KDC supplied additional data: %s)", + m, err_reply->text.data); +#endif + break; + } + } krb5_free_error(context, err_reply); goto error_4; diff --git a/src/lib/krb5/krb/kerrs.c b/src/lib/krb5/krb/kerrs.c new file mode 100644 index 000000000..8439e2327 --- /dev/null +++ b/src/lib/krb5/krb/kerrs.c @@ -0,0 +1,48 @@ +/* foo */ +#include +#include "k5-int.h" + +void +krb5_set_error_message (krb5_context ctx, krb5_error_code code, + const char *fmt, ...) +{ + va_list args; + if (ctx == NULL) + return; + va_start (args, fmt); + krb5int_vset_error (&ctx->err, code, fmt, args); + va_end (args); +} + +void +krb5_vset_error_message (krb5_context ctx, krb5_error_code code, + const char *fmt, va_list args) +{ + if (ctx == NULL) + return; + krb5int_vset_error (&ctx->err, code, fmt, args); +} + +char * +krb5_get_error_message (krb5_context ctx, krb5_error_code code) +{ + if (ctx == NULL) + return error_message(code); + return krb5int_get_error (&ctx->err, code); +} + +void +krb5_free_error_message (krb5_context ctx, char *msg) +{ + if (ctx == NULL) + return; + krb5int_free_error (&ctx->err, msg); +} + +void +krb5_clear_error_message (krb5_context ctx) +{ + if (ctx == NULL) + return; + krb5int_clear_error (&ctx->err); +} diff --git a/src/lib/krb5/krb5_libinit.c b/src/lib/krb5/krb5_libinit.c index 6771776ce..fce97ffb2 100644 --- a/src/lib/krb5/krb5_libinit.c +++ b/src/lib/krb5/krb5_libinit.c @@ -31,6 +31,8 @@ int krb5int_lib_init(void) { int err; + krb5int_set_error_info_callout_fn (error_message); + #ifdef SHOW_INITFINI_FUNCS printf("krb5int_lib_init\n"); #endif @@ -55,6 +57,7 @@ int krb5int_lib_init(void) err = k5_mutex_finish_init(&krb5int_us_time_mutex); if (err) return err; + return 0; } @@ -98,6 +101,7 @@ void krb5int_lib_fini(void) remove_error_table(&et_asn1_error_table); remove_error_table(&et_k524_error_table); #endif + krb5int_set_error_info_callout_fn (0); } /* Still exists because it went into the export list on Windows. But diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports index f16b45cf8..8831bf781 100644 --- a/src/lib/krb5/libkrb5.exports +++ b/src/lib/krb5/libkrb5.exports @@ -726,3 +726,8 @@ profile_update_file_data profile_update_relation profile_verify_node profile_write_tree_file +krb5_set_error_message +krb5_vset_error_message +krb5_get_error_message +krb5_free_error_message +krb5_clear_error_message diff --git a/src/plugins/locate/python/ChangeLog b/src/plugins/locate/python/ChangeLog index 897919e11..db471def6 100644 --- a/src/plugins/locate/python/ChangeLog +++ b/src/plugins/locate/python/ChangeLog @@ -1,3 +1,11 @@ +2006-03-26 Ken Raeburn + + * Makefile.in (SHLIB_EXPLIBS, SHLIB_EXPDEPS): Add krb5 lib. + * py-locate.c (sctx): New variable. + (my_init, lookup): Call krb5_set_error_message instead of fprintf + in most cases. Use sctx to pass context (not thread safe!), and + store it as "blob" value. + 2006-03-07 Ken Raeburn * py-locate.c: Include k5-locate.h instead of k5-plugin.h. diff --git a/src/plugins/locate/python/Makefile.in b/src/plugins/locate/python/Makefile.in index 46a83fede..1d0b95964 100644 --- a/src/plugins/locate/python/Makefile.in +++ b/src/plugins/locate/python/Makefile.in @@ -10,8 +10,8 @@ SO_EXT=.so RELDIR=../plugins/locate/python MODULE_INSTALL_DIR = $(KRB5_LIBKRB5_MODULE_DIR) -SHLIB_EXPDEPS= -SHLIB_EXPLIBS= -lpython2.3 +SHLIB_EXPDEPS= $(KRB5_DEPLIB) +SHLIB_EXPLIBS= -lpython2.3 $(KRB5_LIB) SHLIB_DIRS=-L$(TOPLIBD) SHLIB_RDIRS=$(KRB5_LIBDIR) @@ -34,9 +34,10 @@ clean-unix:: clean-libs clean-libobjs # the Makefile.in file # py-locate.so py-locate.po $(OUTPRE)py-locate.$(OBJEXT): \ - py-locate.c $(BUILDTOP)/include/krb5/autoconf.h $(SRCTOP)/include/k5-int.h \ - $(BUILDTOP)/include/krb5/osconf.h $(SRCTOP)/include/k5-platform.h \ + py-locate.c $(BUILDTOP)/include/autoconf.h $(SRCTOP)/include/k5-int.h \ + $(BUILDTOP)/include/osconf.h $(SRCTOP)/include/k5-platform.h \ $(SRCTOP)/include/k5-thread.h $(BUILDTOP)/include/krb5.h \ $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h $(SRCTOP)/include/port-sockets.h \ - $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/krb5/kdb.h \ + $(SRCTOP)/include/socket-utils.h $(SRCTOP)/include/k5-err.h \ + $(SRCTOP)/include/k5-locate.h $(SRCTOP)/include/kdb.h \ $(SRCTOP)/include/k5-plugin.h diff --git a/src/plugins/locate/python/py-locate.c b/src/plugins/locate/python/py-locate.c index 548210a6b..f5dc62932 100644 --- a/src/plugins/locate/python/py-locate.c +++ b/src/plugins/locate/python/py-locate.c @@ -79,6 +79,8 @@ MAKE_FINI_FUNCTION(my_fini); #define F (strchr(__FILE__, '/') ? 1 + strrchr(__FILE__, '/') : __FILE__) +static krb5_context sctx; /* XXX ugly hack! */ + int my_init (void) { @@ -88,8 +90,13 @@ my_init (void) Py_Initialize (); // fprintf(stderr, "trying to load %s\n", SCRIPT_PATH); f = fopen(SCRIPT_PATH, "r"); - if (f == NULL) + if (f == NULL) { + if (sctx) + krb5_set_error_message(sctx, -1, + "couldn't open Python script %s (%s)", + SCRIPT_PATH, strerror(errno)); return -1; + } PyRun_SimpleFile (f, SCRIPT_PATH); fclose(f); mainmodule = PyModule_GetDict(PyImport_AddModule("__main__")); @@ -128,7 +135,7 @@ ctxinit (krb5_context ctx, void **blobptr) interpreter, this would be a good place for it; the blob could be allocated to hold the reference to the interpreter instance. */ - *blobptr = 0; + *blobptr = ctx; return 0; } @@ -164,10 +171,12 @@ lookup (void *blob, enum locate_service_type svc, const char *realm, // fprintf(stderr, "%s:%d: lookup(%d,%s,%d,%d)\n", F, __LINE__, // svc, realm, socktype, family); + sctx = blob; /* XXX: Not thread safe! */ i = CALL_INIT_FUNCTION (my_init); if (i) { - fprintf(stderr, "%s:%d: module initialization failed %d\n", - F, __LINE__, i); +#if 0 + fprintf(stderr, "%s:%d: module initialization failed\n", F, __LINE__); +#endif return i; } if (locatefn == 0) @@ -187,7 +196,13 @@ lookup (void *blob, enum locate_service_type svc, const char *realm, py_result = PyObject_CallObject (locatefn, arglist); Py_DECREF (arglist); - if (PyErr_Occurred()) { fprintf(stderr,"%s:%d: python error\n", F, __LINE__); PyErr_Print(); return -1; } + if (PyErr_Occurred()) { + fprintf(stderr,"%s:%d: python error\n", F, __LINE__); + PyErr_Print(); + krb5_set_error_message(blob, -1, + "Python evaluation error, see stderr"); + return -1; + } if (py_result == 0) { fprintf(stderr, "%s:%d: returned null object\n", F, __LINE__); return -1; @@ -197,6 +212,8 @@ lookup (void *blob, enum locate_service_type svc, const char *realm, if (! PyList_Check (py_result)) { Py_DECREF (py_result); fprintf(stderr, "%s:%d: returned non-list, non-False\n", F, __LINE__); + krb5_set_error_message(blob, -1, + "Python script error -- returned non-list, non-False result"); return -1; } listsize = PyList_Size (py_result); @@ -211,20 +228,24 @@ lookup (void *blob, enum locate_service_type svc, const char *realm, answer = PyList_GetItem (py_result, i); if (! PyTuple_Check (answer)) { - fprintf(stderr, "%s:%d: item %d non-tuple\n", F, __LINE__, i); + krb5_set_error_message(blob, -1, + "Python script error -- returned item %d not a tuple", i); /* leak? */ return -1; } if (PyTuple_Size (answer) != 3) { - fprintf(stderr, "%s:%d: item %d tuple size %d should be 3\n", F, __LINE__, i, - PyTuple_Size (answer)); + krb5_set_error_message(blob, -1, + "Python script error -- returned tuple %d size %d should be 3", + i, PyTuple_Size (answer)); /* leak? */ return -1; } field = PyTuple_GetItem (answer, 0); if (! PyString_Check (field)) { /* leak? */ - fprintf(stderr, "%s:%d: item %d first component not a string\n", F, __LINE__, i); + krb5_set_error_message(blob, -1, + "Python script error -- first component of tuple %d is not a string", + i); return -1; } hoststr = PyString_AsString (field); @@ -235,14 +256,17 @@ lookup (void *blob, enum locate_service_type svc, const char *realm, sprintf(portbuf, "%ld", PyInt_AsLong (field)); portstr = portbuf; } else { - fprintf(stderr, "%s:%d: item %d second component neither string nor int\n", - F, __LINE__, i); + krb5_set_error_message(blob, -1, + "Python script error -- second component of tuple %d neither a string nor an integer", + i); /* leak? */ return -1; } field = PyTuple_GetItem (answer, 2); if (! PyInt_Check (field)) { - fprintf(stderr, "%s:%d: item %d third component not int\n", F, __LINE__, i); + krb5_set_error_message(blob, -1, + "Python script error -- third component of tuple %d not an integer", + i); /* leak? */ return -1; } @@ -252,16 +276,18 @@ lookup (void *blob, enum locate_service_type svc, const char *realm, case SOCK_DGRAM: /* okay */ if (socktype != 0 && socktype != thissocktype) { - fprintf(stderr, "%s:%d: item %d socket type %d should be %d\n", - F, __LINE__, i, thissocktype, socktype); + krb5_set_error_message(blob, -1, + "Python script error -- tuple %d has socket type %d, should only have %d", + i, thissocktype, socktype); /* leak? */ return -1; } break; default: /* 0 is not acceptable */ - fprintf(stderr, "%s:%d: item %d socket type %d invalid\n", F, __LINE__, i, - thissocktype); + krb5_set_error_message(blob, -1, + "Python script error -- tuple %d has invalid socket type %d", + i, thissocktype); /* leak? */ return -1; } diff --git a/src/util/support/ChangeLog b/src/util/support/ChangeLog index 295f42f12..d1fae1dbe 100644 --- a/src/util/support/ChangeLog +++ b/src/util/support/ChangeLog @@ -1,3 +1,11 @@ +2006-03-26 Ken Raeburn + + * errors.c: New file. + * Makefile.in (SRCS, LIBOBJS, STLIBOBJS): Add it. + * threads.c (krb5int_thread_support_init): Call krb5int_err_init + to initialize the new file. + * libkrb5support.exports: Add the new symbols. + 2006-03-13 Ken Raeburn * plugins.c (krb5int_get_plugin_dir_data): If dirhandle is null or diff --git a/src/util/support/Makefile.in b/src/util/support/Makefile.in index e6c75f525..2e96a88db 100644 --- a/src/util/support/Makefile.in +++ b/src/util/support/Makefile.in @@ -28,12 +28,14 @@ STLIBOBJS= \ threads.o \ init-addrinfo.o \ plugins.o \ + errors.o \ fake-addrinfo.o LIBOBJS= \ $(OUTPRE)threads.$(OBJEXT) \ $(OUTPRE)init-addrinfo.$(OBJEXT) \ $(OUTPRE)plugins.$(OBJEXT) \ + $(OUTPRE)errors.$(OBJEXT) \ $(OUTPRE)fake-addrinfo.$(OBJEXT) STOBJLISTS=OBJS.ST @@ -45,6 +47,7 @@ LOCALINCLUDES=-I. -I$(srcdir) SRCS=\ $(srcdir)/threads.c \ $(srcdir)/init-addrinfo.c \ + $(srcdir)/errors.c \ $(srcdir)/fake-addrinfo.c SHLIB_EXPDEPS = # Add -lm if dumping thread stats, for sqrt. diff --git a/src/util/support/errors.c b/src/util/support/errors.c new file mode 100644 index 000000000..185cb425a --- /dev/null +++ b/src/util/support/errors.c @@ -0,0 +1,134 @@ +/* Can't include krb5.h here, or k5-int.h which includes it, because + krb5.h needs to be generated with error tables, after util/et, + which builds after this directory. */ +#include +#include +#include +#include +#include "k5-err.h" + +#include "k5-thread.h" +#include "k5-platform.h" + +/* It would be nice to just use error_message() always. Pity that + it's defined in a library that depends on this one, and we're not + allowed to make circular dependencies. */ +/* We really want a rwlock here, since we should hold it while calling + the function and copying out its results. But I haven't + implemented shims for rwlock yet. */ +static k5_mutex_t krb5int_error_info_support_mutex = + K5_MUTEX_PARTIAL_INITIALIZER; +static const char *(KRB5_CALLCONV *fptr)(long); /* = &error_message */ + +int +krb5int_err_init (void) +{ + return k5_mutex_finish_init (&krb5int_error_info_support_mutex); +} +#define initialize() krb5int_call_thread_support_init() +#define lock() k5_mutex_lock(&krb5int_error_info_support_mutex) +#define unlock() k5_mutex_unlock(&krb5int_error_info_support_mutex) + +void +krb5int_set_error (struct errinfo *ep, long code, const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + krb5int_vset_error (ep, code, fmt, args); + va_end (args); +} + +void +krb5int_vset_error (struct errinfo *ep, long code, + const char *fmt, va_list args) +{ + if (ep->msg && ep->msg != ep->scratch_buf) { + free (ep->msg); + ep->msg = NULL; + } + ep->code = code; +#ifdef HAVE_VASPRINTF + { + char *str = NULL; + if (vasprintf(&str, fmt, args) >= 0 && str != NULL) { + ep->msg = str; + return; + } + } +#endif + vsnprintf(ep->scratch_buf, sizeof(ep->scratch_buf), fmt, args); + ep->msg = ep->scratch_buf; +} + +char * +krb5int_get_error (struct errinfo *ep, long code) +{ + char *r, *r2; + if (code != ep->code) + krb5int_clear_error (ep); + if (ep->msg) { + r = ep->msg; + ep->msg = NULL; + return r; + } + if (initialize() != 0) { + strncpy(ep->scratch_buf, _("Kerberos library initialization failure"), + sizeof(ep->scratch_buf)); + ep->scratch_buf[sizeof(ep->scratch_buf)-1] = 0; + ep->msg = NULL; + return ep->scratch_buf; + } + lock(); + if (fptr == NULL) { + unlock(); + r = strerror (code); + if (r) { + if (strlen (r) < sizeof (ep->scratch_buf) + || (r2 = strdup (r)) == NULL) { + strncpy (ep->scratch_buf, r, sizeof(ep->scratch_buf)); + return ep->scratch_buf; + } else + return r2; + } + format_number: + sprintf (ep->scratch_buf, _("error %ld"), code); + return ep->scratch_buf; + } + r = fptr(code); + if (r == NULL) { + unlock(); + goto format_number; + } + r2 = strdup (r); + if (r2 == NULL) { + strncpy(ep->scratch_buf, r, sizeof(ep->scratch_buf)); + unlock(); + return ep->scratch_buf; + } else { + unlock(); + return r2; + } +} + +void +krb5int_free_error (struct errinfo *ep, char *msg) +{ + if (msg != ep->scratch_buf) + free (msg); +} + +void +krb5int_clear_error (struct errinfo *ep) +{ + krb5int_free_error (ep, ep->msg); + ep->msg = NULL; +} + +void +krb5int_set_error_info_callout_fn (const char *(KRB5_CALLCONV *f)(long)) +{ + initialize(); + lock(); + fptr = f; + unlock(); +} diff --git a/src/util/support/libkrb5support.exports b/src/util/support/libkrb5support.exports index 1d7bc717f..00ce5c3e3 100644 --- a/src/util/support/libkrb5support.exports +++ b/src/util/support/libkrb5support.exports @@ -25,3 +25,9 @@ krb5int_mutex_alloc krb5int_mutex_free krb5int_mutex_lock krb5int_mutex_unlock +krb5int_set_error +krb5int_vset_error +krb5int_get_error +krb5int_free_error +krb5int_clear_error +krb5int_set_error_info_callout_fn diff --git a/src/util/support/threads.c b/src/util/support/threads.c index d0697bd93..7dc2e4828 100644 --- a/src/util/support/threads.c +++ b/src/util/support/threads.c @@ -453,6 +453,10 @@ int krb5int_thread_support_init (void) if (err) return err; + err = krb5int_err_init(); + if (err) + return err; + return 0; } -- 2.26.2