~ubuntu-branches/ubuntu/vivid/cctools/vivid

« back to all changes in this revision

Viewing changes to ftp_lite/src/ftp_lite.c

  • Committer: Bazaar Package Importer
  • Author(s): Michael Hanke
  • Date: 2011-05-07 09:05:00 UTC
  • Revision ID: james.westby@ubuntu.com-20110507090500-lqpmdtwndor6e7os
Tags: upstream-3.3.2
ImportĀ upstreamĀ versionĀ 3.3.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
Copyright (C) 2003-2004 Douglas Thain and the University of Wisconsin
 
3
Copyright (C) 2005- The University of Notre Dame
 
4
This software is distributed under the GNU General Public License.
 
5
See the file COPYING for details.
 
6
*/
 
7
 
 
8
#ifdef HAS_GLOBUS_GSS
 
9
#include "globus_gss_assist.h"
 
10
#endif
 
11
 
 
12
#include "ftp_lite.h"
 
13
#include "error.h"
 
14
#include "radix.h"
 
15
#include "network.h"
 
16
 
 
17
#include "stringtools.h"
 
18
#include "debug.h"
 
19
#include "full_io.h"
 
20
 
 
21
#include <string.h>
 
22
#include <stdio.h>
 
23
#include <stdlib.h>
 
24
#include <errno.h>
 
25
#include <string.h>
 
26
#include <stdarg.h>
 
27
#include <unistd.h>
 
28
#include <fcntl.h>
 
29
#include <ctype.h>
 
30
#include <unistd.h>
 
31
#include <signal.h>
 
32
#include <sys/types.h>
 
33
 
 
34
int ftp_lite_data_channel_authentication = 0;
 
35
 
 
36
static int ftp_lite_send_command_gss( struct ftp_lite_server *s, const char *outbuffer );
 
37
static int ftp_lite_get_response_gss( struct ftp_lite_server *s, char *outbuffer );
 
38
static int ftp_lite_data_channel_auth( struct ftp_lite_server *s, FILE *stream );
 
39
 
 
40
struct ftp_lite_server {
 
41
        FILE *command;
 
42
        FILE *response;
 
43
        char *hostname;
 
44
        int broken;
 
45
        int went_binary;
 
46
        enum { PLAIN, GLOBUS_GSS } authtype;
 
47
        int auth_done;
 
48
        int data_channel_authentication;
 
49
        #ifdef HAS_GLOBUS_GSS
 
50
                gss_ctx_id_t context;
 
51
                gss_ctx_id_t data_context;
 
52
                gss_cred_id_t credential;
 
53
        #endif
 
54
};
 
55
 
 
56
static int ftp_lite_send_command_raw( struct ftp_lite_server *s, const char *line )
 
57
{
 
58
        char buf[FTP_LITE_LINE_MAX];
 
59
        int length;
 
60
        length = sprintf(buf,"%s\r\n",line);
 
61
        return(full_fwrite(s->command,buf,length)==length);
 
62
}
 
63
 
 
64
static int ftp_lite_get_response_raw( struct ftp_lite_server *s, char *line )
 
65
{
 
66
        char *result;
 
67
 
 
68
        while(1) {
 
69
                result = fgets(line,FTP_LITE_LINE_MAX,s->response);
 
70
                if(result) {
 
71
                        string_chomp(line);
 
72
                        return 1;
 
73
                } else {
 
74
                        if(errno==EINTR) {
 
75
                                continue;
 
76
                        } else {
 
77
                                errno = ECONNRESET;
 
78
                                return 0;
 
79
                        }
 
80
                }
 
81
        }
 
82
}
 
83
 
 
84
static int ftp_lite_send_command( struct ftp_lite_server *s, const char *fmt, ... )
 
85
{
 
86
        char buffer[FTP_LITE_LINE_MAX];
 
87
        va_list args;
 
88
 
 
89
        va_start(args,fmt);
 
90
        vsprintf(buffer,fmt,args);
 
91
        va_end(args);
 
92
 
 
93
        if(!strncmp(buffer,"PASS",4)) {
 
94
                debug(D_FTP,"%s PASS ******\n",s->hostname);
 
95
        } else {
 
96
                debug(D_FTP,"%s %s\n",s->hostname,buffer);
 
97
        }
 
98
 
 
99
        switch(s->authtype) {
 
100
                case PLAIN:
 
101
                        return ftp_lite_send_command_raw(s,buffer);
 
102
                case GLOBUS_GSS:
 
103
                        return ftp_lite_send_command_gss(s,buffer);
 
104
                default:
 
105
                        errno = ENOTSUP;
 
106
                        return 0;
 
107
        }
 
108
}
 
109
 
 
110
static int ftp_lite_get_response( struct ftp_lite_server *s, int accept_note, char *buffer )
 
111
{
 
112
        char c, dash;
 
113
        int result;
 
114
        int response;
 
115
        int fields;
 
116
        int do_message = 0;
 
117
 
 
118
        while(1) {
 
119
                switch(s->authtype) {
 
120
                        case PLAIN:
 
121
                                result = ftp_lite_get_response_raw(s,buffer);
 
122
                                break;
 
123
                        case GLOBUS_GSS:
 
124
                                /*
 
125
                                Depending on the server, some responses are
 
126
                                encrypted and some are not, even once the secure
 
127
                                channel has been established.
 
128
                                */
 
129
                                do {
 
130
                                        errno = 0;
 
131
                                        c = fgetc(s->response);
 
132
                                } while(c==EOF && errno==EINTR);
 
133
                                ungetc(c,s->response);
 
134
                                if(!isdigit((int)c)) {
 
135
                                        result = 0;
 
136
                                        errno = ECONNRESET;
 
137
                                } else if(c=='6') {
 
138
                                        result = ftp_lite_get_response_gss(s,buffer);                           
 
139
                                } else {
 
140
                                        result = ftp_lite_get_response_raw(s,buffer);
 
141
                                }
 
142
                                break;
 
143
                        default:
 
144
                                errno = ENOTSUP;
 
145
                                return 0;
 
146
                }
 
147
 
 
148
                if(!result) return 0;
 
149
 
 
150
                string_chomp(buffer);
 
151
 
 
152
                debug(D_FTP,"%s %s\n",s->hostname,buffer);
 
153
 
 
154
                if(!isdigit((int)(buffer[0]))) continue;
 
155
 
 
156
                fields = sscanf(buffer,"%d%c",&response,&dash);
 
157
                if(fields!=2) {
 
158
                        continue;
 
159
                } else {
 
160
                        if( do_message ) {
 
161
                                if( (dash==' ') && (response==do_message) ) {
 
162
                                        do_message = 0;
 
163
                                } else {
 
164
                                        continue;
 
165
                                }
 
166
                        } else {
 
167
                                if( dash=='-' ) {
 
168
                                        do_message = response;
 
169
                                        continue;
 
170
                                }
 
171
                        }
 
172
 
 
173
                        if( (response/100)==1 ) { 
 
174
                                if(accept_note) {
 
175
                                        return response;
 
176
                                } else {
 
177
                                        continue;
 
178
                                }
 
179
                        } else {
 
180
                                return response;
 
181
                        }
 
182
                }
 
183
        }
 
184
        return response;
 
185
}
 
186
 
 
187
static int ftp_lite_parse_passive( const char *buffer, char *addr, int *port )
 
188
{
 
189
        int response, fields;
 
190
        int hi,lo;
 
191
        int a,b,c,d;
 
192
 
 
193
        fields = sscanf(buffer,"%d %*[^(] (%d,%d,%d,%d,%d,%d)",&response,&a,&b,&c,&d,&hi,&lo);
 
194
        if(fields!=7) return 0;
 
195
 
 
196
        *port = hi*256+lo;
 
197
        sprintf(addr,"%d.%d.%d.%d",a,b,c,d);
 
198
 
 
199
        return 1;
 
200
}
 
201
 
 
202
static int ftp_lite_send_active( struct ftp_lite_server *s, char *addr, int port )
 
203
{
 
204
        char buffer[FTP_LITE_LINE_MAX];
 
205
        int a,b,c,d;
 
206
        int fields;
 
207
 
 
208
        fields = sscanf(addr,"%d.%d.%d.%d",&a,&b,&c,&d);
 
209
        if(fields!=4) return 0;
 
210
        
 
211
        sprintf(buffer,"PORT %d,%d,%d,%d,%d,%d",a,b,c,d,port/256,port&0xff);
 
212
        return ftp_lite_send_command(s,buffer);
 
213
}
 
214
 
 
215
struct ftp_lite_server * ftp_lite_open_and_auth( const char *host, int port )
 
216
{
 
217
        struct ftp_lite_server *s;
 
218
        int save_errno;
 
219
        int gss_port = FTP_LITE_GSS_DEFAULT_PORT;
 
220
        int normal_port = FTP_LITE_DEFAULT_PORT;
 
221
 
 
222
        if(port) {
 
223
                gss_port = port;
 
224
                normal_port = port;
 
225
        }
 
226
 
 
227
        debug(D_FTP,"*** attempting secure connection to %s port %d\n",host,gss_port);
 
228
 
 
229
        s = ftp_lite_open(host,gss_port);
 
230
        if(s) {
 
231
                if(ftp_lite_auth_globus(s)) {
 
232
                        return s;
 
233
                }
 
234
                ftp_lite_close(s);
 
235
        }
 
236
 
 
237
        debug(D_FTP,"*** attempting insecure connection to %s port %d\n",host,normal_port);
 
238
 
 
239
        s = ftp_lite_open(host,normal_port);
 
240
        if(s) {
 
241
                char name[FTP_LITE_LINE_MAX];
 
242
                char pass[FTP_LITE_LINE_MAX];
 
243
 
 
244
                if(ftp_lite_login(host,name,FTP_LITE_LINE_MAX,pass,FTP_LITE_LINE_MAX)) {
 
245
                        if(ftp_lite_auth_userpass(s,name,pass)) {
 
246
                                memset(pass,0,strlen(pass));
 
247
                                return s;
 
248
                        }
 
249
                        memset(pass,0,strlen(pass));
 
250
                }
 
251
                save_errno = errno;
 
252
                ftp_lite_close(s);
 
253
                errno = save_errno;
 
254
        }
 
255
 
 
256
        return 0;
 
257
}
 
258
 
 
259
struct ftp_lite_server * ftp_lite_open( const char *host, int port )
 
260
{
 
261
        char buffer[FTP_LITE_LINE_MAX];
 
262
        struct ftp_lite_server *s;
 
263
        int response;
 
264
        int save_errno;
 
265
        int net=-1;
 
266
 
 
267
        s = malloc(sizeof(*s));
 
268
        if(!s) return 0;
 
269
 
 
270
        s->authtype = PLAIN;
 
271
        s->auth_done = 0;
 
272
        s->hostname = strdup(host);
 
273
        s->went_binary = 0;
 
274
        s->data_channel_authentication = 0;
 
275
 
 
276
        if(!s->hostname) {
 
277
                free(s);
 
278
                return 0;
 
279
        }
 
280
 
 
281
        #ifdef HAS_GLOBUS_GSS
 
282
                s->context = GSS_C_NO_CONTEXT;
 
283
                s->data_context = GSS_C_NO_CONTEXT;
 
284
                s->credential = GSS_C_NO_CREDENTIAL;
 
285
        #endif
 
286
 
 
287
        net = network_connect(host,port);
 
288
        if(net<0) {
 
289
                save_errno = errno;
 
290
                free(s->hostname);
 
291
                free(s);
 
292
                errno = save_errno;
 
293
                return 0;
 
294
        }
 
295
 
 
296
        s->command = fdopen(net,"r+");
 
297
        if(!s->command) {
 
298
                save_errno = errno;
 
299
                network_close(net);
 
300
                free(s->hostname);
 
301
                free(s);
 
302
                errno = save_errno;
 
303
                return 0;
 
304
        }
 
305
 
 
306
        s->response = fdopen(net,"r");
 
307
        if(!s->response) {
 
308
                save_errno = errno;
 
309
                fclose(s->command);
 
310
                free(s->hostname);
 
311
                free(s);
 
312
                errno = save_errno;
 
313
                return 0;
 
314
        }
 
315
 
 
316
        setbuf(s->command,0);
 
317
        setbuf(s->response,0);
 
318
 
 
319
        response = ftp_lite_get_response(s,0,buffer);
 
320
        if((response/100)!=2) {
 
321
                fclose(s->response);
 
322
                fclose(s->command);
 
323
                free(s->hostname);
 
324
                free(s);
 
325
                errno = ftp_lite_error(response);
 
326
                return 0;
 
327
        }
 
328
 
 
329
        /* Most servers send 220, but promiscuous servers send 230 */
 
330
        if(response==230) {
 
331
                s->auth_done=1;
 
332
        }
 
333
 
 
334
        return s;
 
335
}
 
336
 
 
337
int ftp_lite_auth_anonymous( struct ftp_lite_server *s )
 
338
{
 
339
        return ftp_lite_auth_userpass(s,"anonymous","anonymous");
 
340
}
 
341
 
 
342
int ftp_lite_auth_userpass( struct ftp_lite_server *s, const char *user, const char *pass )
 
343
{
 
344
        int r1, r2;
 
345
        char buffer[FTP_LITE_LINE_MAX];
 
346
 
 
347
        if(s->auth_done) return 1;
 
348
 
 
349
        ftp_lite_send_command(s,"USER %s",user);
 
350
        ftp_lite_send_command(s,"PASS %s",pass);
 
351
 
 
352
        r1 = ftp_lite_get_response(s,0,buffer);
 
353
        r2 = ftp_lite_get_response(s,0,buffer);
 
354
 
 
355
        if( ((r1/100)!=3) && ((r1/100)!=2) ) {
 
356
                errno = ftp_lite_error(r1);
 
357
                return 0;
 
358
        }
 
359
 
 
360
        if((r2/100)!=2) {
 
361
                errno = ftp_lite_error(r2);
 
362
                return 0;
 
363
        }
 
364
 
 
365
        s->auth_done = 1;
 
366
 
 
367
        return 1;
 
368
}
 
369
 
 
370
static FILE * ftp_lite_xfer_setup( struct ftp_lite_server *s, char *command )
 
371
{
 
372
        char buffer[FTP_LITE_LINE_MAX];
 
373
        char host[NETWORK_ADDR_MAX];
 
374
        int passive;
 
375
        FILE *stream;
 
376
        int net;
 
377
        int port;
 
378
        int response;
 
379
        int save_errno;
 
380
 
 
381
        if(!s->went_binary) {
 
382
                ftp_lite_send_command(s,"TYPE I");
 
383
                response = ftp_lite_get_response(s,0,buffer);
 
384
                if((response/100)!=2) return 0;
 
385
                s->went_binary = 1;
 
386
        }
 
387
 
 
388
        ftp_lite_send_command(s,"PASV");
 
389
        response = ftp_lite_get_response(s,0,buffer);
 
390
 
 
391
        if((response/100)!=2) {
 
392
                network_address caddr, paddr;
 
393
                int cport, pport;
 
394
 
 
395
                network_address_local(fileno(s->command),&caddr,&cport);
 
396
 
 
397
                passive = network_serve(0);
 
398
                if(passive<0) return 0;
 
399
 
 
400
                network_address_local(passive,&paddr,&pport);
 
401
                network_address_to_string(caddr,host);
 
402
 
 
403
                ftp_lite_send_active(s,host,pport);
 
404
                response = ftp_lite_get_response(s,0,buffer);
 
405
                if((response/100)!=2) {
 
406
                        network_close(passive);
 
407
                        errno = ftp_lite_error(response);
 
408
                        return 0;
 
409
                }
 
410
        } else {
 
411
                passive = -1;
 
412
                if(!ftp_lite_parse_passive(buffer,host,&port)) {
 
413
                        errno = EINVAL;
 
414
                        return 0;
 
415
                }
 
416
        }
 
417
 
 
418
        ftp_lite_send_command(s,command);
 
419
 
 
420
        if(passive>=0) {
 
421
                while(1) {
 
422
                        if(network_sleep(passive,100000)) {
 
423
                                net = network_accept(passive);
 
424
                                if(net<0) {
 
425
                                        save_errno = errno;
 
426
                                        network_close(passive);
 
427
                                        errno = save_errno;
 
428
                                        return 0;
 
429
                                } else {
 
430
                                        network_close(passive);
 
431
                                        break;
 
432
                                }
 
433
                        } else {
 
434
                                if(network_sleep(fileno(s->response),0)) {
 
435
                                        response = ftp_lite_get_response(s,1,buffer);
 
436
                                        if((response/100)==1) {
 
437
                                                continue;
 
438
                                        } else {
 
439
                                                network_close(passive);
 
440
                                                errno = ftp_lite_error(response);
 
441
                                                return 0;
 
442
                                        }
 
443
                                }
 
444
                        }
 
445
                }
 
446
        } else {
 
447
                net = network_connect(host,port);
 
448
                if(net<0) return 0;
 
449
 
 
450
                /*
 
451
                This is ridiculous.
 
452
                When data channel authentication is enabled,
 
453
                if the STOR or RETR fails because of a filesystem error
 
454
                on the server side, then the server sends an error code
 
455
                AFTER the network connection, but before the authentication.
 
456
                If the command will succeed, then the server sends a
 
457
                100 code AFTER authentication.  Arg!  So, we sit here and
 
458
                wait for 100ms to see if a response comes back.
 
459
                Fortunately, we have already done a round trip to make
 
460
                the connection, so we don't have to measure that time.
 
461
                */
 
462
 
 
463
                if(network_sleep(fileno(s->response),10000)) {
 
464
                        response = ftp_lite_get_response(s,1,buffer);
 
465
                        if((response/100)==1) {
 
466
                                /* keep going */
 
467
                        } else {
 
468
                                network_close(net);
 
469
                                errno = ftp_lite_error(response);
 
470
                                return 0;
 
471
                        }
 
472
                }
 
473
        }
 
474
 
 
475
        stream = fdopen(net,"r+");
 
476
        if(!stream) {
 
477
                network_close(net);
 
478
                return 0;
 
479
        }
 
480
 
 
481
        if(ftp_lite_data_channel_auth(s,stream)) {
 
482
                return stream;
 
483
        } else {
 
484
                fclose(stream);
 
485
                return 0;
 
486
        }
 
487
}
 
488
 
 
489
FILE * ftp_lite_get( struct ftp_lite_server *s, const char *path, ftp_lite_off_t offset )
 
490
{
 
491
        char buffer[FTP_LITE_LINE_MAX];
 
492
        int response;
 
493
        FILE *data;
 
494
 
 
495
        if(offset!=0) {
 
496
                ftp_lite_send_command(s,"REST %d",offset);
 
497
                response = ftp_lite_get_response(s,0,buffer);
 
498
                if(response/100!=3) {
 
499
                        errno = ftp_lite_error(response);
 
500
                        return 0;
 
501
                }
 
502
        }
 
503
 
 
504
        sprintf(buffer,"RETR %s",path);
 
505
        data = ftp_lite_xfer_setup(s,buffer);
 
506
        if(data) {
 
507
                return data;
 
508
        } else {
 
509
                return 0;
 
510
        }
 
511
}
 
512
 
 
513
FILE * ftp_lite_put( struct ftp_lite_server *s, const char *path, ftp_lite_off_t offset, ftp_lite_size_t size )
 
514
{
 
515
        char buffer[FTP_LITE_LINE_MAX];
 
516
        int response;
 
517
        FILE *data;
 
518
 
 
519
        if( offset!=0 ) {
 
520
                if( size==FTP_LITE_WHOLE_FILE ) {
 
521
                        ftp_lite_send_command(s,"REST %lld",(long long)offset);
 
522
                        response = ftp_lite_get_response(s,0,buffer);
 
523
                        if(response/100!=3) {
 
524
                                errno = ftp_lite_error(response);
 
525
                                return 0;
 
526
                        }
 
527
                        sprintf(buffer,"STOR %s",path);
 
528
                } else {
 
529
                        sprintf(buffer,"ESTO A %lld %s",(long long)offset,path);
 
530
                }
 
531
        } else {
 
532
                sprintf(buffer,"STOR %s",path);
 
533
        }
 
534
 
 
535
        data = ftp_lite_xfer_setup(s,buffer);
 
536
        if(data) {
 
537
                return data;
 
538
        } else {
 
539
                return 0;
 
540
        }
 
541
}
 
542
 
 
543
FILE *ftp_lite_list( struct ftp_lite_server *s, const char *dir )
 
544
{
 
545
        char buffer[FTP_LITE_LINE_MAX];
 
546
        FILE *data;
 
547
 
 
548
        sprintf(buffer,"NLST %s",dir);
 
549
 
 
550
        data = ftp_lite_xfer_setup(s,buffer);
 
551
        if(data) {
 
552
                return data;
 
553
        } else {
 
554
                return 0;
 
555
        }
 
556
}
 
557
 
 
558
int ftp_lite_done( struct ftp_lite_server *s )
 
559
{
 
560
        char buffer[FTP_LITE_LINE_MAX];
 
561
        int response;
 
562
 
 
563
        response = ftp_lite_get_response(s,0,buffer);
 
564
        if(response/100!=2) {
 
565
                errno = ftp_lite_error(response);
 
566
                return 0;
 
567
        } else {
 
568
                return 1;
 
569
        }
 
570
}
 
571
 
 
572
ftp_lite_size_t ftp_lite_size( struct ftp_lite_server *s, const char *path )
 
573
{
 
574
        char buffer[FTP_LITE_LINE_MAX];
 
575
        ftp_lite_size_t size;
 
576
        int response;
 
577
        int fields;
 
578
 
 
579
        ftp_lite_send_command(s,"SIZE %s",path);
 
580
        response = ftp_lite_get_response(s,0,buffer);
 
581
        if(response/100!=2) {
 
582
                errno = ftp_lite_error(response);
 
583
                return -1;
 
584
        }
 
585
 
 
586
        fields = sscanf(buffer,"%d %lld",&response,&size);
 
587
        if(fields!=2) {
 
588
                errno = EINVAL;
 
589
                return -1;
 
590
        }
 
591
 
 
592
        return size;
 
593
}
 
594
 
 
595
int ftp_lite_delete( struct ftp_lite_server *s, const char *path )
 
596
{
 
597
        char buffer[FTP_LITE_LINE_MAX];
 
598
        int response;
 
599
 
 
600
        ftp_lite_send_command(s,"DELE %s",path);
 
601
        response = ftp_lite_get_response(s,0,buffer);
 
602
        if(response/100!=2) {
 
603
                errno = ftp_lite_error(response);
 
604
                return 0;
 
605
        }
 
606
 
 
607
        return 1;
 
608
}
 
609
 
 
610
int ftp_lite_rename( struct ftp_lite_server *s, const char *oldname, const char *newname )
 
611
{
 
612
        char buffer[FTP_LITE_LINE_MAX];
 
613
        int r1, r2;
 
614
 
 
615
        ftp_lite_send_command(s,"RNFR %s",oldname);
 
616
        ftp_lite_send_command(s,"RNTO %s",newname);
 
617
 
 
618
        r1 = ftp_lite_get_response(s,0,buffer);
 
619
        r2 = ftp_lite_get_response(s,0,buffer);
 
620
 
 
621
        if( r1/100 != 3 ) {
 
622
                errno = ftp_lite_error(r1);
 
623
                return 0;
 
624
        }
 
625
 
 
626
        if( r2/100 != 2 ) {
 
627
                errno = ftp_lite_error(r2);
 
628
                return 0;
 
629
        }
 
630
 
 
631
        return 1;
 
632
}
 
633
 
 
634
int ftp_lite_current_dir( struct ftp_lite_server *s, char *dir )
 
635
{
 
636
        char buffer[FTP_LITE_LINE_MAX];
 
637
        int response;
 
638
 
 
639
        ftp_lite_send_command(s,"PWD");
 
640
        response = ftp_lite_get_response(s,0,buffer);
 
641
        if(response/100!=2) {
 
642
                errno = ftp_lite_error(response);
 
643
                return 0;
 
644
        } else {
 
645
                if(sscanf(buffer,"%d \"%[^\"]\"",&response,dir)==2) {
 
646
                        return 1;
 
647
                } else {
 
648
                        debug(D_FTP,"couldn't parse response from PWD!");
 
649
                        return 0;
 
650
                }
 
651
        }
 
652
}
 
653
 
 
654
int ftp_lite_change_dir( struct ftp_lite_server *s, const char *dir )
 
655
{
 
656
        char buffer[FTP_LITE_LINE_MAX];
 
657
        int response;
 
658
 
 
659
        ftp_lite_send_command(s,"CWD %s",dir);
 
660
        response = ftp_lite_get_response(s,0,buffer);
 
661
        if(response/100!=2) {
 
662
                errno = ftp_lite_error(response);
 
663
                return 0;
 
664
        }
 
665
 
 
666
        return 1;
 
667
}
 
668
 
 
669
int ftp_lite_make_dir( struct ftp_lite_server *s, const char *dir )
 
670
{
 
671
        char buffer[FTP_LITE_LINE_MAX];
 
672
        int response;
 
673
 
 
674
        ftp_lite_send_command(s,"MKD %s",dir);
 
675
        response = ftp_lite_get_response(s,0,buffer);
 
676
        if(response/100!=2) {
 
677
                errno = ftp_lite_error(response);
 
678
                return 0;
 
679
        }
 
680
 
 
681
        return 1;
 
682
}
 
683
 
 
684
int ftp_lite_delete_dir( struct ftp_lite_server *s, const char *dir )
 
685
{
 
686
        char buffer[FTP_LITE_LINE_MAX];
 
687
        int response;
 
688
 
 
689
        ftp_lite_send_command(s,"RMD %s",dir);
 
690
        response = ftp_lite_get_response(s,0,buffer);
 
691
        if(response/100!=2) {
 
692
                errno = ftp_lite_error(response);
 
693
                return 0;
 
694
        }
 
695
 
 
696
        return 1;
 
697
}
 
698
 
 
699
int ftp_lite_nop( struct ftp_lite_server *s )
 
700
{
 
701
        char buffer[FTP_LITE_LINE_MAX];
 
702
        int response;
 
703
 
 
704
        ftp_lite_send_command(s,"NOOP");
 
705
        response = ftp_lite_get_response(s,0,buffer);
 
706
        if(response/100!=2) {
 
707
                errno = ftp_lite_error(response);
 
708
                return 0;
 
709
        }
 
710
 
 
711
        return 1;
 
712
}
 
713
 
 
714
static int ftp_lite_third_party_setup( struct ftp_lite_server *source, struct ftp_lite_server *target )
 
715
{
 
716
        char buffer[FTP_LITE_LINE_MAX];
 
717
        int response;
 
718
        int port;
 
719
        char host[NETWORK_ADDR_MAX];
 
720
 
 
721
        ftp_lite_send_command(source,"PASV");
 
722
        response = ftp_lite_get_response(source,0,buffer);
 
723
        if(response/100!=2) {
 
724
                errno = ftp_lite_error(response);
 
725
                return 0;
 
726
        }
 
727
 
 
728
 
 
729
        if(!ftp_lite_parse_passive(buffer,host,&port)) {
 
730
                errno = EINVAL;
 
731
                return 0;
 
732
        }
 
733
 
 
734
        ftp_lite_send_active(target,host,port);
 
735
        response = ftp_lite_get_response(target,0,buffer);
 
736
        if(response/100!=2) {
 
737
                errno = ftp_lite_error(response);
 
738
                return 0;
 
739
        }
 
740
 
 
741
        return 1;
 
742
}
 
743
 
 
744
 
 
745
int ftp_lite_third_party_transfer( struct ftp_lite_server *source, const char *source_file, struct ftp_lite_server *target, const char *target_file )
 
746
{
 
747
        char buffer[FTP_LITE_LINE_MAX];
 
748
        int response;
 
749
 
 
750
        if(!source->went_binary) {
 
751
                ftp_lite_send_command(source,"TYPE I");
 
752
                response = ftp_lite_get_response(source,0,buffer);
 
753
                if((response/100)!=2) {
 
754
                        errno = ftp_lite_error(response);
 
755
                        return 0;
 
756
                }
 
757
                source->went_binary = 1;
 
758
        }
 
759
 
 
760
        if(!target->went_binary) {
 
761
                ftp_lite_send_command(target,"TYPE I");
 
762
                response = ftp_lite_get_response(target,0,buffer);
 
763
                if((response/100)!=2) {
 
764
                        errno = ftp_lite_error(response);
 
765
                        return 0;
 
766
                }
 
767
                target->went_binary = 1;
 
768
        }
 
769
 
 
770
        if(!ftp_lite_third_party_setup(source,target)) {
 
771
                if(!ftp_lite_third_party_setup(target,source)) {
 
772
                        return 0;
 
773
                }
 
774
        }
 
775
 
 
776
        ftp_lite_send_command(target,"STOR %s",target_file);
 
777
        ftp_lite_send_command(source,"RETR %s",source_file);
 
778
 
 
779
        while(1) {
 
780
                if(network_sleep(fileno(target->response),10000)) {
 
781
                        response = ftp_lite_get_response(target,1,buffer);
 
782
                        if(response/100==1) {
 
783
                                continue;
 
784
                        } else if(response/100==2) {
 
785
                                response = ftp_lite_get_response(source,0,buffer);
 
786
                                if(response/100==2) {
 
787
                                        return 1;
 
788
                                } else {
 
789
                                        errno = ftp_lite_error(response);
 
790
                                        return 0;
 
791
                                }
 
792
                        } else {
 
793
                                ftp_lite_send_command(source,"ABOR");
 
794
                                ftp_lite_get_response(source,0,buffer);
 
795
                                errno = ftp_lite_error(response);
 
796
                                return 0;
 
797
                        }
 
798
                }
 
799
                if(network_sleep(fileno(source->response),10000)) {
 
800
                        response = ftp_lite_get_response(source,1,buffer);
 
801
                        if(response/100==1) {
 
802
                                continue;
 
803
                        } else if(response/100==2) {
 
804
                                response = ftp_lite_get_response(target,0,buffer);
 
805
                                if(response/100==2) {
 
806
                                        return 1;
 
807
                                } else {
 
808
                                        errno = ftp_lite_error(response);
 
809
                                        return 0;
 
810
                                }
 
811
                        } else {
 
812
                                ftp_lite_send_command(target,"ABOR");
 
813
                                ftp_lite_get_response(target,0,buffer);
 
814
                                errno = ftp_lite_error(response);
 
815
                                return 0;
 
816
                        }
 
817
                }
 
818
        }
 
819
}
 
820
 
 
821
void ftp_lite_close( struct ftp_lite_server *s )
 
822
{
 
823
        #ifdef HAS_GLOBUS_GSS
 
824
                OM_uint32 major;
 
825
 
 
826
                if(s->context!=GSS_C_NO_CONTEXT) {
 
827
                        gss_delete_sec_context(&major,&s->context,GSS_C_NO_BUFFER);
 
828
                }
 
829
                if(s->credential!=GSS_C_NO_CREDENTIAL) {
 
830
                        gss_release_cred(&major,&s->credential);
 
831
                }
 
832
        #endif
 
833
 
 
834
        network_close(fileno(s->command));
 
835
        fclose(s->command);
 
836
        fclose(s->response);
 
837
        free(s->hostname);
 
838
        free(s);
 
839
}
 
840
 
 
841
#ifdef HAS_GLOBUS_GSS
 
842
 
 
843
static int ftp_lite_send_gss( void *arg, void *buffer, size_t length )
 
844
{
 
845
        struct ftp_lite_server *s = (struct ftp_lite_server *)arg;
 
846
        char line[FTP_LITE_LINE_MAX];
 
847
        int ilength = length;
 
848
 
 
849
        sprintf(line,"MIC ");
 
850
        if(!ftp_lite_radix_encode(buffer,(unsigned char*)&line[4],&ilength)) return -1;
 
851
        line[ilength+4] = 0;
 
852
 
 
853
        if(ftp_lite_send_command_raw(s,line)) {
 
854
                return 0;
 
855
        } else {
 
856
                return -1;
 
857
        }
 
858
}
 
859
 
 
860
static int ftp_lite_send_command_gss( struct ftp_lite_server *s, const char *buffer )
 
861
{
 
862
        OM_uint32 minor;
 
863
        int token;
 
864
 
 
865
        return globus_gss_assist_wrap_send(&minor,s->context,(char *)buffer,strlen(buffer),&token,ftp_lite_send_gss,s,stderr)==GSS_S_COMPLETE;
 
866
}
 
867
 
 
868
static int ftp_lite_get_gss( void *arg, void **buffer, size_t *length )
 
869
{
 
870
        char line[FTP_LITE_LINE_MAX];
 
871
        struct ftp_lite_server *s = (struct ftp_lite_server *)arg;
 
872
 
 
873
        if(!ftp_lite_get_response_raw(s,line)) return -1;
 
874
        *length = strlen(line)-4;
 
875
 
 
876
        *buffer = malloc(*length+1);
 
877
        if(!*buffer) return -1;
 
878
 
 
879
        int ilength = *length;
 
880
        if(!ftp_lite_radix_decode((unsigned char*)&line[4],*buffer,&ilength)) return -1;
 
881
        *length = ilength;
 
882
 
 
883
        return 0;
 
884
}
 
885
 
 
886
static int ftp_lite_get_response_gss( struct ftp_lite_server *s, char *outbuffer )
 
887
{
 
888
        OM_uint32 major, minor;
 
889
        int token;
 
890
        size_t length;
 
891
        char *buffer;
 
892
 
 
893
        major = globus_gss_assist_get_unwrap(&minor,s->context,&buffer,&length,&token,ftp_lite_get_gss,s,stderr);
 
894
        if(major==GSS_S_COMPLETE) {
 
895
                strcpy(outbuffer,buffer);
 
896
                outbuffer[length] = 0;
 
897
                return 1;
 
898
        } else {
 
899
                errno = ECONNRESET;
 
900
                return 0;
 
901
        }
 
902
}
 
903
 
 
904
static int ftp_lite_get_adat( void *arg, void **outbuf, size_t *length )
 
905
{       
 
906
        char buffer[FTP_LITE_LINE_MAX];
 
907
        struct ftp_lite_server *s = (struct ftp_lite_server *)arg;
 
908
        int response;
 
909
 
 
910
        response = ftp_lite_get_response(s,0,buffer);
 
911
        if(response/100!=3) return -1;
 
912
        
 
913
        if(strncmp(buffer,"335 ADAT=",9)) return -1;
 
914
        
 
915
        *length = strlen(buffer)-9;
 
916
        *outbuf = malloc(*length+1);
 
917
        if(!*outbuf) return -1;
 
918
 
 
919
        int ilength = *length;
 
920
        if(!ftp_lite_radix_decode((unsigned char*)&buffer[9],(unsigned char *)*outbuf,&ilength)) {
 
921
                free(*outbuf);
 
922
                return -1;
 
923
        }
 
924
 
 
925
        *length = ilength;
 
926
 
 
927
        return 0;
 
928
}
 
929
 
 
930
static int ftp_lite_put_adat( void *arg, void *buf, size_t size )
 
931
{
 
932
        char buffer[FTP_LITE_LINE_MAX];
 
933
        struct ftp_lite_server *s = (struct ftp_lite_server *)arg;
 
934
 
 
935
        int ilength = size;
 
936
        if(!ftp_lite_radix_encode((unsigned char *)buf,(unsigned char*)buffer,&ilength)) return -1;
 
937
        
 
938
        ftp_lite_send_command(s,"ADAT %s",buffer);
 
939
        return 0;
 
940
}
 
941
 
 
942
int ftp_lite_data_channel_auth( struct ftp_lite_server *s, FILE *data )
 
943
{
 
944
        OM_uint32 major, minor, flags=0;
 
945
        int token;
 
946
 
 
947
        if(!s->data_channel_authentication) return 1;
 
948
        
 
949
        setbuf(data,0);
 
950
 
 
951
        debug(D_FTP,"data channel authentication in progress...");
 
952
 
 
953
        major = globus_gss_assist_init_sec_context( &minor, s->credential, &s->data_context, 0, 0, &flags, &token, globus_gss_assist_token_get_fd, data, globus_gss_assist_token_send_fd, data );
 
954
        if( major!=GSS_S_COMPLETE ) {
 
955
                char *reason;
 
956
                globus_gss_assist_display_status_str(&reason,"",major,minor,token);
 
957
                if(!reason) reason = strdup("unknown error");
 
958
                debug(D_FTP,"data channel authentication failed: %s",reason);
 
959
                free(reason);
 
960
                errno = EACCES;
 
961
                return 0;
 
962
        }
 
963
 
 
964
        gss_delete_sec_context(&major,&s->data_context,GSS_C_NO_BUFFER);
 
965
 
 
966
        debug(D_FTP,"data channel authentication succeeded");
 
967
 
 
968
        return 1;
 
969
 
 
970
}
 
971
 
 
972
int ftp_lite_auth_globus( struct ftp_lite_server *s )
 
973
{
 
974
        char buffer[FTP_LITE_LINE_MAX];
 
975
        char principal_buf[FTP_LITE_LINE_MAX];
 
976
        char *principal;
 
977
        OM_uint32 major, minor, flags=0;
 
978
        network_address addr;
 
979
        int token,port;
 
980
        int response;
 
981
        
 
982
        if(s->auth_done) return 1;
 
983
        
 
984
        major = globus_gss_assist_acquire_cred(&minor,GSS_C_INITIATE,&s->credential); 
 
985
        if(major!=GSS_S_COMPLETE) {
 
986
                errno = EACCES;
 
987
                return 0;
 
988
        }
 
989
 
 
990
        ftp_lite_send_command(s,"AUTH GSSAPI");
 
991
        response = ftp_lite_get_response(s,0,buffer);
 
992
 
 
993
        if(response/100==2) {
 
994
                /* Promiscuous servers respond with 200 here */
 
995
                return 1;
 
996
        }
 
997
 
 
998
        if(response/100!=3) {
 
999
                errno = ftp_lite_error(response);
 
1000
                return 0;
 
1001
        }
 
1002
 
 
1003
        principal = getenv("FTP_LITE_PRINCIPAL");
 
1004
        if(!principal) {
 
1005
                strcpy(principal_buf,"ftp@");
 
1006
                if(!network_address_remote(fileno(s->command),&addr,&port)) return 0;
 
1007
                if(!network_address_to_name(addr,&principal_buf[4])) return 0;
 
1008
                principal = principal_buf;
 
1009
        }
 
1010
 
 
1011
        major = globus_gss_assist_init_sec_context( &minor, s->credential, &s->context, principal, GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG, &flags, &token, ftp_lite_get_adat, s, ftp_lite_put_adat, s );
 
1012
        if( major!=GSS_S_COMPLETE ) {
 
1013
                gss_release_cred( &major, &s->credential );
 
1014
                errno = EACCES;
 
1015
                return 0;
 
1016
        }
 
1017
 
 
1018
        debug(D_FTP,"*** secure channel established\n");
 
1019
 
 
1020
        s->authtype = GLOBUS_GSS;
 
1021
 
 
1022
        response = ftp_lite_get_response(s,0,buffer);
 
1023
        if((response/100)!=2) {
 
1024
                errno = ftp_lite_error(response);
 
1025
                return 0;
 
1026
        }
 
1027
 
 
1028
        if(ftp_lite_auth_userpass(s,":globus-mapping:","nothing")) {
 
1029
                if(ftp_lite_data_channel_authentication) {
 
1030
                        ftp_lite_send_command(s,"DCAU A");
 
1031
                        response = ftp_lite_get_response(s,0,buffer);
 
1032
                        s->data_channel_authentication = (response==200);
 
1033
                } else {
 
1034
                        ftp_lite_send_command(s,"DCAU N");
 
1035
                        response = ftp_lite_get_response(s,0,buffer);
 
1036
                        s->data_channel_authentication = 0;
 
1037
                }
 
1038
                return 1;
 
1039
        } else {
 
1040
                return 0;
 
1041
        }
 
1042
}
 
1043
 
 
1044
#else
 
1045
 
 
1046
int ftp_lite_data_channel_auth( struct ftp_lite_server *s, FILE *data )
 
1047
{
 
1048
        return 1;
 
1049
}
 
1050
 
 
1051
static int ftp_lite_send_command_gss( struct ftp_lite_server *s, const char *buffer )
 
1052
{
 
1053
        errno = ENOSYS;
 
1054
        return 0;
 
1055
}
 
1056
 
 
1057
static int ftp_lite_get_response_gss( struct ftp_lite_server *s, char *outbuffer )
 
1058
{
 
1059
        errno = ENOSYS;
 
1060
        return 0;
 
1061
}
 
1062
 
 
1063
int ftp_lite_auth_globus( struct ftp_lite_server *s )
 
1064
{
 
1065
        errno = ENOSYS;
 
1066
        return 0;
 
1067
}
 
1068
 
 
1069
#endif
 
1070