OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [libnetworking/] [rtems_servers/] [ftpd.c] - Blame information for rev 279

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 30 unneback
/* FIXME: 1. Parse command is a hack.  We can do better.
2
 *        2. chdir is a hack.  We can do better.
3
 *        3. PWD doesn't work.
4
 *        4. Some sort of access control?
5
 *
6
 *  FTP Server Daemon
7
 *
8
 *  Submitted by: Jake Janovetz <janovetz@tempest.ece.uiuc.edu>
9
 *
10
 *  $Id: ftpd.c,v 1.2 2001-09-27 12:02:00 chris Exp $
11
 */
12
 
13
/**************************************************************************
14
 *                                 ftpd.c                                 *
15
 **************************************************************************
16
 * Description:                                                           *
17
 *                                                                        *
18
 *    This file contains the daemon which services requests that appear   *
19
 *    on the FTP port.  This server is compatible with FTP, but it        *
20
 *    also provides 'hooks' to make it usable in situations where files   *
21
 *    are not used/necessary.  Once the server is started, it runs        *
22
 *    forever.                                                            *
23
 *                                                                        *
24
 *                                                                        *
25
 *    Organization:                                                       *
26
 *                                                                        *
27
 *       The FTP daemon is started upon boot.  It runs all the time       *
28
 *       and waits for connections on the known FTP port (21).  When      *
29
 *       a connection is made, it starts a 'session' task.  That          *
30
 *       session then interacts with the remote host.  When the session   *
31
 *       is complete, the session task deletes itself.  The daemon still  *
32
 *       runs, however.                                                   *
33
 *                                                                        *
34
 *                                                                        *
35
 * Supported commands are:                                                *
36
 *                                                                        *
37
 * RETR xxx     - Sends a file from the client.                           *
38
 * STOR xxx     - Receives a file from the client.  xxx = filename.       *
39
 * LIST xxx     - Sends a file list to the client.                        *
40
 *                (LIST xxx isn't working yet...)                         *
41
 * USER         - Does nothing.                                           *
42
 * PASS         - Does nothing.                                           *
43
 * SYST         - Replies with the system type (`RTEMS').                 *
44
 * DELE xxx     - Delete file xxx.                                        *
45
 * MKD xxx      - Create directory xxx.                                   *
46
 * RMD xxx      - Remove directory xxx.                                   *
47
 * PWD          - Print working directory.                                *
48
 * CWD xxx      - Change working directory.                               *
49
 * SITE CHMOD xxx yyy - Change permissions on file yyy to xxx.            *
50
 * PORT a,b,c,d,x,y   - Setup for a data port to IP address a.b.c.d       *
51
 *                      and port (x*256 + y).                             *
52
 *                                                                        *
53
 *                                                                        *
54
 * The public routines contained in this file are:                        *
55
 *                                                                        *
56
 *    rtems_initialize_ftpd_start - Starts the server daemon, then        *
57
 *                                  returns to its caller.                *
58
 *                                                                        *
59
 *                                                                        *
60
 * The private routines contained in this file are:                       *
61
 *                                                                        *
62
 *    rtems_ftpd_send_reply    - Sends a reply code and text through the  *
63
 *                               control port.                            *
64
 *    rtems_ftpd_command_retrieve - Performs to "RETR" command.           *
65
 *    rtems_ftpd_command_store - Performs the "STOR" command.             *
66
 *    rtems_ftpd_command_list  - Performs the "LIST" command.             *
67
 *    rtems_ftpd_command_port  - Opens a data port (the "PORT" command).  *
68
 *    rtems_ftpd_parse_command - Parses an incoming command.              *
69
 *    rtmes_ftpd_session       - Begins a service session.                *
70
 *    rtems_ftpd_daemon        - Listens on the FTP port for service      *
71
 *                               requests.                                *
72
 *------------------------------------------------------------------------*
73
 * Jake Janovetz                                                          *
74
 * University of Illinois                                                 *
75
 * 1406 West Green Street                                                 *
76
 * Urbana IL  61801                                                       *
77
 **************************************************************************
78
 * Change History:                                                        *
79
 *  12/01/97 - Creation (JWJ)                                             *
80
 *************************************************************************/
81
 
82
#include <stdio.h>
83
#include <stdlib.h>
84
#include <string.h>
85
#include <unistd.h>
86
#include <fcntl.h>
87
#include <dirent.h>
88
 
89
#include <rtems.h>
90
#include <rtems/rtems_bsdnet.h>
91
#include <rtems/error.h>
92
#include <syslog.h>
93
 
94
#include <sys/types.h>
95
#include <sys/socket.h>
96
#include <arpa/ftp.h>
97
#include <netinet/in.h>
98
 
99
#include "ftpd.h"
100
 
101
 
102
extern struct rtems_ftpd_configuration rtems_ftpd_configuration;
103
 
104
/**************************************************************************
105
 * Meanings of first and second digits of reply codes:
106
 *
107
 * Reply:  Description:
108
 *-------- --------------
109
 *  1yz    Positive preliminary reply.  The action is being started but
110
 *         expect another reply before sending another command.
111
 *  2yz    Positive completion reply.  A new command can be sent.
112
 *  3yz    Positive intermediate reply.  The command has been accpeted
113
 *         but another command must be sent.
114
 *  4yz    Transient negative completion reply.  The requested action did
115
 *         not take place, but the error condition is temporary so the
116
 *         command can be reissued later.
117
 *  5yz    Permanent negative completion reply.  The command was not
118
 *         accepted and should not be retried.
119
 *-------------------------------------------------------------------------
120
 *  x0z    Syntax errors.
121
 *  x1z    Information.
122
 *  x2z    Connections.  Replies referring to the control or data
123
 *         connections.
124
 *  x3z    Authentication and accounting.  Replies for the login or
125
 *         accounting commands.
126
 *  x4z    Unspecified.
127
 *  x5z    Filesystem status.
128
 *************************************************************************/
129
 
130
 
131
/**************************************************************************
132
 * SessionInfo structure.
133
 *
134
 * The following structure is allocated for each session.  The pointer
135
 * to this structure is contained in the tasks notepad entry.
136
 *************************************************************************/
137
typedef struct
138
{
139
   struct sockaddr_in  data_addr;   /* Data address for PORT commands */
140
   FILE                *ctrl_fp;    /* File pointer for control connection */
141
   char                cwd[255];    /* Current working directory */
142
                                    /* Login -- future use -- */
143
   int                 xfer_mode;   /* Transfer mode (ASCII/binary) */
144
} FTPD_SessionInfo_t;
145
 
146
 
147
#define FTPD_SERVER_MESSAGE  "RTEMS FTP server (Version 1.0-JWJ) ready."
148
#define FTPD_WELCOME_MESSAGE \
149
   "Welcome to the RTEMS FTP server.\n" \
150
   "\n" \
151
   "Login accepted.\n"
152
 
153
 
154
/**************************************************************************
155
 * Function: rtems_ftpd_send_reply                                        *
156
 **************************************************************************
157
 * Description:                                                           *
158
 *                                                                        *
159
 *    This procedure sends a reply to the client via the control          *
160
 *    connection.                                                         *
161
 *                                                                        *
162
 *                                                                        *
163
 * Inputs:                                                                *
164
 *                                                                        *
165
 *    int  code  - The 3-digit reply code.                                *
166
 *    char *text - Reply text.                                            *
167
 *                                                                        *
168
 * Output:                                                                *
169
 *                                                                        *
170
 *    none                                                                *
171
 *                                                                        *
172
 **************************************************************************
173
 * Change History:                                                        *
174
 *  12/01/97 - Creation (JWJ)                                             *
175
 *************************************************************************/
176
static void
177
rtems_ftpd_send_reply(int code, char *text)
178
{
179
   rtems_status_code   sc;
180
   FTPD_SessionInfo_t  *info = NULL;
181
   char                str[80];
182
 
183
 
184
   sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
185
                            (rtems_unsigned32 *)&info);
186
 
187
   /***********************************************************************
188
    * code must be a 3-digit number.
189
    **********************************************************************/
190
   if ((code < 100) || (code > 999))
191
   {
192
      syslog(LOG_ERR, "ftpd: Code not 3-digits.");
193
      return;
194
   }
195
 
196
   /***********************************************************************
197
    * If a text reply exists, add it to the reply data.
198
    **********************************************************************/
199
   if (text != NULL)
200
   {
201
      sprintf(str, "%d %.70s\r\n", code, text);
202
      fprintf(info->ctrl_fp, "%d %.70s\r\n", code, text);
203
   }
204
   else
205
   {
206
      sprintf(str, "%d\r\n", code);
207
      fprintf(info->ctrl_fp, "%d\r\n", code);
208
   }
209
   fflush(info->ctrl_fp);
210
}
211
 
212
 
213
/**************************************************************************
214
 * Function: rtems_ftpd_command_retrieve                                  *
215
 **************************************************************************
216
 * Description:                                                           *
217
 *                                                                        *
218
 *    This performs the "RETR" command.  A data connection must already   *
219
 *    be open (via the "PORT" command.)  Here, we send the data to the    *
220
 *    connection.                                                         *
221
 *                                                                        *
222
 *                                                                        *
223
 * Inputs:                                                                *
224
 *                                                                        *
225
 *    char *filename   - Source filename.                                 *
226
 *                                                                        *
227
 * Output:                                                                *
228
 *                                                                        *
229
 *    int  - 0 for reply sent.                                            *
230
 *           1 for no reply sent.                                         *
231
 *                                                                        *
232
 **************************************************************************
233
 * Change History:                                                        *
234
 *  04/29/98 - Creation (JWJ)                                             *
235
 *************************************************************************/
236
static int
237
rtems_ftpd_command_retrieve(char *filename)
238
{
239
   int                 s;
240
   int                 n;
241
   int                 fd;
242
   unsigned char       *bufr;
243
   rtems_status_code   sc;
244
   FTPD_SessionInfo_t  *info = NULL;
245
 
246
 
247
   sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
248
                            (rtems_unsigned32 *)&info);
249
 
250
   if ((fd = open(filename, O_RDONLY)) == -1)
251
   {
252
      rtems_ftpd_send_reply(450, "Error opening file.");
253
      return(0);
254
   }
255
 
256
   bufr = (unsigned char *)malloc(BUFSIZ);
257
   if (bufr == NULL)
258
   {
259
      rtems_ftpd_send_reply(440, "Server error - malloc fail.");
260
      close(fd);
261
      return(0);
262
   }
263
 
264
   /***********************************************************************
265
    * Connect to the data connection (PORT made in an earlier PORT call).
266
    **********************************************************************/
267
   rtems_ftpd_send_reply(150, "BINARY data connection.");
268
   s = socket(AF_INET, SOCK_STREAM, 0);
269
   if (connect(s, (struct sockaddr *)&info->data_addr,
270
               sizeof(struct sockaddr)) < 0)
271
   {
272
      rtems_ftpd_send_reply(420, "Server error - could not connect socket.");
273
      free(bufr);
274
      close(fd);
275
      close(s);
276
      return(1);
277
   }
278
 
279
   /***********************************************************************
280
    * Send the data over the ether.
281
    **********************************************************************/
282
   while ((n = read(fd, bufr, BUFSIZ)) > 0)
283
   {
284
      send(s, bufr, n, 0);
285
      bufr[n-1] = '\0';
286
   }
287
 
288
   if (n == 0)
289
   {
290
      rtems_ftpd_send_reply(210, "File sent successfully.");
291
   }
292
   else
293
   {
294
      rtems_ftpd_send_reply(450, "Retrieve failed.");
295
   }
296
 
297
   if (close(s) != 0)
298
   {
299
      syslog(LOG_ERR, "ftpd: Error closing data socket");
300
   }
301
 
302
   free(bufr);
303
   close(fd);
304
   return(0);
305
}
306
 
307
 
308
/**************************************************************************
309
 * Function: rtems_ftpd_command_store                                     *
310
 **************************************************************************
311
 * Description:                                                           *
312
 *                                                                        *
313
 *    This performs the "STOR" command.  A data connection must already   *
314
 *    be open (via the "PORT" command.)  Here, we get the data from the   *
315
 *    connection and figure out what to do with it.                       *
316
 *                                                                        *
317
 *                                                                        *
318
 * Inputs:                                                                *
319
 *                                                                        *
320
 *    char *filename   - Destination filename.                            *
321
 *                                                                        *
322
 * Output:                                                                *
323
 *                                                                        *
324
 *    int  - 0 for success.                                               *
325
 *           1 for failure.                                               *
326
 *                                                                        *
327
 **************************************************************************
328
 * Change History:                                                        *
329
 *  12/01/97 - Creation (JWJ)                                             *
330
 *************************************************************************/
331
static int
332
rtems_ftpd_command_store(char *filename)
333
{
334
   char                   *bufr;
335
   int                    s;
336
   int                    n;
337
   unsigned long          size = 0;
338
   rtems_status_code      sc;
339
   FTPD_SessionInfo_t     *info = NULL;
340
   struct rtems_ftpd_hook *usehook = NULL;
341
 
342
 
343
   sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
344
                            (rtems_unsigned32 *)&info);
345
 
346
   bufr = (char *)malloc(BUFSIZ * sizeof(char));
347
   if (bufr == NULL)
348
   {
349
      rtems_ftpd_send_reply(440, "Server error - malloc fail.");
350
      return(1);
351
   }
352
 
353
   rtems_ftpd_send_reply(150, "BINARY data connection.");
354
 
355
   s = socket(AF_INET, SOCK_STREAM, 0);
356
   if (connect(s, (struct sockaddr *)&info->data_addr,
357
               sizeof(struct sockaddr)) < 0)
358
   {
359
      free(bufr);
360
      close(s);
361
      return(1);
362
   }
363
 
364
 
365
   /***********************************************************************
366
    * File: "/dev/null" just throws the data away.
367
    * Otherwise, search our list of hooks to see if we need to do something
368
    *   special.
369
    **********************************************************************/
370
   if (!strncmp("/dev/null", filename, 9))
371
   {
372
      while ((n = read(s, bufr, BUFSIZ)) > 0);
373
   }
374
   else if (rtems_ftpd_configuration.hooks != NULL)
375
   {
376
      struct rtems_ftpd_hook *hook;
377
      int i;
378
 
379
      i = 0;
380
      hook = &rtems_ftpd_configuration.hooks[i++];
381
      while (hook->filename != NULL)
382
      {
383
         if (!strcmp(hook->filename, filename))
384
         {
385
            usehook = hook;
386
            break;
387
         }
388
         hook = &rtems_ftpd_configuration.hooks[i++];
389
      }
390
   }
391
 
392
   if (usehook != NULL)
393
   {
394
      char                *bigBufr;
395
 
396
      /***********************************************************************
397
       * Allocate space for our "file".
398
       **********************************************************************/
399
      bigBufr = (char *)malloc(
400
                  rtems_ftpd_configuration.max_hook_filesize * sizeof(char));
401
      if (bigBufr == NULL)
402
      {
403
         rtems_ftpd_send_reply(440, "Server error - malloc fail.");
404
         free(bufr);
405
         return(1);
406
      }
407
 
408
      /***********************************************************************
409
       * Retrieve the file into our buffer space.
410
       **********************************************************************/
411
      size = 0;
412
      while ((n = read(s, bufr, BUFSIZ)) > 0)
413
      {
414
         if (size + n >
415
               rtems_ftpd_configuration.max_hook_filesize * sizeof(char))
416
         {
417
            rtems_ftpd_send_reply(440, "Server error - Buffer size exceeded.");
418
            free(bufr);
419
            free(bigBufr);
420
            close(s);
421
            return(1);
422
         }
423
         memcpy(&bigBufr[size], bufr, n);
424
         size += n;
425
      }
426
      close(s);
427
 
428
      /***********************************************************************
429
       * Call our hook.
430
       **********************************************************************/
431
      if ((usehook->hook_function)(bigBufr, size) == 0)
432
      {
433
         rtems_ftpd_send_reply(210, "File transferred successfully.");
434
      }
435
      else
436
      {
437
         rtems_ftpd_send_reply(440, "File transfer failed.");
438
      }
439
      free(bigBufr);
440
   }
441
   else
442
   {
443
      int    fd;
444
      size_t written;
445
 
446
      fd = creat(filename, S_IRUSR | S_IWUSR |
447
                           S_IRGRP | S_IWGRP |
448
                           S_IROTH | S_IWOTH);
449
      if (fd == -1)
450
      {
451
         rtems_ftpd_send_reply(450, "Could not open file.");
452
         close(s);
453
         free(bufr);
454
         return(1);
455
      }
456
      while ((n = read(s, bufr, BUFSIZ)) > 0)
457
      {
458
         written = write(fd, bufr, n);
459
         if (written == -1)
460
         {
461
            rtems_ftpd_send_reply(450, "Error during write.");
462
            close(fd);
463
            close(s);
464
            free(bufr);
465
            return(1);
466
         }
467
      }
468
      close(fd);
469
      close(s);
470
      rtems_ftpd_send_reply(226, "Transfer complete.");
471
   }
472
 
473
   free(bufr);
474
   return(0);
475
}
476
 
477
 
478
/**************************************************************************
479
 * Function: rtems_ftpd_command_list                                      *
480
 **************************************************************************
481
 * Description:                                                           *
482
 *                                                                        *
483
 *    Sends a file list through a data connection.  The data              *
484
 *    connection must have already been opened with the "PORT" command.   *
485
 *                                                                        *
486
 *                                                                        *
487
 * Inputs:                                                                *
488
 *                                                                        *
489
 *    char *fname  - File (or directory) to list.                         *
490
 *                                                                        *
491
 * Output:                                                                *
492
 *                                                                        *
493
 *    none                                                                *
494
 *                                                                        *
495
 **************************************************************************
496
 * Change History:                                                        *
497
 *  12/01/97 - Creation (JWJ)                                             *
498
 *************************************************************************/
499
static void
500
rtems_ftpd_command_list(char *fname)
501
{
502
   int                 s;
503
   rtems_status_code   sc;
504
   FTPD_SessionInfo_t  *info = NULL;
505
   DIR                 *dirp;
506
   struct dirent       *dp;
507
   char                dirline[255];
508
   struct stat         stat_buf;
509
 
510
 
511
   sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
512
                            (rtems_unsigned32 *)&info);
513
 
514
   rtems_ftpd_send_reply(150, "ASCII data connection for LIST.");
515
 
516
   s = socket(AF_INET, SOCK_STREAM, 0);
517
   if (connect(s, (struct sockaddr *)&info->data_addr,
518
               sizeof(struct sockaddr)) < 0)
519
   {
520
      syslog(LOG_ERR, "ftpd: Error connecting to data socket.");
521
      return;
522
   }
523
 
524
   if ((dirp = opendir(fname)) == NULL)
525
   {
526
      sprintf(dirline, "%s: No such file or directory.%s\n",
527
              fname, (info->xfer_mode==TYPE_A)?("\r"):(""));
528
      send(s, dirline, strlen(dirline), 0);
529
      close(s);
530
      rtems_ftpd_send_reply(226, "Transfer complete.");
531
      return;
532
   }
533
   while ((dp = readdir(dirp)) != NULL)
534
   {
535
      if (stat(dp->d_name, &stat_buf) == 0)
536
      {
537
         sprintf(dirline, "%c%c%c%c%c%c%c%c%c%c  %5d %5d %11d  %s%s\n",
538
                 (S_ISLNK(stat_buf.st_mode)?('l'):
539
                    (S_ISDIR(stat_buf.st_mode)?('d'):('-'))),
540
                 (stat_buf.st_mode & S_IRUSR)?('r'):('-'),
541
                 (stat_buf.st_mode & S_IWUSR)?('w'):('-'),
542
                 (stat_buf.st_mode & S_IXUSR)?('x'):('-'),
543
                 (stat_buf.st_mode & S_IRGRP)?('r'):('-'),
544
                 (stat_buf.st_mode & S_IWGRP)?('w'):('-'),
545
                 (stat_buf.st_mode & S_IXGRP)?('x'):('-'),
546
                 (stat_buf.st_mode & S_IROTH)?('r'):('-'),
547
                 (stat_buf.st_mode & S_IWOTH)?('w'):('-'),
548
                 (stat_buf.st_mode & S_IXOTH)?('x'):('-'),
549
                 (int)stat_buf.st_uid,
550
                 (int)stat_buf.st_gid,
551
                 (int)stat_buf.st_size,
552
                 dp->d_name,
553
                 (info->xfer_mode==TYPE_A)?("\r"):(""));
554
         send(s, dirline, strlen(dirline), 0);
555
      }
556
   }
557
   closedir(dirp);
558
 
559
   close(s);
560
   rtems_ftpd_send_reply(226, "Transfer complete.");
561
}
562
 
563
 
564
/*
565
 * Cheesy way to change directories
566
 */
567
static void
568
rtems_ftpd_CWD(char *dir)
569
{
570
   rtems_status_code   sc;
571
   FTPD_SessionInfo_t  *info = NULL;
572
 
573
 
574
   sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
575
                            (rtems_unsigned32 *)&info);
576
 
577
   if (chdir(dir) == 0)
578
   {
579
      rtems_ftpd_send_reply(250, "CWD command successful.");
580
   }
581
   else
582
   {
583
      rtems_ftpd_send_reply(550, "CWD command failed.");
584
   }
585
}
586
 
587
 
588
/**************************************************************************
589
 * Function: rtems_ftpd_command_port                                      *
590
 **************************************************************************
591
 * Description:                                                           *
592
 *                                                                        *
593
 *    This procedure opens up a data port given the IP address of the     *
594
 *    remote machine and the port on the remote machine.  This connection *
595
 *    will then be used to transfer data between the hosts.               *
596
 *                                                                        *
597
 *                                                                        *
598
 * Inputs:                                                                *
599
 *                                                                        *
600
 *    char *bufr - Arguments to the "PORT" command.                       *
601
 *                                                                        *
602
 *                                                                        *
603
 * Output:                                                                *
604
 *                                                                        *
605
 *    none                                                                *
606
 *                                                                        *
607
 **************************************************************************
608
 * Change History:                                                        *
609
 *  12/01/97 - Creation (JWJ)                                             *
610
 *************************************************************************/
611
static void
612
rtems_ftpd_command_port(char *bufr)
613
{
614
   char                *ip;
615
   char                *port;
616
   int                 ip0, ip1, ip2, ip3, port0, port1;
617
   rtems_status_code   sc;
618
   FTPD_SessionInfo_t  *info = NULL;
619
 
620
 
621
   sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
622
                            (rtems_unsigned32 *)&info);
623
 
624
   sscanf(bufr, "%d,%d,%d,%d,%d,%d", &ip0, &ip1, &ip2, &ip3, &port0, &port1);
625
   ip = (char *)&(info->data_addr.sin_addr);
626
   ip[0] = ip0 & 0xff;
627
   ip[1] = ip1 & 0xff;
628
   ip[2] = ip2 & 0xff;
629
   ip[3] = ip3 & 0xff;
630
   port = (char *)&(info->data_addr.sin_port);
631
   port[0] = port0 & 0xff;
632
   port[1] = port1 & 0xff;
633
   info->data_addr.sin_family = AF_INET;
634
}
635
 
636
 
637
/**************************************************************************
638
 * Function: rtems_ftpd_parse_command                                     *
639
 **************************************************************************
640
 * Description:                                                           *
641
 *                                                                        *
642
 *    Here, we parse the commands that have come through the control      *
643
 *    connection.                                                         *
644
 *                                                                        *
645
 * FIXME: This section is somewhat of a hack.  We should have a better    *
646
 *        way to parse commands.                                          *
647
 *                                                                        *
648
 * Inputs:                                                                *
649
 *                                                                        *
650
 *    char *bufr     - Pointer to the buffer which contains the command   *
651
 *                     text.                                              *
652
 *                                                                        *
653
 * Output:                                                                *
654
 *                                                                        *
655
 *    none                                                                *
656
 *                                                                        *
657
 **************************************************************************
658
 * Change History:                                                        *
659
 *  12/01/97 - Creation (JWJ)                                             *
660
 *************************************************************************/
661
static void
662
rtems_ftpd_parse_command(char *bufr)
663
{
664
   char fname[255];
665
   rtems_status_code   sc;
666
   FTPD_SessionInfo_t  *info = NULL;
667
 
668
 
669
   sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
670
                            (rtems_unsigned32 *)&info);
671
 
672
   if (!strncmp("PORT", bufr, 4))
673
   {
674
      rtems_ftpd_send_reply(200, "PORT command successful.");
675
      rtems_ftpd_command_port(&bufr[5]);
676
   }
677
   else if (!strncmp("RETR", bufr, 4))
678
   {
679
      sscanf(&bufr[5], "%254s", fname);
680
      rtems_ftpd_command_retrieve(fname);
681
   }
682
   else if (!strncmp("STOR", bufr, 4))
683
   {
684
      sscanf(&bufr[5], "%254s", fname);
685
      rtems_ftpd_command_store(fname);
686
   }
687
   else if (!strncmp("LIST", bufr, 4))
688
   {
689
      if (bufr[5] == '\n')
690
      {
691
         rtems_ftpd_command_list(".");
692
      }
693
      else
694
      {
695
         sscanf(&bufr[5], "%254s", fname);
696
         rtems_ftpd_command_list(fname);
697
      }
698
   }
699
   else if (!strncmp("USER", bufr, 4))
700
   {
701
      rtems_ftpd_send_reply(230, "User logged in.");
702
   }
703
   else if (!strncmp("SYST", bufr, 4))
704
   {
705
      rtems_ftpd_send_reply(240, "RTEMS");
706
   }
707
   else if (!strncmp("TYPE", bufr, 4))
708
   {
709
      if (bufr[5] == 'I')
710
      {
711
         info->xfer_mode = TYPE_I;
712
         rtems_ftpd_send_reply(200, "Type set to I.");
713
      }
714
      else if (bufr[5] == 'A')
715
      {
716
         info->xfer_mode = TYPE_A;
717
         rtems_ftpd_send_reply(200, "Type set to A.");
718
      }
719
      else
720
      {
721
         info->xfer_mode = TYPE_I;
722
         rtems_ftpd_send_reply(504, "Type not implemented.  Set to I.");
723
      }
724
   }
725
   else if (!strncmp("PASS", bufr, 4))
726
   {
727
      rtems_ftpd_send_reply(230, "User logged in.");
728
   }
729
   else if (!strncmp("DELE", bufr, 4))
730
   {
731
      sscanf(&bufr[4], "%254s", fname);
732
      if (unlink(fname) == 0)
733
      {
734
         rtems_ftpd_send_reply(257, "DELE successful.");
735
      }
736
      else
737
      {
738
         rtems_ftpd_send_reply(550, "DELE failed.");
739
      }
740
   }
741
   else if (!strncmp("SITE CHMOD", bufr, 10))
742
   {
743
      int mask;
744
 
745
      sscanf(&bufr[11], "%o %254s", &mask, fname);
746
      if (chmod(fname, (mode_t)mask) == 0)
747
      {
748
         rtems_ftpd_send_reply(257, "CHMOD successful.");
749
      }
750
      else
751
      {
752
         rtems_ftpd_send_reply(550, "CHMOD failed.");
753
      }
754
   }
755
   else if (!strncmp("RMD", bufr, 3))
756
   {
757
      sscanf(&bufr[4], "%254s", fname);
758
      if (rmdir(fname) == 0)
759
      {
760
         rtems_ftpd_send_reply(257, "RMD successful.");
761
      }
762
      else
763
      {
764
         rtems_ftpd_send_reply(550, "RMD failed.");
765
      }
766
   }
767
   else if (!strncmp("MKD", bufr, 3))
768
   {
769
      sscanf(&bufr[4], "%254s", fname);
770
      if (mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO) == 0)
771
      {
772
         rtems_ftpd_send_reply(257, "MKD successful.");
773
      }
774
      else
775
      {
776
         rtems_ftpd_send_reply(550, "MKD failed.");
777
      }
778
   }
779
   else if (!strncmp("CWD", bufr, 3))
780
   {
781
      sscanf(&bufr[4], "%254s", fname);
782
      rtems_ftpd_CWD(fname);
783
   }
784
   else if (!strncmp("PWD", bufr, 3))
785
   {
786
      char *cwd = getcwd(0, 0);
787
      sprintf(bufr, "\"%s\" is the current directory.", cwd);
788
      rtems_ftpd_send_reply(250, bufr);
789
      free(cwd);
790
   }
791
   else
792
   {
793
      rtems_ftpd_send_reply(500, "Unrecognized/unsupported command.");
794
   }
795
}
796
 
797
 
798
/**************************************************************************
799
 * Function: rtems_ftpd_session                                           *
800
 **************************************************************************
801
 * Description:                                                           *
802
 *                                                                        *
803
 *    This task is started when the FTP daemon gets a service request     *
804
 *    from a remote machine.  Here, we watch for commands that will       *
805
 *    come through the "control" connection.  These commands are then     *
806
 *    parsed and executed until the connection is closed, either          *
807
 *    unintentionally or intentionally with the "QUIT" command.           *
808
 *                                                                        *
809
 *                                                                        *
810
 * Inputs:                                                                *
811
 *                                                                        *
812
 *    rtems_task_argument arg - The daemon task passes the socket         *
813
 *                              which serves as the control connection.   *
814
 *                                                                        *
815
 * Output:                                                                *
816
 *                                                                        *
817
 *    none                                                                *
818
 *                                                                        *
819
 **************************************************************************
820
 * Change History:                                                        *
821
 *  12/01/97 - Creation (JWJ)                                             *
822
 *************************************************************************/
823
static void
824
rtems_ftpd_session(rtems_task_argument arg)
825
{
826
   char                cmd[256];
827
   rtems_status_code   sc;
828
   FTPD_SessionInfo_t  *info = NULL;
829
 
830
 
831
   sc = rtems_task_get_note(RTEMS_SELF, RTEMS_NOTEPAD_0,
832
                            (rtems_unsigned32 *)&info);
833
 
834
   rtems_ftpd_send_reply(220, FTPD_SERVER_MESSAGE);
835
 
836
   /***********************************************************************
837
    * Set initial directory to "/".
838
    **********************************************************************/
839
   strcpy(info->cwd, "/");
840
   info->xfer_mode = TYPE_A;
841
   while (1)
842
   {
843
      if (fgets(cmd, 256, info->ctrl_fp) == NULL)
844
      {
845
         syslog(LOG_INFO, "ftpd: Connection aborted.");
846
         break;
847
      }
848
 
849
      if (!strncmp("QUIT", cmd, 4))
850
      {
851
         rtems_ftpd_send_reply(221, "Goodbye.");
852
         break;
853
      }
854
      else
855
      {
856
         rtems_ftpd_parse_command(cmd);
857
      }
858
   }
859
 
860
   if (fclose(info->ctrl_fp) != 0)
861
   {
862
      syslog(LOG_ERR, "ftpd: Could not close session.");
863
   }
864
 
865
 
866
   /* Least we can do is put the CWD back to /. */
867
   chdir("/");
868
 
869
   /***********************************************************************
870
    * Free up the allocated SessionInfo struct and exit.
871
    **********************************************************************/
872
   free(info);
873
   sc = rtems_task_delete(RTEMS_SELF);
874
   syslog(LOG_ERR, "ftpd: Task deletion failed: %s",
875
          rtems_status_text(sc));
876
}
877
 
878
 
879
/**************************************************************************
880
 * Function: rtems_ftpd_daemon                                            *
881
 **************************************************************************
882
 * Description:                                                           *
883
 *                                                                        *
884
 *    This task runs in the background forever.  It waits for service     *
885
 *    requests on the FTP port (port 21).  When a request is received,    *
886
 *    it opens a new session to handle those requests until the           *
887
 *    connection is closed.                                               *
888
 *                                                                        *
889
 *                                                                        *
890
 * Inputs:                                                                *
891
 *                                                                        *
892
 *    none                                                                *
893
 *                                                                        *
894
 * Output:                                                                *
895
 *                                                                        *
896
 *    none                                                                *
897
 *                                                                        *
898
 **************************************************************************
899
 * Change History:                                                        *
900
 *  12/01/97 - Creation (JWJ)                                             *
901
 *************************************************************************/
902
 
903
/* this is not prototyped in strict ansi mode */
904
 
905
FILE *fdopen (int fildes, const char *mode);
906
 
907
static void
908
rtems_ftpd_daemon()
909
{
910
   int                 s;
911
   int                 s1;
912
   int                 addrLen;
913
   struct sockaddr_in  remoteAddr;
914
   struct sockaddr_in  localAddr;
915
   char                sessionID;
916
   rtems_task_priority priority;
917
   rtems_status_code   sc;
918
   rtems_id            tid;
919
   FTPD_SessionInfo_t  *info = NULL;
920
 
921
 
922
   sessionID = 'a';
923
 
924
   s = socket(AF_INET, SOCK_STREAM, 0);
925
   if (s < 0)
926
   {
927
      perror("Creating socket");
928
   }
929
 
930
   localAddr.sin_family      = AF_INET;
931
   localAddr.sin_port        = htons(rtems_ftpd_configuration.port);
932
   localAddr.sin_addr.s_addr = INADDR_ANY;
933
   memset(localAddr.sin_zero, '\0', sizeof(localAddr.sin_zero));
934
   if (bind(s, (struct sockaddr *)&localAddr,
935
            sizeof(localAddr)) < 0)
936
   {
937
      perror("Binding control socket");
938
   }
939
 
940
   if (listen(s, 2) < 0)
941
   {
942
      perror("Listening on control socket");
943
   }
944
 
945
   while (1)
946
   {
947
      /********************************************************************
948
       * Allocate a SessionInfo structure for the session task.
949
       *******************************************************************/
950
      info = (FTPD_SessionInfo_t *)malloc(sizeof(FTPD_SessionInfo_t));
951
      if (info == NULL)
952
      {
953
         syslog(LOG_ERR, "ftpd: Could not allocate session info struct.");
954
         rtems_panic("Malloc fail.");
955
      }
956
 
957
      /********************************************************************
958
       * Accept on the socket and start the session task.
959
       *******************************************************************/
960
      addrLen = sizeof(remoteAddr);
961
      s1 = accept(s, (struct sockaddr *)&remoteAddr, &addrLen);
962
      if (s1 < 0)
963
      {
964
         perror("Accepting control connection");
965
      }
966
 
967
      rtems_task_set_priority(RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &priority);
968
      sc = rtems_task_create(rtems_build_name('F', 'T', 'P', sessionID),
969
                             priority, 8*1024,
970
                             RTEMS_PREEMPT | RTEMS_NO_TIMESLICE |
971
                             RTEMS_NO_ASR | RTEMS_INTERRUPT_LEVEL(0),
972
                             RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
973
                             &tid);
974
      if (sc != RTEMS_SUCCESSFUL)
975
      {
976
         syslog(LOG_ERR, "ftpd: Could not create FTPD session: %s",
977
                rtems_status_text(sc));
978
      }
979
 
980
      if (sessionID == 'z')
981
      {
982
         sessionID = 'a';
983
      }
984
      else
985
      {
986
         sessionID++;
987
      }
988
 
989
      /********************************************************************
990
       * Send the socket on to the new session.
991
       *******************************************************************/
992
      if ((info->ctrl_fp = fdopen(s1, "r+")) == NULL)
993
      {
994
         syslog(LOG_ERR, "ftpd: fdopen() on socket failed.");
995
         close(s1);
996
      }
997
      else
998
      {
999
         sc = rtems_task_set_note(tid, RTEMS_NOTEPAD_0,
1000
                                  (rtems_unsigned32)info);
1001
         sc = rtems_task_start(tid, rtems_ftpd_session, 0);
1002
         if (sc != RTEMS_SUCCESSFUL)
1003
         {
1004
            syslog(LOG_ERR, "ftpd: Could not start FTPD session: %s",
1005
                   rtems_status_text(sc));
1006
         }
1007
      }
1008
   }
1009
}
1010
 
1011
 
1012
/**************************************************************************
1013
 * Function: rtems_ftpd_start                                             *
1014
 **************************************************************************
1015
 * Description:                                                           *
1016
 *                                                                        *
1017
 *    Here, we start the FTPD task which waits for FTP requests and       *
1018
 *    services them.  This procedure returns to its caller once the       *
1019
 *    task is started.                                                    *
1020
 *                                                                        *
1021
 *                                                                        *
1022
 * Inputs:                                                                *
1023
 *                                                                        *
1024
 *    rtems_task_priority priority - Priority to assign to this task.     *
1025
 *                                                                        *
1026
 * Output:                                                                *
1027
 *                                                                        *
1028
 *    int - RTEMS_SUCCESSFUL on successful start of the daemon.           *
1029
 *                                                                        *
1030
 **************************************************************************
1031
 * Change History:                                                        *
1032
 *  12/01/97 - Creation (JWJ)                                             *
1033
 *************************************************************************/
1034
int
1035
rtems_initialize_ftpd()
1036
{
1037
   rtems_status_code   sc;
1038
   rtems_id            tid;
1039
 
1040
 
1041
   if (rtems_ftpd_configuration.port == 0)
1042
   {
1043
      rtems_ftpd_configuration.port = FTPD_CONTROL_PORT;
1044
   }
1045
 
1046
   /***********************************************************************
1047
    * Default FTPD priority.
1048
    **********************************************************************/
1049
   if (rtems_ftpd_configuration.priority == 0)
1050
   {
1051
      rtems_ftpd_configuration.priority = 40;
1052
   }
1053
   sc = rtems_task_create(rtems_build_name('F', 'T', 'P', 'D'),
1054
                          rtems_ftpd_configuration.priority, 8*1024,
1055
                          RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR |
1056
                          RTEMS_INTERRUPT_LEVEL(0),
1057
                          RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
1058
                          &tid);
1059
   if (sc != RTEMS_SUCCESSFUL)
1060
   {
1061
      syslog(LOG_ERR, "ftpd: Could not create FTP daemon: %s",
1062
             rtems_status_text(sc));
1063
      return(RTEMS_UNSATISFIED);
1064
   }
1065
 
1066
   sc = rtems_task_start(tid, rtems_ftpd_daemon, 0);
1067
   if (sc != RTEMS_SUCCESSFUL)
1068
   {
1069
      syslog(LOG_ERR, "ftpd: Could not start FTP daemon: %s",
1070
             rtems_status_text(sc));
1071
      return(RTEMS_UNSATISFIED);
1072
   }
1073
 
1074
   syslog(LOG_INFO, "ftpd: FTP daemon started.");
1075
   return(RTEMS_SUCCESSFUL);
1076
}
1077
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.