genericunixprotocols/ftpsrv/src/ftpd.cpp
changeset 0 c6b0df440bee
equal deleted inserted replaced
-1:000000000000 0:c6b0df440bee
       
     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