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