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