Subversion Repositories tpanel

Rev

Rev 355 | Rev 380 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
117 andreas 1
#ifndef NOLFS
2
#define _LARGEFILE_SOURCE
3
#define _LARGEFILE64_SOURCE
4
#endif
5
 
120 andreas 6
#include <iostream>
7
 
117 andreas 8
#ifndef NOSSL
9
#include <openssl/ssl.h>
10
#endif
11
 
12
#include "ftplib.h"
13
 
14
#ifndef NOSSL
15
#include <openssl/ssl.h>
16
#endif
17
 
18
#include <sys/socket.h>
19
#include <netinet/in.h>
20
#include <netdb.h>
21
#include <arpa/inet.h>
22
 
23
#include <stdio.h>
24
#include <stdlib.h>
25
#include <string.h>
26
#include <errno.h>
27
#include <ctype.h>
28
#include <sys/types.h>
29
 
30
#define SETSOCKOPT_OPTVAL_TYPE (void *)
31
 
32
using namespace std;
33
 
34
/* socket values */
35
#define FTPLIB_BUFSIZ 1024
36
#define ACCEPT_TIMEOUT 30
37
 
38
/* io types */
39
#define FTPLIB_CONTROL 0
40
#define FTPLIB_READ 1
41
#define FTPLIB_WRITE 2
42
 
43
/*
44
 * Constructor
45
 */
46
 
47
ftplib::ftplib()
48
{
49
#ifndef NOSSL
235 andreas 50
#if OPENSSL_API_COMPAT < 0x010100000
117 andreas 51
    SSL_library_init();
52
#endif
235 andreas 53
#endif
117 andreas 54
 
55
    mp_ftphandle = static_cast<ftphandle *>(calloc(1, sizeof(ftphandle)));
56
 
57
    if (mp_ftphandle == NULL)
120 andreas 58
        errorHandler("calloc", errno, __LINE__);
117 andreas 59
 
60
    mp_ftphandle->buf = static_cast<char *>(malloc(FTPLIB_BUFSIZ));
61
 
62
    if (mp_ftphandle->buf == NULL)
63
    {
120 andreas 64
        errorHandler("calloc", errno, __LINE__);
117 andreas 65
        free(mp_ftphandle);
66
    }
67
 
68
#ifndef NOSSL
69
    mp_ftphandle->ctx = SSL_CTX_new(TLS_client_method());
70
    SSL_CTX_set_verify(mp_ftphandle->ctx, SSL_VERIFY_NONE, NULL);
71
    mp_ftphandle->ssl = SSL_new(mp_ftphandle->ctx);
72
#endif
73
    ClearHandle();
74
}
75
 
76
/*
77
 * Destructor
78
 */
79
 
80
ftplib::~ftplib()
81
{
82
#ifndef NOSSL
83
    SSL_free(mp_ftphandle->ssl);
84
    SSL_CTX_free(mp_ftphandle->ctx);
85
#endif
86
    free(mp_ftphandle->buf);
87
    free(mp_ftphandle);
88
}
89
 
242 andreas 90
void ftplib::sprint_rest(char *buf, off64_t offset, size_t len)
117 andreas 91
{
242 andreas 92
#if defined(__LP64__) && not defined(__MACH__)
93
    snprintf(buf, len, "REST %ld", offset);
117 andreas 94
#else
242 andreas 95
    snprintf(buf, len, "REST %lld", offset);
117 andreas 96
#endif
97
}
98
 
99
/*
100
 * socket_wait - wait for socket to receive or flush data
101
 *
102
 * return 1 if no user callback, otherwise, return value returned by
103
 * user callback
104
 */
105
int ftplib::socket_wait(ftphandle *ctl)
106
{
107
    fd_set fd, *rfd = NULL, *wfd = NULL;
108
    struct timeval tv;
109
    int rv = 0;
110
 
111
    if (ctl->idlecb == NULL)
112
        return 1;
113
 
114
    /*if ((ctl->dir == FTPLIB_CONTROL)
115
     *  || (ctl->idlecb == NULL)
116
     *  || ((ctl->idletime.tv_sec == 0)
117
     *  && //(ctl->idletime.tv_usec 0))
118
     * return 1;*/
119
 
120
    if (ctl->dir == FTPLIB_WRITE)
121
        wfd = &fd;
122
    else
123
        rfd = &fd;
124
 
125
    FD_ZERO(&fd);
126
 
127
    do
128
    {
129
        FD_SET(ctl->handle, &fd);
130
        tv = ctl->idletime;
131
        rv = select(ctl->handle + 1, rfd, wfd, NULL, &tv);
132
 
133
        if (rv == -1)
134
        {
135
            rv = 0;
120 andreas 136
            errorHandler("select", errno, __LINE__);
117 andreas 137
            strncpy(ctl->ctrl->response, strerror(errno), sizeof(ctl->ctrl->response));
138
            break;
139
        }
140
        else if (rv > 0)
141
        {
142
            rv = 1;
143
            break;
144
        }
145
    }
146
    while ((rv = ctl->idlecb(ctl->cbarg)));
147
 
148
    return rv;
149
}
150
 
151
/*
152
 * read a line of text
153
 *
154
 * return -1 on error or bytecount
155
 */
156
int ftplib::readline(char *buf, int max, ftphandle *ctl)
157
{
158
    int x, retval = 0;
159
    char *end, *bp = buf;
160
    int eof = 0;
161
 
162
    if ((ctl->dir != FTPLIB_CONTROL) && (ctl->dir != FTPLIB_READ))
163
        return -1;
164
 
165
    if (max == 0)
166
        return 0;
167
 
168
    do
169
    {
170
        if (ctl->cavail > 0)
171
        {
172
            x = (max >= ctl->cavail) ? ctl->cavail : max - 1;
173
            end = static_cast<char*>(memccpy(bp, ctl->cget, '\n', x));
174
 
175
            if (end != NULL)
370 andreas 176
                x = (int)(end - bp);
117 andreas 177
 
178
            retval += x;
179
            bp += x;
180
            *bp = '\0';
181
            max -= x;
182
            ctl->cget += x;
183
            ctl->cavail -= x;
184
 
185
            if (end != NULL)
186
            {
187
                bp -= 2;
188
 
189
                if (strcmp(bp, "\r\n") == 0)
190
                {
191
                    *bp++ = '\n';
192
                    *bp++ = '\0';
193
                    --retval;
194
                }
195
 
196
                break;
197
            }
198
        }
199
 
200
        if (max == 1)
201
        {
202
            *buf = '\0';
203
            break;
204
        }
205
 
206
        if (ctl->cput == ctl->cget)
207
        {
208
            ctl->cput = ctl->cget = ctl->buf;
209
            ctl->cavail = 0;
210
            ctl->cleft = FTPLIB_BUFSIZ;
211
        }
212
 
213
        if (eof)
214
        {
215
            if (retval == 0)
216
                retval = -1;
217
 
218
            break;
219
        }
220
 
221
        if (!socket_wait(ctl))
222
            return retval;
223
 
224
#ifndef NOSSL
225
        if (ctl->tlsdata)
226
            x = SSL_read(ctl->ssl, ctl->cput, ctl->cleft);
227
        else
228
        {
229
            if (ctl->tlsctrl)
230
                x = SSL_read(ctl->ssl, ctl->cput, ctl->cleft);
231
            else
370 andreas 232
                x = (int)read(ctl->handle, ctl->cput, ctl->cleft);
117 andreas 233
        }
234
 
235
#else
118 andreas 236
        x = read(ctl->handle, ctl->cput, ctl->cleft);
117 andreas 237
#endif
238
 
239
        if (x == -1)
240
        {
120 andreas 241
            errorHandler("read", errno, __LINE__);
117 andreas 242
            retval = -1;
243
            break;
244
        }
245
 
246
        // LOGGING FUNCTIONALITY!!!
247
 
248
        if ((ctl->dir == FTPLIB_CONTROL) && (mp_ftphandle->logcb != NULL))
249
        {
250
            *((ctl->cput) + x) = '\0';
251
            mp_ftphandle->logcb(ctl->cput, mp_ftphandle->cbarg, true);
252
        }
253
 
254
        if (x == 0)
255
            eof = 1;
256
 
257
        ctl->cleft -= x;
258
        ctl->cavail += x;
259
        ctl->cput += x;
260
    }
261
    while (1);
262
 
263
    return retval;
264
}
265
 
266
/*
267
 * write lines of text
268
 *
269
 * return -1 on error or bytecount
270
 */
271
int ftplib::writeline(char *buf, int len, ftphandle *nData)
272
{
273
    int x, nb = 0, w;
274
    char *ubp = buf, *nbp;
275
    char lc = 0;
276
 
277
    if (nData->dir != FTPLIB_WRITE)
278
        return -1;
279
 
280
    nbp = nData->buf;
281
 
282
    for (x = 0; x < len; x++)
283
    {
284
        if ((*ubp == '\n') && (lc != '\r'))
285
        {
286
            if (nb == FTPLIB_BUFSIZ)
287
            {
288
                if (!socket_wait(nData))
289
                    return x;
290
 
291
#ifndef NOSSL
292
 
293
                if (nData->tlsctrl)
294
                    w = SSL_write(nData->ssl, nbp, FTPLIB_BUFSIZ);
295
                else
370 andreas 296
                    w = (int)write(nData->handle, nbp, FTPLIB_BUFSIZ);
117 andreas 297
 
298
#else
118 andreas 299
                w = write(nData->handle, nbp, FTPLIB_BUFSIZ);
117 andreas 300
#endif
301
 
302
                if (w != FTPLIB_BUFSIZ)
303
                {
120 andreas 304
                    std::string msg = "write(1) returned " + std::to_string(w) + ", errno = " + std::to_string(errno);
305
                    errorHandler(msg.c_str(), 0, 0);
117 andreas 306
                    return (-1);
307
                }
308
 
309
                nb = 0;
310
            }
311
 
312
            nbp[nb++] = '\r';
313
        }
314
 
315
        if (nb == FTPLIB_BUFSIZ)
316
        {
317
            if (!socket_wait(nData))
318
                return x;
319
 
320
#ifndef NOSSL
321
 
322
            if (nData->tlsctrl)
323
                w = SSL_write(nData->ssl, nbp, FTPLIB_BUFSIZ);
324
            else
370 andreas 325
                w = (int)write(nData->handle, nbp, FTPLIB_BUFSIZ);
117 andreas 326
 
327
#else
118 andreas 328
            w = write(nData->handle, nbp, FTPLIB_BUFSIZ);
117 andreas 329
#endif
330
 
331
            if (w != FTPLIB_BUFSIZ)
332
            {
120 andreas 333
                std::string msg = "write(2) returned " + std::to_string(w) + ", errno = " + std::to_string(errno);
334
                errorHandler(msg.c_str(), 0, 0);
117 andreas 335
                return (-1);
336
            }
337
 
338
            nb = 0;
339
        }
340
 
341
        nbp[nb++] = lc = *ubp++;
342
    }
343
 
344
    if (nb)
345
    {
346
        if (!socket_wait(nData))
347
            return x;
348
 
349
#ifndef NOSSL
350
 
370 andreas 351
        if (nData->tlsctrl)
352
            w = SSL_write(nData->ssl, nbp, nb);
353
        else
354
            w = (int)write(nData->handle, nbp, nb);
117 andreas 355
 
356
#else
118 andreas 357
        w = write(nData->handle, nbp, nb);
117 andreas 358
#endif
359
 
360
        if (w != nb)
361
        {
120 andreas 362
            std::string msg = "write(2) returned " + std::to_string(w) + ", errno = " + std::to_string(errno);
363
            errorHandler(msg.c_str(), 0, 0);
117 andreas 364
            return (-1);
365
        }
366
    }
367
 
368
    return len;
369
}
370
 
371
/*
372
 * read a response from the server
373
 *
374
 * return 0 if first char doesn't match
375
 * return 1 if first char matches
376
 */
377
int ftplib::readresp(char c, ftphandle *nControl)
378
{
379
    char match[5];
380
 
381
    if (readline(nControl->response, 256, nControl) == -1)
382
    {
120 andreas 383
        errorHandler("Control socket read failed", errno, __LINE__);
117 andreas 384
        return 0;
385
    }
386
 
387
    if (nControl->response[3] == '-')
388
    {
389
        strncpy(match, nControl->response, 3);
390
        match[3] = ' ';
391
        match[4] = '\0';
392
 
393
        do
394
        {
395
            if (readline(nControl->response, 256, nControl) == -1)
396
            {
120 andreas 397
                errorHandler("Control socket read failed", errno, __LINE__);
117 andreas 398
                return 0;
399
            }
400
        }
401
        while (strncmp(nControl->response, match, 4));
402
    }
403
 
404
    if (nControl->response[0] == c)
405
        return 1;
406
 
407
    return 0;
408
}
409
 
410
/*
411
 * FtpLastResponse - return a pointer to the last response received
412
 */
413
char* ftplib::LastResponse()
414
{
415
    if ((mp_ftphandle) && (mp_ftphandle->dir == FTPLIB_CONTROL))
416
        return mp_ftphandle->response;
417
 
418
    return NULL;
419
}
420
 
421
/*
422
 * ftplib::Connect - connect to remote server
423
 *
424
 * return 1 if connected, 0 if not
425
 */
426
int ftplib::Connect(const char *host)
427
{
428
    int sControl;
429
    struct sockaddr_in sin;
430
    struct hostent *phe;
431
    struct servent *pse;
432
    int on = 1;
433
    int ret;
434
    char *lhost;
435
    char *pnum;
436
 
437
    mp_ftphandle->dir = FTPLIB_CONTROL;
438
    mp_ftphandle->ctrl = NULL;
439
    mp_ftphandle->xfered = 0;
440
    mp_ftphandle->xfered1 = 0;
441
#ifndef NOSSL
442
    mp_ftphandle->tlsctrl = 0;
443
    mp_ftphandle->tlsdata = 0;
444
#endif
445
    mp_ftphandle->offset = 0;
446
    mp_ftphandle->handle = 0;
447
 
448
    memset(&sin, 0, sizeof(sin));
449
    sin.sin_family = AF_INET;
450
    lhost = strdup(host);
451
    pnum = strchr(lhost, ':');
452
 
453
    if (pnum == NULL)
454
    {
455
        if ((pse = getservbyname("ftp", "tcp")) == NULL)
456
        {
120 andreas 457
            errorHandler("getservbyname", errno, __LINE__);
117 andreas 458
            free(lhost);
459
            return 0;
460
        }
461
 
462
        sin.sin_port = pse->s_port;
463
    }
464
    else
465
    {
466
        *pnum++ = '\0';
467
 
468
        if (isdigit(*pnum))
469
            sin.sin_port = htons(atoi(pnum));
470
        else
471
        {
472
            pse = getservbyname(pnum, "tcp");
473
            sin.sin_port = pse->s_port;
474
        }
475
    }
476
 
477
    ret = inet_aton(lhost, &sin.sin_addr);
478
 
479
    if (ret == 0)
480
    {
481
        if ((phe = gethostbyname(lhost)) == NULL)
482
        {
120 andreas 483
            errorHandler("gethostbyname", errno, __LINE__);
117 andreas 484
            free(lhost);
485
            return 0;
486
        }
487
 
488
        memcpy((char *)&sin.sin_addr, phe->h_addr, phe->h_length);
489
    }
490
 
491
    free(lhost);
492
 
493
    sControl = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
494
 
495
    if (sControl == -1)
496
    {
120 andreas 497
        errorHandler("socket", errno, __LINE__);
117 andreas 498
        return 0;
499
    }
500
 
501
    if (setsockopt(sControl, SOL_SOCKET, SO_REUSEADDR, SETSOCKOPT_OPTVAL_TYPE & on, sizeof(on)) == -1)
502
    {
120 andreas 503
        errorHandler("setsockopt", errno, __LINE__);
118 andreas 504
        close(sControl);
117 andreas 505
        return 0;
506
    }
507
 
508
    if (connect(sControl, (struct sockaddr *)&sin, sizeof(sin)) == -1)
509
    {
120 andreas 510
        errorHandler("connect", errno, __LINE__);
118 andreas 511
        close(sControl);
117 andreas 512
        return 0;
513
    }
514
 
515
    mp_ftphandle->handle = sControl;
137 andreas 516
    Log(LOG_DEBUG, string("Successfully connected to ") + host);
117 andreas 517
 
518
    if (readresp('2', mp_ftphandle) == 0)
519
    {
118 andreas 520
        close(sControl);
117 andreas 521
        mp_ftphandle->handle = 0;
522
        return 0;
523
    }
524
 
525
    return 1;
526
}
527
 
528
/*
529
 * FtpSendCmd - send a command and wait for expected response
530
 *
531
 * return 1 if proper response received, 0 otherwise
532
 */
533
int ftplib::FtpSendCmd(const char *cmd, char expresp, ftphandle *nControl)
534
{
535
    char buf[256];
536
    int x;
537
 
120 andreas 538
    if (!nControl->handle)
539
        return 0;
117 andreas 540
 
120 andreas 541
    if (nControl->dir != FTPLIB_CONTROL)
542
        return 0;
117 andreas 543
 
242 andreas 544
    snprintf(buf, sizeof(buf), "%s\r\n", cmd);
117 andreas 545
 
546
#ifndef NOSSL
547
    if (nControl->tlsctrl)
370 andreas 548
        x = SSL_write(nControl->ssl, buf, (int)strlen(buf));
117 andreas 549
    else
370 andreas 550
        x = (int)write(nControl->handle, buf, (int)strlen(buf));
117 andreas 551
 
552
#else
118 andreas 553
    x = write(nControl->handle, buf, strlen(buf));
117 andreas 554
#endif
555
 
556
    if (x <= 0)
557
    {
120 andreas 558
        errorHandler("write", errno, __LINE__);
117 andreas 559
        return 0;
560
    }
561
 
562
    if (mp_ftphandle->logcb != NULL)
563
        mp_ftphandle->logcb(buf, mp_ftphandle->cbarg, false);
564
 
565
    return readresp(expresp, nControl);
566
}
567
 
568
/*
569
 * FtpLogin - log in to remote server
570
 *
571
 * return 1 if logged in, 0 otherwise
572
 */
573
int ftplib::Login(const char *user, const char *pass)
574
{
575
    char tempbuf[64];
576
 
577
    if (((strlen(user) + 7) > sizeof(tempbuf)) || ((strlen(pass) + 7) > sizeof(tempbuf)))
578
        return 0;
579
 
242 andreas 580
    snprintf(tempbuf, sizeof(tempbuf), "USER %s", user);
117 andreas 581
 
582
    if (!FtpSendCmd(tempbuf, '3', mp_ftphandle))
583
    {
584
        if (mp_ftphandle->ctrl != NULL)
585
            return 1;
586
 
587
        if (*LastResponse() == '2')
588
            return 1;
589
 
590
        return 0;
591
    }
592
 
242 andreas 593
    snprintf(tempbuf, sizeof(tempbuf), "PASS %s", pass);
117 andreas 594
    return FtpSendCmd(tempbuf, '2', mp_ftphandle);
595
}
596
 
597
/*
598
 * FtpAcceptConnection - accept connection from server
599
 *
600
 * return 1 if successful, 0 otherwise
601
 */
602
int ftplib::FtpAcceptConnection(ftphandle *nData, ftphandle *nControl)
603
{
604
    int sData;
605
    struct sockaddr addr;
606
    socklen_t l;
607
    int i;
608
    struct timeval tv;
609
    fd_set mask;
610
    int rv = 0;
611
 
612
    FD_ZERO(&mask);
613
    FD_SET(nControl->handle, &mask);
614
    FD_SET(nData->handle, &mask);
615
    tv.tv_usec = 0;
616
    tv.tv_sec = ACCEPT_TIMEOUT;
617
    i = nControl->handle;
618
 
619
    if (i < nData->handle)
620
        i = nData->handle;
621
 
622
    i = select(i + 1, &mask, NULL, NULL, &tv);
623
 
624
    if (i == -1)
625
    {
626
        strncpy(nControl->response, strerror(errno), sizeof(nControl->response));
118 andreas 627
        close(nData->handle);
117 andreas 628
        nData->handle = 0;
629
        rv = 0;
630
    }
631
    else if (i == 0)
632
    {
633
        strcpy(nControl->response, "timed out waiting for connection");
118 andreas 634
        close(nData->handle);
117 andreas 635
        nData->handle = 0;
636
        rv = 0;
637
    }
638
    else
639
    {
640
        if (FD_ISSET(nData->handle, &mask))
641
        {
642
            l = sizeof(addr);
643
            sData = accept(nData->handle, &addr, &l);
644
            i = errno;
118 andreas 645
            close(nData->handle);
117 andreas 646
 
647
            if (sData > 0)
648
            {
649
                rv = 1;
650
                nData->handle = sData;
651
                nData->ctrl = nControl;
652
            }
653
            else
654
            {
655
                strncpy(nControl->response, strerror(i), sizeof(nControl->response));
656
                nData->handle = 0;
657
                rv = 0;
658
            }
659
        }
660
        else if (FD_ISSET(nControl->handle, &mask))
661
        {
118 andreas 662
            close(nData->handle);
117 andreas 663
            nData->handle = 0;
664
            readresp('2', nControl);
665
            rv = 0;
666
        }
667
    }
668
 
669
    return rv;
670
}
671
 
672
/*
673
 * FtpAccess - return a handle for a data stream
674
 *
675
 * return 1 if successful, 0 otherwise
676
 */
677
int ftplib::FtpAccess(const char *path, accesstype type, transfermode mode, ftphandle *nControl, ftphandle **nData)
678
{
679
    char buf[256];
680
    int dir;
681
 
682
    if ((path == NULL) && ((type == ftplib::filewrite)
683
                           || (type == ftplib::fileread)
684
                           || (type == ftplib::filereadappend)
685
                           || (type == ftplib::filewriteappend)))
686
    {
242 andreas 687
        snprintf(nControl->response, sizeof(ftphandle::response), "Missing path argument for file transfer\n");
120 andreas 688
        errorHandler(nControl->response, 0, __LINE__);
117 andreas 689
        return 0;
690
    }
691
 
242 andreas 692
    snprintf(buf, sizeof(buf), "TYPE %c", mode);
117 andreas 693
 
120 andreas 694
    if (!FtpSendCmd(buf, '2', nControl))
695
        return 0;
117 andreas 696
 
697
    switch (type)
698
    {
699
        case ftplib::dir:
700
            strcpy(buf, "NLST");
701
            dir = FTPLIB_READ;
702
            break;
703
 
704
        case ftplib::dirverbose:
179 andreas 705
//            strcpy(buf, "LIST -aL");
706
            strcpy(buf, "LIST");
117 andreas 707
            dir = FTPLIB_READ;
708
            break;
709
 
710
        case ftplib::filereadappend:
711
        case ftplib::fileread:
712
            strcpy(buf, "RETR");
713
            dir = FTPLIB_READ;
714
            break;
715
 
716
        case ftplib::filewriteappend:
717
        case ftplib::filewrite:
718
            strcpy(buf, "STOR");
719
            dir = FTPLIB_WRITE;
720
            break;
721
 
722
        default:
242 andreas 723
            snprintf(nControl->response, sizeof(ftphandle::response), "Invalid open type %d\n", type);
120 andreas 724
            errorHandler(nControl->response, 0, __LINE__);
117 andreas 725
            return 0;
726
    }
727
 
728
    if (path != NULL)
729
    {
730
        int i = strlen(buf);
731
        buf[i++] = ' ';
732
 
733
        if ((strlen(path) + i) >= sizeof(buf))
734
            return 0;
735
 
370 andreas 736
        strncpy(&buf[i], path, sizeof(buf));
117 andreas 737
    }
738
 
739
    if (nControl->cmode == ftplib::pasv)
740
    {
741
        if (FtpOpenPasv(nControl, nData, mode, dir, buf) == -1)
742
            return 0;
743
    }
744
 
745
    if (nControl->cmode == ftplib::port)
746
    {
747
        if (FtpOpenPort(nControl, nData, mode, dir, buf) == -1)
748
            return 0;
749
 
750
        if (!FtpAcceptConnection(*nData, nControl))
751
        {
752
            FtpClose(*nData);
753
            *nData = NULL;
754
            return 0;
755
        }
756
    }
757
 
758
#ifndef NOSSL
759
 
760
    if (nControl->tlsdata)
761
    {
762
        (*nData)->ssl = SSL_new(nControl->ctx);
763
        (*nData)->sbio = BIO_new_socket((*nData)->handle, BIO_NOCLOSE);
764
        SSL_set_bio((*nData)->ssl, (*nData)->sbio, (*nData)->sbio);
765
        int ret = SSL_connect((*nData)->ssl);
766
 
767
        if (ret != 1)
768
            return 0;
769
 
770
        (*nData)->tlsdata = 1;
771
    }
772
 
773
#endif
774
    return 1;
775
}
776
 
777
/*
778
 * FtpOpenPort - Establishes a PORT connection for data transfer
779
 *
780
 * return 1 if successful, -1 otherwise
781
 */
782
int ftplib::FtpOpenPort(ftphandle *nControl, ftphandle **nData, transfermode mode, int dir, char *cmd)
783
{
784
    int sData;
785
 
786
    union
787
    {
788
        struct sockaddr sa;
789
        struct sockaddr_in in;
790
    } sin;
791
 
792
    struct linger lng = { 0, 0 };
793
    socklen_t l;
794
    int on = 1;
795
    ftphandle *ctrl;
796
    char buf[256];
797
 
798
    if (nControl->dir != FTPLIB_CONTROL)
799
        return -1;
800
 
801
    if ((dir != FTPLIB_READ) && (dir != FTPLIB_WRITE))
802
    {
242 andreas 803
        snprintf(nControl->response, sizeof(ftphandle::response), "Invalid direction %d\n", dir);
117 andreas 804
        return -1;
805
    }
806
 
807
    if ((mode != ftplib::ascii) && (mode != ftplib::image))
808
    {
242 andreas 809
        snprintf(nControl->response, sizeof(ftphandle::response), "Invalid mode %c\n", mode);
117 andreas 810
        return -1;
811
    }
812
 
813
    l = sizeof(sin);
814
 
815
    if (getsockname(nControl->handle, &sin.sa, &l) < 0)
816
    {
120 andreas 817
        errorHandler("getsockname", errno, __LINE__);
117 andreas 818
        return -1;
819
    }
820
 
821
    sData = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
822
 
823
    if (sData == -1)
824
    {
120 andreas 825
        errorHandler("socket", errno, __LINE__);
117 andreas 826
        return -1;
827
    }
828
 
829
    if (setsockopt(sData, SOL_SOCKET, SO_REUSEADDR, SETSOCKOPT_OPTVAL_TYPE & on, sizeof(on)) == -1)
830
    {
120 andreas 831
        errorHandler("setsockopt", errno, __LINE__);
118 andreas 832
        close(sData);
117 andreas 833
        return -1;
834
    }
835
 
836
    if (setsockopt(sData, SOL_SOCKET, SO_LINGER, SETSOCKOPT_OPTVAL_TYPE & lng, sizeof(lng)) == -1)
837
    {
120 andreas 838
        errorHandler("setsockopt", errno, __LINE__);
118 andreas 839
        close(sData);
117 andreas 840
        return -1;
841
    }
842
 
843
    sin.in.sin_port = 0;
844
 
120 andreas 845
    if (::bind(sData, &sin.sa, sizeof(sin)) == -1)
117 andreas 846
    {
120 andreas 847
        errorHandler("bind", errno, __LINE__);
118 andreas 848
        close(sData);
117 andreas 849
        return -1;
850
    }
851
 
852
    if (listen(sData, 1) < 0)
853
    {
120 andreas 854
        errorHandler("listen", errno, __LINE__);
118 andreas 855
        close(sData);
117 andreas 856
        return -1;
857
    }
858
 
859
    if (getsockname(sData, &sin.sa, &l) < 0)
860
        return 0;
861
 
242 andreas 862
    snprintf(buf, sizeof(buf), "PORT %hhu,%hhu,%hhu,%hhu,%hhu,%hhu",
117 andreas 863
            (unsigned char) sin.sa.sa_data[2],
864
            (unsigned char) sin.sa.sa_data[3],
865
            (unsigned char) sin.sa.sa_data[4],
866
            (unsigned char) sin.sa.sa_data[5],
867
            (unsigned char) sin.sa.sa_data[0],
868
            (unsigned char) sin.sa.sa_data[1]);
869
 
870
    if (!FtpSendCmd(buf, '2', nControl))
871
    {
118 andreas 872
        close(sData);
117 andreas 873
        return -1;
874
    }
875
 
876
    if (mp_ftphandle->offset != 0)
877
    {
878
        char buf[256];
242 andreas 879
        sprint_rest(buf, mp_ftphandle->offset, sizeof(buf));
117 andreas 880
 
881
        if (!FtpSendCmd(buf, '3', nControl))
882
        {
118 andreas 883
            close(sData);
117 andreas 884
            return 0;
885
        }
886
    }
887
 
888
    ctrl = static_cast<ftphandle*>(calloc(1, sizeof(ftphandle)));
889
 
890
    if (ctrl == NULL)
891
    {
120 andreas 892
        errorHandler("calloc", errno, __LINE__);
118 andreas 893
        close(sData);
117 andreas 894
        return -1;
895
    }
896
 
897
    if ((mode == 'A') && ((ctrl->buf = static_cast<char*>(malloc(FTPLIB_BUFSIZ))) == NULL))
898
    {
120 andreas 899
        errorHandler("calloc", errno, __LINE__);
118 andreas 900
        close(sData);
117 andreas 901
        free(ctrl);
902
        return -1;
903
    }
904
 
905
    if (!FtpSendCmd(cmd, '1', nControl))
906
    {
907
        FtpClose(*nData);
908
        *nData = NULL;
909
        return -1;
910
    }
911
 
912
    ctrl->handle = sData;
913
    ctrl->dir = dir;
914
    ctrl->ctrl = (nControl->cmode == ftplib::pasv) ? nControl : NULL;
915
    ctrl->idletime = nControl->idletime;
916
    ctrl->cbarg = nControl->cbarg;
917
    ctrl->xfered = 0;
918
    ctrl->xfered1 = 0;
919
    ctrl->cbbytes = nControl->cbbytes;
920
 
921
    if (ctrl->idletime.tv_sec || ctrl->idletime.tv_usec)
922
        ctrl->idlecb = nControl->idlecb;
923
    else
924
        ctrl->idlecb = NULL;
925
 
926
    if (ctrl->cbbytes)
927
        ctrl->xfercb = nControl->xfercb;
928
    else
929
        ctrl->xfercb = NULL;
930
 
931
    *nData = ctrl;
932
 
933
    return 1;
934
}
935
 
936
/*
937
 * FtpOpenPasv - Establishes a PASV connection for data transfer
938
 *
939
 * return 1 if successful, -1 otherwise
940
 */
941
int ftplib::FtpOpenPasv(ftphandle *nControl, ftphandle **nData, transfermode mode, int dir, char *cmd)
942
{
943
    int sData;
944
 
945
    union
946
    {
947
        struct sockaddr sa;
948
        struct sockaddr_in in;
949
    } sin;
950
 
951
    struct linger lng = { 0, 0 };
952
    unsigned int l;
953
    int on = 1;
954
    ftphandle *ctrl;
955
    char *cp;
956
    unsigned char v[6];
957
    int ret;
958
 
959
    if (nControl->dir != FTPLIB_CONTROL)
960
        return -1;
961
 
962
    if ((dir != FTPLIB_READ) && (dir != FTPLIB_WRITE))
963
    {
242 andreas 964
        snprintf(nControl->response, sizeof(ftphandle::response), "Invalid direction %d\n", dir);
117 andreas 965
        return -1;
966
    }
967
 
968
    if ((mode != ftplib::ascii) && (mode != ftplib::image))
969
    {
242 andreas 970
        snprintf(nControl->response, sizeof(ftphandle::response), "Invalid mode %c\n", mode);
117 andreas 971
        return -1;
972
    }
973
 
974
    l = sizeof(sin);
975
 
976
    memset(&sin, 0, l);
977
    sin.in.sin_family = AF_INET;
978
 
979
    if (!FtpSendCmd("PASV", '2', nControl))
980
        return -1;
981
 
982
    cp = strchr(nControl->response, '(');
983
 
984
    if (cp == NULL)
985
        return -1;
986
 
987
    cp++;
988
    sscanf(cp, "%hhu,%hhu,%hhu,%hhu,%hhu,%hhu", &v[2], &v[3], &v[4], &v[5], &v[0], &v[1]);
989
 
990
    if (nControl->correctpasv)
991
        if (!CorrectPasvResponse(v))
992
            return -1;
993
 
994
    sin.sa.sa_data[2] = v[2];
995
    sin.sa.sa_data[3] = v[3];
996
    sin.sa.sa_data[4] = v[4];
997
    sin.sa.sa_data[5] = v[5];
998
    sin.sa.sa_data[0] = v[0];
999
    sin.sa.sa_data[1] = v[1];
1000
 
1001
    if (mp_ftphandle->offset != 0)
1002
    {
1003
        char buf[256];
242 andreas 1004
        sprint_rest(buf, mp_ftphandle->offset, sizeof(buf));
117 andreas 1005
 
1006
        if (!FtpSendCmd(buf, '3', nControl))
1007
            return 0;
1008
    }
1009
 
1010
    sData = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
1011
 
1012
    if (sData == -1)
1013
    {
120 andreas 1014
        errorHandler("socket", errno, __LINE__);
117 andreas 1015
        return -1;
1016
    }
1017
 
1018
    if (setsockopt(sData, SOL_SOCKET, SO_REUSEADDR, SETSOCKOPT_OPTVAL_TYPE & on, sizeof(on)) == -1)
1019
    {
120 andreas 1020
        errorHandler("setsockopt", errno, __LINE__);
118 andreas 1021
        close(sData);
117 andreas 1022
        return -1;
1023
    }
1024
 
1025
    if (setsockopt(sData, SOL_SOCKET, SO_LINGER, SETSOCKOPT_OPTVAL_TYPE & lng, sizeof(lng)) == -1)
1026
    {
120 andreas 1027
        errorHandler("setsockopt", errno, __LINE__);
118 andreas 1028
        close(sData);
117 andreas 1029
        return -1;
1030
    }
1031
 
1032
    if (nControl->dir != FTPLIB_CONTROL)
1033
        return -1;
1034
 
1035
    memcpy(cmd + strlen(cmd), "\r\n\0", 3);
1036
#ifndef NOSSL
1037
 
1038
    if (nControl->tlsctrl)
370 andreas 1039
        ret = SSL_write(nControl->ssl, cmd, (int)strlen(cmd));
117 andreas 1040
    else
370 andreas 1041
        ret = (int)write(nControl->handle, cmd, (int)strlen(cmd));
117 andreas 1042
 
1043
#else
118 andreas 1044
    ret = write(nControl->handle, cmd, strlen(cmd));
117 andreas 1045
#endif
1046
 
1047
    if (ret <= 0)
1048
    {
120 andreas 1049
        errorHandler("write", errno, __LINE__);
117 andreas 1050
        return -1;
1051
    }
1052
 
1053
    if (connect(sData, &sin.sa, sizeof(sin.sa)) == -1)
1054
    {
120 andreas 1055
        errorHandler("connect", errno, __LINE__);
118 andreas 1056
        close(sData);
117 andreas 1057
        return -1;
1058
    }
1059
 
1060
    if (!readresp('1', nControl))
1061
    {
118 andreas 1062
        close(sData);
117 andreas 1063
        return -1;
1064
    }
1065
 
1066
    ctrl = static_cast<ftphandle*>(calloc(1, sizeof(ftphandle)));
1067
 
1068
    if (ctrl == NULL)
1069
    {
120 andreas 1070
        errorHandler("calloc", errno, __LINE__);
118 andreas 1071
        close(sData);
117 andreas 1072
        return -1;
1073
    }
1074
 
1075
    if ((mode == 'A') && ((ctrl->buf = static_cast<char*>(malloc(FTPLIB_BUFSIZ))) == NULL))
1076
    {
120 andreas 1077
        errorHandler("calloc", errno, __LINE__);
118 andreas 1078
        close(sData);
117 andreas 1079
        free(ctrl);
1080
        return -1;
1081
    }
1082
 
1083
    ctrl->handle = sData;
1084
    ctrl->dir = dir;
1085
    ctrl->ctrl = (nControl->cmode == ftplib::pasv) ? nControl : NULL;
1086
    ctrl->idletime = nControl->idletime;
1087
    ctrl->cbarg = nControl->cbarg;
1088
    ctrl->xfered = 0;
1089
    ctrl->xfered1 = 0;
1090
    ctrl->cbbytes = nControl->cbbytes;
1091
 
1092
    if (ctrl->idletime.tv_sec || ctrl->idletime.tv_usec)
1093
        ctrl->idlecb = nControl->idlecb;
1094
    else
1095
        ctrl->idlecb = NULL;
1096
 
1097
    if (ctrl->cbbytes)
1098
        ctrl->xfercb = nControl->xfercb;
1099
    else
1100
        ctrl->xfercb = NULL;
1101
 
1102
    *nData = ctrl;
1103
 
1104
    return 1;
1105
}
1106
 
1107
/*
1108
 * FtpClose - close a data connection
1109
 */
1110
int ftplib::FtpClose(ftphandle *nData)
1111
{
1112
    ftphandle *ctrl;
1113
 
370 andreas 1114
    if (!nData)
1115
        return 0;
1116
 
117 andreas 1117
    if (nData->dir == FTPLIB_WRITE)
1118
    {
118 andreas 1119
        if (nData->buf != NULL)
1120
            writeline(NULL, 0, nData);
117 andreas 1121
    }
1122
    else if (nData->dir != FTPLIB_READ)
1123
        return 0;
1124
 
1125
    if (nData->buf)
1126
        free(nData->buf);
1127
 
1128
    shutdown(nData->handle, 2);
118 andreas 1129
    close(nData->handle);
117 andreas 1130
 
1131
    ctrl = nData->ctrl;
1132
#ifndef NOSSL
1133
    SSL_free(nData->ssl);
1134
#endif
1135
    free(nData);
1136
 
1137
    if (ctrl)
1138
        return readresp('2', ctrl);
1139
 
1140
    return 1;
1141
}
1142
 
1143
/*
1144
 * FtpRead - read from a data connection
1145
 */
1146
int ftplib::FtpRead(void *buf, int max, ftphandle *nData)
1147
{
1148
    int i;
1149
 
1150
    if (nData->dir != FTPLIB_READ)
1151
        return 0;
1152
 
1153
    if (nData->buf)
1154
        i = readline(static_cast<char*>(buf), max, nData);
1155
    else
1156
    {
1157
        i = socket_wait(nData);
1158
 
1159
        if (i != 1)
1160
            return 0;
1161
 
1162
#ifndef NOSSL
1163
        if (nData->tlsdata)
1164
            i = SSL_read(nData->ssl, buf, max);
1165
        else
370 andreas 1166
            i = (int)read(nData->handle, buf, max);
117 andreas 1167
 
1168
#else
118 andreas 1169
        i = read(nData->handle, buf, max);
117 andreas 1170
#endif
1171
    }
1172
 
120 andreas 1173
    if (i == -1)
1174
        return 0;
117 andreas 1175
 
1176
    nData->xfered += i;
1177
 
120 andreas 1178
    if (mp_ftphandle->xfercb && nData->cbbytes)
117 andreas 1179
    {
1180
        nData->xfered1 += i;
1181
 
1182
        if (nData->xfered1 > nData->cbbytes)
1183
        {
120 andreas 1184
            if (mp_ftphandle->xfercb(nData->xfered, mp_ftphandle->cbarg) == 0)
117 andreas 1185
                return 0;
1186
 
1187
            nData->xfered1 = 0;
1188
        }
1189
    }
1190
 
1191
    return i;
1192
}
1193
 
1194
/*
1195
 * FtpWrite - write to a data connection
1196
 */
1197
int ftplib::FtpWrite(void *buf, int len, ftphandle *nData)
1198
{
1199
    int i;
1200
 
1201
    if (nData->dir != FTPLIB_WRITE) return 0;
1202
 
1203
    if (nData->buf)
1204
        i = writeline(static_cast<char*>(buf), len, nData);
1205
    else
1206
    {
1207
        socket_wait(nData);
1208
#ifndef NOSSL
1209
 
1210
        if (nData->tlsdata)
1211
            i = SSL_write(nData->ssl, buf, len);
1212
        else
370 andreas 1213
            i = (int)write(nData->handle, buf, len);
117 andreas 1214
 
1215
#else
118 andreas 1216
        i = write(nData->handle, buf, len);
117 andreas 1217
#endif
1218
    }
1219
 
1220
    if (i == -1)
1221
        return 0;
1222
 
1223
    nData->xfered += i;
1224
 
120 andreas 1225
    if (mp_ftphandle->xfercb && nData->cbbytes)
117 andreas 1226
    {
1227
        nData->xfered1 += i;
1228
 
1229
        if (nData->xfered1 > nData->cbbytes)
1230
        {
120 andreas 1231
            if (mp_ftphandle->xfercb(nData->xfered, mp_ftphandle->cbarg) == 0)
117 andreas 1232
                return 0;
1233
 
1234
            nData->xfered1 = 0;
1235
        }
1236
    }
1237
 
1238
    return i;
1239
}
1240
 
1241
/*
1242
 * FtpSite - send a SITE command
1243
 *
1244
 * return 1 if command successful, 0 otherwise
1245
 */
1246
int ftplib::Site(const char *cmd)
1247
{
1248
    char buf[256];
1249
 
1250
    if ((strlen(cmd) + 7) > sizeof(buf))
1251
        return 0;
1252
 
242 andreas 1253
    snprintf(buf, sizeof(buf), "SITE %s", cmd);
117 andreas 1254
 
1255
    if (!FtpSendCmd(buf, '2', mp_ftphandle))
1256
        return 0;
1257
 
1258
    return 1;
1259
}
1260
 
1261
/*
1262
 * FtpRaw - send a raw string string
1263
 *
1264
 * return 1 if command successful, 0 otherwise
1265
 */
1266
 
1267
int ftplib::Raw(const char *cmd)
1268
{
1269
    char buf[256];
1270
    strncpy(buf, cmd, 256);
1271
 
1272
    if (!FtpSendCmd(buf, '2', mp_ftphandle))
1273
        return 0;
1274
 
1275
    return 1;
1276
}
1277
 
1278
/*
1279
 * FtpSysType - send a SYST command
1280
 *
1281
 * Fills in the user buffer with the remote system type.  If more
1282
 * information from the response is required, the user can parse
1283
 * it out of the response buffer returned by FtpLastResponse().
1284
 *
1285
 * return 1 if command successful, 0 otherwise
1286
 */
1287
int ftplib::SysType(char *buf, int max)
1288
{
1289
    int l = max;
1290
    char *b = buf;
1291
    char *s;
1292
 
1293
    if (!FtpSendCmd("SYST", '2', mp_ftphandle))
1294
        return 0;
1295
 
1296
    s = &mp_ftphandle->response[4];
1297
 
1298
    while ((--l) && (*s != ' '))
1299
        *b++ = *s++;
1300
 
1301
    *b++ = '\0';
1302
    return 1;
1303
}
1304
 
1305
/*
1306
 * FtpMkdir - create a directory at server
1307
 *
1308
 * return 1 if successful, 0 otherwise
1309
 */
1310
int ftplib::Mkdir(const char *path)
1311
{
1312
    char buf[256];
1313
 
1314
    if ((strlen(path) + 6) > sizeof(buf))
1315
        return 0;
1316
 
242 andreas 1317
    snprintf(buf, sizeof(buf), "MKD %s", path);
117 andreas 1318
 
1319
    if (!FtpSendCmd(buf, '2', mp_ftphandle))
1320
        return 0;
1321
 
1322
    return 1;
1323
}
1324
 
1325
/*
1326
 * FtpChdir - change path at remote
1327
 *
1328
 * return 1 if successful, 0 otherwise
1329
 */
1330
int ftplib::Chdir(const char *path)
1331
{
1332
    char buf[256];
1333
 
1334
    if ((strlen(path) + 6) > sizeof(buf))
1335
        return 0;
1336
 
242 andreas 1337
    snprintf(buf, sizeof(buf), "CWD %s", path);
117 andreas 1338
 
1339
    if (!FtpSendCmd(buf, '2', mp_ftphandle))
1340
        return 0;
1341
 
1342
    return 1;
1343
}
1344
 
1345
/*
1346
 * FtpCDUp - move to parent directory at remote
1347
 *
1348
 * return 1 if successful, 0 otherwise
1349
 */
1350
int ftplib::Cdup()
1351
{
1352
    if (!FtpSendCmd("CDUP", '2', mp_ftphandle))
1353
        return 0;
1354
 
1355
    return 1;
1356
}
1357
 
1358
/*
1359
 * FtpRmdir - remove directory at remote
1360
 *
1361
 * return 1 if successful, 0 otherwise
1362
 */
1363
int ftplib::Rmdir(const char *path)
1364
{
1365
    char buf[256];
1366
 
1367
    if ((strlen(path) + 6) > sizeof(buf))
1368
        return 0;
1369
 
242 andreas 1370
    snprintf(buf, sizeof(buf), "RMD %s", path);
117 andreas 1371
 
1372
    if (!FtpSendCmd(buf, '2', mp_ftphandle))
1373
        return 0;
1374
 
1375
    return 1;
1376
}
1377
 
1378
/*
1379
 * FtpPwd - get working directory at remote
1380
 *
1381
 * return 1 if successful, 0 otherwise
1382
 */
1383
int ftplib::Pwd(char *path, int max)
1384
{
1385
    int l = max;
1386
    char *b = path;
1387
    char *s;
1388
 
1389
    if (!FtpSendCmd("PWD", '2', mp_ftphandle))
1390
        return 0;
1391
 
1392
    s = strchr(mp_ftphandle->response, '"');
1393
 
1394
    if (s == NULL)
1395
        return 0;
1396
 
1397
    s++;
1398
 
1399
    while ((--l) && (*s) && (*s != '"'))
1400
        *b++ = *s++;
1401
 
1402
    *b = '\0';
1403
    return 1;
1404
}
1405
 
1406
/*
1407
 * FtpXfer - issue a command and transfer data
1408
 *
1409
 * return 1 if successful, 0 otherwise
1410
 */
1411
int ftplib::FtpXfer(const char *localfile, const char *path, ftphandle *nControl, accesstype type, transfermode mode)
1412
{
1413
    int l, c;
1414
    char *dbuf;
1415
    FILE *local = NULL;
1416
    ftphandle *nData;
1417
 
1418
    if (localfile != NULL)
1419
    {
1420
        char ac[3] = "  ";
1421
 
1422
        if ((type == ftplib::dir) || (type == ftplib::dirverbose))
1423
        {
1424
            ac[0] = 'w';
1425
            ac[1] = '\0';
1426
        }
1427
 
1428
        if (type == ftplib::fileread)
1429
        {
1430
            ac[0] = 'w';
1431
            ac[1] = '\0';
1432
        }
1433
 
1434
        if (type == ftplib::filewriteappend)
1435
        {
1436
            ac[0] = 'r';
1437
            ac[1] = '\0';
1438
        }
1439
 
1440
        if (type == ftplib::filereadappend)
1441
        {
1442
            ac[0] = 'a';
1443
            ac[1] = '\0';
1444
        }
1445
 
1446
        if (type == ftplib::filewrite)
1447
        {
1448
            ac[0] = 'r';
1449
            ac[1] = '\0';
1450
        }
1451
 
1452
        if (mode == ftplib::image) ac[1] = 'b';
355 andreas 1453
#ifdef __ANDROID__
1454
        local = fopen(localfile, ac);
1455
#else
117 andreas 1456
        local = fopen64(localfile, ac);
355 andreas 1457
#endif
117 andreas 1458
        if (local == NULL)
1459
        {
120 andreas 1460
            std::string msg = string("Opening local file ") + localfile;
1461
            errorHandler(msg.c_str(), errno, __LINE__);
117 andreas 1462
            strncpy(nControl->response, strerror(errno), sizeof(nControl->response));
1463
            return 0;
1464
        }
1465
 
1466
        if (type == ftplib::filewriteappend)
355 andreas 1467
#ifdef __ANDROID__
1468
            fseek(local, mp_ftphandle->offset, SEEK_SET);
1469
#else
117 andreas 1470
            fseeko64(local, mp_ftphandle->offset, SEEK_SET);
355 andreas 1471
#endif
117 andreas 1472
    }
1473
 
1474
    if (local == NULL) local = ((type == ftplib::filewrite)
1475
                                    || (type == ftplib::filewriteappend)) ? stdin : stdout;
1476
 
1477
    if (!FtpAccess(path, type, mode, nControl, &nData))
1478
    {
1479
        if (localfile != NULL)
1480
            fclose(local);
1481
 
1482
        return 0;
1483
    }
1484
 
1485
    dbuf = static_cast<char*>(malloc(FTPLIB_BUFSIZ));
1486
 
1487
    if ((type == ftplib::filewrite) || (type == ftplib::filewriteappend))
1488
    {
370 andreas 1489
        while ((l = (int)fread(dbuf, 1, FTPLIB_BUFSIZ, local)) > 0)
117 andreas 1490
        {
1491
            if ((c = FtpWrite(dbuf, l, nData)) < l)
1492
            {
120 andreas 1493
                std::string msg = string("short write: passed ") + std::to_string(l) + ", wrote " + std::to_string(c);
1494
                errorHandler(msg.c_str(), 0, 0);
117 andreas 1495
                break;
1496
            }
1497
        }
1498
    }
1499
    else
1500
    {
1501
        while ((l = FtpRead(dbuf, FTPLIB_BUFSIZ, nData)) > 0)
1502
        {
1503
            if (fwrite(dbuf, 1, l, local) <= 0)
1504
            {
120 andreas 1505
                errorHandler("localfile write", errno, __LINE__);
117 andreas 1506
                break;
1507
            }
1508
        }
1509
    }
1510
 
1511
    free(dbuf);
1512
    fflush(local);
1513
 
1514
    if (localfile != NULL)
1515
        fclose(local);
1516
 
1517
    return FtpClose(nData);
1518
}
1519
 
1520
/*
1521
 * FtpNlst - issue an NLST command and write response to output
1522
 *
1523
 * return 1 if successful, 0 otherwise
1524
 */
1525
int ftplib::Nlst(const char *outputfile, const char *path)
1526
{
1527
    mp_ftphandle->offset = 0;
1528
    return FtpXfer(outputfile, path, mp_ftphandle, ftplib::dir, ftplib::ascii);
1529
}
1530
 
1531
/*
1532
 * FtpDir - issue a LIST command and write response to output
1533
 *
1534
 * return 1 if successful, 0 otherwise
1535
 */
1536
int ftplib::Dir(const char *outputfile, const char *path)
1537
{
1538
    mp_ftphandle->offset = 0;
1539
    return FtpXfer(outputfile, path, mp_ftphandle, ftplib::dirverbose, ftplib::ascii);
1540
}
1541
 
1542
/*
1543
 * FtpSize - determine the size of a remote file
1544
 *
1545
 * return 1 if successful, 0 otherwise
1546
 */
1547
int ftplib::Size(const char *path, int *size, transfermode mode)
1548
{
1549
    char cmd[256];
1550
    int resp, sz, rv = 1;
1551
 
1552
    if ((strlen(path) + 7) > sizeof(cmd))
1553
        return 0;
1554
 
242 andreas 1555
    snprintf(cmd, sizeof(cmd), "TYPE %c", mode);
117 andreas 1556
 
1557
    if (!FtpSendCmd(cmd, '2', mp_ftphandle))
1558
        return 0;
1559
 
242 andreas 1560
    snprintf(cmd, sizeof(cmd), "SIZE %s", path);
117 andreas 1561
 
1562
    if (!FtpSendCmd(cmd, '2', mp_ftphandle))
1563
        rv = 0;
1564
    else
1565
    {
1566
        if (sscanf(mp_ftphandle->response, "%d %d", &resp, &sz) == 2)
1567
            *size = sz;
1568
        else
1569
            rv = 0;
1570
    }
1571
 
1572
    return rv;
1573
}
1574
 
1575
/*
1576
 * FtpModDate - determine the modification date of a remote file
1577
 *
1578
 * return 1 if successful, 0 otherwise
1579
 */
1580
int ftplib::ModDate(const char *path, char *dt, int max)
1581
{
1582
    char buf[256];
1583
    int rv = 1;
1584
 
1585
    if ((strlen(path) + 7) > sizeof(buf))
1586
        return 0;
1587
 
242 andreas 1588
    snprintf(buf, sizeof(buf), "MDTM %s", path);
117 andreas 1589
 
1590
    if (!FtpSendCmd(buf, '2', mp_ftphandle))
1591
        rv = 0;
1592
    else
1593
        strncpy(dt, &mp_ftphandle->response[4], max);
1594
 
1595
    return rv;
1596
}
1597
 
1598
/*
1599
 * FtpGet - issue a GET command and write received data to output
1600
 *
1601
 * return 1 if successful, 0 otherwise
1602
 */
1603
 
1604
int ftplib::Get(const char *outputfile, const char *path, transfermode mode, off64_t offset)
1605
{
1606
    mp_ftphandle->offset = offset;
1607
 
1608
    if (offset == 0)
1609
        return FtpXfer(outputfile, path, mp_ftphandle, ftplib::fileread, mode);
1610
    else
1611
        return FtpXfer(outputfile, path, mp_ftphandle, ftplib::filereadappend, mode);
1612
}
1613
 
1614
/*
1615
 * FtpPut - issue a PUT command and send data from input
1616
 *
1617
 * return 1 if successful, 0 otherwise
1618
 */
1619
 
1620
int ftplib::Put(const char *inputfile, const char *path, transfermode mode, off64_t offset)
1621
{
1622
    mp_ftphandle->offset = offset;
1623
 
1624
    if (offset == 0)
1625
        return FtpXfer(inputfile, path, mp_ftphandle, ftplib::filewrite, mode);
1626
    else
1627
        return FtpXfer(inputfile, path, mp_ftphandle, ftplib::filewriteappend, mode);
1628
}
1629
 
1630
 
1631
int ftplib::Rename(const char *src, const char *dst)
1632
{
1633
    char cmd[256];
1634
 
1635
    if (((strlen(src) + 7) > sizeof(cmd)) || ((strlen(dst) + 7) > sizeof(cmd)))
1636
        return 0;
1637
 
242 andreas 1638
    snprintf(cmd, sizeof(cmd), "RNFR %s", src);
117 andreas 1639
 
1640
    if (!FtpSendCmd(cmd, '3', mp_ftphandle))
1641
        return 0;
1642
 
242 andreas 1643
    snprintf(cmd, sizeof(cmd), "RNTO %s", dst);
117 andreas 1644
 
1645
    if (!FtpSendCmd(cmd, '2', mp_ftphandle))
1646
        return 0;
1647
 
1648
    return 1;
1649
}
1650
 
1651
int ftplib::Delete(const char *path)
1652
{
1653
    char cmd[256];
1654
 
1655
    if ((strlen(path) + 7) > sizeof(cmd))
1656
        return 0;
1657
 
242 andreas 1658
    snprintf(cmd, sizeof(cmd), "DELE %s", path);
117 andreas 1659
 
1660
    if (!FtpSendCmd(cmd, '2', mp_ftphandle))
1661
        return 0;
1662
 
1663
    return 1;
1664
}
1665
 
1666
/*
1667
 * FtpQuit - disconnect from remote
1668
 *
1669
 * return 1 if successful, 0 otherwise
1670
 */
1671
int ftplib::Quit()
1672
{
1673
    if (mp_ftphandle->dir != FTPLIB_CONTROL)
1674
        return 0;
1675
 
1676
    if (mp_ftphandle->handle == 0)
1677
    {
1678
        strcpy(mp_ftphandle->response, "error: no anwser from server\n");
1679
        return 0;
1680
    }
1681
 
1682
    if (!FtpSendCmd("QUIT", '2', mp_ftphandle))
1683
    {
118 andreas 1684
        close(mp_ftphandle->handle);
117 andreas 1685
        return 0;
1686
    }
1687
    else
1688
    {
118 andreas 1689
        close(mp_ftphandle->handle);
117 andreas 1690
        return 1;
1691
    }
1692
}
1693
 
1694
int ftplib::Fxp(ftplib* src, ftplib* dst, const char *pathSrc, const char *pathDst, transfermode mode, fxpmethod method)
1695
{
1696
    char *cp;
1697
    unsigned char v[6];
1698
    char buf[256];
1699
    int retval = 0;
1700
 
242 andreas 1701
    snprintf(buf, sizeof(buf), "TYPE %c", mode);
117 andreas 1702
 
1703
    if (!dst->FtpSendCmd(buf, '2', dst->mp_ftphandle))
1704
        return -1;
1705
 
1706
    if (!src->FtpSendCmd(buf, '2', src->mp_ftphandle))
1707
        return -1;
1708
 
1709
    if (method == ftplib::defaultfxp)
1710
    {
1711
        // PASV dst
1712
 
1713
        if (!dst->FtpSendCmd("PASV", '2', dst->mp_ftphandle))
1714
            return -1;
1715
 
1716
        cp = strchr(dst->mp_ftphandle->response, '(');
1717
 
1718
        if (cp == NULL) return -1;
1719
 
1720
        cp++;
1721
        sscanf(cp, "%hhu,%hhu,%hhu,%hhu,%hhu,%hhu", &v[2], &v[3], &v[4], &v[5], &v[0], &v[1]);
1722
 
1723
        if (dst->mp_ftphandle->correctpasv)
1724
            if (!dst->CorrectPasvResponse(v))
1725
                return -1;
1726
 
1727
        // PORT src
1728
 
242 andreas 1729
        snprintf(buf, sizeof(buf), "PORT %d,%d,%d,%d,%d,%d", v[2], v[3], v[4], v[5], v[0], v[1]);
117 andreas 1730
 
1731
        if (!src->FtpSendCmd(buf, '2', src->mp_ftphandle))
1732
            return -1;
1733
 
1734
        // RETR src
1735
 
1736
        strcpy(buf, "RETR");
1737
 
1738
        if (pathSrc != NULL)
1739
        {
370 andreas 1740
            int i = (int)strlen(buf);
117 andreas 1741
            buf[i++] = ' ';
1742
 
1743
            if ((strlen(pathSrc) + i) >= sizeof(buf))
1744
                return 0;
1745
 
1746
            strcpy(&buf[i], pathSrc);
1747
        }
1748
 
1749
        if (!src->FtpSendCmd(buf, '1', src->mp_ftphandle))
1750
            return 0;
1751
 
1752
        // STOR dst
1753
 
1754
        strcpy(buf, "STOR");
1755
 
1756
        if (pathDst != NULL)
1757
        {
1758
            int i = strlen(buf);
1759
            buf[i++] = ' ';
1760
 
1761
            if ((strlen(pathDst) + i) >= sizeof(buf))
1762
                return 0;
1763
 
1764
            strcpy(&buf[i], pathDst);
1765
        }
1766
 
1767
        if (!dst->FtpSendCmd(buf, '1', dst->mp_ftphandle))
1768
        {
1769
            /* this closes the data connection, to abort the RETR on
1770
             *      the source ftp. all hail pftp, it took me several
1771
             *      hours and i was absolutely clueless, playing around with
1772
             *      ABOR and whatever, when i desperately checked the pftp
1773
             *      source which gave me this final hint. thanks dude(s). */
1774
 
1775
            dst->FtpSendCmd("PASV", '2', dst->mp_ftphandle);
1776
            src->readresp('4', src->mp_ftphandle);
1777
            return 0;
1778
        }
1779
 
1780
        retval = (src->readresp('2', src->mp_ftphandle)) & (dst->readresp('2', dst->mp_ftphandle));
1781
 
1782
    }
1783
    else
1784
    {
1785
        // PASV src
1786
        if (!src->FtpSendCmd("PASV", '2', src->mp_ftphandle))
1787
            return -1;
1788
 
1789
        cp = strchr(src->mp_ftphandle->response, '(');
1790
 
1791
        if (cp == NULL)
1792
            return -1;
1793
 
1794
        cp++;
1795
        sscanf(cp, "%hhu,%hhu,%hhu,%hhu,%hhu,%hhu", &v[2], &v[3], &v[4], &v[5], &v[0], &v[1]);
1796
 
1797
        if (src->mp_ftphandle->correctpasv)
1798
            if (!src->CorrectPasvResponse(v))
1799
                return -1;
1800
 
1801
        // PORT dst
1802
 
242 andreas 1803
        snprintf(buf, sizeof(buf), "PORT %d,%d,%d,%d,%d,%d", v[2], v[3], v[4], v[5], v[0], v[1]);
117 andreas 1804
 
1805
        if (!dst->FtpSendCmd(buf, '2', dst->mp_ftphandle))
1806
            return -1;
1807
 
1808
        // STOR dest
1809
 
1810
        strcpy(buf, "STOR");
1811
 
1812
        if (pathDst != NULL)
1813
        {
1814
            int i = strlen(buf);
1815
            buf[i++] = ' ';
1816
 
1817
            if ((strlen(pathDst) + i) >= sizeof(buf))
1818
                return 0;
1819
 
1820
            strcpy(&buf[i], pathDst);
1821
        }
1822
 
1823
        if (!dst->FtpSendCmd(buf, '1', dst->mp_ftphandle))
1824
            return 0;
1825
 
1826
        // RETR src
1827
 
1828
        strcpy(buf, "RETR");
1829
 
1830
        if (pathSrc != NULL)
1831
        {
1832
            int i = strlen(buf);
1833
            buf[i++] = ' ';
1834
 
1835
            if ((strlen(pathSrc) + i) >= sizeof(buf))
1836
                return 0;
1837
 
1838
            strcpy(&buf[i], pathSrc);
1839
        }
1840
 
1841
        if (!src->FtpSendCmd(buf, '1', src->mp_ftphandle))
1842
        {
1843
            src->FtpSendCmd("PASV", '2', src->mp_ftphandle);
1844
            dst->readresp('4', dst->mp_ftphandle);
1845
            return 0;
1846
        }
1847
 
1848
        // wait til its finished!
1849
 
1850
        retval = (src->readresp('2', src->mp_ftphandle)) & (dst->readresp('2', dst->mp_ftphandle));
1851
 
1852
    }
1853
 
1854
    return retval;
1855
}
1856
 
1857
 
1858
int ftplib::SetDataEncryption(dataencryption enc)
1859
{
1860
#ifdef NOSSL
1861
    (void)enc;
1862
    return 0;
1863
#else
1864
 
1865
    if (!mp_ftphandle->tlsctrl) return 0;
1866
 
1867
    if (!FtpSendCmd("PBSZ 0", '2', mp_ftphandle)) return 0;
1868
 
1869
    switch (enc)
1870
    {
1871
        case ftplib::unencrypted:
1872
            mp_ftphandle->tlsdata = 0;
1873
 
1874
            if (!FtpSendCmd("PROT C", '2', mp_ftphandle)) return 0;
1875
 
1876
            break;
1877
 
1878
        case ftplib::secure:
1879
            mp_ftphandle->tlsdata = 1;
1880
 
1881
            if (!FtpSendCmd("PROT P", '2', mp_ftphandle)) return 0;
1882
 
1883
            break;
1884
 
1885
        default:
1886
            return 0;
1887
    }
1888
 
1889
    return 1;
1890
#endif
1891
}
1892
 
1893
int ftplib::NegotiateEncryption()
1894
{
1895
#ifdef NOSSL
1896
    return 0;
1897
#else
1898
    int ret;
1899
 
1900
    if (!FtpSendCmd("AUTH TLS", '2', mp_ftphandle))
1901
        return 0;
1902
 
1903
    mp_ftphandle->sbio = BIO_new_socket(mp_ftphandle->handle, BIO_NOCLOSE);
1904
    SSL_set_bio(mp_ftphandle->ssl, mp_ftphandle->sbio, mp_ftphandle->sbio);
1905
 
1906
    ret = SSL_connect(mp_ftphandle->ssl);
1907
 
1908
    if (ret == 1)
1909
        mp_ftphandle->tlsctrl = 1;
1910
 
1911
    if (mp_ftphandle->certcb != NULL)
1912
    {
1913
        X509 *cert = SSL_get_peer_certificate(mp_ftphandle->ssl);
1914
 
1915
        if (!mp_ftphandle->certcb(mp_ftphandle->cbarg, cert))
1916
            return 0;
1917
    }
1918
 
1919
    if (ret < 1)
1920
        return 0;
1921
 
1922
    return 1;
1923
#endif
1924
}
1925
 
1926
void ftplib::SetCallbackCertFunction(FtpCallbackCert pointer)
1927
{
1928
#ifdef NOSSL
1929
    (void)pointer;
1930
#else
1931
    mp_ftphandle->certcb = pointer;
1932
#endif
1933
}
1934
 
1935
void ftplib::SetCallbackIdleFunction(FtpCallbackIdle pointer)
1936
{
1937
    mp_ftphandle->idlecb = pointer;
1938
}
1939
 
1940
void ftplib::SetCallbackXferFunction(FtpCallbackXfer pointer)
1941
{
1942
    mp_ftphandle->xfercb = pointer;
1943
}
1944
 
1945
void ftplib::SetCallbackLogFunction(FtpCallbackLog pointer)
1946
{
1947
    mp_ftphandle->logcb = pointer;
1948
}
1949
 
120 andreas 1950
void ftplib::SetCallbackErrorFunction(FtpCallbackError pointer)
1951
{
1952
    mp_ftphandle->errorcb = pointer;
1953
}
1954
 
117 andreas 1955
void ftplib::SetCallbackArg(void *arg)
1956
{
1957
    mp_ftphandle->cbarg = arg;
1958
}
1959
 
1960
void ftplib::SetCallbackBytes(off64_t bytes)
1961
{
1962
    mp_ftphandle->cbbytes = bytes;
1963
}
1964
 
1965
void ftplib::SetCallbackIdletime(int time)
1966
{
1967
    mp_ftphandle->idletime.tv_sec = time / 1000;
1968
    mp_ftphandle->idletime.tv_usec = (time % 1000) * 1000;
1969
}
1970
 
1971
void ftplib::SetConnmode(connmode mode)
1972
{
1973
    mp_ftphandle->cmode = mode;
137 andreas 1974
    Log(LOG_DEBUG, string("Mode was set to ") + (mode == pasv ? "PASSIVE" : "PORT"));
117 andreas 1975
}
1976
 
1977
void ftplib::ClearHandle()
1978
{
1979
    mp_ftphandle->dir = FTPLIB_CONTROL;
1980
    mp_ftphandle->ctrl = NULL;
1981
    mp_ftphandle->cmode = ftplib::pasv;
1982
    mp_ftphandle->idlecb = NULL;
1983
    mp_ftphandle->idletime.tv_sec = mp_ftphandle->idletime.tv_usec = 0;
1984
    mp_ftphandle->cbarg = NULL;
1985
    mp_ftphandle->xfered = 0;
1986
    mp_ftphandle->xfered1 = 0;
1987
    mp_ftphandle->cbbytes = 0;
1988
#ifndef NOSSL
1989
    mp_ftphandle->tlsctrl = 0;
1990
    mp_ftphandle->tlsdata = 0;
1991
    mp_ftphandle->certcb = NULL;
1992
#endif
1993
    mp_ftphandle->offset = 0;
1994
    mp_ftphandle->handle = 0;
1995
    mp_ftphandle->logcb = NULL;
1996
    mp_ftphandle->xfercb = NULL;
1997
    mp_ftphandle->correctpasv = false;
1998
}
1999
 
2000
int ftplib::CorrectPasvResponse(unsigned char *v)
2001
{
2002
    struct sockaddr ipholder;
2003
    socklen_t ipholder_size = sizeof(ipholder);
2004
 
2005
    if (getpeername(mp_ftphandle->handle, &ipholder, &ipholder_size) == -1)
2006
    {
120 andreas 2007
        errorHandler("getpeername", errno, __LINE__);
118 andreas 2008
        close(mp_ftphandle->handle);
117 andreas 2009
        return 0;
2010
    }
2011
 
2012
    for (int i = 2; i < 6; i++)
2013
        v[i] = ipholder.sa_data[i];
2014
 
2015
    return 1;
2016
}
2017
 
2018
ftphandle* ftplib::RawOpen(const char *path, accesstype type, transfermode mode)
2019
{
2020
    int ret;
137 andreas 2021
    ftphandle* datahandle{nullptr};
117 andreas 2022
    ret = FtpAccess(path, type, mode, mp_ftphandle, &datahandle);
2023
 
2024
    if (ret)
2025
        return datahandle;
2026
    else
137 andreas 2027
        return nullptr;
117 andreas 2028
}
2029
 
2030
int ftplib::RawClose(ftphandle* handle)
2031
{
2032
    return FtpClose(handle);
2033
}
2034
 
2035
int ftplib::RawWrite(void* buf, int len, ftphandle* handle)
2036
{
2037
    return FtpWrite(buf, len, handle);
2038
}
2039
 
2040
int ftplib::RawRead(void* buf, int max, ftphandle* handle)
2041
{
2042
    return FtpRead(buf, max, handle);
2043
}
120 andreas 2044
 
2045
void ftplib::errorHandler(const char* stub, int err, int line)
2046
{
2047
    char emsg[BUFSIZ];
2048
 
2049
    memset(emsg, 0, BUFSIZ);
2050
 
2051
    if (err != 0)
2052
        snprintf(emsg, sizeof(emsg), "%d: %s: %s", line, stub, strerror(err));
2053
    else if (line > 0)
2054
        snprintf(emsg, sizeof(emsg), "%d: %s", line, stub);
2055
    else
2056
        strncpy(emsg, stub, BUFSIZ-1);
2057
 
2058
    if (mp_ftphandle && mp_ftphandle->errorcb)
2059
        mp_ftphandle->errorcb(emsg, mp_ftphandle->cbarg, err);
137 andreas 2060
    else if (_Logging)
2061
        Log(LOG_ERROR, emsg);
120 andreas 2062
    else
2063
        std::cerr << emsg << std::endl;
2064
}
137 andreas 2065
 
2066
void ftplib::Log(int level, const std::string& msg)
2067
{
2068
    if (!_Logging)
2069
        return;
2070
 
2071
    _Logging(level, msg);
2072
}