Coverage Report

Created: 2022-11-30 06:20

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