17c478bd9Sstevel@tonic-gate /*
27c64d375Smp  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate 
77c478bd9Sstevel@tonic-gate /*
87c478bd9Sstevel@tonic-gate  * Copyright 1997 by Massachusetts Institute of Technology
9*55fea89dSDan Cross  *
107c478bd9Sstevel@tonic-gate  * Copyright 1987, 1988 by MIT Student Information Processing Board
117c478bd9Sstevel@tonic-gate  *
127c478bd9Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software
137c478bd9Sstevel@tonic-gate  * and its documentation for any purpose and without fee is
147c478bd9Sstevel@tonic-gate  * hereby granted, provided that the above copyright notice
157c478bd9Sstevel@tonic-gate  * appear in all copies and that both that copyright notice and
167c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation,
177c478bd9Sstevel@tonic-gate  * and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
187c478bd9Sstevel@tonic-gate  * used in advertising or publicity pertaining to distribution
197c478bd9Sstevel@tonic-gate  * of the software without specific, written prior permission.
207c478bd9Sstevel@tonic-gate  * Furthermore if you modify this software you must label
217c478bd9Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
227c478bd9Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
237c478bd9Sstevel@tonic-gate  * M.I.T. and the M.I.T. S.I.P.B. make no representations about
247c478bd9Sstevel@tonic-gate  * the suitability of this software for any purpose.  It is
257c478bd9Sstevel@tonic-gate  * provided "as is" without express or implied warranty.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <stdio.h>
297c478bd9Sstevel@tonic-gate #include <string.h>
30159d09a2SMark Phalan #include <stdlib.h>
317c478bd9Sstevel@tonic-gate #include <locale.h>
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include "com_err.h"
347c478bd9Sstevel@tonic-gate #include "error_table.h"
357c478bd9Sstevel@tonic-gate 
36159d09a2SMark Phalan #if defined(_WIN32)
377c478bd9Sstevel@tonic-gate #include <io.h>
387c478bd9Sstevel@tonic-gate #endif
39159d09a2SMark Phalan 
40159d09a2SMark Phalan k5_mutex_t com_err_hook_lock = K5_MUTEX_PARTIAL_INITIALIZER;
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate static void default_com_err_proc
43505d05c7Sgtb (const char  *whoami, errcode_t code,
44505d05c7Sgtb 	const char  *fmt, va_list ap);
457c478bd9Sstevel@tonic-gate 
46159d09a2SMark Phalan #if defined(_WIN32)
isGuiApp()47159d09a2SMark Phalan BOOL  isGuiApp() {
48159d09a2SMark Phalan 	DWORD mypid;
49159d09a2SMark Phalan 	HANDLE myprocess;
50159d09a2SMark Phalan 	mypid = GetCurrentProcessId();
51159d09a2SMark Phalan 	myprocess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, mypid);
52159d09a2SMark Phalan 	return GetGuiResources(myprocess, 1) > 0;
53159d09a2SMark Phalan 	}
54159d09a2SMark Phalan #endif
55159d09a2SMark Phalan 
567c64d375Smp /*
577c64d375Smp  * Solaris Kerberos:
587c64d375Smp  * It is sometimes desirable to have more than a single hook called
597c64d375Smp  * when com_err() is invoked. A number of new functions have been
607c64d375Smp  * added which allow hooks to be added and removed:
617c64d375Smp  *    add_com_err_hook()
627c64d375Smp  *    add_default_com_err_hook()
637c64d375Smp  *    remove_com_err_hook()
647c64d375Smp  *    remove_default_com_err_hook()
657c64d375Smp  * The existing functions:
667c64d375Smp  *    set_com_err_hook()
677c64d375Smp  *    reset_com_err_hook()
687c64d375Smp  *    com_err()
697c64d375Smp  * have been modified to work with the new scheme. Applications using
707c64d375Smp  * the original function calls are not affected.
717c64d375Smp  */
727c64d375Smp #define	MAX_HOOKS 3
737c64d375Smp static et_old_error_hook_func com_err_hook[MAX_HOOKS] = { default_com_err_proc,
747c64d375Smp     NULL, NULL };
757c64d375Smp static int hook_count = 1;
767c64d375Smp 
777c478bd9Sstevel@tonic-gate /* Solaris Kerberos specific fix start --------------------------- */
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate #define gettext(X)	X
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate struct msg_map {
827c478bd9Sstevel@tonic-gate 	char *msgid;
837c478bd9Sstevel@tonic-gate 	char *c_msgstr;
847c478bd9Sstevel@tonic-gate };
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate struct msg_map msgmap[] = {
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate #define	MSG_WHILE 0
897c478bd9Sstevel@tonic-gate 	{ gettext("%s\n## com_err msg of format: 'while ...'"),
907c478bd9Sstevel@tonic-gate 		"%s\n" },
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate #define	MSG_ERROR_MSG 1
937c478bd9Sstevel@tonic-gate 	{ gettext("%s\n## com_err message of format: 'error msg ...'"),
947c478bd9Sstevel@tonic-gate 		"%s\n" },
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate #define	MSG_ERROR_MSG_WHILE 2
977c478bd9Sstevel@tonic-gate 	{ gettext("%1$s %2$s\n## com_err message of format: "
987c478bd9Sstevel@tonic-gate 		"'error msg ... while ...'"),
997c478bd9Sstevel@tonic-gate 		"%1$s %2$s\n" },
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate #define	MSG_WHOAMI_WHILE 3
1027c478bd9Sstevel@tonic-gate 	{ gettext("%1$s: %2$s\n## com_err msg of format: 'whoami: while ...'"),
1037c478bd9Sstevel@tonic-gate 		"%1$s: %2$s\n" },
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate #define	MSG_WHOAMI_ERROR_MSG 4
1067c478bd9Sstevel@tonic-gate 	{ gettext("%1$s: %2$s\n## com_err message of format: "
1077c478bd9Sstevel@tonic-gate 		"'whoami: error msg ...'"),
1087c478bd9Sstevel@tonic-gate 		"%1$s: %2$s\n" },
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate #define	MSG_WHOAMI_ERROR_MSG_WHILE 5
1117c478bd9Sstevel@tonic-gate 	{ gettext("%1$s: %2$s %3$s\n## com_err message of format: "
1127c478bd9Sstevel@tonic-gate 		"'whoami: error msg ... while ...'"),
1137c478bd9Sstevel@tonic-gate 		"%1$s: %2$s %3$s\n" },
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate #define	MSG_WHOAMI 6
1167c478bd9Sstevel@tonic-gate 	{ gettext("%s:\n ## com_err message of format: "
1177c478bd9Sstevel@tonic-gate 		"'whoami: with no error msg or while ...'"),
1187c478bd9Sstevel@tonic-gate 		"%s:\n " }
1197c478bd9Sstevel@tonic-gate };
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate #undef gettext
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate /*
1247c478bd9Sstevel@tonic-gate  * The idea is that we provide a unique message id that contains extra junk
1257c478bd9Sstevel@tonic-gate  * that we never want to display in the C locale. If dgettext() returns
1267c478bd9Sstevel@tonic-gate  * a string that is equal to the message id, then we return the c_msgstr,
1277c478bd9Sstevel@tonic-gate  * for display in the locale.
1287c478bd9Sstevel@tonic-gate  */
1297c478bd9Sstevel@tonic-gate static char *
my_gettext(int msg_idx)1307c478bd9Sstevel@tonic-gate my_gettext(int msg_idx)
1317c478bd9Sstevel@tonic-gate {
1327c478bd9Sstevel@tonic-gate 	char *msgid = msgmap[msg_idx].msgid;
1337c478bd9Sstevel@tonic-gate 	char *c_msgstr = msgmap[msg_idx].c_msgstr;
1347c478bd9Sstevel@tonic-gate 	char *msgstr = dgettext(TEXT_DOMAIN, msgid);
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	if (strcmp(msgstr, msgid) == 0)
1377c478bd9Sstevel@tonic-gate 		return (c_msgstr);
1387c478bd9Sstevel@tonic-gate 	else
1397c478bd9Sstevel@tonic-gate 		return (msgstr);
1407c478bd9Sstevel@tonic-gate }
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate /* Solaris Kerberos specific fix end --------------------------- */
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate /* Solaris Kerberos:  this code is significantly altered from
1457c478bd9Sstevel@tonic-gate  * the MIT 1.2.1 version to work with internationalization */
146159d09a2SMark Phalan 
default_com_err_proc(const char * whoami,errcode_t code,const char * fmt,va_list ap)147159d09a2SMark Phalan static void default_com_err_proc (const char *whoami, errcode_t code,
148159d09a2SMark Phalan 				  const char *fmt, va_list ap)
1497c478bd9Sstevel@tonic-gate {
1507c478bd9Sstevel@tonic-gate 	char whilebuf[1024] = "";
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	*whilebuf = '\0';
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	/*
1557c478bd9Sstevel@tonic-gate 	 * Because 'while ...' message could contain a format string
1567c478bd9Sstevel@tonic-gate 	 * we have to intepret it now, in a buffer. We need to put it
1577c478bd9Sstevel@tonic-gate 	 * into a buffer so that the message can be juxtaposed in a locale
1587c478bd9Sstevel@tonic-gate 	 * meaningful manner. In some natural languages, the 'while ...' phrase
1597c478bd9Sstevel@tonic-gate 	 * must be first.
1607c478bd9Sstevel@tonic-gate 	 */
1617c478bd9Sstevel@tonic-gate 	if (fmt) {
1627c478bd9Sstevel@tonic-gate 		vsprintf(whilebuf, fmt, ap);
1637c478bd9Sstevel@tonic-gate 	}
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	/*
1667c478bd9Sstevel@tonic-gate 	 * There are 8 possible combinations here depending on whether
1677c478bd9Sstevel@tonic-gate 	 * a whoami string was provided, error code is non-zero, and if a
1687c478bd9Sstevel@tonic-gate 	 * a 'while ...' messge was provided.
1697c478bd9Sstevel@tonic-gate 	 */
1707c478bd9Sstevel@tonic-gate 	if (!whoami) {
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 		if ((!code) && fmt) {
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 			fprintf(stderr, my_gettext(MSG_WHILE),
1757c478bd9Sstevel@tonic-gate 				whilebuf);
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 		} else if (code && !fmt) {
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 			fprintf(stderr, my_gettext(MSG_ERROR_MSG),
1807c478bd9Sstevel@tonic-gate 				error_message(code));
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 		} else if (code && fmt) {
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 			fprintf(stderr, my_gettext(MSG_ERROR_MSG_WHILE),
1857c478bd9Sstevel@tonic-gate 				error_message(code), whilebuf);
1867c478bd9Sstevel@tonic-gate 		} else
1877c478bd9Sstevel@tonic-gate 			return;
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	} else {
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 		if ((!code) && fmt) {
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 			fprintf(stderr, my_gettext(MSG_WHOAMI_WHILE),
1947c478bd9Sstevel@tonic-gate 				whoami, whilebuf);
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 		} else if (code && !fmt) {
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 			fprintf(stderr, my_gettext(MSG_WHOAMI_ERROR_MSG),
1997c478bd9Sstevel@tonic-gate 				whoami, error_message(code));
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 		} else if (code && fmt) {
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 			fprintf(stderr,
2047c478bd9Sstevel@tonic-gate 				my_gettext(MSG_WHOAMI_ERROR_MSG_WHILE),
2057c478bd9Sstevel@tonic-gate 				whoami, error_message(code), whilebuf);
2067c478bd9Sstevel@tonic-gate 		} else {
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 			fprintf(stderr,
2097c478bd9Sstevel@tonic-gate 				my_gettext(MSG_WHOAMI),
2107c478bd9Sstevel@tonic-gate 				whoami);
2117c478bd9Sstevel@tonic-gate 		}
2127c478bd9Sstevel@tonic-gate 	}
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 	fflush(stderr);
2157c478bd9Sstevel@tonic-gate }
2167c478bd9Sstevel@tonic-gate 
com_err_va(const char * whoami,errcode_t code,const char * fmt,va_list ap)217159d09a2SMark Phalan void KRB5_CALLCONV com_err_va(const char *whoami,
218159d09a2SMark Phalan 			      errcode_t code,
219159d09a2SMark Phalan 			      const char *fmt,
220159d09a2SMark Phalan 			      va_list ap)
2217c478bd9Sstevel@tonic-gate {
222159d09a2SMark Phalan     int err;
223159d09a2SMark Phalan     int i;
224159d09a2SMark Phalan     err = com_err_finish_init();
225159d09a2SMark Phalan     if (err)
226159d09a2SMark Phalan 	goto best_try;
227159d09a2SMark Phalan     err = k5_mutex_lock(&com_err_hook_lock);
228159d09a2SMark Phalan     if (err)
229159d09a2SMark Phalan 	goto best_try;
230159d09a2SMark Phalan     for (i = 0; i < hook_count; i++) {
231159d09a2SMark Phalan 	(com_err_hook[i])(whoami, code, fmt, ap);
232159d09a2SMark Phalan     }
233159d09a2SMark Phalan     k5_mutex_unlock(&com_err_hook_lock);
234159d09a2SMark Phalan     return;
235159d09a2SMark Phalan 
236159d09a2SMark Phalan best_try:
237159d09a2SMark Phalan     /* Yikes.  Our library initialization failed or we couldn't lock
238159d09a2SMark Phalan        the lock we want.  We could be in trouble.  Gosh, we should
239159d09a2SMark Phalan        probably print an error message.  Oh, wait.  That's what we're
240159d09a2SMark Phalan        trying to do.  In fact, if we're losing on initialization here,
241159d09a2SMark Phalan        there's a good chance it has to do with failed initialization
242159d09a2SMark Phalan        of the caller.  */
243159d09a2SMark Phalan 
244159d09a2SMark Phalan     for (i = 0; i < hook_count; i++) {
245159d09a2SMark Phalan 	(com_err_hook[i])(whoami, code, fmt, ap);
246159d09a2SMark Phalan     }
247159d09a2SMark Phalan     assert(err == 0);
248159d09a2SMark Phalan     abort();
2497c478bd9Sstevel@tonic-gate }
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 
com_err(const char * whoami,errcode_t code,const char * fmt,...)252159d09a2SMark Phalan void KRB5_CALLCONV_C com_err(const char *whoami,
253159d09a2SMark Phalan 			     errcode_t code,
254159d09a2SMark Phalan 			     const char *fmt, ...)
2557c478bd9Sstevel@tonic-gate {
2567c478bd9Sstevel@tonic-gate 	va_list ap;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
2597c478bd9Sstevel@tonic-gate 	com_err_va(whoami, code, fmt, ap);
2607c478bd9Sstevel@tonic-gate 	va_end(ap);
2617c478bd9Sstevel@tonic-gate }
2627c478bd9Sstevel@tonic-gate 
263159d09a2SMark Phalan /* Make a separate function because the assert invocations below
264159d09a2SMark Phalan    use the macro expansion on some platforms, which may be insanely
265159d09a2SMark Phalan    long and incomprehensible.  */
com_err_lock_hook_handle(void)266159d09a2SMark Phalan static int com_err_lock_hook_handle(void)
267159d09a2SMark Phalan {
268159d09a2SMark Phalan     return k5_mutex_lock(&com_err_hook_lock);
269159d09a2SMark Phalan }
270159d09a2SMark Phalan 
set_com_err_hook(et_old_error_hook_func new_proc)271159d09a2SMark Phalan et_old_error_hook_func set_com_err_hook (et_old_error_hook_func new_proc)
2727c478bd9Sstevel@tonic-gate {
2737c64d375Smp 	int i;
274159d09a2SMark Phalan 	et_old_error_hook_func x;
275159d09a2SMark Phalan 
276159d09a2SMark Phalan 	/* Broken initialization?  What can we do?  */
277159d09a2SMark Phalan 	assert(com_err_finish_init() == 0);
278159d09a2SMark Phalan 	assert(com_err_lock_hook_handle() == 0);
279159d09a2SMark Phalan 
280159d09a2SMark Phalan 	x = com_err_hook[0];
2817c64d375Smp 
2827c64d375Smp 	for (i = 0; i < hook_count; i++)
2837c64d375Smp 		com_err_hook[i] = NULL;
2847c64d375Smp 
2857c64d375Smp 	com_err_hook[0] = new_proc;
2867c64d375Smp 	hook_count = 1;
2877c478bd9Sstevel@tonic-gate 
288159d09a2SMark Phalan 	k5_mutex_unlock(&com_err_hook_lock);
2897c478bd9Sstevel@tonic-gate 	return x;
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate 
reset_com_err_hook()2927c478bd9Sstevel@tonic-gate et_old_error_hook_func reset_com_err_hook ()
2937c478bd9Sstevel@tonic-gate {
2947c64d375Smp 	int i;
295159d09a2SMark Phalan 	et_old_error_hook_func x;
2967c64d375Smp 
297159d09a2SMark Phalan 	/* Broken initialization?  What can we do?  */
298159d09a2SMark Phalan 	assert(com_err_finish_init() == 0);
299159d09a2SMark Phalan 	assert(com_err_lock_hook_handle() == 0);
300159d09a2SMark Phalan 	x = com_err_hook[0];
3017c64d375Smp 	for (i = 0; i < hook_count; i++)
3027c64d375Smp 		com_err_hook[i] = NULL;
3037c64d375Smp 
3047c64d375Smp 	com_err_hook[0] = default_com_err_proc;
3057c64d375Smp 	hook_count = 1;
306159d09a2SMark Phalan 	k5_mutex_unlock(&com_err_hook_lock);
3077c478bd9Sstevel@tonic-gate 	return x;
3087c478bd9Sstevel@tonic-gate }
3097c64d375Smp 
3107c64d375Smp /*
3117c64d375Smp  * Solaris Kerberos:
3127c64d375Smp  * Register a hook which will be called every time
3137c64d375Smp  * com_err() is called.
3147c64d375Smp  */
add_com_err_hook(et_old_error_hook_func f)3157c64d375Smp void add_com_err_hook(et_old_error_hook_func f) {
3167c64d375Smp 	int i;
3177c64d375Smp 	if (hook_count < MAX_HOOKS) {
3187c64d375Smp 		for (i = 0; i < hook_count; i++) {
3197c64d375Smp 			if (com_err_hook[i] == NULL)
3207c64d375Smp 				break;
3217c64d375Smp 		}
3227c64d375Smp 		com_err_hook[i] = f;
3237c64d375Smp 		hook_count++;
3247c64d375Smp 	}
3257c64d375Smp }
3267c64d375Smp 
3277c64d375Smp /*
3287c64d375Smp  * Solaris Kerberos:
3297c64d375Smp  * Remove a logging hook. The first hook matching 'f' will
3307c64d375Smp  * be removed.
3317c64d375Smp  */
rem_com_err_hook(et_old_error_hook_func f)3327c64d375Smp void rem_com_err_hook(et_old_error_hook_func f) {
3337c64d375Smp 	int i, j;
3347c64d375Smp 
3357c64d375Smp 	for (i = 0; i < hook_count; i++) {
3367c64d375Smp 		if (com_err_hook[i] == f) {
3377c64d375Smp 			for (j = i; j < hook_count - 1; j++) {
3387c64d375Smp 				com_err_hook[j] = com_err_hook[j+1];
3397c64d375Smp 			}
3407c64d375Smp 			com_err_hook[j] = NULL;
3417c64d375Smp 			hook_count--;
3427c64d375Smp 		}
3437c64d375Smp 	}
3447c64d375Smp }
3457c64d375Smp 
3467c64d375Smp /*
3477c64d375Smp  * Solaris Kerberos:
3487c64d375Smp  * Remove the default hook.
3497c64d375Smp  */
rem_default_com_err_hook()3507c64d375Smp void rem_default_com_err_hook() {
3517c64d375Smp 	rem_com_err_hook(default_com_err_proc);
3527c64d375Smp }
3537c64d375Smp 
3547c64d375Smp /*
3557c64d375Smp  * Solaris Kerberos:
3567c64d375Smp  * Add back the default hook
3577c64d375Smp  */
add_default_com_err_hook()3587c64d375Smp void add_default_com_err_hook() {
3597c64d375Smp 	add_com_err_hook(default_com_err_proc);
3607c64d375Smp }
361