xref: /curl/lib/strerror.c (revision 9cc24640)
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_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 "Could not resume download";
162 
163   case CURLE_FILE_COULDNT_READ_FILE:
164     return "Could not 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 "Could not 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   case CURLE_TOO_LARGE:
323     return "A value or data field grew larger than allowed";
324 
325   case CURLE_ECH_REQUIRED:
326     return "ECH attempted but failed";
327 
328     /* error codes not used by current libcurl */
329   case CURLE_OBSOLETE20:
330   case CURLE_OBSOLETE24:
331   case CURLE_OBSOLETE29:
332   case CURLE_OBSOLETE32:
333   case CURLE_OBSOLETE40:
334   case CURLE_OBSOLETE44:
335   case CURLE_OBSOLETE46:
336   case CURLE_OBSOLETE50:
337   case CURLE_OBSOLETE51:
338   case CURLE_OBSOLETE57:
339   case CURLE_OBSOLETE62:
340   case CURLE_OBSOLETE75:
341   case CURLE_OBSOLETE76:
342   case CURL_LAST:
343     break;
344   }
345   /*
346    * By using a switch, gcc -Wall will complain about enum values
347    * which do not appear, helping keep this function up-to-date.
348    * By using gcc -Wall -Werror, you cannot forget.
349    *
350    * A table would not have the same benefit. Most compilers will generate
351    * code similar to a table in any case, so there is little performance gain
352    * from a table. Something is broken for the user's application, anyways, so
353    * does it matter how fast it _does not_ work?
354    *
355    * The line number for the error will be near this comment, which is why it
356    * is here, and not at the start of the switch.
357    */
358   return "Unknown error";
359 #else
360   if(!error)
361     return "No error";
362   else
363     return "Error";
364 #endif
365 }
366 
367 const char *
curl_multi_strerror(CURLMcode error)368 curl_multi_strerror(CURLMcode error)
369 {
370 #ifndef CURL_DISABLE_VERBOSE_STRINGS
371   switch(error) {
372   case CURLM_CALL_MULTI_PERFORM:
373     return "Please call curl_multi_perform() soon";
374 
375   case CURLM_OK:
376     return "No error";
377 
378   case CURLM_BAD_HANDLE:
379     return "Invalid multi handle";
380 
381   case CURLM_BAD_EASY_HANDLE:
382     return "Invalid easy handle";
383 
384   case CURLM_OUT_OF_MEMORY:
385     return "Out of memory";
386 
387   case CURLM_INTERNAL_ERROR:
388     return "Internal error";
389 
390   case CURLM_BAD_SOCKET:
391     return "Invalid socket argument";
392 
393   case CURLM_UNKNOWN_OPTION:
394     return "Unknown option";
395 
396   case CURLM_ADDED_ALREADY:
397     return "The easy handle is already added to a multi handle";
398 
399   case CURLM_RECURSIVE_API_CALL:
400     return "API function called from within callback";
401 
402   case CURLM_WAKEUP_FAILURE:
403     return "Wakeup is unavailable or failed";
404 
405   case CURLM_BAD_FUNCTION_ARGUMENT:
406     return "A libcurl function was given a bad argument";
407 
408   case CURLM_ABORTED_BY_CALLBACK:
409     return "Operation was aborted by an application callback";
410 
411   case CURLM_UNRECOVERABLE_POLL:
412     return "Unrecoverable error in select/poll";
413 
414   case CURLM_LAST:
415     break;
416   }
417 
418   return "Unknown error";
419 #else
420   if(error == CURLM_OK)
421     return "No error";
422   else
423     return "Error";
424 #endif
425 }
426 
427 const char *
curl_share_strerror(CURLSHcode error)428 curl_share_strerror(CURLSHcode error)
429 {
430 #ifndef CURL_DISABLE_VERBOSE_STRINGS
431   switch(error) {
432   case CURLSHE_OK:
433     return "No error";
434 
435   case CURLSHE_BAD_OPTION:
436     return "Unknown share option";
437 
438   case CURLSHE_IN_USE:
439     return "Share currently in use";
440 
441   case CURLSHE_INVALID:
442     return "Invalid share handle";
443 
444   case CURLSHE_NOMEM:
445     return "Out of memory";
446 
447   case CURLSHE_NOT_BUILT_IN:
448     return "Feature not enabled in this library";
449 
450   case CURLSHE_LAST:
451     break;
452   }
453 
454   return "CURLSHcode unknown";
455 #else
456   if(error == CURLSHE_OK)
457     return "No error";
458   else
459     return "Error";
460 #endif
461 }
462 
463 const char *
curl_url_strerror(CURLUcode error)464 curl_url_strerror(CURLUcode error)
465 {
466 #ifndef CURL_DISABLE_VERBOSE_STRINGS
467   switch(error) {
468   case CURLUE_OK:
469     return "No error";
470 
471   case CURLUE_BAD_HANDLE:
472     return "An invalid CURLU pointer was passed as argument";
473 
474   case CURLUE_BAD_PARTPOINTER:
475     return "An invalid 'part' argument was passed as argument";
476 
477   case CURLUE_MALFORMED_INPUT:
478     return "Malformed input to a URL function";
479 
480   case CURLUE_BAD_PORT_NUMBER:
481     return "Port number was not a decimal number between 0 and 65535";
482 
483   case CURLUE_UNSUPPORTED_SCHEME:
484     return "Unsupported URL scheme";
485 
486   case CURLUE_URLDECODE:
487     return "URL decode error, most likely because of rubbish in the input";
488 
489   case CURLUE_OUT_OF_MEMORY:
490     return "A memory function failed";
491 
492   case CURLUE_USER_NOT_ALLOWED:
493     return "Credentials was passed in the URL when prohibited";
494 
495   case CURLUE_UNKNOWN_PART:
496     return "An unknown part ID was passed to a URL API function";
497 
498   case CURLUE_NO_SCHEME:
499     return "No scheme part in the URL";
500 
501   case CURLUE_NO_USER:
502     return "No user part in the URL";
503 
504   case CURLUE_NO_PASSWORD:
505     return "No password part in the URL";
506 
507   case CURLUE_NO_OPTIONS:
508     return "No options part in the URL";
509 
510   case CURLUE_NO_HOST:
511     return "No host part in the URL";
512 
513   case CURLUE_NO_PORT:
514     return "No port part in the URL";
515 
516   case CURLUE_NO_QUERY:
517     return "No query part in the URL";
518 
519   case CURLUE_NO_FRAGMENT:
520     return "No fragment part in the URL";
521 
522   case CURLUE_NO_ZONEID:
523     return "No zoneid part in the URL";
524 
525   case CURLUE_BAD_LOGIN:
526     return "Bad login part";
527 
528   case CURLUE_BAD_IPV6:
529     return "Bad IPv6 address";
530 
531   case CURLUE_BAD_HOSTNAME:
532     return "Bad hostname";
533 
534   case CURLUE_BAD_FILE_URL:
535     return "Bad file:// URL";
536 
537   case CURLUE_BAD_SLASHES:
538     return "Unsupported number of slashes following scheme";
539 
540   case CURLUE_BAD_SCHEME:
541     return "Bad scheme";
542 
543   case CURLUE_BAD_PATH:
544     return "Bad path";
545 
546   case CURLUE_BAD_FRAGMENT:
547     return "Bad fragment";
548 
549   case CURLUE_BAD_QUERY:
550     return "Bad query";
551 
552   case CURLUE_BAD_PASSWORD:
553     return "Bad password";
554 
555   case CURLUE_BAD_USER:
556     return "Bad user";
557 
558   case CURLUE_LACKS_IDN:
559     return "libcurl lacks IDN support";
560 
561   case CURLUE_TOO_LARGE:
562     return "A value or data field is larger than allowed";
563 
564   case CURLUE_LAST:
565     break;
566   }
567 
568   return "CURLUcode unknown";
569 #else
570   if(error == CURLUE_OK)
571     return "No error";
572   else
573     return "Error";
574 #endif
575 }
576 
577 #ifdef USE_WINSOCK
578 /* This is a helper function for Curl_strerror that converts Winsock error
579  * codes (WSAGetLastError) to error messages.
580  * Returns NULL if no error message was found for error code.
581  */
582 static const char *
get_winsock_error(int err,char * buf,size_t len)583 get_winsock_error(int err, char *buf, size_t len)
584 {
585 #ifndef CURL_DISABLE_VERBOSE_STRINGS
586   const char *p;
587   size_t alen;
588 #endif
589 
590   if(!len)
591     return NULL;
592 
593   *buf = '\0';
594 
595 #ifdef CURL_DISABLE_VERBOSE_STRINGS
596   (void)err;
597   return NULL;
598 #else
599   switch(err) {
600   case WSAEINTR:
601     p = "Call interrupted";
602     break;
603   case WSAEBADF:
604     p = "Bad file";
605     break;
606   case WSAEACCES:
607     p = "Bad access";
608     break;
609   case WSAEFAULT:
610     p = "Bad argument";
611     break;
612   case WSAEINVAL:
613     p = "Invalid arguments";
614     break;
615   case WSAEMFILE:
616     p = "Out of file descriptors";
617     break;
618   case WSAEWOULDBLOCK:
619     p = "Call would block";
620     break;
621   case WSAEINPROGRESS:
622   case WSAEALREADY:
623     p = "Blocking call in progress";
624     break;
625   case WSAENOTSOCK:
626     p = "Descriptor is not a socket";
627     break;
628   case WSAEDESTADDRREQ:
629     p = "Need destination address";
630     break;
631   case WSAEMSGSIZE:
632     p = "Bad message size";
633     break;
634   case WSAEPROTOTYPE:
635     p = "Bad protocol";
636     break;
637   case WSAENOPROTOOPT:
638     p = "Protocol option is unsupported";
639     break;
640   case WSAEPROTONOSUPPORT:
641     p = "Protocol is unsupported";
642     break;
643   case WSAESOCKTNOSUPPORT:
644     p = "Socket is unsupported";
645     break;
646   case WSAEOPNOTSUPP:
647     p = "Operation not supported";
648     break;
649   case WSAEAFNOSUPPORT:
650     p = "Address family not supported";
651     break;
652   case WSAEPFNOSUPPORT:
653     p = "Protocol family not supported";
654     break;
655   case WSAEADDRINUSE:
656     p = "Address already in use";
657     break;
658   case WSAEADDRNOTAVAIL:
659     p = "Address not available";
660     break;
661   case WSAENETDOWN:
662     p = "Network down";
663     break;
664   case WSAENETUNREACH:
665     p = "Network unreachable";
666     break;
667   case WSAENETRESET:
668     p = "Network has been reset";
669     break;
670   case WSAECONNABORTED:
671     p = "Connection was aborted";
672     break;
673   case WSAECONNRESET:
674     p = "Connection was reset";
675     break;
676   case WSAENOBUFS:
677     p = "No buffer space";
678     break;
679   case WSAEISCONN:
680     p = "Socket is already connected";
681     break;
682   case WSAENOTCONN:
683     p = "Socket is not connected";
684     break;
685   case WSAESHUTDOWN:
686     p = "Socket has been shut down";
687     break;
688   case WSAETOOMANYREFS:
689     p = "Too many references";
690     break;
691   case WSAETIMEDOUT:
692     p = "Timed out";
693     break;
694   case WSAECONNREFUSED:
695     p = "Connection refused";
696     break;
697   case WSAELOOP:
698     p = "Loop??";
699     break;
700   case WSAENAMETOOLONG:
701     p = "Name too long";
702     break;
703   case WSAEHOSTDOWN:
704     p = "Host down";
705     break;
706   case WSAEHOSTUNREACH:
707     p = "Host unreachable";
708     break;
709   case WSAENOTEMPTY:
710     p = "Not empty";
711     break;
712   case WSAEPROCLIM:
713     p = "Process limit reached";
714     break;
715   case WSAEUSERS:
716     p = "Too many users";
717     break;
718   case WSAEDQUOT:
719     p = "Bad quota";
720     break;
721   case WSAESTALE:
722     p = "Something is stale";
723     break;
724   case WSAEREMOTE:
725     p = "Remote error";
726     break;
727 #ifdef WSAEDISCON  /* missing in SalfordC! */
728   case WSAEDISCON:
729     p = "Disconnected";
730     break;
731 #endif
732     /* Extended Winsock errors */
733   case WSASYSNOTREADY:
734     p = "Winsock library is not ready";
735     break;
736   case WSANOTINITIALISED:
737     p = "Winsock library not initialised";
738     break;
739   case WSAVERNOTSUPPORTED:
740     p = "Winsock version not supported";
741     break;
742 
743     /* getXbyY() errors (already handled in herrmsg):
744      * Authoritative Answer: Host not found */
745   case WSAHOST_NOT_FOUND:
746     p = "Host not found";
747     break;
748 
749     /* Non-Authoritative: Host not found, or SERVERFAIL */
750   case WSATRY_AGAIN:
751     p = "Host not found, try again";
752     break;
753 
754     /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
755   case WSANO_RECOVERY:
756     p = "Unrecoverable error in call to nameserver";
757     break;
758 
759     /* Valid name, no data record of requested type */
760   case WSANO_DATA:
761     p = "No data record of requested type";
762     break;
763 
764   default:
765     return NULL;
766   }
767   alen = strlen(p);
768   if(alen < len)
769     strcpy(buf, p);
770   return buf;
771 #endif
772 }
773 #endif   /* USE_WINSOCK */
774 
775 #if defined(_WIN32) || defined(_WIN32_WCE)
776 /* This is a helper function for Curl_strerror that converts Windows API error
777  * codes (GetLastError) to error messages.
778  * Returns NULL if no error message was found for error code.
779  */
780 static const char *
get_winapi_error(int err,char * buf,size_t buflen)781 get_winapi_error(int err, char *buf, size_t buflen)
782 {
783   char *p;
784   wchar_t wbuf[256];
785 
786   if(!buflen)
787     return NULL;
788 
789   *buf = '\0';
790   *wbuf = L'\0';
791 
792   /* We return the local codepage version of the error string because if it is
793      output to the user's terminal it will likely be with functions which
794      expect the local codepage (eg fprintf, failf, infof).
795      FormatMessageW -> wcstombs is used for Windows CE compatibility. */
796   if(FormatMessageW((FORMAT_MESSAGE_FROM_SYSTEM |
797                      FORMAT_MESSAGE_IGNORE_INSERTS), NULL, (DWORD)err,
798                     LANG_NEUTRAL, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL)) {
799     size_t written = wcstombs(buf, wbuf, buflen - 1);
800     if(written != (size_t)-1)
801       buf[written] = '\0';
802     else
803       *buf = '\0';
804   }
805 
806   /* Truncate multiple lines */
807   p = strchr(buf, '\n');
808   if(p) {
809     if(p > buf && *(p-1) == '\r')
810       *(p-1) = '\0';
811     else
812       *p = '\0';
813   }
814 
815   return (*buf ? buf : NULL);
816 }
817 #endif /* _WIN32 || _WIN32_WCE */
818 
819 /*
820  * Our thread-safe and smart strerror() replacement.
821  *
822  * The 'err' argument passed in to this function MUST be a true errno number
823  * as reported on this system. We do no range checking on the number before
824  * we pass it to the "number-to-message" conversion function and there might
825  * be systems that do not do proper range checking in there themselves.
826  *
827  * We do not do range checking (on systems other than Windows) since there is
828  * no good reliable and portable way to do it.
829  *
830  * On Windows different types of error codes overlap. This function has an
831  * order of preference when trying to match error codes:
832  * CRT (errno), Winsock (WSAGetLastError), Windows API (GetLastError).
833  *
834  * It may be more correct to call one of the variant functions instead:
835  * Call Curl_sspi_strerror if the error code is definitely Windows SSPI.
836  * Call Curl_winapi_strerror if the error code is definitely Windows API.
837  */
Curl_strerror(int err,char * buf,size_t buflen)838 const char *Curl_strerror(int err, char *buf, size_t buflen)
839 {
840 #ifdef PRESERVE_WINDOWS_ERROR_CODE
841   DWORD old_win_err = GetLastError();
842 #endif
843   int old_errno = errno;
844   char *p;
845 
846   if(!buflen)
847     return NULL;
848 
849 #ifndef _WIN32
850   DEBUGASSERT(err >= 0);
851 #endif
852 
853   *buf = '\0';
854 
855 #if defined(_WIN32) || defined(_WIN32_WCE)
856 #if defined(_WIN32)
857   /* 'sys_nerr' is the maximum errno number, it is not widely portable */
858   if(err >= 0 && err < sys_nerr)
859     msnprintf(buf, buflen, "%s", sys_errlist[err]);
860   else
861 #endif
862   {
863     if(
864 #ifdef USE_WINSOCK
865        !get_winsock_error(err, buf, buflen) &&
866 #endif
867        !get_winapi_error(err, buf, buflen))
868       msnprintf(buf, buflen, "Unknown error %d (%#x)", err, err);
869   }
870 #else /* not Windows coming up */
871 
872 #if defined(HAVE_STRERROR_R) && defined(HAVE_POSIX_STRERROR_R)
873  /*
874   * The POSIX-style strerror_r() may set errno to ERANGE if insufficient
875   * storage is supplied via 'strerrbuf' and 'buflen' to hold the generated
876   * message string, or EINVAL if 'errnum' is not a valid error number.
877   */
878   if(0 != strerror_r(err, buf, buflen)) {
879     if('\0' == buf[0])
880       msnprintf(buf, buflen, "Unknown error %d", err);
881   }
882 #elif defined(HAVE_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R)
883  /*
884   * The glibc-style strerror_r() only *might* use the buffer we pass to
885   * the function, but it always returns the error message as a pointer,
886   * so we must copy that string unconditionally (if non-NULL).
887   */
888   {
889     char buffer[256];
890     char *msg = strerror_r(err, buffer, sizeof(buffer));
891     if(msg)
892       msnprintf(buf, buflen, "%s", msg);
893     else
894       msnprintf(buf, buflen, "Unknown error %d", err);
895   }
896 #else
897   {
898     /* !checksrc! disable STRERROR 1 */
899     const char *msg = strerror(err);
900     if(msg)
901       msnprintf(buf, buflen, "%s", msg);
902     else
903       msnprintf(buf, buflen, "Unknown error %d", err);
904   }
905 #endif
906 
907 #endif /* end of not Windows */
908 
909   /* strip trailing '\r\n' or '\n'. */
910   p = strrchr(buf, '\n');
911   if(p && (p - buf) >= 2)
912     *p = '\0';
913   p = strrchr(buf, '\r');
914   if(p && (p - buf) >= 1)
915     *p = '\0';
916 
917   if(errno != old_errno)
918     errno = old_errno;
919 
920 #ifdef PRESERVE_WINDOWS_ERROR_CODE
921   if(old_win_err != GetLastError())
922     SetLastError(old_win_err);
923 #endif
924 
925   return buf;
926 }
927 
928 /*
929  * Curl_winapi_strerror:
930  * Variant of Curl_strerror if the error code is definitely Windows API.
931  */
932 #if defined(_WIN32) || defined(_WIN32_WCE)
Curl_winapi_strerror(DWORD err,char * buf,size_t buflen)933 const char *Curl_winapi_strerror(DWORD err, char *buf, size_t buflen)
934 {
935 #ifdef PRESERVE_WINDOWS_ERROR_CODE
936   DWORD old_win_err = GetLastError();
937 #endif
938   int old_errno = errno;
939 
940   if(!buflen)
941     return NULL;
942 
943   *buf = '\0';
944 
945 #ifndef CURL_DISABLE_VERBOSE_STRINGS
946   if(!get_winapi_error((int)err, buf, buflen)) {
947     msnprintf(buf, buflen, "Unknown error %lu (0x%08lX)", err, err);
948   }
949 #else
950   {
951     const char *txt = (err == ERROR_SUCCESS) ? "No error" : "Error";
952     if(strlen(txt) < buflen)
953       strcpy(buf, txt);
954   }
955 #endif
956 
957   if(errno != old_errno)
958     errno = old_errno;
959 
960 #ifdef PRESERVE_WINDOWS_ERROR_CODE
961   if(old_win_err != GetLastError())
962     SetLastError(old_win_err);
963 #endif
964 
965   return buf;
966 }
967 #endif /* _WIN32 || _WIN32_WCE */
968 
969 #ifdef USE_WINDOWS_SSPI
970 /*
971  * Curl_sspi_strerror:
972  * Variant of Curl_strerror if the error code is definitely Windows SSPI.
973  */
Curl_sspi_strerror(int err,char * buf,size_t buflen)974 const char *Curl_sspi_strerror(int err, char *buf, size_t buflen)
975 {
976 #ifdef PRESERVE_WINDOWS_ERROR_CODE
977   DWORD old_win_err = GetLastError();
978 #endif
979   int old_errno = errno;
980   const char *txt;
981 
982   if(!buflen)
983     return NULL;
984 
985   *buf = '\0';
986 
987 #ifndef CURL_DISABLE_VERBOSE_STRINGS
988 
989   switch(err) {
990     case SEC_E_OK:
991       txt = "No error";
992       break;
993 #define SEC2TXT(sec) case sec: txt = #sec; break
994     SEC2TXT(CRYPT_E_REVOKED);
995     SEC2TXT(CRYPT_E_NO_REVOCATION_DLL);
996     SEC2TXT(CRYPT_E_NO_REVOCATION_CHECK);
997     SEC2TXT(CRYPT_E_REVOCATION_OFFLINE);
998     SEC2TXT(CRYPT_E_NOT_IN_REVOCATION_DATABASE);
999     SEC2TXT(SEC_E_ALGORITHM_MISMATCH);
1000     SEC2TXT(SEC_E_BAD_BINDINGS);
1001     SEC2TXT(SEC_E_BAD_PKGID);
1002     SEC2TXT(SEC_E_BUFFER_TOO_SMALL);
1003     SEC2TXT(SEC_E_CANNOT_INSTALL);
1004     SEC2TXT(SEC_E_CANNOT_PACK);
1005     SEC2TXT(SEC_E_CERT_EXPIRED);
1006     SEC2TXT(SEC_E_CERT_UNKNOWN);
1007     SEC2TXT(SEC_E_CERT_WRONG_USAGE);
1008     SEC2TXT(SEC_E_CONTEXT_EXPIRED);
1009     SEC2TXT(SEC_E_CROSSREALM_DELEGATION_FAILURE);
1010     SEC2TXT(SEC_E_CRYPTO_SYSTEM_INVALID);
1011     SEC2TXT(SEC_E_DECRYPT_FAILURE);
1012     SEC2TXT(SEC_E_DELEGATION_POLICY);
1013     SEC2TXT(SEC_E_DELEGATION_REQUIRED);
1014     SEC2TXT(SEC_E_DOWNGRADE_DETECTED);
1015     SEC2TXT(SEC_E_ENCRYPT_FAILURE);
1016     SEC2TXT(SEC_E_ILLEGAL_MESSAGE);
1017     SEC2TXT(SEC_E_INCOMPLETE_CREDENTIALS);
1018     SEC2TXT(SEC_E_INCOMPLETE_MESSAGE);
1019     SEC2TXT(SEC_E_INSUFFICIENT_MEMORY);
1020     SEC2TXT(SEC_E_INTERNAL_ERROR);
1021     SEC2TXT(SEC_E_INVALID_HANDLE);
1022     SEC2TXT(SEC_E_INVALID_PARAMETER);
1023     SEC2TXT(SEC_E_INVALID_TOKEN);
1024     SEC2TXT(SEC_E_ISSUING_CA_UNTRUSTED);
1025     SEC2TXT(SEC_E_ISSUING_CA_UNTRUSTED_KDC);
1026     SEC2TXT(SEC_E_KDC_CERT_EXPIRED);
1027     SEC2TXT(SEC_E_KDC_CERT_REVOKED);
1028     SEC2TXT(SEC_E_KDC_INVALID_REQUEST);
1029     SEC2TXT(SEC_E_KDC_UNABLE_TO_REFER);
1030     SEC2TXT(SEC_E_KDC_UNKNOWN_ETYPE);
1031     SEC2TXT(SEC_E_LOGON_DENIED);
1032     SEC2TXT(SEC_E_MAX_REFERRALS_EXCEEDED);
1033     SEC2TXT(SEC_E_MESSAGE_ALTERED);
1034     SEC2TXT(SEC_E_MULTIPLE_ACCOUNTS);
1035     SEC2TXT(SEC_E_MUST_BE_KDC);
1036     SEC2TXT(SEC_E_NOT_OWNER);
1037     SEC2TXT(SEC_E_NO_AUTHENTICATING_AUTHORITY);
1038     SEC2TXT(SEC_E_NO_CREDENTIALS);
1039     SEC2TXT(SEC_E_NO_IMPERSONATION);
1040     SEC2TXT(SEC_E_NO_IP_ADDRESSES);
1041     SEC2TXT(SEC_E_NO_KERB_KEY);
1042     SEC2TXT(SEC_E_NO_PA_DATA);
1043     SEC2TXT(SEC_E_NO_S4U_PROT_SUPPORT);
1044     SEC2TXT(SEC_E_NO_TGT_REPLY);
1045     SEC2TXT(SEC_E_OUT_OF_SEQUENCE);
1046     SEC2TXT(SEC_E_PKINIT_CLIENT_FAILURE);
1047     SEC2TXT(SEC_E_PKINIT_NAME_MISMATCH);
1048     SEC2TXT(SEC_E_POLICY_NLTM_ONLY);
1049     SEC2TXT(SEC_E_QOP_NOT_SUPPORTED);
1050     SEC2TXT(SEC_E_REVOCATION_OFFLINE_C);
1051     SEC2TXT(SEC_E_REVOCATION_OFFLINE_KDC);
1052     SEC2TXT(SEC_E_SECPKG_NOT_FOUND);
1053     SEC2TXT(SEC_E_SECURITY_QOS_FAILED);
1054     SEC2TXT(SEC_E_SHUTDOWN_IN_PROGRESS);
1055     SEC2TXT(SEC_E_SMARTCARD_CERT_EXPIRED);
1056     SEC2TXT(SEC_E_SMARTCARD_CERT_REVOKED);
1057     SEC2TXT(SEC_E_SMARTCARD_LOGON_REQUIRED);
1058     SEC2TXT(SEC_E_STRONG_CRYPTO_NOT_SUPPORTED);
1059     SEC2TXT(SEC_E_TARGET_UNKNOWN);
1060     SEC2TXT(SEC_E_TIME_SKEW);
1061     SEC2TXT(SEC_E_TOO_MANY_PRINCIPALS);
1062     SEC2TXT(SEC_E_UNFINISHED_CONTEXT_DELETED);
1063     SEC2TXT(SEC_E_UNKNOWN_CREDENTIALS);
1064     SEC2TXT(SEC_E_UNSUPPORTED_FUNCTION);
1065     SEC2TXT(SEC_E_UNSUPPORTED_PREAUTH);
1066     SEC2TXT(SEC_E_UNTRUSTED_ROOT);
1067     SEC2TXT(SEC_E_WRONG_CREDENTIAL_HANDLE);
1068     SEC2TXT(SEC_E_WRONG_PRINCIPAL);
1069     SEC2TXT(SEC_I_COMPLETE_AND_CONTINUE);
1070     SEC2TXT(SEC_I_COMPLETE_NEEDED);
1071     SEC2TXT(SEC_I_CONTEXT_EXPIRED);
1072     SEC2TXT(SEC_I_CONTINUE_NEEDED);
1073     SEC2TXT(SEC_I_INCOMPLETE_CREDENTIALS);
1074     SEC2TXT(SEC_I_LOCAL_LOGON);
1075     SEC2TXT(SEC_I_NO_LSA_CONTEXT);
1076     SEC2TXT(SEC_I_RENEGOTIATE);
1077     SEC2TXT(SEC_I_SIGNATURE_NEEDED);
1078     default:
1079       txt = "Unknown error";
1080   }
1081 
1082   if(err == SEC_E_ILLEGAL_MESSAGE) {
1083     msnprintf(buf, buflen,
1084               "SEC_E_ILLEGAL_MESSAGE (0x%08X) - This error usually occurs "
1085               "when a fatal SSL/TLS alert is received (e.g. handshake failed)."
1086               " More detail may be available in the Windows System event log.",
1087               err);
1088   }
1089   else {
1090     char msgbuf[256];
1091     if(get_winapi_error(err, msgbuf, sizeof(msgbuf)))
1092       msnprintf(buf, buflen, "%s (0x%08X) - %s", txt, err, msgbuf);
1093     else
1094       msnprintf(buf, buflen, "%s (0x%08X)", txt, err);
1095   }
1096 
1097 #else
1098   if(err == SEC_E_OK)
1099     txt = "No error";
1100   else
1101     txt = "Error";
1102   if(buflen > strlen(txt))
1103     strcpy(buf, txt);
1104 #endif
1105 
1106   if(errno != old_errno)
1107     errno = old_errno;
1108 
1109 #ifdef PRESERVE_WINDOWS_ERROR_CODE
1110   if(old_win_err != GetLastError())
1111     SetLastError(old_win_err);
1112 #endif
1113 
1114   return buf;
1115 }
1116 #endif /* USE_WINDOWS_SSPI */
1117