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