Home | History | Annotate | Download | only in et
      1 /*
      2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 
      6 
      7 /*
      8  * Copyright 1997 by Massachusetts Institute of Technology
      9  *
     10  * Copyright 1987, 1988 by MIT Student Information Processing Board
     11  *
     12  * Permission to use, copy, modify, and distribute this software
     13  * and its documentation for any purpose and without fee is
     14  * hereby granted, provided that the above copyright notice
     15  * appear in all copies and that both that copyright notice and
     16  * this permission notice appear in supporting documentation,
     17  * and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
     18  * used in advertising or publicity pertaining to distribution
     19  * of the software without specific, written prior permission.
     20  * Furthermore if you modify this software you must label
     21  * your software as modified software and not distribute it in such a
     22  * fashion that it might be confused with the original M.I.T. software.
     23  * M.I.T. and the M.I.T. S.I.P.B. make no representations about
     24  * the suitability of this software for any purpose.  It is
     25  * provided "as is" without express or implied warranty.
     26  */
     27 
     28 #include <stdio.h>
     29 #include <string.h>
     30 #include <stdlib.h>
     31 #include <locale.h>
     32 
     33 #include "com_err.h"
     34 #include "error_table.h"
     35 
     36 #if defined(_WIN32)
     37 #include <io.h>
     38 #endif
     39 
     40 k5_mutex_t com_err_hook_lock = K5_MUTEX_PARTIAL_INITIALIZER;
     41 
     42 static void default_com_err_proc
     43 (const char  *whoami, errcode_t code,
     44 	const char  *fmt, va_list ap);
     45 
     46 #if defined(_WIN32)
     47 BOOL  isGuiApp() {
     48 	DWORD mypid;
     49 	HANDLE myprocess;
     50 	mypid = GetCurrentProcessId();
     51 	myprocess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, mypid);
     52 	return GetGuiResources(myprocess, 1) > 0;
     53 	}
     54 #endif
     55 
     56 /*
     57  * Solaris Kerberos:
     58  * It is sometimes desirable to have more than a single hook called
     59  * when com_err() is invoked. A number of new functions have been
     60  * added which allow hooks to be added and removed:
     61  *    add_com_err_hook()
     62  *    add_default_com_err_hook()
     63  *    remove_com_err_hook()
     64  *    remove_default_com_err_hook()
     65  * The existing functions:
     66  *    set_com_err_hook()
     67  *    reset_com_err_hook()
     68  *    com_err()
     69  * have been modified to work with the new scheme. Applications using
     70  * the original function calls are not affected.
     71  */
     72 #define	MAX_HOOKS 3
     73 static et_old_error_hook_func com_err_hook[MAX_HOOKS] = { default_com_err_proc,
     74     NULL, NULL };
     75 static int hook_count = 1;
     76 
     77 /* Solaris Kerberos specific fix start --------------------------- */
     78 
     79 #define gettext(X)	X
     80 
     81 struct msg_map {
     82 	char *msgid;
     83 	char *c_msgstr;
     84 };
     85 
     86 struct msg_map msgmap[] = {
     87 
     88 #define	MSG_WHILE 0
     89 	{ gettext("%s\n## com_err msg of format: 'while ...'"),
     90 		"%s\n" },
     91 
     92 #define	MSG_ERROR_MSG 1
     93 	{ gettext("%s\n## com_err message of format: 'error msg ...'"),
     94 		"%s\n" },
     95 
     96 #define	MSG_ERROR_MSG_WHILE 2
     97 	{ gettext("%1$s %2$s\n## com_err message of format: "
     98 		"'error msg ... while ...'"),
     99 		"%1$s %2$s\n" },
    100 
    101 #define	MSG_WHOAMI_WHILE 3
    102 	{ gettext("%1$s: %2$s\n## com_err msg of format: 'whoami: while ...'"),
    103 		"%1$s: %2$s\n" },
    104 
    105 #define	MSG_WHOAMI_ERROR_MSG 4
    106 	{ gettext("%1$s: %2$s\n## com_err message of format: "
    107 		"'whoami: error msg ...'"),
    108 		"%1$s: %2$s\n" },
    109 
    110 #define	MSG_WHOAMI_ERROR_MSG_WHILE 5
    111 	{ gettext("%1$s: %2$s %3$s\n## com_err message of format: "
    112 		"'whoami: error msg ... while ...'"),
    113 		"%1$s: %2$s %3$s\n" },
    114 
    115 #define	MSG_WHOAMI 6
    116 	{ gettext("%s:\n ## com_err message of format: "
    117 		"'whoami: with no error msg or while ...'"),
    118 		"%s:\n " }
    119 };
    120 
    121 #undef gettext
    122 
    123 /*
    124  * The idea is that we provide a unique message id that contains extra junk
    125  * that we never want to display in the C locale. If dgettext() returns
    126  * a string that is equal to the message id, then we return the c_msgstr,
    127  * for display in the locale.
    128  */
    129 static char *
    130 my_gettext(int msg_idx)
    131 {
    132 	char *msgid = msgmap[msg_idx].msgid;
    133 	char *c_msgstr = msgmap[msg_idx].c_msgstr;
    134 	char *msgstr = dgettext(TEXT_DOMAIN, msgid);
    135 
    136 	if (strcmp(msgstr, msgid) == 0)
    137 		return (c_msgstr);
    138 	else
    139 		return (msgstr);
    140 }
    141 
    142 /* Solaris Kerberos specific fix end --------------------------- */
    143 
    144 /* Solaris Kerberos:  this code is significantly altered from
    145  * the MIT 1.2.1 version to work with internationalization */
    146 
    147 static void default_com_err_proc (const char *whoami, errcode_t code,
    148 				  const char *fmt, va_list ap)
    149 {
    150 	char whilebuf[1024] = "";
    151 
    152 	*whilebuf = '\0';
    153 
    154 	/*
    155 	 * Because 'while ...' message could contain a format string
    156 	 * we have to intepret it now, in a buffer. We need to put it
    157 	 * into a buffer so that the message can be juxtaposed in a locale
    158 	 * meaningful manner. In some natural languages, the 'while ...' phrase
    159 	 * must be first.
    160 	 */
    161 	if (fmt) {
    162 		vsprintf(whilebuf, fmt, ap);
    163 	}
    164 
    165 	/*
    166 	 * There are 8 possible combinations here depending on whether
    167 	 * a whoami string was provided, error code is non-zero, and if a
    168 	 * a 'while ...' messge was provided.
    169 	 */
    170 	if (!whoami) {
    171 
    172 		if ((!code) && fmt) {
    173 
    174 			fprintf(stderr, my_gettext(MSG_WHILE),
    175 				whilebuf);
    176 
    177 		} else if (code && !fmt) {
    178 
    179 			fprintf(stderr, my_gettext(MSG_ERROR_MSG),
    180 				error_message(code));
    181 
    182 		} else if (code && fmt) {
    183 
    184 			fprintf(stderr, my_gettext(MSG_ERROR_MSG_WHILE),
    185 				error_message(code), whilebuf);
    186 		} else
    187 			return;
    188 
    189 	} else {
    190 
    191 		if ((!code) && fmt) {
    192 
    193 			fprintf(stderr, my_gettext(MSG_WHOAMI_WHILE),
    194 				whoami, whilebuf);
    195 
    196 		} else if (code && !fmt) {
    197 
    198 			fprintf(stderr, my_gettext(MSG_WHOAMI_ERROR_MSG),
    199 				whoami, error_message(code));
    200 
    201 		} else if (code && fmt) {
    202 
    203 			fprintf(stderr,
    204 				my_gettext(MSG_WHOAMI_ERROR_MSG_WHILE),
    205 				whoami, error_message(code), whilebuf);
    206 		} else {
    207 
    208 			fprintf(stderr,
    209 				my_gettext(MSG_WHOAMI),
    210 				whoami);
    211 		}
    212 	}
    213 
    214 	fflush(stderr);
    215 }
    216 
    217 void KRB5_CALLCONV com_err_va(const char *whoami,
    218 			      errcode_t code,
    219 			      const char *fmt,
    220 			      va_list ap)
    221 {
    222     int err;
    223     int i;
    224     err = com_err_finish_init();
    225     if (err)
    226 	goto best_try;
    227     err = k5_mutex_lock(&com_err_hook_lock);
    228     if (err)
    229 	goto best_try;
    230     for (i = 0; i < hook_count; i++) {
    231 	(com_err_hook[i])(whoami, code, fmt, ap);
    232     }
    233     k5_mutex_unlock(&com_err_hook_lock);
    234     return;
    235 
    236 best_try:
    237     /* Yikes.  Our library initialization failed or we couldn't lock
    238        the lock we want.  We could be in trouble.  Gosh, we should
    239        probably print an error message.  Oh, wait.  That's what we're
    240        trying to do.  In fact, if we're losing on initialization here,
    241        there's a good chance it has to do with failed initialization
    242        of the caller.  */
    243 
    244     for (i = 0; i < hook_count; i++) {
    245 	(com_err_hook[i])(whoami, code, fmt, ap);
    246     }
    247     assert(err == 0);
    248     abort();
    249 }
    250 
    251 
    252 void KRB5_CALLCONV_C com_err(const char *whoami,
    253 			     errcode_t code,
    254 			     const char *fmt, ...)
    255 {
    256 	va_list ap;
    257 
    258 	va_start(ap, fmt);
    259 	com_err_va(whoami, code, fmt, ap);
    260 	va_end(ap);
    261 }
    262 
    263 /* Make a separate function because the assert invocations below
    264    use the macro expansion on some platforms, which may be insanely
    265    long and incomprehensible.  */
    266 static int com_err_lock_hook_handle(void)
    267 {
    268     return k5_mutex_lock(&com_err_hook_lock);
    269 }
    270 
    271 et_old_error_hook_func set_com_err_hook (et_old_error_hook_func new_proc)
    272 {
    273 	int i;
    274 	et_old_error_hook_func x;
    275 
    276 	/* Broken initialization?  What can we do?  */
    277 	assert(com_err_finish_init() == 0);
    278 	assert(com_err_lock_hook_handle() == 0);
    279 
    280 	x = com_err_hook[0];
    281 
    282 	for (i = 0; i < hook_count; i++)
    283 		com_err_hook[i] = NULL;
    284 
    285 	com_err_hook[0] = new_proc;
    286 	hook_count = 1;
    287 
    288 	k5_mutex_unlock(&com_err_hook_lock);
    289 	return x;
    290 }
    291 
    292 et_old_error_hook_func reset_com_err_hook ()
    293 {
    294 	int i;
    295 	et_old_error_hook_func x;
    296 
    297 	/* Broken initialization?  What can we do?  */
    298 	assert(com_err_finish_init() == 0);
    299 	assert(com_err_lock_hook_handle() == 0);
    300 	x = com_err_hook[0];
    301 	for (i = 0; i < hook_count; i++)
    302 		com_err_hook[i] = NULL;
    303 
    304 	com_err_hook[0] = default_com_err_proc;
    305 	hook_count = 1;
    306 	k5_mutex_unlock(&com_err_hook_lock);
    307 	return x;
    308 }
    309 
    310 /*
    311  * Solaris Kerberos:
    312  * Register a hook which will be called every time
    313  * com_err() is called.
    314  */
    315 void add_com_err_hook(et_old_error_hook_func f) {
    316 	int i;
    317 	if (hook_count < MAX_HOOKS) {
    318 		for (i = 0; i < hook_count; i++) {
    319 			if (com_err_hook[i] == NULL)
    320 				break;
    321 		}
    322 		com_err_hook[i] = f;
    323 		hook_count++;
    324 	}
    325 }
    326 
    327 /*
    328  * Solaris Kerberos:
    329  * Remove a logging hook. The first hook matching 'f' will
    330  * be removed.
    331  */
    332 void rem_com_err_hook(et_old_error_hook_func f) {
    333 	int i, j;
    334 
    335 	for (i = 0; i < hook_count; i++) {
    336 		if (com_err_hook[i] == f) {
    337 			for (j = i; j < hook_count - 1; j++) {
    338 				com_err_hook[j] = com_err_hook[j+1];
    339 			}
    340 			com_err_hook[j] = NULL;
    341 			hook_count--;
    342 		}
    343 	}
    344 }
    345 
    346 /*
    347  * Solaris Kerberos:
    348  * Remove the default hook.
    349  */
    350 void rem_default_com_err_hook() {
    351 	rem_com_err_hook(default_com_err_proc);
    352 }
    353 
    354 /*
    355  * Solaris Kerberos:
    356  * Add back the default hook
    357  */
    358 void add_default_com_err_hook() {
    359 	add_com_err_hook(default_com_err_proc);
    360 }
    361