|
1 // |
|
2 // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 // All rights reserved. |
|
4 // This component and the accompanying materials are made available |
|
5 // under the terms of "Eclipse Public License v1.0" |
|
6 // which accompanies this distribution, and is available |
|
7 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 // |
|
9 // Initial Contributors: |
|
10 // Nokia Corporation - initial contribution. |
|
11 // |
|
12 // Contributors: |
|
13 // |
|
14 // Description: |
|
15 // |
|
16 |
|
17 /* |
|
18 * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994 |
|
19 * The Regents of the University of California. All rights reserved. |
|
20 * |
|
21 * Redistribution and use in source and binary forms, with or without |
|
22 * modification, are permitted provided that the following conditions |
|
23 * are met: |
|
24 * 1. Redistributions of source code must retain the above copyright |
|
25 * notice, this list of conditions and the following disclaimer. |
|
26 * 2. Redistributions in binary form must reproduce the above copyright |
|
27 * notice, this list of conditions and the following disclaimer in the |
|
28 * documentation and/or other materials provided with the distribution. |
|
29 * 3. All advertising materials mentioning features or use of this software |
|
30 * must display the following acknowledgement: |
|
31 * This product includes software developed by the University of |
|
32 * California, Berkeley and its contributors. |
|
33 * 4. Neither the name of the University nor the names of its contributors |
|
34 * may be used to endorse or promote products derived from this software |
|
35 * without specific prior written permission. |
|
36 * |
|
37 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
|
38 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
40 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
|
41 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|
42 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
|
43 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|
44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
45 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
|
46 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|
47 * SUCH DAMAGE. |
|
48 */ |
|
49 |
|
50 /* |
|
51 * FTP server. |
|
52 */ |
|
53 |
|
54 |
|
55 #include <netinet/net_types.h> |
|
56 #include <sys/param.h> |
|
57 #include <sys/stat.h> |
|
58 #include <sys/socket.h> |
|
59 #include <sys/mman.h> |
|
60 #include <netinet/in.h> |
|
61 |
|
62 #define FTP_NAMES |
|
63 #include <arpa/ftp.h> |
|
64 #include <ctype.h> |
|
65 #include <dirent.h> |
|
66 #include <fcntl.h> |
|
67 #include <glob.h> |
|
68 #include <limits.h> /* for CHAR_BIT */ |
|
69 #include <netdb.h> |
|
70 #include <pwd.h> |
|
71 #include <setjmp.h> |
|
72 #include <stdio.h> |
|
73 #include <stdlib.h> |
|
74 #include <string.h> |
|
75 #include <unistd.h> |
|
76 #include <utmp.h> |
|
77 #include <spawn.h> |
|
78 |
|
79 #include "pathnames.h" |
|
80 #include "extern.h" |
|
81 |
|
82 // Symbian includes |
|
83 |
|
84 #include <f32file.h> |
|
85 #include <in_iface.h> |
|
86 |
|
87 static char version[]="v1.0.1000"; |
|
88 |
|
89 extern off_t restart_point; |
|
90 extern char cbuf[]; |
|
91 |
|
92 struct sockaddr_in server_addr; |
|
93 struct sockaddr_in ctrl_addr; |
|
94 struct sockaddr_in data_source; |
|
95 struct sockaddr_in data_dest; |
|
96 struct sockaddr_in his_addr; |
|
97 struct sockaddr_in pasv_addr; |
|
98 |
|
99 in_addr server_in_addr; |
|
100 |
|
101 int daemon_mode = 0; |
|
102 int data; |
|
103 jmp_buf errcatch, urgcatch; |
|
104 int logged_in; |
|
105 struct passwd *pw; |
|
106 int debug = 0; |
|
107 int timeout = 900; /* timeout after 15 minutes of inactivity */ |
|
108 int maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */ |
|
109 int logging = 0; |
|
110 int replicate = 0; |
|
111 int high_data_ports = 0; |
|
112 int anon_only = 0; |
|
113 int multihome = 0; |
|
114 int guest; |
|
115 int stats; |
|
116 int statfd = -1; |
|
117 int portcheck = 1; |
|
118 int dochroot; |
|
119 int type; |
|
120 int form; |
|
121 int stru; /* avoid C keyword */ |
|
122 int mode; |
|
123 int doutmp = 0; /* update utmp file */ |
|
124 int usedefault = 1; /* for data transfers */ |
|
125 int pdata = -1; /* for passive mode */ |
|
126 int port = 21; /* default FTP port */ |
|
127 //sig_atomic_t transflag; |
|
128 int transflag; |
|
129 off_t file_size; |
|
130 off_t byte_count; |
|
131 #if !defined(CMASK) || CMASK == 0 |
|
132 #undef CMASK |
|
133 #define CMASK 027 |
|
134 #endif |
|
135 int defumask = CMASK; /* default umask value */ |
|
136 char tmpline[7]; |
|
137 char hostname[]="Symbian"; |
|
138 char* remotehost=hostname; |
|
139 char* dhostname=hostname; |
|
140 char *guestpw; |
|
141 static char ttyline[20]; |
|
142 char *tty = ttyline; /* for klogin */ |
|
143 static struct utmp utmp; /* for utmp */ |
|
144 |
|
145 TDriveNumber drive; |
|
146 |
|
147 char *ident = NULL; |
|
148 |
|
149 int root = 1; |
|
150 FILE* logFile; |
|
151 /* |
|
152 * Timeout intervals for retrying connections |
|
153 * to hosts that don't accept PORT cmds. This |
|
154 * is a kludge, but given the problems with TCP... |
|
155 */ |
|
156 #define SWAITMAX 90 /* wait at most 90 seconds */ |
|
157 #define SWAITINT 5 /* interval between retries */ |
|
158 |
|
159 int swaitmax = SWAITMAX; |
|
160 int swaitint = SWAITINT; |
|
161 |
|
162 #ifdef HASSETPROCTITLE |
|
163 char proctitle[BUFSIZ]; /* initial part of title */ |
|
164 #endif /* HASSETPROCTITLE */ |
|
165 |
|
166 #define LOG(message) \ |
|
167 if (logging/* > 1*/) { \ |
|
168 fprintf(logFile, "LOG_INFO %s\r\n", message); \ |
|
169 fflush(logFile); } |
|
170 |
|
171 #define LOGCMD(cmd, file) \ |
|
172 if (logging/* > 1*/) { \ |
|
173 fprintf(logFile, "LOG_INFO %s %s\r\n", cmd, file); \ |
|
174 fflush(logFile); } |
|
175 #define LOGCMD2(cmd, file1, file2) \ |
|
176 if (logging/* > 1*/) { \ |
|
177 fprintf(logFile, "LOG_INFO %s %s %s\r\n", cmd, file1, file2); \ |
|
178 fflush(logFile); } |
|
179 #define LOGBYTES(cmd, file, cnt) \ |
|
180 if (logging/* > 1*/) { \ |
|
181 if (cnt == (off_t)-1) \ |
|
182 fprintf(logFile, "LOG_INFO %s %s\r\n", cmd, file); \ |
|
183 else \ |
|
184 fprintf(logFile, "LOG_INFO %s %s = %qd bytes\r\n", cmd, file, (quad_t)(cnt)); \ |
|
185 fflush(logFile) ; \ |
|
186 } |
|
187 |
|
188 static void ack __P((const char *)); |
|
189 static FILE *dataconn __P((const char *, off_t, const char *)); |
|
190 static void dolog __P((struct sockaddr_in *)); |
|
191 static void end_login __P((void)); |
|
192 static FILE *getdatasock __P((const char *)); |
|
193 static int guniquefd __P((const char *, char **)); |
|
194 static int receive_data __P((FILE *, FILE *)); |
|
195 static void replydirname __P((const char *, const char *)); |
|
196 static void send_data __P((FILE *, FILE *, off_t, off_t, int)); |
|
197 |
|
198 #if defined(TCPWRAPPERS) |
|
199 static int check_host __P((struct sockaddr_in *)); |
|
200 #endif |
|
201 |
|
202 in_addr getServerAddress(); |
|
203 TDriveNumber getSystemDrive(); |
|
204 |
|
205 void logxfer __P((const char *, off_t, time_t)); |
|
206 |
|
207 #define MAXUSERNAME 64 |
|
208 char * username[MAXUSERNAME]; |
|
209 char * userhome[MAXPATHLEN]; |
|
210 |
|
211 #undef IP_PORTRANGE |
|
212 |
|
213 int |
|
214 main(int argc, char *argv[], char **envp) |
|
215 { |
|
216 int ch, on = 1; |
|
217 socklen_t addrlen; |
|
218 char *cp, line[LINE_MAX]; |
|
219 FILE *fd; |
|
220 const char *argstr = "RAdDhlMSt:T:u:UvP:"; |
|
221 |
|
222 tzset(); /* in case no timezone database in ~ftp */ |
|
223 |
|
224 /* set this here so klogin can use it... */ |
|
225 (void)snprintf(ttyline, sizeof(ttyline), "ftp%d", getpid()); |
|
226 |
|
227 while ((ch = getopt(argc, argv, argstr)) != -1) { |
|
228 switch (ch) { |
|
229 case 'A': |
|
230 anon_only = 1; |
|
231 break; |
|
232 |
|
233 case 'd': |
|
234 debug = 1; |
|
235 break; |
|
236 |
|
237 case 'D': |
|
238 |
|
239 for(int i=1 /*no name*/; i<argc; i++) |
|
240 { |
|
241 for(unsigned int j=0;j<strlen(argv[i]); j++) |
|
242 if(argv[i][j]=='D') |
|
243 { |
|
244 //Daemon token found, change it to allow replication to new background processes |
|
245 argv[i][j]='R'; |
|
246 } |
|
247 } |
|
248 posix_spawn(NULL,argv[0],NULL,NULL,argv,envp); |
|
249 exit(0); |
|
250 |
|
251 break; |
|
252 |
|
253 case 'R': |
|
254 replicate = 1; |
|
255 break; |
|
256 |
|
257 case 'P': |
|
258 port = atoi(optarg); |
|
259 break; |
|
260 |
|
261 case 'h': |
|
262 high_data_ports = 1; |
|
263 break; |
|
264 |
|
265 case 'l': |
|
266 logging++; /* > 1 == extra logging */ |
|
267 break; |
|
268 |
|
269 case 'M': |
|
270 multihome = 1; |
|
271 break; |
|
272 |
|
273 case 'S': |
|
274 stats = 1; |
|
275 break; |
|
276 |
|
277 case 't': |
|
278 timeout = atoi(optarg); |
|
279 if (maxtimeout < timeout) |
|
280 maxtimeout = timeout; |
|
281 break; |
|
282 |
|
283 case 'T': |
|
284 maxtimeout = atoi(optarg); |
|
285 if (timeout > maxtimeout) |
|
286 timeout = maxtimeout; |
|
287 break; |
|
288 |
|
289 case 'u': |
|
290 { |
|
291 long val = 0; |
|
292 |
|
293 val = strtol(optarg, &optarg, 8); |
|
294 if (*optarg != '\0' || val < 0 || (val & ~ACCESSPERMS)) |
|
295 printf("bad value for -u"); |
|
296 else |
|
297 defumask = val; |
|
298 break; |
|
299 } |
|
300 |
|
301 case 'U': |
|
302 doutmp = 1; |
|
303 break; |
|
304 |
|
305 case 'v': |
|
306 debug = 1; |
|
307 break; |
|
308 |
|
309 default: |
|
310 printf("unknown flag -%c ignored", optopt); |
|
311 scanf(""); |
|
312 break; |
|
313 } |
|
314 } |
|
315 |
|
316 (void) freopen(_PATH_DEVNULL, "w", stderr); |
|
317 |
|
318 /* |
|
319 * LOG_NDELAY sets up the logging connection immediately, |
|
320 * necessary for anonymous ftp's that chroot and can't do it later. |
|
321 */ |
|
322 #ifndef LOG_FTP |
|
323 #define LOG_FTP LOG_DAEMON |
|
324 #endif |
|
325 |
|
326 int ctl_sock, fd2; |
|
327 |
|
328 server_in_addr = getServerAddress(); |
|
329 |
|
330 /* |
|
331 * Open a socket, bind it to the FTP port, and start |
|
332 * listening. |
|
333 */ |
|
334 ctl_sock = socket(AF_INET, SOCK_STREAM, 0); |
|
335 if (ctl_sock < 0) { |
|
336 User::Panic(_L("socket error"),0); |
|
337 LOG("socket error"); |
|
338 exit(1); |
|
339 } |
|
340 |
|
341 setsockopt(ctl_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); |
|
342 |
|
343 server_addr.sin_family = 0; |
|
344 server_addr.sin_addr.s_addr = INADDR_ANY; |
|
345 server_addr.sin_port = port; |
|
346 if (bind(ctl_sock, (struct sockaddr *)&server_addr, |
|
347 sizeof(server_addr))) { |
|
348 User::Panic(_L("bind error"),0); |
|
349 LOG("bind error"); |
|
350 exit(1); |
|
351 } |
|
352 if (listen(ctl_sock, 32) < 0) { |
|
353 User::Panic(_L("listen error"),0); |
|
354 LOG("listen error"); |
|
355 exit(1); |
|
356 } |
|
357 addrlen = sizeof(his_addr); |
|
358 fd2 = accept(ctl_sock, (struct sockaddr *)&his_addr, |
|
359 &addrlen); |
|
360 |
|
361 (void) dup2(fd2, 0); |
|
362 (void) dup2(fd2, 1); |
|
363 close(ctl_sock); |
|
364 close(fd2); |
|
365 |
|
366 |
|
367 drive = getSystemDrive(); |
|
368 |
|
369 if(logging) |
|
370 { |
|
371 char logFileName[MAXPATHLEN]; |
|
372 |
|
373 char driveLetter = 'A'+drive; |
|
374 |
|
375 sprintf(logFileName,"%c:\\ftpd_%d.log",driveLetter,getpid()); |
|
376 logFile = fopen(logFileName,"w"); |
|
377 |
|
378 fprintf(logFile, "** Log file for the FTP instance with PID %d **\r\n",getpid()); |
|
379 fflush(logFile); |
|
380 } |
|
381 |
|
382 |
|
383 addrlen = sizeof(ctrl_addr); |
|
384 if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) { |
|
385 User::Panic(_L("getsockname error"),0); |
|
386 exit(1); |
|
387 } |
|
388 |
|
389 //clone to accept new connections |
|
390 if(replicate) |
|
391 posix_spawn(NULL,argv[0],NULL,NULL,argv,envp); |
|
392 |
|
393 data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1); |
|
394 |
|
395 dolog(&his_addr); |
|
396 /* |
|
397 * Set up default state |
|
398 */ |
|
399 data = -1; |
|
400 type = TYPE_A; |
|
401 form = FORM_N; |
|
402 stru = STRU_F; |
|
403 mode = MODE_S; |
|
404 tmpline[0] = '\0'; |
|
405 |
|
406 /* If logins are disabled, print out the message. */ |
|
407 if ((fd = fopen(_PATH_NOLOGIN,"r")) != NULL) { |
|
408 while (fgets(line, sizeof(line), fd) != NULL) { |
|
409 if ((cp = strchr(line, '\n')) != NULL) |
|
410 *cp = '\0'; |
|
411 lreply(530, "%s", line); |
|
412 } |
|
413 (void) fflush(stdout); |
|
414 (void) fclose(fd); |
|
415 reply(530, "System not available."); |
|
416 exit(0); |
|
417 } |
|
418 if ((fd = fopen(_PATH_FTPWELCOME, "r")) != NULL) { |
|
419 while (fgets(line, sizeof(line), fd) != NULL) { |
|
420 if ((cp = strchr(line, '\n')) != NULL) |
|
421 *cp = '\0'; |
|
422 lreply(220, "%s", line); |
|
423 } |
|
424 (void) fflush(stdout); |
|
425 (void) fclose(fd); |
|
426 /* reply(220,) must follow */ |
|
427 } |
|
428 |
|
429 reply(220, "%s FTP server (%s) ready.", |
|
430 hostname, version); |
|
431 (void) setjmp(errcatch); |
|
432 for (;;) |
|
433 (void) yyparse(); |
|
434 /* NOTREACHED */ |
|
435 } |
|
436 |
|
437 static int login_attempts; /* number of failed login attempts */ |
|
438 static int askpasswd; /* had user command, ask for passwd */ |
|
439 static char curname[16]; /* current USER name */ |
|
440 |
|
441 /* |
|
442 * USER command. |
|
443 * Sets global passwd pointer pw if named account exists and is acceptable; |
|
444 * sets askpasswd if a PASS command is expected. If logged in previously, |
|
445 * need to reset state. If name is "ftp" or "anonymous", the name is not in |
|
446 * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return. |
|
447 * If account doesn't exist, ask for passwd anyway. Otherwise, check user |
|
448 * requesting login privileges. Disallow anyone who does not have a standard |
|
449 * shell as returned by getusershell(). Disallow anyone mentioned in the file |
|
450 * _PATH_FTPUSERS to allow people such as root and uucp to be avoided. |
|
451 */ |
|
452 void user(char *name) |
|
453 { |
|
454 //const char *cp, *shell; |
|
455 |
|
456 if (logged_in) { |
|
457 if (guest) { |
|
458 reply(530, "Can't change user from guest login."); |
|
459 return; |
|
460 } else if (dochroot) { |
|
461 reply(530, "Can't change user from chroot user."); |
|
462 return; |
|
463 } |
|
464 end_login(); |
|
465 } |
|
466 |
|
467 guest = 0; |
|
468 |
|
469 // check password |
|
470 |
|
471 pw = (passwd *)malloc(sizeof(pw)); |
|
472 |
|
473 strcpy((char*)username,name); |
|
474 pw->pw_name = (char*)username; |
|
475 |
|
476 strcpy((char*)userhome,"/"); |
|
477 pw->pw_dir = (char*)userhome; |
|
478 |
|
479 if (logging) { |
|
480 strncpy(curname, name, sizeof(curname)-1); |
|
481 curname[sizeof(curname)-1] = '\0'; |
|
482 } |
|
483 |
|
484 if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) |
|
485 reply(331,"Guest login ok, type your name as password."); |
|
486 else |
|
487 reply(331, "Password required for %s.", name); |
|
488 |
|
489 askpasswd = 1; |
|
490 /* |
|
491 * Delay before reading passwd after first failed |
|
492 * attempt to slow down passwd-guessing programs. |
|
493 */ |
|
494 if (login_attempts) |
|
495 sleep((unsigned) login_attempts); |
|
496 } |
|
497 |
|
498 |
|
499 /* |
|
500 * Terminate login as previous user, if any, resetting state; |
|
501 * used when USER command is given or login fails. |
|
502 */ |
|
503 static void end_login(void) |
|
504 { |
|
505 (void) seteuid((uid_t)0); |
|
506 if (logged_in) { |
|
507 if (doutmp) |
|
508 logout(utmp.ut_line); |
|
509 } |
|
510 pw = NULL; |
|
511 logged_in = 0; |
|
512 guest = 0; |
|
513 dochroot = 0; |
|
514 } |
|
515 |
|
516 void pass(char *passwd) |
|
517 { |
|
518 int rval; |
|
519 FILE *fd; |
|
520 |
|
521 if (logged_in || askpasswd == 0) { |
|
522 reply(503, "Login with USER first."); |
|
523 return; |
|
524 } |
|
525 askpasswd = 0; |
|
526 |
|
527 if (!guest) { /* "ftp" is only account allowed no password */ |
|
528 |
|
529 /* |
|
530 * Authenticate password... |
|
531 */ |
|
532 |
|
533 rval = 0; |
|
534 |
|
535 /* |
|
536 * If rval == 1, the user failed the authentication check |
|
537 * above. If rval == 0, either Kerberos or local authentication |
|
538 * succeeded. |
|
539 */ |
|
540 if (rval) { |
|
541 reply(530, "Login incorrect."); |
|
542 pw = NULL; |
|
543 return; |
|
544 } |
|
545 } else { |
|
546 /* Save anonymous' password. */ |
|
547 guestpw = strdup(passwd); |
|
548 if (guestpw == (char *)NULL) |
|
549 fatal("Out of memory"); |
|
550 } |
|
551 login_attempts = 0; /* this time successful */ |
|
552 |
|
553 if (setegid((gid_t)pw->pw_gid) < 0) { |
|
554 reply(550, "Can't set gid."); |
|
555 return; |
|
556 } |
|
557 (void) initgroups(pw->pw_name, pw->pw_gid); |
|
558 |
|
559 /* open utmp before chroot */ |
|
560 if (doutmp) { |
|
561 memset((void *)&utmp, 0, sizeof(utmp)); |
|
562 (void)time(&utmp.ut_time); |
|
563 (void)strncpy(utmp.ut_name, pw->pw_name, sizeof(utmp.ut_name)); |
|
564 (void)strncpy(utmp.ut_host, remotehost, sizeof(utmp.ut_host)); |
|
565 (void)strncpy(utmp.ut_line, ttyline, sizeof(utmp.ut_line)); |
|
566 login(&utmp); |
|
567 } |
|
568 |
|
569 /* open stats file before chroot */ |
|
570 if (guest && (stats == 1) && (statfd < 0)) |
|
571 if ((statfd = open(_PATH_FTPDSTATFILE, O_WRONLY|O_APPEND)) < 0) |
|
572 stats = 0; |
|
573 |
|
574 logged_in = 1; |
|
575 dochroot = 0; |
|
576 |
|
577 /* |
|
578 * Set home directory to root |
|
579 */ |
|
580 chdir("/"); //root |
|
581 |
|
582 /* |
|
583 * Display a login message, if it exists. |
|
584 * N.B. reply(230,) must follow the message. |
|
585 */ |
|
586 if ((fd = fopen(_PATH_FTPLOGINMESG, "r")) != NULL) { |
|
587 char *cp, line[LINE_MAX]; |
|
588 |
|
589 while (fgets(line, sizeof(line), fd) != NULL) { |
|
590 if ((cp = strchr(line, '\n')) != NULL) |
|
591 *cp = '\0'; |
|
592 lreply(230, "%s", line); |
|
593 } |
|
594 (void) fflush(stdout); |
|
595 (void) fclose(fd); |
|
596 } |
|
597 if (guest) { |
|
598 if (ident != NULL) |
|
599 free(ident); |
|
600 ident = strdup(passwd); |
|
601 if (ident == (char *)NULL) |
|
602 fatal("Ran out of memory."); |
|
603 reply(230, "Guest login ok, access restrictions apply."); |
|
604 } else { |
|
605 reply(230, "User %s logged in.", pw->pw_name); |
|
606 } |
|
607 (void) umask(defumask); |
|
608 return; |
|
609 } |
|
610 |
|
611 void internalName(char* output, const char *input) |
|
612 { |
|
613 //from /c/aaa.txt to c:\aaa.txt |
|
614 |
|
615 strcpy(output,input); |
|
616 |
|
617 //root is a special case |
|
618 if(strcmp(output,"/")==0) |
|
619 { |
|
620 return; |
|
621 } |
|
622 |
|
623 for(unsigned int i=0 ; i<strlen(output); i++) |
|
624 { |
|
625 if(output[i]=='/') |
|
626 output[i]= '\\'; |
|
627 } |
|
628 |
|
629 //relative path, do not modify |
|
630 if((output[0]!='\\' && strlen(output)>1) || strcmp(output,".")==0) |
|
631 { |
|
632 return; |
|
633 } |
|
634 |
|
635 if(strlen(output)==1 && root) |
|
636 { |
|
637 //it's a drive: C\0 -> C:\0 |
|
638 output[2]=output[1]; |
|
639 output[1]=':'; |
|
640 |
|
641 } |
|
642 else |
|
643 { |
|
644 |
|
645 // /C/system\n -> C:/system\n |
|
646 output[0]=output[1]; |
|
647 output[1]=':'; |
|
648 } |
|
649 } |
|
650 |
|
651 void externalName(char* output, const char *input) |
|
652 { |
|
653 //from c:/aaa.txt to /c/aaa.txt |
|
654 |
|
655 strcpy(output,input); |
|
656 |
|
657 for(unsigned int i=0 ; i<strlen(output); i++) |
|
658 { |
|
659 if(output[i]=='\\') |
|
660 output[i]= '/'; |
|
661 } |
|
662 |
|
663 output[1]=output[0]; |
|
664 output[0]='/'; |
|
665 } |
|
666 |
|
667 void retrieve(const char *cmd, const char *name) |
|
668 { |
|
669 FILE *fin, *dout; |
|
670 struct stat st; |
|
671 int (*closefunc) __P((FILE *)); |
|
672 time_t start; |
|
673 |
|
674 char adaptedName[MAXPATHLEN]; |
|
675 internalName(adaptedName,name); |
|
676 |
|
677 LOGCMD("RETR", adaptedName); |
|
678 |
|
679 if (cmd == 0) { |
|
680 fin = fopen(adaptedName, "r"); closefunc = fclose; |
|
681 st.st_size = 0; |
|
682 } else { |
|
683 char line[BUFSIZ]; |
|
684 |
|
685 (void) snprintf(line, sizeof(line), cmd, adaptedName); |
|
686 name = line; |
|
687 fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose; |
|
688 st.st_size = -1; |
|
689 st.st_blksize = BUFSIZ; |
|
690 } |
|
691 if (fin == NULL) { |
|
692 if (errno != 0) { |
|
693 perror_reply(550, name); |
|
694 if (cmd == 0) { |
|
695 LOGCMD("get", adaptedName); |
|
696 } |
|
697 } |
|
698 return; |
|
699 } |
|
700 byte_count = -1; |
|
701 if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) { |
|
702 reply(550, "%s: not a plain file.", name); |
|
703 goto done; |
|
704 } |
|
705 |
|
706 |
|
707 if (restart_point) { |
|
708 if (type == TYPE_A) { |
|
709 off_t i, n; |
|
710 int c; |
|
711 |
|
712 n = restart_point; |
|
713 i = 0; |
|
714 while (i++ < n) { |
|
715 if ((c=getc(fin)) == EOF) { |
|
716 perror_reply(550, name); |
|
717 goto done; |
|
718 } |
|
719 if (c == '\n') |
|
720 i++; |
|
721 } |
|
722 } else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) { |
|
723 perror_reply(550, name); |
|
724 goto done; |
|
725 } |
|
726 } |
|
727 |
|
728 dout = dataconn(name, st.st_size, "w"); |
|
729 if (dout == NULL) |
|
730 goto done; |
|
731 time(&start); |
|
732 send_data(fin, dout, st.st_blksize, st.st_size, |
|
733 (restart_point == 0 && cmd == 0 && S_ISREG(st.st_mode))); |
|
734 if ((cmd == 0) && stats) |
|
735 logxfer(name, st.st_size, start); |
|
736 (void) fclose(dout); |
|
737 data = -1; |
|
738 pdata = -1; |
|
739 done: |
|
740 if (cmd == 0) |
|
741 LOGBYTES("get", name, byte_count); |
|
742 (*closefunc)(fin); |
|
743 } |
|
744 |
|
745 void store(const char *name, const char *mode, int unique) |
|
746 { |
|
747 |
|
748 FILE *fout, *din; |
|
749 int (*closefunc) __P((FILE *)); |
|
750 struct stat st; |
|
751 int fd; |
|
752 |
|
753 char adaptedName[MAXPATHLEN]; |
|
754 internalName(adaptedName,name); |
|
755 |
|
756 LOGCMD("STOR", adaptedName); |
|
757 |
|
758 if (unique && stat(adaptedName, &st) == 0) { |
|
759 char *nam; |
|
760 |
|
761 fd = guniquefd(adaptedName, &nam); |
|
762 if (fd == -1) { |
|
763 LOGCMD(*mode == 'w' ? "put" : "append", name); |
|
764 return; |
|
765 } |
|
766 name = nam; |
|
767 if (restart_point) |
|
768 mode = "r+"; |
|
769 fout = fdopen(fd, mode); |
|
770 } else |
|
771 fout = fopen(adaptedName, mode); |
|
772 |
|
773 closefunc = fclose; |
|
774 if (fout == NULL) { |
|
775 perror_reply(553, name); |
|
776 LOGCMD(*mode == 'w' ? "put" : "append", name); |
|
777 return; |
|
778 } |
|
779 byte_count = -1; |
|
780 if (restart_point) { |
|
781 if (type == TYPE_A) { |
|
782 off_t i, n; |
|
783 int c; |
|
784 |
|
785 n = restart_point; |
|
786 i = 0; |
|
787 while (i++ < n) { |
|
788 if ((c=getc(fout)) == EOF) { |
|
789 perror_reply(550, name); |
|
790 goto done; |
|
791 } |
|
792 if (c == '\n') |
|
793 i++; |
|
794 } |
|
795 /* |
|
796 * We must do this seek to "current" position |
|
797 * because we are changing from reading to |
|
798 * writing. |
|
799 */ |
|
800 if (fseek(fout, 0L, SEEK_CUR) < 0) { |
|
801 perror_reply(550, name); |
|
802 goto done; |
|
803 } |
|
804 } else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) { |
|
805 perror_reply(550, name); |
|
806 goto done; |
|
807 } |
|
808 } |
|
809 din = dataconn(adaptedName, (off_t)-1, "r"); |
|
810 if (din == NULL) |
|
811 goto done; |
|
812 if (receive_data(din, fout) == 0) { |
|
813 if (unique) |
|
814 reply(226, "Transfer complete (unique file name:%s).", |
|
815 name); |
|
816 else |
|
817 reply(226, "Transfer complete."); |
|
818 } |
|
819 (void) fclose(din); |
|
820 data = -1; |
|
821 pdata = -1; |
|
822 done: |
|
823 LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count); |
|
824 (*closefunc)(fout); |
|
825 } |
|
826 |
|
827 static FILE * getdatasock(const char *mode) |
|
828 { |
|
829 int on = 1, s, t, tries; |
|
830 |
|
831 if (data >= 0) |
|
832 return (fdopen(data, mode)); |
|
833 (void) seteuid((uid_t)0); |
|
834 s = socket(AF_INET, SOCK_STREAM, 0); |
|
835 if (s < 0) |
|
836 goto bad; |
|
837 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, |
|
838 (char *) &on, sizeof(on)) < 0) |
|
839 goto bad; |
|
840 /* anchor socket to avoid multi-homing problems */ |
|
841 |
|
842 data_source.sin_family = AF_INET; |
|
843 data_source.sin_addr = ctrl_addr.sin_addr; |
|
844 for (tries = 1; ; tries++) { |
|
845 if (bind(s, (struct sockaddr *)&data_source, |
|
846 sizeof(data_source)) >= 0) |
|
847 break; |
|
848 if (errno != EADDRINUSE || tries > 10) |
|
849 goto bad; |
|
850 sleep(tries); |
|
851 } |
|
852 (void) seteuid((uid_t)pw->pw_uid); |
|
853 |
|
854 return (fdopen(s, mode)); |
|
855 bad: |
|
856 /* Return the real value of errno (close may change it) */ |
|
857 t = errno; |
|
858 (void) seteuid((uid_t)pw->pw_uid); |
|
859 (void) close(s); |
|
860 errno = t; |
|
861 return (NULL); |
|
862 } |
|
863 |
|
864 static FILE * dataconn(const char *name, off_t size, const char *mode) |
|
865 { |
|
866 char sizebuf[32]; |
|
867 FILE *file; |
|
868 int retry = 0; |
|
869 |
|
870 file_size = size; |
|
871 byte_count = 0; |
|
872 if (size != (off_t) -1) { |
|
873 (void) snprintf(sizebuf, sizeof(sizebuf), " (%lld bytes)", |
|
874 (quad_t) size); |
|
875 } else |
|
876 sizebuf[0] = '\0'; |
|
877 |
|
878 if (pdata >= 0) { |
|
879 struct sockaddr_in from; |
|
880 int s; |
|
881 socklen_t fromlen = sizeof(from); |
|
882 |
|
883 s = accept(pdata, (struct sockaddr *)&from, &fromlen); |
|
884 |
|
885 //TODO: OE bug ? sizebuf seems to be changed to 0x18 after accept |
|
886 //reassigning sizebuf |
|
887 if (size != (off_t) -1) { |
|
888 (void) snprintf(sizebuf, sizeof(sizebuf), " (%lld bytes)", |
|
889 (quad_t) size); |
|
890 } else |
|
891 sizebuf[0] = '\0'; |
|
892 |
|
893 |
|
894 if (s < 0) { |
|
895 reply(425, "Can't open data connection."); |
|
896 (void) close(pdata); |
|
897 pdata = -1; |
|
898 return (NULL); |
|
899 } |
|
900 if (ntohs(from.sin_port) < IPPORT_RESERVED) { |
|
901 perror_reply(425, "Can't build data connection"); |
|
902 (void) close(pdata); |
|
903 (void) close(s); |
|
904 pdata = -1; |
|
905 return (NULL); |
|
906 } |
|
907 if (from.sin_addr.s_addr != his_addr.sin_addr.s_addr) { |
|
908 perror_reply(435, "Can't build data connection"); |
|
909 (void) close(pdata); |
|
910 (void) close(s); |
|
911 pdata = -1; |
|
912 return (NULL); |
|
913 } |
|
914 (void) close(pdata); |
|
915 pdata = s; |
|
916 |
|
917 if (size != (off_t) -1) { |
|
918 (void) snprintf(sizebuf, sizeof(sizebuf), " (%lld bytes)", |
|
919 (quad_t) size); |
|
920 } else |
|
921 sizebuf[0] = '\0'; |
|
922 |
|
923 reply(150, "Opening %s mode data connection for '%s'%s.", |
|
924 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); |
|
925 return (fdopen(pdata, mode)); |
|
926 } |
|
927 if (data >= 0) { |
|
928 reply(125, "Using existing data connection for '%s'%s.", |
|
929 name, sizebuf); |
|
930 usedefault = 1; |
|
931 return (fdopen(data, mode)); |
|
932 } |
|
933 if (usedefault) |
|
934 data_dest = his_addr; |
|
935 usedefault = 1; |
|
936 file = getdatasock(mode); |
|
937 if (file == NULL) { |
|
938 reply(425, "Can't create data socket (%s,%d): %s.", |
|
939 inet_ntoa(data_source.sin_addr), |
|
940 ntohs(data_source.sin_port), strerror(errno)); |
|
941 return (NULL); |
|
942 } |
|
943 data = fileno(file); |
|
944 |
|
945 /* |
|
946 * attempt to connect to reserved port on client machine; |
|
947 * this looks like an attack |
|
948 */ |
|
949 if (ntohs(data_dest.sin_port) < IPPORT_RESERVED || |
|
950 ntohs(data_dest.sin_port) == 2049) { /* XXX */ |
|
951 perror_reply(425, "Can't build data connection"); |
|
952 (void) fclose(file); |
|
953 data = -1; |
|
954 return NULL; |
|
955 } |
|
956 if (data_dest.sin_addr.s_addr != his_addr.sin_addr.s_addr) { |
|
957 perror_reply(435, "Can't build data connection"); |
|
958 (void) fclose(file); |
|
959 data = -1; |
|
960 return NULL; |
|
961 } |
|
962 while (connect(data, (struct sockaddr *)&data_dest, |
|
963 sizeof(data_dest)) < 0) { |
|
964 if (errno == EADDRINUSE && retry < swaitmax) { |
|
965 sleep((unsigned) swaitint); |
|
966 retry += swaitint; |
|
967 continue; |
|
968 } |
|
969 perror_reply(425, "Can't build data connection"); |
|
970 (void) fclose(file); |
|
971 data = -1; |
|
972 return (NULL); |
|
973 } |
|
974 reply(150, "Opening %s mode data connection for '%s'%s.", |
|
975 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); |
|
976 return (file); |
|
977 } |
|
978 |
|
979 /* |
|
980 * Tranfer the contents of "instr" to "outstr" peer using the appropriate |
|
981 * encapsulation of the data subject to Mode, Structure, and Type. |
|
982 * |
|
983 * NB: Form isn't handled. |
|
984 */ |
|
985 static void send_data(FILE *instr, FILE *outstr, off_t blksize, off_t filesize, int isreg) |
|
986 { |
|
987 int c, cnt, filefd, netfd; |
|
988 char *buf, *bp; |
|
989 size_t len,size; |
|
990 |
|
991 transflag++; |
|
992 if (setjmp(urgcatch)) { |
|
993 transflag = 0; |
|
994 return; |
|
995 } |
|
996 switch (type) { |
|
997 |
|
998 case TYPE_A: |
|
999 while ((c = getc(instr)) != EOF) { |
|
1000 byte_count++; |
|
1001 (void) putc(c, outstr); |
|
1002 } |
|
1003 fflush(outstr); |
|
1004 transflag = 0; |
|
1005 if (ferror(instr)) |
|
1006 goto file_err; |
|
1007 if (ferror(outstr)) |
|
1008 goto data_err; |
|
1009 reply(226, "Transfer complete."); |
|
1010 return; |
|
1011 |
|
1012 case TYPE_I: |
|
1013 case TYPE_L: |
|
1014 /* |
|
1015 * isreg is only set if we are not doing restart and we |
|
1016 * are sending a regular file |
|
1017 */ |
|
1018 netfd = fileno(outstr); |
|
1019 filefd = fileno(instr); |
|
1020 |
|
1021 if (isreg && filesize < (off_t)16 * 1024 * 1024) { |
|
1022 buf = (char *)mmap(0, filesize, PROT_READ, MAP_SHARED, filefd, (off_t)0); |
|
1023 if (buf==MAP_FAILED || buf==NULL) { |
|
1024 goto oldway; |
|
1025 } |
|
1026 bp = buf; |
|
1027 len = filesize; |
|
1028 do { |
|
1029 cnt = write(netfd, bp, len); |
|
1030 len -= cnt; |
|
1031 bp += cnt; |
|
1032 if (cnt > 0) byte_count += cnt; |
|
1033 } while(cnt > 0 && len > 0); |
|
1034 |
|
1035 transflag = 0; |
|
1036 munmap(buf, (size_t)filesize); |
|
1037 if (cnt < 0) |
|
1038 goto data_err; |
|
1039 reply(226, "Transfer complete."); |
|
1040 return; |
|
1041 } |
|
1042 |
|
1043 oldway: |
|
1044 size = blksize * 16; |
|
1045 |
|
1046 if ((buf = (char *)malloc(size)) == NULL) { |
|
1047 transflag = 0; |
|
1048 perror_reply(451, "Local resource failure: malloc"); |
|
1049 return; |
|
1050 } |
|
1051 |
|
1052 while ((cnt = read(filefd, buf, size)) > 0 && |
|
1053 write(netfd, buf, cnt) == cnt) |
|
1054 byte_count += cnt; |
|
1055 |
|
1056 transflag = 0; |
|
1057 (void)free(buf); |
|
1058 if (cnt != 0) { |
|
1059 if (cnt < 0) |
|
1060 goto file_err; |
|
1061 goto data_err; |
|
1062 } |
|
1063 reply(226, "Transfer complete."); |
|
1064 return; |
|
1065 default: |
|
1066 transflag = 0; |
|
1067 reply(550, "Unimplemented TYPE %d in send_data", type); |
|
1068 return; |
|
1069 } |
|
1070 |
|
1071 data_err: |
|
1072 transflag = 0; |
|
1073 perror_reply(426, "Data connection"); |
|
1074 return; |
|
1075 |
|
1076 file_err: |
|
1077 transflag = 0; |
|
1078 perror_reply(551, "Error on input file"); |
|
1079 } |
|
1080 |
|
1081 /* |
|
1082 * Transfer data from peer to "outstr" using the appropriate encapulation of |
|
1083 * the data subject to Mode, Structure, and Type. |
|
1084 * |
|
1085 * N.B.: Form isn't handled. |
|
1086 */ |
|
1087 static int receive_data(FILE *instr, FILE *outstr) |
|
1088 { |
|
1089 int c; |
|
1090 int cnt; |
|
1091 volatile int bare_lfs = 0; |
|
1092 char buf[BUFSIZ]; |
|
1093 |
|
1094 transflag++; |
|
1095 if (setjmp(urgcatch)) { |
|
1096 transflag = 0; |
|
1097 return (-1); |
|
1098 } |
|
1099 switch (type) { |
|
1100 |
|
1101 case TYPE_I: |
|
1102 case TYPE_L: |
|
1103 |
|
1104 do { |
|
1105 cnt = read(fileno(instr), buf, sizeof(buf)); |
|
1106 |
|
1107 if (cnt > 0) { |
|
1108 if (write(fileno(outstr), buf, cnt) != cnt) |
|
1109 goto file_err; |
|
1110 byte_count += cnt; |
|
1111 } |
|
1112 } while (cnt > 0); |
|
1113 transflag = 0; |
|
1114 return (0); |
|
1115 |
|
1116 case TYPE_E: |
|
1117 reply(553, "TYPE E not implemented."); |
|
1118 transflag = 0; |
|
1119 return (-1); |
|
1120 |
|
1121 case TYPE_A: |
|
1122 while ((c = getc(instr)) != EOF) { |
|
1123 byte_count++; |
|
1124 (void) putc(c, outstr); |
|
1125 } |
|
1126 fflush(outstr); |
|
1127 if (ferror(outstr)) |
|
1128 goto file_err; |
|
1129 transflag = 0; |
|
1130 if (bare_lfs) { |
|
1131 lreply(226, |
|
1132 "WARNING! %d bare linefeeds received in ASCII mode", |
|
1133 bare_lfs); |
|
1134 (void)printf(" File may not have transferred correctly.\r\n"); |
|
1135 } |
|
1136 return (0); |
|
1137 default: |
|
1138 reply(550, "Unimplemented TYPE %d in receive_data", type); |
|
1139 transflag = 0; |
|
1140 return (-1); |
|
1141 } |
|
1142 |
|
1143 file_err: |
|
1144 transflag = 0; |
|
1145 perror_reply(452, "Error writing file"); |
|
1146 return (-1); |
|
1147 } |
|
1148 |
|
1149 void statfilecmd(char *filename) |
|
1150 { |
|
1151 FILE *fin; |
|
1152 int c; |
|
1153 char line[LINE_MAX]; |
|
1154 |
|
1155 char adaptedName[MAXPATHLEN]; |
|
1156 internalName(adaptedName,filename); |
|
1157 |
|
1158 (void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename); |
|
1159 fin = ftpd_popen(line, "r"); |
|
1160 |
|
1161 lreply(211, "status of %s:", filename); |
|
1162 while ((c = getc(fin)) != EOF) { |
|
1163 if (c == '\n') { |
|
1164 if (ferror(stdout)){ |
|
1165 perror_reply(421, "control connection"); |
|
1166 (void) ftpd_pclose(fin); |
|
1167 dologout(1); |
|
1168 /* NOTREACHED */ |
|
1169 } |
|
1170 if (ferror(fin)) { |
|
1171 perror_reply(551, filename); |
|
1172 (void) ftpd_pclose(fin); |
|
1173 return; |
|
1174 } |
|
1175 (void) putc('\r', stdout); |
|
1176 } |
|
1177 (void) putc(c, stdout); |
|
1178 } |
|
1179 (void) ftpd_pclose(fin); |
|
1180 |
|
1181 |
|
1182 reply(211, "End of Status"); |
|
1183 } |
|
1184 |
|
1185 void statcmd(void) |
|
1186 { |
|
1187 struct sockaddr_in *sn; |
|
1188 u_char *a, *p; |
|
1189 |
|
1190 lreply(211, "%s FTP server status:", hostname, version); |
|
1191 printf(" %s\r\n", version); |
|
1192 printf(" Connected to %s", remotehost); |
|
1193 if (!isdigit(remotehost[0])) |
|
1194 printf(" (%s)", inet_ntoa(server_in_addr)); |
|
1195 printf("\r\n"); |
|
1196 if (logged_in) { |
|
1197 if (guest) |
|
1198 printf(" Logged in anonymously\r\n"); |
|
1199 else |
|
1200 printf(" Logged in as %s\r\n", pw->pw_name); |
|
1201 } else if (askpasswd) |
|
1202 printf(" Waiting for password\r\n"); |
|
1203 else |
|
1204 printf(" Waiting for user name\r\n"); |
|
1205 printf(" TYPE: %s", typenames[type]); |
|
1206 if (type == TYPE_A || type == TYPE_E) |
|
1207 printf(", FORM: %s", formnames[form]); |
|
1208 if (type == TYPE_L) |
|
1209 #if CHAR_BIT == 8 |
|
1210 printf(" %d", CHAR_BIT); |
|
1211 #else |
|
1212 printf(" %d", bytesize); /* need definition! */ |
|
1213 #endif |
|
1214 printf("; STRUcture: %s; transfer MODE: %s\r\n", |
|
1215 strunames[stru], modenames[mode]); |
|
1216 if (data != -1) |
|
1217 printf(" Data connection open\r\n"); |
|
1218 else if (pdata != -1) { |
|
1219 printf(" in Passive mode"); |
|
1220 sn = &pasv_addr; |
|
1221 goto printaddr; |
|
1222 } else if (usedefault == 0) { |
|
1223 printf(" PORT"); |
|
1224 sn = &data_dest; |
|
1225 printaddr: |
|
1226 a = (u_char *) &sn->sin_addr; |
|
1227 p = (u_char *) &sn->sin_port; |
|
1228 #define UC(b) (((int) b) & 0xff) |
|
1229 printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]), |
|
1230 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); |
|
1231 #undef UC |
|
1232 } else |
|
1233 printf(" No data connection\r\n"); |
|
1234 |
|
1235 |
|
1236 printf(" System Drive: %c\r\n",'A'+drive); |
|
1237 |
|
1238 reply(211, "End of status"); |
|
1239 } |
|
1240 |
|
1241 void fatal(const char *s) |
|
1242 { |
|
1243 |
|
1244 reply(451, "Error in server: %s\n", s); |
|
1245 reply(221, "Closing connection due to server error."); |
|
1246 dologout(0); |
|
1247 /* NOTREACHED */ |
|
1248 } |
|
1249 |
|
1250 void |
|
1251 #ifdef __STDC__ |
|
1252 reply(int n, const char *fmt, ...) |
|
1253 #else |
|
1254 reply(int n, char *fmt, va_dcl va_alist) |
|
1255 #endif |
|
1256 { |
|
1257 va_list ap; |
|
1258 #ifdef __STDC__ |
|
1259 va_start(ap, fmt); |
|
1260 #else |
|
1261 va_start(ap); |
|
1262 #endif |
|
1263 (void)printf("%d ", n); |
|
1264 (void)vprintf(fmt, ap); |
|
1265 (void)printf("\r\n"); |
|
1266 (void)fflush(stdout); |
|
1267 } |
|
1268 |
|
1269 void |
|
1270 #ifdef __STDC__ |
|
1271 lreply(int n, const char *fmt, ...) |
|
1272 #else |
|
1273 lreply(n, fmt, va_alist) |
|
1274 int n; |
|
1275 char *fmt; |
|
1276 va_dcl |
|
1277 #endif |
|
1278 { |
|
1279 va_list ap; |
|
1280 #ifdef __STDC__ |
|
1281 va_start(ap, fmt); |
|
1282 #else |
|
1283 va_start(ap); |
|
1284 #endif |
|
1285 (void)printf("%d- ", n); |
|
1286 (void)vprintf(fmt, ap); |
|
1287 (void)printf("\r\n"); |
|
1288 (void)fflush(stdout); |
|
1289 } |
|
1290 |
|
1291 static void ack(const char *s) |
|
1292 { |
|
1293 |
|
1294 reply(250, "%s command successful.", s); |
|
1295 } |
|
1296 |
|
1297 void nack(const char *s) |
|
1298 { |
|
1299 |
|
1300 reply(502, "%s command not implemented.", s); |
|
1301 } |
|
1302 |
|
1303 /* ARGSUSED */ |
|
1304 |
|
1305 void yyerror(char *s) |
|
1306 { |
|
1307 char *cp; |
|
1308 |
|
1309 (void)s; /* ignore argument */ |
|
1310 |
|
1311 if ((cp = strchr(cbuf,'\n'))!=NULL) |
|
1312 *cp = '\0'; |
|
1313 reply(500, "'%s': command not understood.", cbuf); |
|
1314 } |
|
1315 |
|
1316 void dele(char *name) |
|
1317 { |
|
1318 struct stat st; |
|
1319 |
|
1320 char internalPath[MAXPATHLEN]; |
|
1321 internalName(internalPath,name); |
|
1322 |
|
1323 LOGCMD("delete", name); |
|
1324 if (stat(internalPath, &st) < 0) { |
|
1325 perror_reply(550, name); |
|
1326 return; |
|
1327 } |
|
1328 if ((st.st_mode&S_IFMT) == S_IFDIR) { |
|
1329 if (rmdir(internalPath) < 0) { |
|
1330 perror_reply(550, name); |
|
1331 return; |
|
1332 } |
|
1333 goto done; |
|
1334 } |
|
1335 if (unlink(internalPath) < 0) { |
|
1336 perror_reply(550, name); |
|
1337 return; |
|
1338 } |
|
1339 done: |
|
1340 ack("DELE"); |
|
1341 } |
|
1342 |
|
1343 void cwd(const char *path) |
|
1344 { |
|
1345 FILE *message; |
|
1346 |
|
1347 LOGCMD("cwd", path); |
|
1348 |
|
1349 char internalPath[MAXPATHLEN]; |
|
1350 |
|
1351 char cwd_path[MAXPATHLEN]; |
|
1352 getcwd(cwd_path, sizeof cwd_path); |
|
1353 |
|
1354 |
|
1355 if( (strlen(path)==1 && path[0]=='/') || (strlen(cwd_path)==2 && strcmp(path,"..")==0)) |
|
1356 { |
|
1357 root=1; |
|
1358 ack("CWD"); |
|
1359 } |
|
1360 else |
|
1361 { |
|
1362 |
|
1363 internalName(internalPath, path); |
|
1364 |
|
1365 if (chdir(internalPath) < 0) |
|
1366 perror_reply(550, path); |
|
1367 else { |
|
1368 |
|
1369 if ((message = fopen(_PATH_CWDMESG, "r")) != NULL) { |
|
1370 char *cp, line[LINE_MAX]; |
|
1371 |
|
1372 while (fgets(line, sizeof(line), message) != NULL) { |
|
1373 if ((cp = strchr(line, '\n')) != NULL) |
|
1374 *cp = '\0'; |
|
1375 lreply(250, "%s", line); |
|
1376 } |
|
1377 (void) fflush(stdout); |
|
1378 (void) fclose(message); |
|
1379 } |
|
1380 root = 0; |
|
1381 ack("CWD"); |
|
1382 } |
|
1383 } |
|
1384 } |
|
1385 |
|
1386 void replydirname(const char *name, const char *message) |
|
1387 { |
|
1388 char npath[MAXPATHLEN]; |
|
1389 int i; |
|
1390 |
|
1391 for (i = 0; *name != '\0' && i < (int)sizeof(npath) - 1; i++, name++) { |
|
1392 npath[i] = *name; |
|
1393 if (*name == '"') |
|
1394 npath[++i] = '"'; |
|
1395 } |
|
1396 npath[i] = '\0'; |
|
1397 reply(257, "\"%s\" %s", npath, message); |
|
1398 } |
|
1399 |
|
1400 void makedir(char *name) |
|
1401 { |
|
1402 |
|
1403 LOGCMD("mkdir", name); |
|
1404 |
|
1405 char path[MAXPATHLEN]; |
|
1406 |
|
1407 internalName(path, name); |
|
1408 |
|
1409 if (mkdir(path, 0777) < 0) |
|
1410 perror_reply(550, name); |
|
1411 else |
|
1412 replydirname(name, "directory created."); |
|
1413 } |
|
1414 |
|
1415 void removedir(char *name) |
|
1416 { |
|
1417 |
|
1418 char path[MAXPATHLEN]; |
|
1419 |
|
1420 internalName(path, name); |
|
1421 |
|
1422 LOGCMD("rmdir", name); |
|
1423 if (rmdir(path) < 0) |
|
1424 perror_reply(550, name); |
|
1425 else |
|
1426 ack("RMD"); |
|
1427 } |
|
1428 void pwd(void) |
|
1429 { |
|
1430 char path[MAXPATHLEN]; |
|
1431 |
|
1432 if(root) |
|
1433 { |
|
1434 replydirname("/", "is current directory."); |
|
1435 } |
|
1436 else |
|
1437 if (getcwd(path, sizeof path) == (char *)NULL) |
|
1438 { |
|
1439 externalName(path, path); |
|
1440 reply(550, "%s.", path); |
|
1441 } |
|
1442 else |
|
1443 { |
|
1444 externalName(path, path); |
|
1445 replydirname(path, "is current directory."); |
|
1446 } |
|
1447 } |
|
1448 |
|
1449 char * renamefrom(char *name) |
|
1450 { |
|
1451 struct stat st; |
|
1452 |
|
1453 char internal[MAXPATHLEN]; |
|
1454 |
|
1455 internalName(internal,name); |
|
1456 |
|
1457 if (stat(internal, &st) < 0) { |
|
1458 perror_reply(550, name); |
|
1459 return ((char *)0); |
|
1460 } |
|
1461 reply(350, "File exists, ready for destination name"); |
|
1462 return (name); |
|
1463 } |
|
1464 |
|
1465 void renamecmd(char *from, char *to) |
|
1466 { |
|
1467 |
|
1468 char internalFrom[MAXPATHLEN]; |
|
1469 char internalTo[MAXPATHLEN]; |
|
1470 |
|
1471 internalName(internalFrom,from); |
|
1472 internalName(internalTo,to); |
|
1473 |
|
1474 LOGCMD2("rename", from, to); |
|
1475 if (rename(internalFrom, internalTo) < 0) |
|
1476 perror_reply(550, "rename"); |
|
1477 else |
|
1478 ack("RNTO"); |
|
1479 } |
|
1480 |
|
1481 static void dolog(struct sockaddr_in *sn) |
|
1482 { |
|
1483 struct hostent *hp = gethostbyaddr((char *)&sn->sin_addr, |
|
1484 sizeof(struct in_addr), AF_INET); |
|
1485 |
|
1486 if (hp) |
|
1487 (void) strncpy(remotehost, hp->h_name, sizeof(remotehost)-1); |
|
1488 else |
|
1489 (void) strncpy(remotehost, inet_ntoa(sn->sin_addr), |
|
1490 sizeof(remotehost)-1); |
|
1491 remotehost[sizeof(remotehost)-1] = '\0'; |
|
1492 } |
|
1493 |
|
1494 /* |
|
1495 * Record logout in wtmp file |
|
1496 * and exit with supplied status. |
|
1497 */ |
|
1498 void dologout(int status) |
|
1499 { |
|
1500 transflag = 0; |
|
1501 |
|
1502 if(logging) |
|
1503 { |
|
1504 fclose(logFile); |
|
1505 } |
|
1506 |
|
1507 if (logged_in) { |
|
1508 (void) seteuid((uid_t)0); |
|
1509 if (doutmp) |
|
1510 logout(utmp.ut_line); |
|
1511 } |
|
1512 /* beware of flushing buffers after a SIGPIPE */ |
|
1513 _exit(status); |
|
1514 } |
|
1515 |
|
1516 /* |
|
1517 * Note: a response of 425 is not mentioned as a possible response to |
|
1518 * the PASV command in RFC959. However, it has been blessed as |
|
1519 * a legitimate response by Jon Postel in a telephone conversation |
|
1520 * with Rick Adams on 25 Jan 89. |
|
1521 */ |
|
1522 void passive(void) |
|
1523 { |
|
1524 socklen_t len; |
|
1525 #ifdef IP_PORTRANGE |
|
1526 int on; |
|
1527 #else |
|
1528 u_short port; |
|
1529 #endif |
|
1530 char *p, *a; |
|
1531 |
|
1532 if (pw == NULL) { |
|
1533 reply(530, "Please login with USER and PASS"); |
|
1534 return; |
|
1535 } |
|
1536 if (pdata >= 0) |
|
1537 close(pdata); |
|
1538 pdata = socket(AF_INET, SOCK_STREAM, 0); |
|
1539 if (pdata < 0) { |
|
1540 perror_reply(425, "Can't open passive connection"); |
|
1541 return; |
|
1542 } |
|
1543 |
|
1544 #ifdef IP_PORTRANGE |
|
1545 on = high_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT; |
|
1546 if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE, |
|
1547 (char *)&on, sizeof(on)) < 0) |
|
1548 goto pasv_error; |
|
1549 #else |
|
1550 #define FTP_DATA_BOTTOM 40000 |
|
1551 #define FTP_DATA_TOP 44999 |
|
1552 if (high_data_ports) { |
|
1553 for (port = FTP_DATA_BOTTOM; port <= FTP_DATA_TOP; port++) { |
|
1554 pasv_addr = ctrl_addr; |
|
1555 pasv_addr.sin_port = htons(port); |
|
1556 if (bind(pdata, (struct sockaddr *) &pasv_addr, |
|
1557 sizeof(pasv_addr)) == 0) |
|
1558 break; |
|
1559 if (errno != EADDRINUSE) |
|
1560 goto pasv_error; |
|
1561 } |
|
1562 if (port > FTP_DATA_TOP) |
|
1563 goto pasv_error; |
|
1564 } |
|
1565 else |
|
1566 #endif |
|
1567 { |
|
1568 pasv_addr = ctrl_addr; |
|
1569 pasv_addr.sin_port = 0; |
|
1570 if (bind(pdata, (struct sockaddr *)&pasv_addr, |
|
1571 sizeof(pasv_addr)) < 0) |
|
1572 goto pasv_error; |
|
1573 } |
|
1574 |
|
1575 len = sizeof(pasv_addr); |
|
1576 if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0) |
|
1577 goto pasv_error; |
|
1578 if (listen(pdata, 1) < 0) |
|
1579 goto pasv_error; |
|
1580 |
|
1581 in_addr addr = getServerAddress(); |
|
1582 |
|
1583 a = (char *) &addr; |
|
1584 p = (char *) &pasv_addr.sin_port; |
|
1585 |
|
1586 #define UC(b) (((int) b) & 0xff) |
|
1587 |
|
1588 reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]), |
|
1589 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); |
|
1590 return; |
|
1591 |
|
1592 pasv_error: |
|
1593 (void) close(pdata); |
|
1594 pdata = -1; |
|
1595 perror_reply(425, "Can't open passive connection"); |
|
1596 return; |
|
1597 } |
|
1598 |
|
1599 /* |
|
1600 * Generate unique name for file with basename "local". |
|
1601 * The file named "local" is already known to exist. |
|
1602 * Generates failure reply on error. |
|
1603 */ |
|
1604 static int guniquefd(const char *local, char **nam) |
|
1605 { |
|
1606 static char newch[MAXPATHLEN]; |
|
1607 struct stat st; |
|
1608 int count, len, fd; |
|
1609 char *cp; |
|
1610 |
|
1611 cp = strrchr(local, '/'); |
|
1612 if (cp) |
|
1613 *cp = '\0'; |
|
1614 if (stat(cp ? local : ".", &st) < 0) { |
|
1615 perror_reply(553, cp ? local : "."); |
|
1616 return (-1); |
|
1617 } |
|
1618 if (cp) |
|
1619 *cp = '/'; |
|
1620 (void) strncpy(newch, local, sizeof(newch)-1); |
|
1621 newch[sizeof(newch)-1] = '\0'; |
|
1622 len = strlen(newch); |
|
1623 if (len+2+1 >= (int)sizeof(newch)-1) |
|
1624 return (-1); |
|
1625 cp = newch + len; |
|
1626 *cp++ = '.'; |
|
1627 for (count = 1; count < 100; count++) { |
|
1628 (void)snprintf(cp, sizeof(newch) - (cp - newch), "%d", count); |
|
1629 fd = open(newch, O_RDWR|O_CREAT|O_EXCL, 0666); |
|
1630 if (fd == -1) |
|
1631 continue; |
|
1632 if (nam) |
|
1633 *nam = newch; |
|
1634 return (fd); |
|
1635 } |
|
1636 reply(452, "Unique file name cannot be created."); |
|
1637 return (-1); |
|
1638 } |
|
1639 |
|
1640 /* |
|
1641 * Format and send reply containing system error number. |
|
1642 */ |
|
1643 void perror_reply(int code, const char *string) |
|
1644 { |
|
1645 |
|
1646 reply(code, "%s: %s.", string, strerror(errno)); |
|
1647 } |
|
1648 |
|
1649 static const char *onefile[] = { |
|
1650 "", |
|
1651 0 |
|
1652 }; |
|
1653 |
|
1654 |
|
1655 void send_file_list(const char *whichf, int simple) |
|
1656 { |
|
1657 struct stat st; |
|
1658 DIR *dirp = NULL; |
|
1659 struct dirent *dir; |
|
1660 FILE *volatile dout = NULL; |
|
1661 char const *const *volatile dirlist; |
|
1662 const char *dirname; |
|
1663 //volatile int simple = 0; |
|
1664 volatile int freeglob = 0; |
|
1665 glob_t gl; |
|
1666 char time[26]; |
|
1667 |
|
1668 char internal_whichf[MAXPATHLEN]; |
|
1669 |
|
1670 //remove modifier for hidden files "-a" |
|
1671 if(whichf[0]=='-' && whichf[1]=='a') |
|
1672 { |
|
1673 strcpy(internal_whichf,whichf+2); |
|
1674 |
|
1675 //if target location is empty, set "." |
|
1676 if(internal_whichf[0]==0) |
|
1677 strcpy(internal_whichf,"."); |
|
1678 |
|
1679 internalName(internal_whichf,internal_whichf); |
|
1680 } |
|
1681 else |
|
1682 { |
|
1683 internalName(internal_whichf,whichf); |
|
1684 } |
|
1685 |
|
1686 |
|
1687 LOGCMD("send_file_list",internal_whichf); |
|
1688 |
|
1689 /* XXX: should the { go away if __linux__? */ |
|
1690 |
|
1691 if((root && strcmp(internal_whichf, ".")==0) || strcmp(internal_whichf, "/")==0 ) |
|
1692 { |
|
1693 if (dout == NULL) { |
|
1694 dout = dataconn("file list", (off_t)-1, |
|
1695 "w"); |
|
1696 if (dout == NULL) |
|
1697 goto out; |
|
1698 transflag++; |
|
1699 } |
|
1700 |
|
1701 //get the drives list |
|
1702 RFs fileSystem; |
|
1703 fileSystem.Connect(); |
|
1704 |
|
1705 TDriveList driveList; |
|
1706 fileSystem.DriveList(driveList); |
|
1707 |
|
1708 |
|
1709 if (simple) |
|
1710 { |
|
1711 for(int i=0; i<driveList.Length(); i++) |
|
1712 { |
|
1713 if(driveList[i]!=0) |
|
1714 { |
|
1715 fprintf(dout,"%c%s\n", 'A'+i ,type == TYPE_A ? "\r" : ""); |
|
1716 } |
|
1717 } |
|
1718 } |
|
1719 else |
|
1720 { |
|
1721 |
|
1722 for(int i=0; i<driveList.Length(); i++) |
|
1723 { |
|
1724 if(driveList[i]!=0) |
|
1725 { |
|
1726 fprintf(dout,"drw------- 1 ftp ftp 0 Jan 01 2008 %c%s\n", 'A'+i ,type == TYPE_A ? "\r" : ""); |
|
1727 } |
|
1728 } |
|
1729 } |
|
1730 |
|
1731 fileSystem.Close(); |
|
1732 |
|
1733 } |
|
1734 else |
|
1735 { |
|
1736 |
|
1737 if (strpbrk(whichf, "~{[*?") != NULL) { |
|
1738 #ifdef __linux__ |
|
1739 /* see popen.c */ |
|
1740 int flags = GLOB_NOCHECK; |
|
1741 #else |
|
1742 int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE; |
|
1743 #endif |
|
1744 |
|
1745 memset(&gl, 0, sizeof(gl)); |
|
1746 freeglob = 1; |
|
1747 if (glob(internal_whichf, flags, 0, &gl)) { |
|
1748 reply(550, "not found"); |
|
1749 goto out; |
|
1750 } else if (gl.gl_pathc == 0) { |
|
1751 errno = ENOENT; |
|
1752 perror_reply(550, whichf); |
|
1753 goto out; |
|
1754 } |
|
1755 /* The cast is necessary because of bugs in C's type system */ |
|
1756 dirlist = (char const *const *) gl.gl_pathv; |
|
1757 } else { |
|
1758 onefile[0] = internal_whichf; |
|
1759 dirlist = onefile; |
|
1760 } |
|
1761 |
|
1762 if (setjmp(urgcatch)) { |
|
1763 transflag = 0; |
|
1764 goto out; |
|
1765 } |
|
1766 |
|
1767 while ((dirname = *dirlist++)!=NULL) { |
|
1768 if (stat(dirname, &st) < 0) { |
|
1769 perror_reply(550, whichf); |
|
1770 if (dout != NULL) { |
|
1771 (void) fclose(dout); |
|
1772 transflag = 0; |
|
1773 data = -1; |
|
1774 pdata = -1; |
|
1775 } |
|
1776 goto out; |
|
1777 } |
|
1778 |
|
1779 if (S_ISREG(st.st_mode)) { |
|
1780 if (dout == NULL) { |
|
1781 dout = dataconn("file list", (off_t)-1, "w"); |
|
1782 if (dout == NULL) |
|
1783 goto out; |
|
1784 transflag++; |
|
1785 } |
|
1786 } else if (!S_ISDIR(st.st_mode)) |
|
1787 continue; |
|
1788 |
|
1789 if ((dirp = opendir(dirname)) == NULL) |
|
1790 continue; |
|
1791 |
|
1792 while ((dir = readdir(dirp)) != NULL) { |
|
1793 char nbuf[MAXPATHLEN]; |
|
1794 |
|
1795 if (dir->d_name[0] == '.' && dir->d_namlen == 1) |
|
1796 continue; |
|
1797 if (dir->d_name[0] == '.' && dir->d_name[1] == '.' && |
|
1798 dir->d_namlen == 2) |
|
1799 continue; |
|
1800 |
|
1801 snprintf(nbuf, sizeof(nbuf), "%s/%s", dirname, |
|
1802 dir->d_name); |
|
1803 |
|
1804 /* |
|
1805 * We have to do a stat to insure it's |
|
1806 * not a directory or special file. |
|
1807 */ |
|
1808 stat(nbuf, &st); |
|
1809 |
|
1810 if (simple){ |
|
1811 if (dout == NULL) { |
|
1812 dout = dataconn("file list", (off_t)-1, |
|
1813 "w"); |
|
1814 if (dout == NULL) |
|
1815 goto out; |
|
1816 transflag++; |
|
1817 } |
|
1818 |
|
1819 fprintf(dout, "%s%s\n", dir->d_name, type == TYPE_A ? "\r" : ""); |
|
1820 |
|
1821 byte_count += strlen(nbuf) + 1; |
|
1822 } |
|
1823 else //!simple |
|
1824 { |
|
1825 |
|
1826 if (dout == NULL) { |
|
1827 dout = dataconn("file list", (off_t)-1, |
|
1828 "w"); |
|
1829 if (dout == NULL) |
|
1830 goto out; |
|
1831 transflag++; |
|
1832 } |
|
1833 |
|
1834 ctime_r(&st.st_atime,time); |
|
1835 //"Mon Dec 10 17:35:44 2007" |
|
1836 |
|
1837 char month[4]; |
|
1838 month[0] = time[4]; //'D' |
|
1839 month[1] = time[5]; //'e' |
|
1840 month[2] = time[6]; //'c' |
|
1841 month[3] = '\0'; |
|
1842 |
|
1843 char day[3]; |
|
1844 day[0] = time[8]; //'1' |
|
1845 day[1] = time[9]; //'0' |
|
1846 day[2] = '\0'; |
|
1847 |
|
1848 char year[5]; |
|
1849 year[0] = time[20]; //'2' |
|
1850 year[1] = time[21]; //'0' |
|
1851 year[2] = time[22]; //'0' |
|
1852 year[3] = time[23]; //'7' |
|
1853 year[4] = '\0'; |
|
1854 |
|
1855 |
|
1856 fprintf(dout, "%c%c%c%c%c%c%c%c%c%c 1 ftp ftp %9jd %s %s %s %s%s\n", |
|
1857 S_ISDIR(st.st_mode) ? 'd' : '-', |
|
1858 st.st_mode & S_IRUSR ? 'r' : '-', |
|
1859 st.st_mode & S_IWUSR ? 'w' : '-', |
|
1860 st.st_mode & S_IXUSR ? 'x' : '-', |
|
1861 st.st_mode & S_IRGRP ? 'r' : '-', |
|
1862 st.st_mode & S_IWGRP ? 'w' : '-', |
|
1863 st.st_mode & S_IXGRP ? 'x' : '-', |
|
1864 st.st_mode & S_IROTH ? 'r' : '-', |
|
1865 st.st_mode & S_IWOTH ? 'w' : '-', |
|
1866 st.st_mode & S_IXOTH ? 'x' : '-', |
|
1867 st.st_size, |
|
1868 month, |
|
1869 day, |
|
1870 year, |
|
1871 dir->d_name, |
|
1872 type == TYPE_A ? "\r" : "" |
|
1873 ); |
|
1874 |
|
1875 } |
|
1876 } |
|
1877 (void) closedir(dirp); |
|
1878 } |
|
1879 } |
|
1880 if (dout == NULL) |
|
1881 reply(550, "No files found."); |
|
1882 else if (ferror(dout) != 0) |
|
1883 perror_reply(550, "Data connection"); |
|
1884 else |
|
1885 reply(226, "Transfer complete."); |
|
1886 |
|
1887 transflag = 0; |
|
1888 if (dout != NULL) |
|
1889 (void) fclose(dout); |
|
1890 data = -1; |
|
1891 pdata = -1; |
|
1892 out: |
|
1893 if (freeglob) { |
|
1894 freeglob = 0; |
|
1895 globfree(&gl); |
|
1896 } |
|
1897 } |
|
1898 |
|
1899 void logxfer(const char *name, off_t size, time_t start) |
|
1900 { |
|
1901 char buf[400 + MAXHOSTNAMELEN*4 + MAXPATHLEN*4]; |
|
1902 char dir[MAXPATHLEN], path[MAXPATHLEN], rpath[MAXPATHLEN]; |
|
1903 char vremotehost[MAXHOSTNAMELEN*4], vpath[MAXPATHLEN*4]; |
|
1904 char *vpw; |
|
1905 time_t now; |
|
1906 |
|
1907 if ((statfd >= 0) && (getcwd(dir, sizeof(dir)) != NULL)) { |
|
1908 time(&now); |
|
1909 |
|
1910 vpw = (char *)malloc(strlen((guest) ? guestpw : pw->pw_name)*4+1); |
|
1911 if (vpw == NULL) |
|
1912 return; |
|
1913 |
|
1914 snprintf(path, sizeof path, "%s/%s", dir, name); |
|
1915 if (realpath(path, rpath) == NULL) { |
|
1916 strncpy(rpath, path, sizeof rpath-1); |
|
1917 rpath[sizeof rpath-1] = '\0'; |
|
1918 } |
|
1919 |
|
1920 snprintf(buf, sizeof(buf), |
|
1921 "%.24s %ld %s %qd %s %c %s %c %c %s ftp %d %s %s\n", |
|
1922 ctime(&now), (long)(now - start + (now == start)), |
|
1923 vremotehost, (long long) size, vpath, |
|
1924 ((type == TYPE_A) ? 'a' : 'b'), "*" /* none yet */, |
|
1925 'o', ((guest) ? 'a' : 'r'), |
|
1926 vpw, 0 /* none yet */, |
|
1927 ((guest) ? "*" : pw->pw_name), |
|
1928 dhostname); |
|
1929 write(statfd, buf, strlen(buf)); |
|
1930 free(vpw); |
|
1931 } |
|
1932 } |
|
1933 |
|
1934 TDriveNumber getSystemDrive() |
|
1935 { |
|
1936 _LIT(KFileSrvDll, "efsrv.dll"); |
|
1937 |
|
1938 TDriveNumber defaultSysDrive(EDriveC); |
|
1939 RLibrary pluginLibrary; |
|
1940 TInt pluginErr = pluginLibrary.Load(KFileSrvDll); |
|
1941 |
|
1942 if (pluginErr == KErrNone) |
|
1943 { |
|
1944 typedef TDriveNumber(*fun1)(); |
|
1945 fun1 sysdrive; |
|
1946 |
|
1947 #ifdef __EABI__ |
|
1948 sysdrive = (fun1)pluginLibrary.Lookup(336); |
|
1949 #else |
|
1950 sysdrive = (fun1)pluginLibrary.Lookup(304); |
|
1951 #endif |
|
1952 |
|
1953 if(sysdrive!=NULL) |
|
1954 { |
|
1955 defaultSysDrive = sysdrive(); |
|
1956 } |
|
1957 } |
|
1958 pluginLibrary.Close(); |
|
1959 return defaultSysDrive; |
|
1960 } |
|
1961 |
|
1962 in_addr getServerAddress() |
|
1963 { |
|
1964 |
|
1965 in_addr address; |
|
1966 |
|
1967 //default adddress to be returned if failure |
|
1968 inet_aton("0.0.0.0", &address); |
|
1969 |
|
1970 RSocketServ rSockServer; |
|
1971 if(KErrNone==rSockServer.Connect()) |
|
1972 { |
|
1973 RConnection rConnect; |
|
1974 if(KErrNone==rConnect.Open(rSockServer)) |
|
1975 { |
|
1976 TRequestStatus status; |
|
1977 rConnect.Start(status); |
|
1978 |
|
1979 User::WaitForRequest(status); |
|
1980 } |
|
1981 } |
|
1982 |
|
1983 TAutoClose<RSocketServ> ss; |
|
1984 User::LeaveIfError(ss.iObj.Connect()); |
|
1985 ss.PushL(); |
|
1986 |
|
1987 TAutoClose<RSocket> sock; |
|
1988 User::LeaveIfError(sock.iObj.Open(ss.iObj, _L("udp"))); |
|
1989 sock.PushL(); |
|
1990 |
|
1991 User::LeaveIfError(sock.iObj.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl)); |
|
1992 |
|
1993 TProtocolDesc in; |
|
1994 User::LeaveIfError(sock.iObj.Info(in)); |
|
1995 TPckgBuf<TSoInetInterfaceInfo> info, next; |
|
1996 |
|
1997 TInt res=sock.iObj.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, info); |
|
1998 |
|
1999 while(res==KErrNone) |
|
2000 { |
|
2001 |
|
2002 res=sock.iObj.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, next); |
|
2003 if(info().iState != EIfUp || info().iFeatures&KIfIsLoopback || info().iName.Left(4) == _L("eth6")) |
|
2004 { |
|
2005 info = next; continue; |
|
2006 } |
|
2007 |
|
2008 TName address_descriptor; |
|
2009 char address_string[16]; //xxx.xxx.xxx.xxx\0 |
|
2010 |
|
2011 info().iAddress.Output(address_descriptor); |
|
2012 |
|
2013 int i=0; |
|
2014 |
|
2015 for(i=0; i<address_descriptor.Length(); i++) |
|
2016 { |
|
2017 address_string[i]=address_descriptor[i]; |
|
2018 } |
|
2019 |
|
2020 address_string[i]='\0'; |
|
2021 |
|
2022 inet_aton(address_string, &address); |
|
2023 |
|
2024 if(res==KErrNone) |
|
2025 { |
|
2026 info = next; |
|
2027 } |
|
2028 } |
|
2029 |
|
2030 sock.Pop(); |
|
2031 ss.Pop(); |
|
2032 |
|
2033 rSockServer.Close(); |
|
2034 |
|
2035 return address; |
|
2036 } |
|
2037 |
|
2038 |
|
2039 void sizecmd(char *filename) |
|
2040 { |
|
2041 |
|
2042 char internalFilename[MAXPATHLEN]; |
|
2043 |
|
2044 internalName(internalFilename,filename); |
|
2045 |
|
2046 switch (type) { |
|
2047 case TYPE_L: |
|
2048 case TYPE_I: |
|
2049 case TYPE_A: { |
|
2050 struct stat stbuf; |
|
2051 if (stat(internalFilename, &stbuf) < 0 || !S_ISREG(stbuf.st_mode)) |
|
2052 reply(550, "%s: not a plain file.", filename); |
|
2053 else |
|
2054 reply(213, "%qu", (quad_t) stbuf.st_size); |
|
2055 break; } |
|
2056 default: |
|
2057 reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]); |
|
2058 } |
|
2059 } |
|
2060 |