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