Coverage Report

Created: 2025-07-11 06:33

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