1 /* $NetBSD: strerror.c,v 1.2 2024/08/18 20:47:16 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 2001, 2002 Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* Id: strerror.c,v 1.8 2007/06/19 23:47:19 tbox Exp */ 21 22 #include <config.h> 23 24 #include <stdio.h> 25 #include <string.h> 26 #include <winsock2.h> 27 28 #include <isc/mutex.h> 29 #include <isc/once.h> 30 #include <isc/print.h> 31 #include <isc/strerror.h> 32 #include <isc/util.h> 33 34 #include "lib_strbuf.h" 35 36 /* 37 * Forward declarations 38 */ 39 40 char * 41 FormatError(int error); 42 43 char * 44 GetWSAErrorMessage(int errval); 45 46 char * 47 NTstrerror(int err, BOOL *bfreebuf); 48 49 /* 50 * We need to do this this way for profiled locks. 51 */ 52 53 static isc_mutex_t isc_strerror_lock; 54 static void init_lock(void) { 55 RUNTIME_CHECK(isc_mutex_init(&isc_strerror_lock) == ISC_R_SUCCESS); 56 } 57 58 /* 59 * This routine needs to free up any buffer allocated by FormatMessage 60 * if that routine gets used. 61 */ 62 63 void 64 isc__strerror(int num, char *buf, size_t size) { 65 char *msg; 66 BOOL freebuf; 67 unsigned int unum = num; 68 static isc_once_t once = ISC_ONCE_INIT; 69 70 REQUIRE(buf != NULL); 71 72 RUNTIME_CHECK(isc_once_do(&once, init_lock) == ISC_R_SUCCESS); 73 74 LOCK(&isc_strerror_lock); 75 freebuf = FALSE; 76 msg = NTstrerror(num, &freebuf); 77 if (msg != NULL) 78 snprintf(buf, size, "%s", msg); 79 else 80 snprintf(buf, size, "Unknown error: %u", unum); 81 if(freebuf && msg != NULL) { 82 LocalFree(msg); 83 } 84 UNLOCK(&isc_strerror_lock); 85 } 86 87 /* 88 * Note this will cause a memory leak unless the memory allocated here 89 * is freed by calling LocalFree. isc__strerror does this before unlocking. 90 * This only gets called if there is a system type of error and will likely 91 * be an unusual event. 92 */ 93 char * 94 FormatError(int error) { 95 char *lpMsgBuf = NULL; 96 char *pch; 97 const char boiler[] = 98 " For information about network troubleshooting, see Windows Help."; 99 size_t last; 100 101 FormatMessage( 102 FORMAT_MESSAGE_ALLOCATE_BUFFER | 103 FORMAT_MESSAGE_FROM_SYSTEM | 104 (FORMAT_MESSAGE_MAX_WIDTH_MASK - 1), 105 NULL, 106 error, 107 /* Default language */ 108 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 109 (LPTSTR)(PVOID)&lpMsgBuf, 110 0, 111 NULL); 112 113 /* remove useless boilerplate */ 114 pch = strstr(lpMsgBuf, boiler); 115 if (pch != NULL) { 116 *pch = '\0'; 117 } 118 119 /* strip any trailing CR/LF and spaces */ 120 if (lpMsgBuf != NULL) { 121 last = strlen(lpMsgBuf); 122 if (last > 0) { 123 --last; 124 } 125 while ('\n' == lpMsgBuf[last] || 126 '\r' == lpMsgBuf[last] || 127 ' ' == lpMsgBuf[last]) { 128 129 lpMsgBuf[last] = '\0'; 130 if (last > 0) { 131 --last; 132 } 133 } 134 } 135 136 return (lpMsgBuf); 137 } 138 139 /* 140 * This routine checks the error value and calls the WSA Windows Sockets 141 * Error message function GetWSAErrorMessage below if it's within that range 142 * since those messages are not available in the system error messages. 143 */ 144 char * 145 NTstrerror(int err, BOOL *bfreebuf) { 146 char *retmsg = NULL; 147 148 *bfreebuf = FALSE; 149 150 /* Get the Winsock2 error messages */ 151 /* DLH this may not be needed, FormatError/FormatMessage may handle Winsock error codes */ 152 if (err >= WSABASEERR && err <= (WSABASEERR + 1999)) { 153 retmsg = GetWSAErrorMessage(err); 154 } 155 /* 156 * If it's not one of the standard Unix error codes, 157 * try a system error message 158 */ 159 if (NULL == retmsg) { 160 if (err > _sys_nerr) { 161 *bfreebuf = TRUE; 162 retmsg = FormatError(err); 163 } else { 164 retmsg = lib_getbuf(); 165 if (0 != strerror_s(retmsg, LIB_BUFLENGTH, err)) { 166 snprintf(retmsg, LIB_BUFLENGTH, 167 "Unknown error number %d/0x%x", 168 err, err); 169 } 170 } 171 } 172 return retmsg; 173 } 174 175 /* 176 * This is a replacement for perror 177 */ 178 void __cdecl 179 NTperror(char *errmsg) { 180 /* Copy the error value first in case of other errors */ 181 int errval = errno; 182 BOOL bfreebuf = FALSE; 183 char *msg; 184 185 msg = NTstrerror(errval, &bfreebuf); 186 fprintf(stderr, "%s: %s\n", errmsg, msg); 187 if(bfreebuf == TRUE) { 188 LocalFree(msg); 189 } 190 191 } 192 193 /* 194 * Return the error string related to Winsock2 errors. 195 * This function is necessary since FormatMessage knows nothing about them 196 * and there is no function to get them. 197 */ 198 char * 199 GetWSAErrorMessage(int errval) { 200 char *msg; 201 202 switch (errval) { 203 204 case WSAEINTR: 205 msg = "Interrupted system call"; 206 break; 207 208 case WSAEBADF: 209 msg = "Bad file number"; 210 break; 211 212 case WSAEACCES: 213 msg = "Permission denied"; 214 break; 215 216 case WSAEFAULT: 217 msg = "Bad address"; 218 break; 219 220 case WSAEINVAL: 221 msg = "Invalid argument"; 222 break; 223 224 case WSAEMFILE: 225 msg = "Too many open sockets"; 226 break; 227 228 case WSAEWOULDBLOCK: 229 msg = "Operation would block"; 230 break; 231 232 case WSAEINPROGRESS: 233 msg = "Operation now in progress"; 234 break; 235 236 case WSAEALREADY: 237 msg = "Operation already in progress"; 238 break; 239 240 case WSAENOTSOCK: 241 msg = "Socket operation on non-socket"; 242 break; 243 244 case WSAEDESTADDRREQ: 245 msg = "Destination address required"; 246 break; 247 248 case WSAEMSGSIZE: 249 msg = "Message too long"; 250 break; 251 252 case WSAEPROTOTYPE: 253 msg = "Protocol wrong type for socket"; 254 break; 255 256 case WSAENOPROTOOPT: 257 msg = "Bad protocol option"; 258 break; 259 260 case WSAEPROTONOSUPPORT: 261 msg = "Protocol not supported"; 262 break; 263 264 case WSAESOCKTNOSUPPORT: 265 msg = "Socket type not supported"; 266 break; 267 268 case WSAEOPNOTSUPP: 269 msg = "Operation not supported on socket"; 270 break; 271 272 case WSAEPFNOSUPPORT: 273 msg = "Protocol family not supported"; 274 break; 275 276 case WSAEAFNOSUPPORT: 277 msg = "Address family not supported"; 278 break; 279 280 case WSAEADDRINUSE: 281 msg = "Address already in use"; 282 break; 283 284 case WSAEADDRNOTAVAIL: 285 msg = "Can't assign requested address"; 286 break; 287 288 case WSAENETDOWN: 289 msg = "Network is down"; 290 break; 291 292 case WSAENETUNREACH: 293 msg = "Network is unreachable"; 294 break; 295 296 case WSAENETRESET: 297 msg = "Net connection reset"; 298 break; 299 300 case WSAECONNABORTED: 301 msg = "Software caused connection abort"; 302 break; 303 304 case WSAECONNRESET: 305 msg = "Connection reset by peer"; 306 break; 307 308 case WSAENOBUFS: 309 msg = "No buffer space available"; 310 break; 311 312 case WSAEISCONN: 313 msg = "Socket is already connected"; 314 break; 315 316 case WSAENOTCONN: 317 msg = "Socket is not connected"; 318 break; 319 320 case WSAESHUTDOWN: 321 msg = "Can't send after socket shutdown"; 322 break; 323 324 case WSAETOOMANYREFS: 325 msg = "Too many references: can't splice"; 326 break; 327 328 case WSAETIMEDOUT: 329 msg = "Connection timed out"; 330 break; 331 332 case WSAECONNREFUSED: 333 msg = "Connection refused"; 334 break; 335 336 case WSAELOOP: 337 msg = "Too many levels of symbolic links"; 338 break; 339 340 case WSAENAMETOOLONG: 341 msg = "File name too long"; 342 break; 343 344 case WSAEHOSTDOWN: 345 msg = "Host is down"; 346 break; 347 348 case WSAEHOSTUNREACH: 349 msg = "No route to host"; 350 break; 351 352 case WSAENOTEMPTY: 353 msg = "Directory not empty"; 354 break; 355 356 case WSAEPROCLIM: 357 msg = "Too many processes"; 358 break; 359 360 case WSAEUSERS: 361 msg = "Too many users"; 362 break; 363 364 case WSAEDQUOT: 365 msg = "Disc quota exceeded"; 366 break; 367 368 case WSAESTALE: 369 msg = "Stale NFS file handle"; 370 break; 371 372 case WSAEREMOTE: 373 msg = "Too many levels of remote in path"; 374 break; 375 376 case WSASYSNOTREADY: 377 msg = "Network system is unavailable"; 378 break; 379 380 case WSAVERNOTSUPPORTED: 381 msg = "Winsock version out of range"; 382 break; 383 384 case WSANOTINITIALISED: 385 msg = "WSAStartup not yet called"; 386 break; 387 388 case WSAEDISCON: 389 msg = "Graceful shutdown in progress"; 390 break; 391 /* 392 case WSAHOST_NOT_FOUND: 393 msg = "Host not found"; 394 break; 395 396 case WSANO_DATA: 397 msg = "No host data of that type was found"; 398 break; 399 */ 400 default: 401 msg = NULL; 402 break; 403 } 404 return (msg); 405 } 406 407 /* 408 * These error messages are more informative about CryptAPI Errors than the 409 * standard error messages 410 */ 411 412 char * 413 GetCryptErrorMessage(int errval) { 414 char *msg; 415 416 switch (errval) { 417 418 case NTE_BAD_FLAGS: 419 msg = "The dwFlags parameter has an illegal value."; 420 break; 421 case NTE_BAD_KEYSET: 422 msg = "The Registry entry for the key container " 423 "could not be opened and may not exist."; 424 break; 425 case NTE_BAD_KEYSET_PARAM: 426 msg = "The pszContainer or pszProvider parameter " 427 "is set to an illegal value."; 428 break; 429 case NTE_BAD_PROV_TYPE: 430 msg = "The value of the dwProvType parameter is out " 431 "of range. All provider types must be from " 432 "1 to 999, inclusive."; 433 break; 434 case NTE_BAD_SIGNATURE: 435 msg = "The provider DLL signature did not verify " 436 "correctly. Either the DLL or the digital " 437 "signature has been tampered with."; 438 break; 439 case NTE_EXISTS: 440 msg = "The dwFlags parameter is CRYPT_NEWKEYSET, but the key" 441 " container already exists."; 442 break; 443 case NTE_KEYSET_ENTRY_BAD: 444 msg = "The Registry entry for the pszContainer key container " 445 "was found (in the HKEY_CURRENT_USER window), but is " 446 "corrupt. See the section System Administration for " 447 " etails about CryptoAPI's Registry usage."; 448 break; 449 case NTE_KEYSET_NOT_DEF: 450 msg = "No Registry entry exists in the HKEY_CURRENT_USER " 451 "window for the key container specified by " 452 "pszContainer."; 453 break; 454 case NTE_NO_MEMORY: 455 msg = "The CSP ran out of memory during the operation."; 456 break; 457 case NTE_PROV_DLL_NOT_FOUND: 458 msg = "The provider DLL file does not exist or is not on the " 459 "current path."; 460 break; 461 case NTE_PROV_TYPE_ENTRY_BAD: 462 msg = "The Registry entry for the provider type specified by " 463 "dwProvType is corrupt. This error may relate to " 464 "either the user default CSP list or the machine " 465 "default CSP list. See the section System " 466 "Administration for details about CryptoAPI's " 467 "Registry usage."; 468 break; 469 case NTE_PROV_TYPE_NO_MATCH: 470 msg = "The provider type specified by dwProvType does not " 471 "match the provider type found in the Registry. Note " 472 "that this error can only occur when pszProvider " 473 "specifies an actual CSP name."; 474 break; 475 case NTE_PROV_TYPE_NOT_DEF: 476 msg = "No Registry entry exists for the provider type " 477 "specified by dwProvType."; 478 break; 479 case NTE_PROVIDER_DLL_FAIL: 480 msg = "The provider DLL file could not be loaded, and " 481 "may not exist. If it exists, then the file is " 482 "not a valid DLL."; 483 break; 484 case NTE_SIGNATURE_FILE_BAD: 485 msg = "An error occurred while loading the DLL file image, " 486 "prior to verifying its signature."; 487 break; 488 489 default: 490 msg = NULL; 491 break; 492 } 493 return msg; 494 } 495 496