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