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 47THREAD_LOCAL char buffer[25]; 48 49struct et_list * _et_list = (struct et_list *) NULL; 50struct et_list * _et_dynamic_list = (struct et_list *) NULL; 51 52 53const 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 } 93oops: 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 */ 119static 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 143static int debug_mask = 0; 144static FILE *debug_f = 0; 145 146static 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 */ 172errcode_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 */ 195errcode_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 */ 228void 229add_to_error_table(struct et_list *new_table) 230{ 231 add_error_table(new_table->table); 232} 233