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