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