1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24 25#include "curl_setup.h" 26 27#ifdef HAVE_STRERROR_R 28# if (!defined(HAVE_POSIX_STRERROR_R) && \ 29 !defined(HAVE_GLIBC_STRERROR_R)) || \ 30 (defined(HAVE_POSIX_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R)) 31# error "strerror_r MUST be either POSIX, glibc style" 32# endif 33#endif 34 35#include <curl/curl.h> 36 37#ifdef USE_LIBIDN2 38#include <idn2.h> 39#endif 40 41#ifdef USE_WINDOWS_SSPI 42#include "curl_sspi.h" 43#endif 44 45#include "strerror.h" 46/* The last 3 #include files should be in this order */ 47#include "curl_printf.h" 48#include "curl_memory.h" 49#include "memdebug.h" 50 51#if defined(_WIN32) || defined(_WIN32_WCE) 52#define PRESERVE_WINDOWS_ERROR_CODE 53#endif 54 55const char * 56curl_easy_strerror(CURLcode error) 57{ 58#ifndef CURL_DISABLE_VERBOSE_STRINGS 59 switch(error) { 60 case CURLE_OK: 61 return "No error"; 62 63 case CURLE_UNSUPPORTED_PROTOCOL: 64 return "Unsupported protocol"; 65 66 case CURLE_FAILED_INIT: 67 return "Failed initialization"; 68 69 case CURLE_URL_MALFORMAT: 70 return "URL using bad/illegal format or missing URL"; 71 72 case CURLE_NOT_BUILT_IN: 73 return "A requested feature, protocol or option was not found built-in in" 74 " this libcurl due to a build-time decision."; 75 76 case CURLE_COULDNT_RESOLVE_PROXY: 77 return "Couldn't resolve proxy name"; 78 79 case CURLE_COULDNT_RESOLVE_HOST: 80 return "Couldn't resolve host name"; 81 82 case CURLE_COULDNT_CONNECT: 83 return "Couldn't connect to server"; 84 85 case CURLE_WEIRD_SERVER_REPLY: 86 return "Weird server reply"; 87 88 case CURLE_REMOTE_ACCESS_DENIED: 89 return "Access denied to remote resource"; 90 91 case CURLE_FTP_ACCEPT_FAILED: 92 return "FTP: The server failed to connect to data port"; 93 94 case CURLE_FTP_ACCEPT_TIMEOUT: 95 return "FTP: Accepting server connect has timed out"; 96 97 case CURLE_FTP_PRET_FAILED: 98 return "FTP: The server did not accept the PRET command."; 99 100 case CURLE_FTP_WEIRD_PASS_REPLY: 101 return "FTP: unknown PASS reply"; 102 103 case CURLE_FTP_WEIRD_PASV_REPLY: 104 return "FTP: unknown PASV reply"; 105 106 case CURLE_FTP_WEIRD_227_FORMAT: 107 return "FTP: unknown 227 response format"; 108 109 case CURLE_FTP_CANT_GET_HOST: 110 return "FTP: can't figure out the host in the PASV response"; 111 112 case CURLE_HTTP2: 113 return "Error in the HTTP2 framing layer"; 114 115 case CURLE_FTP_COULDNT_SET_TYPE: 116 return "FTP: couldn't set file type"; 117 118 case CURLE_PARTIAL_FILE: 119 return "Transferred a partial file"; 120 121 case CURLE_FTP_COULDNT_RETR_FILE: 122 return "FTP: couldn't retrieve (RETR failed) the specified file"; 123 124 case CURLE_QUOTE_ERROR: 125 return "Quote command returned error"; 126 127 case CURLE_HTTP_RETURNED_ERROR: 128 return "HTTP response code said error"; 129 130 case CURLE_WRITE_ERROR: 131 return "Failed writing received data to disk/application"; 132 133 case CURLE_UPLOAD_FAILED: 134 return "Upload failed (at start/before it took off)"; 135 136 case CURLE_READ_ERROR: 137 return "Failed to open/read local data from file/application"; 138 139 case CURLE_OUT_OF_MEMORY: 140 return "Out of memory"; 141 142 case CURLE_OPERATION_TIMEDOUT: 143 return "Timeout was reached"; 144 145 case CURLE_FTP_PORT_FAILED: 146 return "FTP: command PORT failed"; 147 148 case CURLE_FTP_COULDNT_USE_REST: 149 return "FTP: command REST failed"; 150 151 case CURLE_RANGE_ERROR: 152 return "Requested range was not delivered by the server"; 153 154 case CURLE_HTTP_POST_ERROR: 155 return "Internal problem setting up the POST"; 156 157 case CURLE_SSL_CONNECT_ERROR: 158 return "SSL connect error"; 159 160 case CURLE_BAD_DOWNLOAD_RESUME: 161 return "Couldn't resume download"; 162 163 case CURLE_FILE_COULDNT_READ_FILE: 164 return "Couldn't read a file:// file"; 165 166 case CURLE_LDAP_CANNOT_BIND: 167 return "LDAP: cannot bind"; 168 169 case CURLE_LDAP_SEARCH_FAILED: 170 return "LDAP: search failed"; 171 172 case CURLE_FUNCTION_NOT_FOUND: 173 return "A required function in the library was not found"; 174 175 case CURLE_ABORTED_BY_CALLBACK: 176 return "Operation was aborted by an application callback"; 177 178 case CURLE_BAD_FUNCTION_ARGUMENT: 179 return "A libcurl function was given a bad argument"; 180 181 case CURLE_INTERFACE_FAILED: 182 return "Failed binding local connection end"; 183 184 case CURLE_TOO_MANY_REDIRECTS: 185 return "Number of redirects hit maximum amount"; 186 187 case CURLE_UNKNOWN_OPTION: 188 return "An unknown option was passed in to libcurl"; 189 190 case CURLE_SETOPT_OPTION_SYNTAX: 191 return "Malformed option provided in a setopt"; 192 193 case CURLE_GOT_NOTHING: 194 return "Server returned nothing (no headers, no data)"; 195 196 case CURLE_SSL_ENGINE_NOTFOUND: 197 return "SSL crypto engine not found"; 198 199 case CURLE_SSL_ENGINE_SETFAILED: 200 return "Can not set SSL crypto engine as default"; 201 202 case CURLE_SSL_ENGINE_INITFAILED: 203 return "Failed to initialise SSL crypto engine"; 204 205 case CURLE_SEND_ERROR: 206 return "Failed sending data to the peer"; 207 208 case CURLE_RECV_ERROR: 209 return "Failure when receiving data from the peer"; 210 211 case CURLE_SSL_CERTPROBLEM: 212 return "Problem with the local SSL certificate"; 213 214 case CURLE_SSL_CIPHER: 215 return "Couldn't use specified SSL cipher"; 216 217 case CURLE_PEER_FAILED_VERIFICATION: 218 return "SSL peer certificate or SSH remote key was not OK"; 219 220 case CURLE_SSL_CACERT_BADFILE: 221 return "Problem with the SSL CA cert (path? access rights?)"; 222 223 case CURLE_BAD_CONTENT_ENCODING: 224 return "Unrecognized or bad HTTP Content or Transfer-Encoding"; 225 226 case CURLE_FILESIZE_EXCEEDED: 227 return "Maximum file size exceeded"; 228 229 case CURLE_USE_SSL_FAILED: 230 return "Requested SSL level failed"; 231 232 case CURLE_SSL_SHUTDOWN_FAILED: 233 return "Failed to shut down the SSL connection"; 234 235 case CURLE_SSL_CRL_BADFILE: 236 return "Failed to load CRL file (path? access rights?, format?)"; 237 238 case CURLE_SSL_ISSUER_ERROR: 239 return "Issuer check against peer certificate failed"; 240 241 case CURLE_SEND_FAIL_REWIND: 242 return "Send failed since rewinding of the data stream failed"; 243 244 case CURLE_LOGIN_DENIED: 245 return "Login denied"; 246 247 case CURLE_TFTP_NOTFOUND: 248 return "TFTP: File Not Found"; 249 250 case CURLE_TFTP_PERM: 251 return "TFTP: Access Violation"; 252 253 case CURLE_REMOTE_DISK_FULL: 254 return "Disk full or allocation exceeded"; 255 256 case CURLE_TFTP_ILLEGAL: 257 return "TFTP: Illegal operation"; 258 259 case CURLE_TFTP_UNKNOWNID: 260 return "TFTP: Unknown transfer ID"; 261 262 case CURLE_REMOTE_FILE_EXISTS: 263 return "Remote file already exists"; 264 265 case CURLE_TFTP_NOSUCHUSER: 266 return "TFTP: No such user"; 267 268 case CURLE_REMOTE_FILE_NOT_FOUND: 269 return "Remote file not found"; 270 271 case CURLE_SSH: 272 return "Error in the SSH layer"; 273 274 case CURLE_AGAIN: 275 return "Socket not ready for send/recv"; 276 277 case CURLE_RTSP_CSEQ_ERROR: 278 return "RTSP CSeq mismatch or invalid CSeq"; 279 280 case CURLE_RTSP_SESSION_ERROR: 281 return "RTSP session error"; 282 283 case CURLE_FTP_BAD_FILE_LIST: 284 return "Unable to parse FTP file list"; 285 286 case CURLE_CHUNK_FAILED: 287 return "Chunk callback failed"; 288 289 case CURLE_NO_CONNECTION_AVAILABLE: 290 return "The max connection limit is reached"; 291 292 case CURLE_SSL_PINNEDPUBKEYNOTMATCH: 293 return "SSL public key does not match pinned public key"; 294 295 case CURLE_SSL_INVALIDCERTSTATUS: 296 return "SSL server certificate status verification FAILED"; 297 298 case CURLE_HTTP2_STREAM: 299 return "Stream error in the HTTP/2 framing layer"; 300 301 case CURLE_RECURSIVE_API_CALL: 302 return "API function called from within callback"; 303 304 case CURLE_AUTH_ERROR: 305 return "An authentication function returned an error"; 306 307 case CURLE_HTTP3: 308 return "HTTP/3 error"; 309 310 case CURLE_QUIC_CONNECT_ERROR: 311 return "QUIC connection error"; 312 313 case CURLE_PROXY: 314 return "proxy handshake error"; 315 316 case CURLE_SSL_CLIENTCERT: 317 return "SSL Client Certificate required"; 318 319 case CURLE_UNRECOVERABLE_POLL: 320 return "Unrecoverable error in select/poll"; 321 322 case CURLE_TOO_LARGE: 323 return "A value or data field grew larger than allowed"; 324 325 /* error codes not used by current libcurl */ 326 case CURLE_OBSOLETE20: 327 case CURLE_OBSOLETE24: 328 case CURLE_OBSOLETE29: 329 case CURLE_OBSOLETE32: 330 case CURLE_OBSOLETE40: 331 case CURLE_OBSOLETE44: 332 case CURLE_OBSOLETE46: 333 case CURLE_OBSOLETE50: 334 case CURLE_OBSOLETE51: 335 case CURLE_OBSOLETE57: 336 case CURLE_OBSOLETE62: 337 case CURLE_OBSOLETE75: 338 case CURLE_OBSOLETE76: 339 case CURL_LAST: 340 break; 341 } 342 /* 343 * By using a switch, gcc -Wall will complain about enum values 344 * which do not appear, helping keep this function up-to-date. 345 * By using gcc -Wall -Werror, you can't forget. 346 * 347 * A table would not have the same benefit. Most compilers will 348 * generate code very similar to a table in any case, so there 349 * is little performance gain from a table. And something is broken 350 * for the user's application, anyways, so does it matter how fast 351 * it _doesn't_ work? 352 * 353 * The line number for the error will be near this comment, which 354 * is why it is here, and not at the start of the switch. 355 */ 356 return "Unknown error"; 357#else 358 if(!error) 359 return "No error"; 360 else 361 return "Error"; 362#endif 363} 364 365const char * 366curl_multi_strerror(CURLMcode error) 367{ 368#ifndef CURL_DISABLE_VERBOSE_STRINGS 369 switch(error) { 370 case CURLM_CALL_MULTI_PERFORM: 371 return "Please call curl_multi_perform() soon"; 372 373 case CURLM_OK: 374 return "No error"; 375 376 case CURLM_BAD_HANDLE: 377 return "Invalid multi handle"; 378 379 case CURLM_BAD_EASY_HANDLE: 380 return "Invalid easy handle"; 381 382 case CURLM_OUT_OF_MEMORY: 383 return "Out of memory"; 384 385 case CURLM_INTERNAL_ERROR: 386 return "Internal error"; 387 388 case CURLM_BAD_SOCKET: 389 return "Invalid socket argument"; 390 391 case CURLM_UNKNOWN_OPTION: 392 return "Unknown option"; 393 394 case CURLM_ADDED_ALREADY: 395 return "The easy handle is already added to a multi handle"; 396 397 case CURLM_RECURSIVE_API_CALL: 398 return "API function called from within callback"; 399 400 case CURLM_WAKEUP_FAILURE: 401 return "Wakeup is unavailable or failed"; 402 403 case CURLM_BAD_FUNCTION_ARGUMENT: 404 return "A libcurl function was given a bad argument"; 405 406 case CURLM_ABORTED_BY_CALLBACK: 407 return "Operation was aborted by an application callback"; 408 409 case CURLM_UNRECOVERABLE_POLL: 410 return "Unrecoverable error in select/poll"; 411 412 case CURLM_LAST: 413 break; 414 } 415 416 return "Unknown error"; 417#else 418 if(error == CURLM_OK) 419 return "No error"; 420 else 421 return "Error"; 422#endif 423} 424 425const char * 426curl_share_strerror(CURLSHcode error) 427{ 428#ifndef CURL_DISABLE_VERBOSE_STRINGS 429 switch(error) { 430 case CURLSHE_OK: 431 return "No error"; 432 433 case CURLSHE_BAD_OPTION: 434 return "Unknown share option"; 435 436 case CURLSHE_IN_USE: 437 return "Share currently in use"; 438 439 case CURLSHE_INVALID: 440 return "Invalid share handle"; 441 442 case CURLSHE_NOMEM: 443 return "Out of memory"; 444 445 case CURLSHE_NOT_BUILT_IN: 446 return "Feature not enabled in this library"; 447 448 case CURLSHE_LAST: 449 break; 450 } 451 452 return "CURLSHcode unknown"; 453#else 454 if(error == CURLSHE_OK) 455 return "No error"; 456 else 457 return "Error"; 458#endif 459} 460 461const char * 462curl_url_strerror(CURLUcode error) 463{ 464#ifndef CURL_DISABLE_VERBOSE_STRINGS 465 switch(error) { 466 case CURLUE_OK: 467 return "No error"; 468 469 case CURLUE_BAD_HANDLE: 470 return "An invalid CURLU pointer was passed as argument"; 471 472 case CURLUE_BAD_PARTPOINTER: 473 return "An invalid 'part' argument was passed as argument"; 474 475 case CURLUE_MALFORMED_INPUT: 476 return "Malformed input to a URL function"; 477 478 case CURLUE_BAD_PORT_NUMBER: 479 return "Port number was not a decimal number between 0 and 65535"; 480 481 case CURLUE_UNSUPPORTED_SCHEME: 482 return "Unsupported URL scheme"; 483 484 case CURLUE_URLDECODE: 485 return "URL decode error, most likely because of rubbish in the input"; 486 487 case CURLUE_OUT_OF_MEMORY: 488 return "A memory function failed"; 489 490 case CURLUE_USER_NOT_ALLOWED: 491 return "Credentials was passed in the URL when prohibited"; 492 493 case CURLUE_UNKNOWN_PART: 494 return "An unknown part ID was passed to a URL API function"; 495 496 case CURLUE_NO_SCHEME: 497 return "No scheme part in the URL"; 498 499 case CURLUE_NO_USER: 500 return "No user part in the URL"; 501 502 case CURLUE_NO_PASSWORD: 503 return "No password part in the URL"; 504 505 case CURLUE_NO_OPTIONS: 506 return "No options part in the URL"; 507 508 case CURLUE_NO_HOST: 509 return "No host part in the URL"; 510 511 case CURLUE_NO_PORT: 512 return "No port part in the URL"; 513 514 case CURLUE_NO_QUERY: 515 return "No query part in the URL"; 516 517 case CURLUE_NO_FRAGMENT: 518 return "No fragment part in the URL"; 519 520 case CURLUE_NO_ZONEID: 521 return "No zoneid part in the URL"; 522 523 case CURLUE_BAD_LOGIN: 524 return "Bad login part"; 525 526 case CURLUE_BAD_IPV6: 527 return "Bad IPv6 address"; 528 529 case CURLUE_BAD_HOSTNAME: 530 return "Bad hostname"; 531 532 case CURLUE_BAD_FILE_URL: 533 return "Bad file:// URL"; 534 535 case CURLUE_BAD_SLASHES: 536 return "Unsupported number of slashes following scheme"; 537 538 case CURLUE_BAD_SCHEME: 539 return "Bad scheme"; 540 541 case CURLUE_BAD_PATH: 542 return "Bad path"; 543 544 case CURLUE_BAD_FRAGMENT: 545 return "Bad fragment"; 546 547 case CURLUE_BAD_QUERY: 548 return "Bad query"; 549 550 case CURLUE_BAD_PASSWORD: 551 return "Bad password"; 552 553 case CURLUE_BAD_USER: 554 return "Bad user"; 555 556 case CURLUE_LACKS_IDN: 557 return "libcurl lacks IDN support"; 558 559 case CURLUE_TOO_LARGE: 560 return "A value or data field is larger than allowed"; 561 562 case CURLUE_LAST: 563 break; 564 } 565 566 return "CURLUcode unknown"; 567#else 568 if(error == CURLUE_OK) 569 return "No error"; 570 else 571 return "Error"; 572#endif 573} 574 575#ifdef USE_WINSOCK 576/* This is a helper function for Curl_strerror that converts Winsock error 577 * codes (WSAGetLastError) to error messages. 578 * Returns NULL if no error message was found for error code. 579 */ 580static const char * 581get_winsock_error(int err, char *buf, size_t len) 582{ 583#ifndef CURL_DISABLE_VERBOSE_STRINGS 584 const char *p; 585 size_t alen; 586#endif 587 588 if(!len) 589 return NULL; 590 591 *buf = '\0'; 592 593#ifdef CURL_DISABLE_VERBOSE_STRINGS 594 (void)err; 595 return NULL; 596#else 597 switch(err) { 598 case WSAEINTR: 599 p = "Call interrupted"; 600 break; 601 case WSAEBADF: 602 p = "Bad file"; 603 break; 604 case WSAEACCES: 605 p = "Bad access"; 606 break; 607 case WSAEFAULT: 608 p = "Bad argument"; 609 break; 610 case WSAEINVAL: 611 p = "Invalid arguments"; 612 break; 613 case WSAEMFILE: 614 p = "Out of file descriptors"; 615 break; 616 case WSAEWOULDBLOCK: 617 p = "Call would block"; 618 break; 619 case WSAEINPROGRESS: 620 case WSAEALREADY: 621 p = "Blocking call in progress"; 622 break; 623 case WSAENOTSOCK: 624 p = "Descriptor is not a socket"; 625 break; 626 case WSAEDESTADDRREQ: 627 p = "Need destination address"; 628 break; 629 case WSAEMSGSIZE: 630 p = "Bad message size"; 631 break; 632 case WSAEPROTOTYPE: 633 p = "Bad protocol"; 634 break; 635 case WSAENOPROTOOPT: 636 p = "Protocol option is unsupported"; 637 break; 638 case WSAEPROTONOSUPPORT: 639 p = "Protocol is unsupported"; 640 break; 641 case WSAESOCKTNOSUPPORT: 642 p = "Socket is unsupported"; 643 break; 644 case WSAEOPNOTSUPP: 645 p = "Operation not supported"; 646 break; 647 case WSAEAFNOSUPPORT: 648 p = "Address family not supported"; 649 break; 650 case WSAEPFNOSUPPORT: 651 p = "Protocol family not supported"; 652 break; 653 case WSAEADDRINUSE: 654 p = "Address already in use"; 655 break; 656 case WSAEADDRNOTAVAIL: 657 p = "Address not available"; 658 break; 659 case WSAENETDOWN: 660 p = "Network down"; 661 break; 662 case WSAENETUNREACH: 663 p = "Network unreachable"; 664 break; 665 case WSAENETRESET: 666 p = "Network has been reset"; 667 break; 668 case WSAECONNABORTED: 669 p = "Connection was aborted"; 670 break; 671 case WSAECONNRESET: 672 p = "Connection was reset"; 673 break; 674 case WSAENOBUFS: 675 p = "No buffer space"; 676 break; 677 case WSAEISCONN: 678 p = "Socket is already connected"; 679 break; 680 case WSAENOTCONN: 681 p = "Socket is not connected"; 682 break; 683 case WSAESHUTDOWN: 684 p = "Socket has been shut down"; 685 break; 686 case WSAETOOMANYREFS: 687 p = "Too many references"; 688 break; 689 case WSAETIMEDOUT: 690 p = "Timed out"; 691 break; 692 case WSAECONNREFUSED: 693 p = "Connection refused"; 694 break; 695 case WSAELOOP: 696 p = "Loop??"; 697 break; 698 case WSAENAMETOOLONG: 699 p = "Name too long"; 700 break; 701 case WSAEHOSTDOWN: 702 p = "Host down"; 703 break; 704 case WSAEHOSTUNREACH: 705 p = "Host unreachable"; 706 break; 707 case WSAENOTEMPTY: 708 p = "Not empty"; 709 break; 710 case WSAEPROCLIM: 711 p = "Process limit reached"; 712 break; 713 case WSAEUSERS: 714 p = "Too many users"; 715 break; 716 case WSAEDQUOT: 717 p = "Bad quota"; 718 break; 719 case WSAESTALE: 720 p = "Something is stale"; 721 break; 722 case WSAEREMOTE: 723 p = "Remote error"; 724 break; 725#ifdef WSAEDISCON /* missing in SalfordC! */ 726 case WSAEDISCON: 727 p = "Disconnected"; 728 break; 729#endif 730 /* Extended Winsock errors */ 731 case WSASYSNOTREADY: 732 p = "Winsock library is not ready"; 733 break; 734 case WSANOTINITIALISED: 735 p = "Winsock library not initialised"; 736 break; 737 case WSAVERNOTSUPPORTED: 738 p = "Winsock version not supported"; 739 break; 740 741 /* getXbyY() errors (already handled in herrmsg): 742 * Authoritative Answer: Host not found */ 743 case WSAHOST_NOT_FOUND: 744 p = "Host not found"; 745 break; 746 747 /* Non-Authoritative: Host not found, or SERVERFAIL */ 748 case WSATRY_AGAIN: 749 p = "Host not found, try again"; 750 break; 751 752 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */ 753 case WSANO_RECOVERY: 754 p = "Unrecoverable error in call to nameserver"; 755 break; 756 757 /* Valid name, no data record of requested type */ 758 case WSANO_DATA: 759 p = "No data record of requested type"; 760 break; 761 762 default: 763 return NULL; 764 } 765 alen = strlen(p); 766 if(alen < len) 767 strcpy(buf, p); 768 return buf; 769#endif 770} 771#endif /* USE_WINSOCK */ 772 773#if defined(_WIN32) || defined(_WIN32_WCE) 774/* This is a helper function for Curl_strerror that converts Windows API error 775 * codes (GetLastError) to error messages. 776 * Returns NULL if no error message was found for error code. 777 */ 778static const char * 779get_winapi_error(int err, char *buf, size_t buflen) 780{ 781 char *p; 782 wchar_t wbuf[256]; 783 784 if(!buflen) 785 return NULL; 786 787 *buf = '\0'; 788 *wbuf = L'\0'; 789 790 /* We return the local codepage version of the error string because if it is 791 output to the user's terminal it will likely be with functions which 792 expect the local codepage (eg fprintf, failf, infof). 793 FormatMessageW -> wcstombs is used for Windows CE compatibility. */ 794 if(FormatMessageW((FORMAT_MESSAGE_FROM_SYSTEM | 795 FORMAT_MESSAGE_IGNORE_INSERTS), NULL, err, 796 LANG_NEUTRAL, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL)) { 797 size_t written = wcstombs(buf, wbuf, buflen - 1); 798 if(written != (size_t)-1) 799 buf[written] = '\0'; 800 else 801 *buf = '\0'; 802 } 803 804 /* Truncate multiple lines */ 805 p = strchr(buf, '\n'); 806 if(p) { 807 if(p > buf && *(p-1) == '\r') 808 *(p-1) = '\0'; 809 else 810 *p = '\0'; 811 } 812 813 return (*buf ? buf : NULL); 814} 815#endif /* _WIN32 || _WIN32_WCE */ 816 817/* 818 * Our thread-safe and smart strerror() replacement. 819 * 820 * The 'err' argument passed in to this function MUST be a true errno number 821 * as reported on this system. We do no range checking on the number before 822 * we pass it to the "number-to-message" conversion function and there might 823 * be systems that don't do proper range checking in there themselves. 824 * 825 * We don't do range checking (on systems other than Windows) since there is 826 * no good reliable and portable way to do it. 827 * 828 * On Windows different types of error codes overlap. This function has an 829 * order of preference when trying to match error codes: 830 * CRT (errno), Winsock (WSAGetLastError), Windows API (GetLastError). 831 * 832 * It may be more correct to call one of the variant functions instead: 833 * Call Curl_sspi_strerror if the error code is definitely Windows SSPI. 834 * Call Curl_winapi_strerror if the error code is definitely Windows API. 835 */ 836const char *Curl_strerror(int err, char *buf, size_t buflen) 837{ 838#ifdef PRESERVE_WINDOWS_ERROR_CODE 839 DWORD old_win_err = GetLastError(); 840#endif 841 int old_errno = errno; 842 char *p; 843 844 if(!buflen) 845 return NULL; 846 847#ifndef _WIN32 848 DEBUGASSERT(err >= 0); 849#endif 850 851 *buf = '\0'; 852 853#if defined(_WIN32) || defined(_WIN32_WCE) 854#if defined(_WIN32) 855 /* 'sys_nerr' is the maximum errno number, it is not widely portable */ 856 if(err >= 0 && err < sys_nerr) 857 msnprintf(buf, buflen, "%s", sys_errlist[err]); 858 else 859#endif 860 { 861 if( 862#ifdef USE_WINSOCK 863 !get_winsock_error(err, buf, buflen) && 864#endif 865 !get_winapi_error((DWORD)err, buf, buflen)) 866 msnprintf(buf, buflen, "Unknown error %d (%#x)", err, err); 867 } 868#else /* not Windows coming up */ 869 870#if defined(HAVE_STRERROR_R) && defined(HAVE_POSIX_STRERROR_R) 871 /* 872 * The POSIX-style strerror_r() may set errno to ERANGE if insufficient 873 * storage is supplied via 'strerrbuf' and 'buflen' to hold the generated 874 * message string, or EINVAL if 'errnum' is not a valid error number. 875 */ 876 if(0 != strerror_r(err, buf, buflen)) { 877 if('\0' == buf[0]) 878 msnprintf(buf, buflen, "Unknown error %d", err); 879 } 880#elif defined(HAVE_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R) 881 /* 882 * The glibc-style strerror_r() only *might* use the buffer we pass to 883 * the function, but it always returns the error message as a pointer, 884 * so we must copy that string unconditionally (if non-NULL). 885 */ 886 { 887 char buffer[256]; 888 char *msg = strerror_r(err, buffer, sizeof(buffer)); 889 if(msg) 890 msnprintf(buf, buflen, "%s", msg); 891 else 892 msnprintf(buf, buflen, "Unknown error %d", err); 893 } 894#else 895 { 896 /* !checksrc! disable STRERROR 1 */ 897 const char *msg = strerror(err); 898 if(msg) 899 msnprintf(buf, buflen, "%s", msg); 900 else 901 msnprintf(buf, buflen, "Unknown error %d", err); 902 } 903#endif 904 905#endif /* end of not Windows */ 906 907 /* strip trailing '\r\n' or '\n'. */ 908 p = strrchr(buf, '\n'); 909 if(p && (p - buf) >= 2) 910 *p = '\0'; 911 p = strrchr(buf, '\r'); 912 if(p && (p - buf) >= 1) 913 *p = '\0'; 914 915 if(errno != old_errno) 916 errno = old_errno; 917 918#ifdef PRESERVE_WINDOWS_ERROR_CODE 919 if(old_win_err != GetLastError()) 920 SetLastError(old_win_err); 921#endif 922 923 return buf; 924} 925 926/* 927 * Curl_winapi_strerror: 928 * Variant of Curl_strerror if the error code is definitely Windows API. 929 */ 930#if defined(_WIN32) || defined(_WIN32_WCE) 931const char *Curl_winapi_strerror(DWORD err, char *buf, size_t buflen) 932{ 933#ifdef PRESERVE_WINDOWS_ERROR_CODE 934 DWORD old_win_err = GetLastError(); 935#endif 936 int old_errno = errno; 937 938 if(!buflen) 939 return NULL; 940 941 *buf = '\0'; 942 943#ifndef CURL_DISABLE_VERBOSE_STRINGS 944 if(!get_winapi_error(err, buf, buflen)) { 945 msnprintf(buf, buflen, "Unknown error %lu (0x%08lX)", err, err); 946 } 947#else 948 { 949 const char *txt = (err == ERROR_SUCCESS) ? "No error" : "Error"; 950 if(strlen(txt) < buflen) 951 strcpy(buf, txt); 952 } 953#endif 954 955 if(errno != old_errno) 956 errno = old_errno; 957 958#ifdef PRESERVE_WINDOWS_ERROR_CODE 959 if(old_win_err != GetLastError()) 960 SetLastError(old_win_err); 961#endif 962 963 return buf; 964} 965#endif /* _WIN32 || _WIN32_WCE */ 966 967#ifdef USE_WINDOWS_SSPI 968/* 969 * Curl_sspi_strerror: 970 * Variant of Curl_strerror if the error code is definitely Windows SSPI. 971 */ 972const char *Curl_sspi_strerror(int err, char *buf, size_t buflen) 973{ 974#ifdef PRESERVE_WINDOWS_ERROR_CODE 975 DWORD old_win_err = GetLastError(); 976#endif 977 int old_errno = errno; 978 const char *txt; 979 980 if(!buflen) 981 return NULL; 982 983 *buf = '\0'; 984 985#ifndef CURL_DISABLE_VERBOSE_STRINGS 986 987 switch(err) { 988 case SEC_E_OK: 989 txt = "No error"; 990 break; 991#define SEC2TXT(sec) case sec: txt = #sec; break 992 SEC2TXT(CRYPT_E_REVOKED); 993 SEC2TXT(CRYPT_E_NO_REVOCATION_DLL); 994 SEC2TXT(CRYPT_E_NO_REVOCATION_CHECK); 995 SEC2TXT(CRYPT_E_REVOCATION_OFFLINE); 996 SEC2TXT(CRYPT_E_NOT_IN_REVOCATION_DATABASE); 997 SEC2TXT(SEC_E_ALGORITHM_MISMATCH); 998 SEC2TXT(SEC_E_BAD_BINDINGS); 999 SEC2TXT(SEC_E_BAD_PKGID); 1000 SEC2TXT(SEC_E_BUFFER_TOO_SMALL); 1001 SEC2TXT(SEC_E_CANNOT_INSTALL); 1002 SEC2TXT(SEC_E_CANNOT_PACK); 1003 SEC2TXT(SEC_E_CERT_EXPIRED); 1004 SEC2TXT(SEC_E_CERT_UNKNOWN); 1005 SEC2TXT(SEC_E_CERT_WRONG_USAGE); 1006 SEC2TXT(SEC_E_CONTEXT_EXPIRED); 1007 SEC2TXT(SEC_E_CROSSREALM_DELEGATION_FAILURE); 1008 SEC2TXT(SEC_E_CRYPTO_SYSTEM_INVALID); 1009 SEC2TXT(SEC_E_DECRYPT_FAILURE); 1010 SEC2TXT(SEC_E_DELEGATION_POLICY); 1011 SEC2TXT(SEC_E_DELEGATION_REQUIRED); 1012 SEC2TXT(SEC_E_DOWNGRADE_DETECTED); 1013 SEC2TXT(SEC_E_ENCRYPT_FAILURE); 1014 SEC2TXT(SEC_E_ILLEGAL_MESSAGE); 1015 SEC2TXT(SEC_E_INCOMPLETE_CREDENTIALS); 1016 SEC2TXT(SEC_E_INCOMPLETE_MESSAGE); 1017 SEC2TXT(SEC_E_INSUFFICIENT_MEMORY); 1018 SEC2TXT(SEC_E_INTERNAL_ERROR); 1019 SEC2TXT(SEC_E_INVALID_HANDLE); 1020 SEC2TXT(SEC_E_INVALID_PARAMETER); 1021 SEC2TXT(SEC_E_INVALID_TOKEN); 1022 SEC2TXT(SEC_E_ISSUING_CA_UNTRUSTED); 1023 SEC2TXT(SEC_E_ISSUING_CA_UNTRUSTED_KDC); 1024 SEC2TXT(SEC_E_KDC_CERT_EXPIRED); 1025 SEC2TXT(SEC_E_KDC_CERT_REVOKED); 1026 SEC2TXT(SEC_E_KDC_INVALID_REQUEST); 1027 SEC2TXT(SEC_E_KDC_UNABLE_TO_REFER); 1028 SEC2TXT(SEC_E_KDC_UNKNOWN_ETYPE); 1029 SEC2TXT(SEC_E_LOGON_DENIED); 1030 SEC2TXT(SEC_E_MAX_REFERRALS_EXCEEDED); 1031 SEC2TXT(SEC_E_MESSAGE_ALTERED); 1032 SEC2TXT(SEC_E_MULTIPLE_ACCOUNTS); 1033 SEC2TXT(SEC_E_MUST_BE_KDC); 1034 SEC2TXT(SEC_E_NOT_OWNER); 1035 SEC2TXT(SEC_E_NO_AUTHENTICATING_AUTHORITY); 1036 SEC2TXT(SEC_E_NO_CREDENTIALS); 1037 SEC2TXT(SEC_E_NO_IMPERSONATION); 1038 SEC2TXT(SEC_E_NO_IP_ADDRESSES); 1039 SEC2TXT(SEC_E_NO_KERB_KEY); 1040 SEC2TXT(SEC_E_NO_PA_DATA); 1041 SEC2TXT(SEC_E_NO_S4U_PROT_SUPPORT); 1042 SEC2TXT(SEC_E_NO_TGT_REPLY); 1043 SEC2TXT(SEC_E_OUT_OF_SEQUENCE); 1044 SEC2TXT(SEC_E_PKINIT_CLIENT_FAILURE); 1045 SEC2TXT(SEC_E_PKINIT_NAME_MISMATCH); 1046 SEC2TXT(SEC_E_POLICY_NLTM_ONLY); 1047 SEC2TXT(SEC_E_QOP_NOT_SUPPORTED); 1048 SEC2TXT(SEC_E_REVOCATION_OFFLINE_C); 1049 SEC2TXT(SEC_E_REVOCATION_OFFLINE_KDC); 1050 SEC2TXT(SEC_E_SECPKG_NOT_FOUND); 1051 SEC2TXT(SEC_E_SECURITY_QOS_FAILED); 1052 SEC2TXT(SEC_E_SHUTDOWN_IN_PROGRESS); 1053 SEC2TXT(SEC_E_SMARTCARD_CERT_EXPIRED); 1054 SEC2TXT(SEC_E_SMARTCARD_CERT_REVOKED); 1055 SEC2TXT(SEC_E_SMARTCARD_LOGON_REQUIRED); 1056 SEC2TXT(SEC_E_STRONG_CRYPTO_NOT_SUPPORTED); 1057 SEC2TXT(SEC_E_TARGET_UNKNOWN); 1058 SEC2TXT(SEC_E_TIME_SKEW); 1059 SEC2TXT(SEC_E_TOO_MANY_PRINCIPALS); 1060 SEC2TXT(SEC_E_UNFINISHED_CONTEXT_DELETED); 1061 SEC2TXT(SEC_E_UNKNOWN_CREDENTIALS); 1062 SEC2TXT(SEC_E_UNSUPPORTED_FUNCTION); 1063 SEC2TXT(SEC_E_UNSUPPORTED_PREAUTH); 1064 SEC2TXT(SEC_E_UNTRUSTED_ROOT); 1065 SEC2TXT(SEC_E_WRONG_CREDENTIAL_HANDLE); 1066 SEC2TXT(SEC_E_WRONG_PRINCIPAL); 1067 SEC2TXT(SEC_I_COMPLETE_AND_CONTINUE); 1068 SEC2TXT(SEC_I_COMPLETE_NEEDED); 1069 SEC2TXT(SEC_I_CONTEXT_EXPIRED); 1070 SEC2TXT(SEC_I_CONTINUE_NEEDED); 1071 SEC2TXT(SEC_I_INCOMPLETE_CREDENTIALS); 1072 SEC2TXT(SEC_I_LOCAL_LOGON); 1073 SEC2TXT(SEC_I_NO_LSA_CONTEXT); 1074 SEC2TXT(SEC_I_RENEGOTIATE); 1075 SEC2TXT(SEC_I_SIGNATURE_NEEDED); 1076 default: 1077 txt = "Unknown error"; 1078 } 1079 1080 if(err == SEC_E_ILLEGAL_MESSAGE) { 1081 msnprintf(buf, buflen, 1082 "SEC_E_ILLEGAL_MESSAGE (0x%08X) - This error usually occurs " 1083 "when a fatal SSL/TLS alert is received (e.g. handshake failed)." 1084 " More detail may be available in the Windows System event log.", 1085 err); 1086 } 1087 else { 1088 char msgbuf[256]; 1089 if(get_winapi_error(err, msgbuf, sizeof(msgbuf))) 1090 msnprintf(buf, buflen, "%s (0x%08X) - %s", txt, err, msgbuf); 1091 else 1092 msnprintf(buf, buflen, "%s (0x%08X)", txt, err); 1093 } 1094 1095#else 1096 if(err == SEC_E_OK) 1097 txt = "No error"; 1098 else 1099 txt = "Error"; 1100 if(buflen > strlen(txt)) 1101 strcpy(buf, txt); 1102#endif 1103 1104 if(errno != old_errno) 1105 errno = old_errno; 1106 1107#ifdef PRESERVE_WINDOWS_ERROR_CODE 1108 if(old_win_err != GetLastError()) 1109 SetLastError(old_win_err); 1110#endif 1111 1112 return buf; 1113} 1114#endif /* USE_WINDOWS_SSPI */ 1115