xref: /third_party/curl/lib/strerror.c (revision 13498266)
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
55const char *
56curl_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
365const char *
366curl_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
425const char *
426curl_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
461const char *
462curl_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 */
580static const char *
581get_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 */
778static const char *
779get_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 */
836const 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)
931const 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 */
972const 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