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