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