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