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