xref: /curl/lib/strerror.c (revision bc34ebc8)
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 "Could not resolve proxy name";
78 
79   case CURLE_COULDNT_RESOLVE_HOST:
80     return "Could not resolve hostname";
81 
82   case CURLE_COULDNT_CONNECT:
83     return "Could not 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: cannot 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: could not 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: could not 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_SSL_CONNECT_ERROR:
155     return "SSL connect error";
156 
157   case CURLE_BAD_DOWNLOAD_RESUME:
158     return "Could not resume download";
159 
160   case CURLE_FILE_COULDNT_READ_FILE:
161     return "Could not read a file:// file";
162 
163   case CURLE_LDAP_CANNOT_BIND:
164     return "LDAP: cannot bind";
165 
166   case CURLE_LDAP_SEARCH_FAILED:
167     return "LDAP: search failed";
168 
169   case CURLE_ABORTED_BY_CALLBACK:
170     return "Operation was aborted by an application callback";
171 
172   case CURLE_BAD_FUNCTION_ARGUMENT:
173     return "A libcurl function was given a bad argument";
174 
175   case CURLE_INTERFACE_FAILED:
176     return "Failed binding local connection end";
177 
178   case CURLE_TOO_MANY_REDIRECTS:
179     return "Number of redirects hit maximum amount";
180 
181   case CURLE_UNKNOWN_OPTION:
182     return "An unknown option was passed in to libcurl";
183 
184   case CURLE_SETOPT_OPTION_SYNTAX:
185     return "Malformed option provided in a setopt";
186 
187   case CURLE_GOT_NOTHING:
188     return "Server returned nothing (no headers, no data)";
189 
190   case CURLE_SSL_ENGINE_NOTFOUND:
191     return "SSL crypto engine not found";
192 
193   case CURLE_SSL_ENGINE_SETFAILED:
194     return "Can not set SSL crypto engine as default";
195 
196   case CURLE_SSL_ENGINE_INITFAILED:
197     return "Failed to initialise SSL crypto engine";
198 
199   case CURLE_SEND_ERROR:
200     return "Failed sending data to the peer";
201 
202   case CURLE_RECV_ERROR:
203     return "Failure when receiving data from the peer";
204 
205   case CURLE_SSL_CERTPROBLEM:
206     return "Problem with the local SSL certificate";
207 
208   case CURLE_SSL_CIPHER:
209     return "Could not use specified SSL cipher";
210 
211   case CURLE_PEER_FAILED_VERIFICATION:
212     return "SSL peer certificate or SSH remote key was not OK";
213 
214   case CURLE_SSL_CACERT_BADFILE:
215     return "Problem with the SSL CA cert (path? access rights?)";
216 
217   case CURLE_BAD_CONTENT_ENCODING:
218     return "Unrecognized or bad HTTP Content or Transfer-Encoding";
219 
220   case CURLE_FILESIZE_EXCEEDED:
221     return "Maximum file size exceeded";
222 
223   case CURLE_USE_SSL_FAILED:
224     return "Requested SSL level failed";
225 
226   case CURLE_SSL_SHUTDOWN_FAILED:
227     return "Failed to shut down the SSL connection";
228 
229   case CURLE_SSL_CRL_BADFILE:
230     return "Failed to load CRL file (path? access rights?, format?)";
231 
232   case CURLE_SSL_ISSUER_ERROR:
233     return "Issuer check against peer certificate failed";
234 
235   case CURLE_SEND_FAIL_REWIND:
236     return "Send failed since rewinding of the data stream failed";
237 
238   case CURLE_LOGIN_DENIED:
239     return "Login denied";
240 
241   case CURLE_TFTP_NOTFOUND:
242     return "TFTP: File Not Found";
243 
244   case CURLE_TFTP_PERM:
245     return "TFTP: Access Violation";
246 
247   case CURLE_REMOTE_DISK_FULL:
248     return "Disk full or allocation exceeded";
249 
250   case CURLE_TFTP_ILLEGAL:
251     return "TFTP: Illegal operation";
252 
253   case CURLE_TFTP_UNKNOWNID:
254     return "TFTP: Unknown transfer ID";
255 
256   case CURLE_REMOTE_FILE_EXISTS:
257     return "Remote file already exists";
258 
259   case CURLE_TFTP_NOSUCHUSER:
260     return "TFTP: No such user";
261 
262   case CURLE_REMOTE_FILE_NOT_FOUND:
263     return "Remote file not found";
264 
265   case CURLE_SSH:
266     return "Error in the SSH layer";
267 
268   case CURLE_AGAIN:
269     return "Socket not ready for send/recv";
270 
271   case CURLE_RTSP_CSEQ_ERROR:
272     return "RTSP CSeq mismatch or invalid CSeq";
273 
274   case CURLE_RTSP_SESSION_ERROR:
275     return "RTSP session error";
276 
277   case CURLE_FTP_BAD_FILE_LIST:
278     return "Unable to parse FTP file list";
279 
280   case CURLE_CHUNK_FAILED:
281     return "Chunk callback failed";
282 
283   case CURLE_NO_CONNECTION_AVAILABLE:
284     return "The max connection limit is reached";
285 
286   case CURLE_SSL_PINNEDPUBKEYNOTMATCH:
287     return "SSL public key does not match pinned public key";
288 
289   case CURLE_SSL_INVALIDCERTSTATUS:
290     return "SSL server certificate status verification FAILED";
291 
292   case CURLE_HTTP2_STREAM:
293     return "Stream error in the HTTP/2 framing layer";
294 
295   case CURLE_RECURSIVE_API_CALL:
296     return "API function called from within callback";
297 
298   case CURLE_AUTH_ERROR:
299     return "An authentication function returned an error";
300 
301   case CURLE_HTTP3:
302     return "HTTP/3 error";
303 
304   case CURLE_QUIC_CONNECT_ERROR:
305     return "QUIC connection error";
306 
307   case CURLE_PROXY:
308     return "proxy handshake error";
309 
310   case CURLE_SSL_CLIENTCERT:
311     return "SSL Client Certificate required";
312 
313   case CURLE_UNRECOVERABLE_POLL:
314     return "Unrecoverable error in select/poll";
315 
316   case CURLE_TOO_LARGE:
317     return "A value or data field grew larger than allowed";
318 
319   case CURLE_ECH_REQUIRED:
320     return "ECH attempted but failed";
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_OBSOLETE34:
328   case CURLE_OBSOLETE40:
329   case CURLE_OBSOLETE41:
330   case CURLE_OBSOLETE44:
331   case CURLE_OBSOLETE46:
332   case CURLE_OBSOLETE50:
333   case CURLE_OBSOLETE51:
334   case CURLE_OBSOLETE57:
335   case CURLE_OBSOLETE62:
336   case CURLE_OBSOLETE75:
337   case CURLE_OBSOLETE76:
338   case CURL_LAST:
339     break;
340   }
341   /*
342    * By using a switch, gcc -Wall will complain about enum values
343    * which do not appear, helping keep this function up-to-date.
344    * By using gcc -Wall -Werror, you cannot forget.
345    *
346    * A table would not have the same benefit. Most compilers will generate
347    * code similar to a table in any case, so there is little performance gain
348    * from a table. Something is broken for the user's application, anyways, so
349    * does it matter how fast it _does not_ work?
350    *
351    * The line number for the error will be near this comment, which is why it
352    * 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_ABORTED_BY_CALLBACK:
405     return "Operation was aborted by an application callback";
406 
407   case CURLM_UNRECOVERABLE_POLL:
408     return "Unrecoverable error in select/poll";
409 
410   case CURLM_LAST:
411     break;
412   }
413 
414   return "Unknown error";
415 #else
416   if(error == CURLM_OK)
417     return "No error";
418   else
419     return "Error";
420 #endif
421 }
422 
423 const char *
curl_share_strerror(CURLSHcode error)424 curl_share_strerror(CURLSHcode error)
425 {
426 #ifndef CURL_DISABLE_VERBOSE_STRINGS
427   switch(error) {
428   case CURLSHE_OK:
429     return "No error";
430 
431   case CURLSHE_BAD_OPTION:
432     return "Unknown share option";
433 
434   case CURLSHE_IN_USE:
435     return "Share currently in use";
436 
437   case CURLSHE_INVALID:
438     return "Invalid share handle";
439 
440   case CURLSHE_NOMEM:
441     return "Out of memory";
442 
443   case CURLSHE_NOT_BUILT_IN:
444     return "Feature not enabled in this library";
445 
446   case CURLSHE_LAST:
447     break;
448   }
449 
450   return "CURLSHcode unknown";
451 #else
452   if(error == CURLSHE_OK)
453     return "No error";
454   else
455     return "Error";
456 #endif
457 }
458 
459 const char *
curl_url_strerror(CURLUcode error)460 curl_url_strerror(CURLUcode error)
461 {
462 #ifndef CURL_DISABLE_VERBOSE_STRINGS
463   switch(error) {
464   case CURLUE_OK:
465     return "No error";
466 
467   case CURLUE_BAD_HANDLE:
468     return "An invalid CURLU pointer was passed as argument";
469 
470   case CURLUE_BAD_PARTPOINTER:
471     return "An invalid 'part' argument was passed as argument";
472 
473   case CURLUE_MALFORMED_INPUT:
474     return "Malformed input to a URL function";
475 
476   case CURLUE_BAD_PORT_NUMBER:
477     return "Port number was not a decimal number between 0 and 65535";
478 
479   case CURLUE_UNSUPPORTED_SCHEME:
480     return "Unsupported URL scheme";
481 
482   case CURLUE_URLDECODE:
483     return "URL decode error, most likely because of rubbish in the input";
484 
485   case CURLUE_OUT_OF_MEMORY:
486     return "A memory function failed";
487 
488   case CURLUE_USER_NOT_ALLOWED:
489     return "Credentials was passed in the URL when prohibited";
490 
491   case CURLUE_UNKNOWN_PART:
492     return "An unknown part ID was passed to a URL API function";
493 
494   case CURLUE_NO_SCHEME:
495     return "No scheme part in the URL";
496 
497   case CURLUE_NO_USER:
498     return "No user part in the URL";
499 
500   case CURLUE_NO_PASSWORD:
501     return "No password part in the URL";
502 
503   case CURLUE_NO_OPTIONS:
504     return "No options part in the URL";
505 
506   case CURLUE_NO_HOST:
507     return "No host part in the URL";
508 
509   case CURLUE_NO_PORT:
510     return "No port part in the URL";
511 
512   case CURLUE_NO_QUERY:
513     return "No query part in the URL";
514 
515   case CURLUE_NO_FRAGMENT:
516     return "No fragment part in the URL";
517 
518   case CURLUE_NO_ZONEID:
519     return "No zoneid part in the URL";
520 
521   case CURLUE_BAD_LOGIN:
522     return "Bad login part";
523 
524   case CURLUE_BAD_IPV6:
525     return "Bad IPv6 address";
526 
527   case CURLUE_BAD_HOSTNAME:
528     return "Bad hostname";
529 
530   case CURLUE_BAD_FILE_URL:
531     return "Bad file:// URL";
532 
533   case CURLUE_BAD_SLASHES:
534     return "Unsupported number of slashes following scheme";
535 
536   case CURLUE_BAD_SCHEME:
537     return "Bad scheme";
538 
539   case CURLUE_BAD_PATH:
540     return "Bad path";
541 
542   case CURLUE_BAD_FRAGMENT:
543     return "Bad fragment";
544 
545   case CURLUE_BAD_QUERY:
546     return "Bad query";
547 
548   case CURLUE_BAD_PASSWORD:
549     return "Bad password";
550 
551   case CURLUE_BAD_USER:
552     return "Bad user";
553 
554   case CURLUE_LACKS_IDN:
555     return "libcurl lacks IDN support";
556 
557   case CURLUE_TOO_LARGE:
558     return "A value or data field is larger than allowed";
559 
560   case CURLUE_LAST:
561     break;
562   }
563 
564   return "CURLUcode unknown";
565 #else
566   if(error == CURLUE_OK)
567     return "No error";
568   else
569     return "Error";
570 #endif
571 }
572 
573 #ifdef USE_WINSOCK
574 /* This is a helper function for Curl_strerror that converts Winsock error
575  * codes (WSAGetLastError) to error messages.
576  * Returns NULL if no error message was found for error code.
577  */
578 static const char *
get_winsock_error(int err,char * buf,size_t len)579 get_winsock_error(int err, char *buf, size_t len)
580 {
581 #ifndef CURL_DISABLE_VERBOSE_STRINGS
582   const char *p;
583   size_t alen;
584 #endif
585 
586   if(!len)
587     return NULL;
588 
589   *buf = '\0';
590 
591 #ifdef CURL_DISABLE_VERBOSE_STRINGS
592   (void)err;
593   return NULL;
594 #else
595   switch(err) {
596   case WSAEINTR:
597     p = "Call interrupted";
598     break;
599   case WSAEBADF:
600     p = "Bad file";
601     break;
602   case WSAEACCES:
603     p = "Bad access";
604     break;
605   case WSAEFAULT:
606     p = "Bad argument";
607     break;
608   case WSAEINVAL:
609     p = "Invalid arguments";
610     break;
611   case WSAEMFILE:
612     p = "Out of file descriptors";
613     break;
614   case WSAEWOULDBLOCK:
615     p = "Call would block";
616     break;
617   case WSAEINPROGRESS:
618   case WSAEALREADY:
619     p = "Blocking call in progress";
620     break;
621   case WSAENOTSOCK:
622     p = "Descriptor is not a socket";
623     break;
624   case WSAEDESTADDRREQ:
625     p = "Need destination address";
626     break;
627   case WSAEMSGSIZE:
628     p = "Bad message size";
629     break;
630   case WSAEPROTOTYPE:
631     p = "Bad protocol";
632     break;
633   case WSAENOPROTOOPT:
634     p = "Protocol option is unsupported";
635     break;
636   case WSAEPROTONOSUPPORT:
637     p = "Protocol is unsupported";
638     break;
639   case WSAESOCKTNOSUPPORT:
640     p = "Socket is unsupported";
641     break;
642   case WSAEOPNOTSUPP:
643     p = "Operation not supported";
644     break;
645   case WSAEAFNOSUPPORT:
646     p = "Address family not supported";
647     break;
648   case WSAEPFNOSUPPORT:
649     p = "Protocol family not supported";
650     break;
651   case WSAEADDRINUSE:
652     p = "Address already in use";
653     break;
654   case WSAEADDRNOTAVAIL:
655     p = "Address not available";
656     break;
657   case WSAENETDOWN:
658     p = "Network down";
659     break;
660   case WSAENETUNREACH:
661     p = "Network unreachable";
662     break;
663   case WSAENETRESET:
664     p = "Network has been reset";
665     break;
666   case WSAECONNABORTED:
667     p = "Connection was aborted";
668     break;
669   case WSAECONNRESET:
670     p = "Connection was reset";
671     break;
672   case WSAENOBUFS:
673     p = "No buffer space";
674     break;
675   case WSAEISCONN:
676     p = "Socket is already connected";
677     break;
678   case WSAENOTCONN:
679     p = "Socket is not connected";
680     break;
681   case WSAESHUTDOWN:
682     p = "Socket has been shut down";
683     break;
684   case WSAETOOMANYREFS:
685     p = "Too many references";
686     break;
687   case WSAETIMEDOUT:
688     p = "Timed out";
689     break;
690   case WSAECONNREFUSED:
691     p = "Connection refused";
692     break;
693   case WSAELOOP:
694     p = "Loop??";
695     break;
696   case WSAENAMETOOLONG:
697     p = "Name too long";
698     break;
699   case WSAEHOSTDOWN:
700     p = "Host down";
701     break;
702   case WSAEHOSTUNREACH:
703     p = "Host unreachable";
704     break;
705   case WSAENOTEMPTY:
706     p = "Not empty";
707     break;
708   case WSAEPROCLIM:
709     p = "Process limit reached";
710     break;
711   case WSAEUSERS:
712     p = "Too many users";
713     break;
714   case WSAEDQUOT:
715     p = "Bad quota";
716     break;
717   case WSAESTALE:
718     p = "Something is stale";
719     break;
720   case WSAEREMOTE:
721     p = "Remote error";
722     break;
723 #ifdef WSAEDISCON  /* missing in SalfordC! */
724   case WSAEDISCON:
725     p = "Disconnected";
726     break;
727 #endif
728     /* Extended Winsock errors */
729   case WSASYSNOTREADY:
730     p = "Winsock library is not ready";
731     break;
732   case WSANOTINITIALISED:
733     p = "Winsock library not initialised";
734     break;
735   case WSAVERNOTSUPPORTED:
736     p = "Winsock version not supported";
737     break;
738 
739     /* getXbyY() errors (already handled in herrmsg):
740      * Authoritative Answer: Host not found */
741   case WSAHOST_NOT_FOUND:
742     p = "Host not found";
743     break;
744 
745     /* Non-Authoritative: Host not found, or SERVERFAIL */
746   case WSATRY_AGAIN:
747     p = "Host not found, try again";
748     break;
749 
750     /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
751   case WSANO_RECOVERY:
752     p = "Unrecoverable error in call to nameserver";
753     break;
754 
755     /* Valid name, no data record of requested type */
756   case WSANO_DATA:
757     p = "No data record of requested type";
758     break;
759 
760   default:
761     return NULL;
762   }
763   alen = strlen(p);
764   if(alen < len)
765     strcpy(buf, p);
766   return buf;
767 #endif
768 }
769 #endif   /* USE_WINSOCK */
770 
771 #if defined(_WIN32) || defined(_WIN32_WCE)
772 /* This is a helper function for Curl_strerror that converts Windows API error
773  * codes (GetLastError) to error messages.
774  * Returns NULL if no error message was found for error code.
775  */
776 static const char *
get_winapi_error(int err,char * buf,size_t buflen)777 get_winapi_error(int err, char *buf, size_t buflen)
778 {
779   char *p;
780   wchar_t wbuf[256];
781 
782   if(!buflen)
783     return NULL;
784 
785   *buf = '\0';
786   *wbuf = L'\0';
787 
788   /* We return the local codepage version of the error string because if it is
789      output to the user's terminal it will likely be with functions which
790      expect the local codepage (eg fprintf, failf, infof).
791      FormatMessageW -> wcstombs is used for Windows CE compatibility. */
792   if(FormatMessageW((FORMAT_MESSAGE_FROM_SYSTEM |
793                      FORMAT_MESSAGE_IGNORE_INSERTS), NULL, (DWORD)err,
794                     LANG_NEUTRAL, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL)) {
795     size_t written = wcstombs(buf, wbuf, buflen - 1);
796     if(written != (size_t)-1)
797       buf[written] = '\0';
798     else
799       *buf = '\0';
800   }
801 
802   /* Truncate multiple lines */
803   p = strchr(buf, '\n');
804   if(p) {
805     if(p > buf && *(p-1) == '\r')
806       *(p-1) = '\0';
807     else
808       *p = '\0';
809   }
810 
811   return (*buf ? buf : NULL);
812 }
813 #endif /* _WIN32 || _WIN32_WCE */
814 
815 /*
816  * Our thread-safe and smart strerror() replacement.
817  *
818  * The 'err' argument passed in to this function MUST be a true errno number
819  * as reported on this system. We do no range checking on the number before
820  * we pass it to the "number-to-message" conversion function and there might
821  * be systems that do not do proper range checking in there themselves.
822  *
823  * We do not do range checking (on systems other than Windows) since there is
824  * no good reliable and portable way to do it.
825  *
826  * On Windows different types of error codes overlap. This function has an
827  * order of preference when trying to match error codes:
828  * CRT (errno), Winsock (WSAGetLastError), Windows API (GetLastError).
829  *
830  * It may be more correct to call one of the variant functions instead:
831  * Call Curl_sspi_strerror if the error code is definitely Windows SSPI.
832  * Call Curl_winapi_strerror if the error code is definitely Windows API.
833  */
Curl_strerror(int err,char * buf,size_t buflen)834 const char *Curl_strerror(int err, char *buf, size_t buflen)
835 {
836 #ifdef PRESERVE_WINDOWS_ERROR_CODE
837   DWORD old_win_err = GetLastError();
838 #endif
839   int old_errno = errno;
840   char *p;
841 
842   if(!buflen)
843     return NULL;
844 
845 #ifndef _WIN32
846   DEBUGASSERT(err >= 0);
847 #endif
848 
849   *buf = '\0';
850 
851 #if defined(_WIN32) || defined(_WIN32_WCE)
852 #if defined(_WIN32)
853   /* 'sys_nerr' is the maximum errno number, it is not widely portable */
854   if(err >= 0 && err < sys_nerr)
855     msnprintf(buf, buflen, "%s", sys_errlist[err]);
856   else
857 #endif
858   {
859     if(
860 #ifdef USE_WINSOCK
861        !get_winsock_error(err, buf, buflen) &&
862 #endif
863        !get_winapi_error(err, buf, buflen))
864       msnprintf(buf, buflen, "Unknown error %d (%#x)", err, err);
865   }
866 #else /* not Windows coming up */
867 
868 #if defined(HAVE_STRERROR_R) && defined(HAVE_POSIX_STRERROR_R)
869  /*
870   * The POSIX-style strerror_r() may set errno to ERANGE if insufficient
871   * storage is supplied via 'strerrbuf' and 'buflen' to hold the generated
872   * message string, or EINVAL if 'errnum' is not a valid error number.
873   */
874   if(0 != strerror_r(err, buf, buflen)) {
875     if('\0' == buf[0])
876       msnprintf(buf, buflen, "Unknown error %d", err);
877   }
878 #elif defined(HAVE_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R)
879  /*
880   * The glibc-style strerror_r() only *might* use the buffer we pass to
881   * the function, but it always returns the error message as a pointer,
882   * so we must copy that string unconditionally (if non-NULL).
883   */
884   {
885     char buffer[256];
886     char *msg = strerror_r(err, buffer, sizeof(buffer));
887     if(msg)
888       msnprintf(buf, buflen, "%s", msg);
889     else
890       msnprintf(buf, buflen, "Unknown error %d", err);
891   }
892 #else
893   {
894     /* !checksrc! disable STRERROR 1 */
895     const char *msg = strerror(err);
896     if(msg)
897       msnprintf(buf, buflen, "%s", msg);
898     else
899       msnprintf(buf, buflen, "Unknown error %d", err);
900   }
901 #endif
902 
903 #endif /* end of not Windows */
904 
905   /* strip trailing '\r\n' or '\n'. */
906   p = strrchr(buf, '\n');
907   if(p && (p - buf) >= 2)
908     *p = '\0';
909   p = strrchr(buf, '\r');
910   if(p && (p - buf) >= 1)
911     *p = '\0';
912 
913   if(errno != old_errno)
914     errno = old_errno;
915 
916 #ifdef PRESERVE_WINDOWS_ERROR_CODE
917   if(old_win_err != GetLastError())
918     SetLastError(old_win_err);
919 #endif
920 
921   return buf;
922 }
923 
924 /*
925  * Curl_winapi_strerror:
926  * Variant of Curl_strerror if the error code is definitely Windows API.
927  */
928 #if defined(_WIN32) || defined(_WIN32_WCE)
Curl_winapi_strerror(DWORD err,char * buf,size_t buflen)929 const char *Curl_winapi_strerror(DWORD err, char *buf, size_t buflen)
930 {
931 #ifdef PRESERVE_WINDOWS_ERROR_CODE
932   DWORD old_win_err = GetLastError();
933 #endif
934   int old_errno = errno;
935 
936   if(!buflen)
937     return NULL;
938 
939   *buf = '\0';
940 
941 #ifndef CURL_DISABLE_VERBOSE_STRINGS
942   if(!get_winapi_error((int)err, buf, buflen)) {
943     msnprintf(buf, buflen, "Unknown error %lu (0x%08lX)", err, err);
944   }
945 #else
946   {
947     const char *txt = (err == ERROR_SUCCESS) ? "No error" : "Error";
948     if(strlen(txt) < buflen)
949       strcpy(buf, txt);
950   }
951 #endif
952 
953   if(errno != old_errno)
954     errno = old_errno;
955 
956 #ifdef PRESERVE_WINDOWS_ERROR_CODE
957   if(old_win_err != GetLastError())
958     SetLastError(old_win_err);
959 #endif
960 
961   return buf;
962 }
963 #endif /* _WIN32 || _WIN32_WCE */
964 
965 #ifdef USE_WINDOWS_SSPI
966 /*
967  * Curl_sspi_strerror:
968  * Variant of Curl_strerror if the error code is definitely Windows SSPI.
969  */
Curl_sspi_strerror(int err,char * buf,size_t buflen)970 const char *Curl_sspi_strerror(int err, char *buf, size_t buflen)
971 {
972 #ifdef PRESERVE_WINDOWS_ERROR_CODE
973   DWORD old_win_err = GetLastError();
974 #endif
975   int old_errno = errno;
976   const char *txt;
977 
978   if(!buflen)
979     return NULL;
980 
981   *buf = '\0';
982 
983 #ifndef CURL_DISABLE_VERBOSE_STRINGS
984 
985   switch(err) {
986     case SEC_E_OK:
987       txt = "No error";
988       break;
989 #define SEC2TXT(sec) case sec: txt = #sec; break
990     SEC2TXT(CRYPT_E_REVOKED);
991     SEC2TXT(CRYPT_E_NO_REVOCATION_DLL);
992     SEC2TXT(CRYPT_E_NO_REVOCATION_CHECK);
993     SEC2TXT(CRYPT_E_REVOCATION_OFFLINE);
994     SEC2TXT(CRYPT_E_NOT_IN_REVOCATION_DATABASE);
995     SEC2TXT(SEC_E_ALGORITHM_MISMATCH);
996     SEC2TXT(SEC_E_BAD_BINDINGS);
997     SEC2TXT(SEC_E_BAD_PKGID);
998     SEC2TXT(SEC_E_BUFFER_TOO_SMALL);
999     SEC2TXT(SEC_E_CANNOT_INSTALL);
1000     SEC2TXT(SEC_E_CANNOT_PACK);
1001     SEC2TXT(SEC_E_CERT_EXPIRED);
1002     SEC2TXT(SEC_E_CERT_UNKNOWN);
1003     SEC2TXT(SEC_E_CERT_WRONG_USAGE);
1004     SEC2TXT(SEC_E_CONTEXT_EXPIRED);
1005     SEC2TXT(SEC_E_CROSSREALM_DELEGATION_FAILURE);
1006     SEC2TXT(SEC_E_CRYPTO_SYSTEM_INVALID);
1007     SEC2TXT(SEC_E_DECRYPT_FAILURE);
1008     SEC2TXT(SEC_E_DELEGATION_POLICY);
1009     SEC2TXT(SEC_E_DELEGATION_REQUIRED);
1010     SEC2TXT(SEC_E_DOWNGRADE_DETECTED);
1011     SEC2TXT(SEC_E_ENCRYPT_FAILURE);
1012     SEC2TXT(SEC_E_ILLEGAL_MESSAGE);
1013     SEC2TXT(SEC_E_INCOMPLETE_CREDENTIALS);
1014     SEC2TXT(SEC_E_INCOMPLETE_MESSAGE);
1015     SEC2TXT(SEC_E_INSUFFICIENT_MEMORY);
1016     SEC2TXT(SEC_E_INTERNAL_ERROR);
1017     SEC2TXT(SEC_E_INVALID_HANDLE);
1018     SEC2TXT(SEC_E_INVALID_PARAMETER);
1019     SEC2TXT(SEC_E_INVALID_TOKEN);
1020     SEC2TXT(SEC_E_ISSUING_CA_UNTRUSTED);
1021     SEC2TXT(SEC_E_ISSUING_CA_UNTRUSTED_KDC);
1022     SEC2TXT(SEC_E_KDC_CERT_EXPIRED);
1023     SEC2TXT(SEC_E_KDC_CERT_REVOKED);
1024     SEC2TXT(SEC_E_KDC_INVALID_REQUEST);
1025     SEC2TXT(SEC_E_KDC_UNABLE_TO_REFER);
1026     SEC2TXT(SEC_E_KDC_UNKNOWN_ETYPE);
1027     SEC2TXT(SEC_E_LOGON_DENIED);
1028     SEC2TXT(SEC_E_MAX_REFERRALS_EXCEEDED);
1029     SEC2TXT(SEC_E_MESSAGE_ALTERED);
1030     SEC2TXT(SEC_E_MULTIPLE_ACCOUNTS);
1031     SEC2TXT(SEC_E_MUST_BE_KDC);
1032     SEC2TXT(SEC_E_NOT_OWNER);
1033     SEC2TXT(SEC_E_NO_AUTHENTICATING_AUTHORITY);
1034     SEC2TXT(SEC_E_NO_CREDENTIALS);
1035     SEC2TXT(SEC_E_NO_IMPERSONATION);
1036     SEC2TXT(SEC_E_NO_IP_ADDRESSES);
1037     SEC2TXT(SEC_E_NO_KERB_KEY);
1038     SEC2TXT(SEC_E_NO_PA_DATA);
1039     SEC2TXT(SEC_E_NO_S4U_PROT_SUPPORT);
1040     SEC2TXT(SEC_E_NO_TGT_REPLY);
1041     SEC2TXT(SEC_E_OUT_OF_SEQUENCE);
1042     SEC2TXT(SEC_E_PKINIT_CLIENT_FAILURE);
1043     SEC2TXT(SEC_E_PKINIT_NAME_MISMATCH);
1044     SEC2TXT(SEC_E_POLICY_NLTM_ONLY);
1045     SEC2TXT(SEC_E_QOP_NOT_SUPPORTED);
1046     SEC2TXT(SEC_E_REVOCATION_OFFLINE_C);
1047     SEC2TXT(SEC_E_REVOCATION_OFFLINE_KDC);
1048     SEC2TXT(SEC_E_SECPKG_NOT_FOUND);
1049     SEC2TXT(SEC_E_SECURITY_QOS_FAILED);
1050     SEC2TXT(SEC_E_SHUTDOWN_IN_PROGRESS);
1051     SEC2TXT(SEC_E_SMARTCARD_CERT_EXPIRED);
1052     SEC2TXT(SEC_E_SMARTCARD_CERT_REVOKED);
1053     SEC2TXT(SEC_E_SMARTCARD_LOGON_REQUIRED);
1054     SEC2TXT(SEC_E_STRONG_CRYPTO_NOT_SUPPORTED);
1055     SEC2TXT(SEC_E_TARGET_UNKNOWN);
1056     SEC2TXT(SEC_E_TIME_SKEW);
1057     SEC2TXT(SEC_E_TOO_MANY_PRINCIPALS);
1058     SEC2TXT(SEC_E_UNFINISHED_CONTEXT_DELETED);
1059     SEC2TXT(SEC_E_UNKNOWN_CREDENTIALS);
1060     SEC2TXT(SEC_E_UNSUPPORTED_FUNCTION);
1061     SEC2TXT(SEC_E_UNSUPPORTED_PREAUTH);
1062     SEC2TXT(SEC_E_UNTRUSTED_ROOT);
1063     SEC2TXT(SEC_E_WRONG_CREDENTIAL_HANDLE);
1064     SEC2TXT(SEC_E_WRONG_PRINCIPAL);
1065     SEC2TXT(SEC_I_COMPLETE_AND_CONTINUE);
1066     SEC2TXT(SEC_I_COMPLETE_NEEDED);
1067     SEC2TXT(SEC_I_CONTEXT_EXPIRED);
1068     SEC2TXT(SEC_I_CONTINUE_NEEDED);
1069     SEC2TXT(SEC_I_INCOMPLETE_CREDENTIALS);
1070     SEC2TXT(SEC_I_LOCAL_LOGON);
1071     SEC2TXT(SEC_I_NO_LSA_CONTEXT);
1072     SEC2TXT(SEC_I_RENEGOTIATE);
1073     SEC2TXT(SEC_I_SIGNATURE_NEEDED);
1074     default:
1075       txt = "Unknown error";
1076   }
1077 
1078   if(err == SEC_E_ILLEGAL_MESSAGE) {
1079     msnprintf(buf, buflen,
1080               "SEC_E_ILLEGAL_MESSAGE (0x%08X) - This error usually occurs "
1081               "when a fatal SSL/TLS alert is received (e.g. handshake failed)."
1082               " More detail may be available in the Windows System event log.",
1083               err);
1084   }
1085   else {
1086     char msgbuf[256];
1087     if(get_winapi_error(err, msgbuf, sizeof(msgbuf)))
1088       msnprintf(buf, buflen, "%s (0x%08X) - %s", txt, err, msgbuf);
1089     else
1090       msnprintf(buf, buflen, "%s (0x%08X)", txt, err);
1091   }
1092 
1093 #else
1094   if(err == SEC_E_OK)
1095     txt = "No error";
1096   else
1097     txt = "Error";
1098   if(buflen > strlen(txt))
1099     strcpy(buf, txt);
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