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