Home | History | Annotate | Download | only in et
      1 /*
      2  * $Header$
      3  * $Source$
      4  * $Locker$
      5  *
      6  * Copyright 1987 by the Student Information Processing Board
      7  * of the Massachusetts Institute of Technology
      8  *
      9  * Permission to use, copy, modify, and distribute this software and
     10  * its documentation for any purpose is hereby granted, provided that
     11  * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
     12  * advertising or publicity pertaining to distribution of the software
     13  * without specific, written prior permission.  M.I.T. and the
     14  * M.I.T. S.I.P.B. make no representations about the suitability of
     15  * this software for any purpose.  It is provided "as is" without
     16  * express or implied warranty.
     17  */
     18 
     19 #include <stdio.h>
     20 #include <stdlib.h>
     21 #include <string.h>
     22 #include <errno.h>
     23 #ifdef HAVE_SYS_PRCTL_H
     24 #include <sys/prctl.h>
     25 #else
     26 #define PR_GET_DUMPABLE 3
     27 #endif
     28 #if (!defined(HAVE_PRCTL) && defined(linux))
     29 #include <sys/syscall.h>
     30 #endif
     31 #if HAVE_UNISTD_H
     32 #include <unistd.h>
     33 #endif
     34 #if HAVE_SYS_TYPES_H
     35 #include <sys/types.h>
     36 #endif
     37 #include "com_err.h"
     38 #include "error_table.h"
     39 #include "internal.h"
     40 
     41 #ifdef TLS
     42 #define THREAD_LOCAL static TLS
     43 #else
     44 #define THREAD_LOCAL static
     45 #endif
     46 
     47 THREAD_LOCAL char buffer[25];
     48 
     49 struct et_list * _et_list = (struct et_list *) NULL;
     50 struct et_list * _et_dynamic_list = (struct et_list *) NULL;
     51 
     52 
     53 const char * error_message (errcode_t code)
     54 {
     55     int offset;
     56     struct et_list *et;
     57     errcode_t table_num;
     58     int started = 0;
     59     char *cp;
     60 
     61     offset = (int) (code & ((1<<ERRCODE_RANGE)-1));
     62     table_num = code - offset;
     63     if (!table_num) {
     64 #ifdef HAS_SYS_ERRLIST
     65 	if (offset < sys_nerr)
     66 	    return(sys_errlist[offset]);
     67 	else
     68 	    goto oops;
     69 #else
     70 	cp = strerror(offset);
     71 	if (cp)
     72 	    return(cp);
     73 	else
     74 	    goto oops;
     75 #endif
     76     }
     77     for (et = _et_list; et; et = et->next) {
     78 	if ((et->table->base & 0xffffffL) == (table_num & 0xffffffL)) {
     79 	    /* This is the right table */
     80 	    if (et->table->n_msgs <= offset)
     81 		goto oops;
     82 	    return(et->table->msgs[offset]);
     83 	}
     84     }
     85     for (et = _et_dynamic_list; et; et = et->next) {
     86 	if ((et->table->base & 0xffffffL) == (table_num & 0xffffffL)) {
     87 	    /* This is the right table */
     88 	    if (et->table->n_msgs <= offset)
     89 		goto oops;
     90 	    return(et->table->msgs[offset]);
     91 	}
     92     }
     93 oops:
     94     strcpy (buffer, "Unknown code ");
     95     if (table_num) {
     96 	strcat (buffer, error_table_name (table_num));
     97 	strcat (buffer, " ");
     98     }
     99     for (cp = buffer; *cp; cp++)
    100 	;
    101     if (offset >= 100) {
    102 	*cp++ = '0' + offset / 100;
    103 	offset %= 100;
    104 	started++;
    105     }
    106     if (started || offset >= 10) {
    107 	*cp++ = '0' + offset / 10;
    108 	offset %= 10;
    109     }
    110     *cp++ = '0' + offset;
    111     *cp = '\0';
    112     return(buffer);
    113 }
    114 
    115 /*
    116  * This routine will only return a value if the we are not running as
    117  * a privileged process.
    118  */
    119 static char *safe_getenv(const char *arg)
    120 {
    121 	if ((getuid() != geteuid()) || (getgid() != getegid()))
    122 		return NULL;
    123 #if HAVE_PRCTL
    124 	if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
    125 		return NULL;
    126 #else
    127 #if (defined(linux) && defined(SYS_prctl))
    128 	if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
    129 		return NULL;
    130 #endif
    131 #endif
    132 
    133 #ifdef HAVE___SECURE_GETENV
    134 	return __secure_getenv(arg);
    135 #else
    136 	return getenv(arg);
    137 #endif
    138 }
    139 
    140 #define DEBUG_INIT	0x8000
    141 #define DEBUG_ADDREMOVE 0x0001
    142 
    143 static int debug_mask = 0;
    144 static FILE *debug_f = 0;
    145 
    146 static void init_debug(void)
    147 {
    148 	char *dstr;
    149 	char *fn;
    150 
    151 	if (debug_mask & DEBUG_INIT)
    152 		return;
    153 
    154 	dstr = getenv("COMERR_DEBUG");
    155 	if (dstr)
    156 		debug_mask = strtoul(dstr, 0, 0);
    157 
    158 	fn = safe_getenv("COMERR_DEBUG_FILE");
    159 	if (fn)
    160 		debug_f = fopen(fn, "a");
    161 	if (!debug_f)
    162 		debug_f = fopen("/dev/tty", "a");
    163 	if (!debug_f)
    164 		debug_mask = 0;
    165 
    166 	debug_mask |= DEBUG_INIT;
    167 }
    168 
    169 /*
    170  * New interface provided by krb5's com_err library
    171  */
    172 errcode_t add_error_table(const struct error_table * et)
    173 {
    174 	struct et_list *el;
    175 
    176 	if (!(el = (struct et_list *) malloc(sizeof(struct et_list))))
    177 		return ENOMEM;
    178 
    179 	el->table = et;
    180 	el->next = _et_dynamic_list;
    181 	_et_dynamic_list = el;
    182 
    183 	init_debug();
    184 	if (debug_mask & DEBUG_ADDREMOVE)
    185 		fprintf(debug_f, "add_error_table: %s (0x%p)\n",
    186 			error_table_name(et->base),
    187 			(const void *) et);
    188 
    189 	return 0;
    190 }
    191 
    192 /*
    193  * New interface provided by krb5's com_err library
    194  */
    195 errcode_t remove_error_table(const struct error_table * et)
    196 {
    197 	struct et_list *el = _et_dynamic_list;
    198 	struct et_list *el2 = 0;
    199 
    200 	init_debug();
    201 	while (el) {
    202 		if (el->table->base == et->base) {
    203 			if (el2)	/* Not the beginning of the list */
    204 				el2->next = el->next;
    205 			else
    206 				_et_dynamic_list = el->next;
    207 			(void) free(el);
    208 			if (debug_mask & DEBUG_ADDREMOVE)
    209 				fprintf(debug_f,
    210 					"remove_error_table: %s (0x%p)\n",
    211 					error_table_name(et->base),
    212 					(const void *) et);
    213 			return 0;
    214 		}
    215 		el2 = el;
    216 		el = el->next;
    217 	}
    218 	if (debug_mask & DEBUG_ADDREMOVE)
    219 		fprintf(debug_f, "remove_error_table FAILED: %s (0x%p)\n",
    220 			error_table_name(et->base),
    221 			(const void *) et);
    222 	return ENOENT;
    223 }
    224 
    225 /*
    226  * Variant of the interface provided by Heimdal's com_err library
    227  */
    228 void
    229 add_to_error_table(struct et_list *new_table)
    230 {
    231 	add_error_table(new_table->table);
    232 }
    233