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