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