1*10275Ssam #ifndef lint 2*10275Ssam static char sccsid[] = "@(#)ftpd.c 4.1 (Berkeley) 83/01/13"; 3*10275Ssam #endif 4*10275Ssam 5*10275Ssam /* 6*10275Ssam * FTP server. 7*10275Ssam */ 8*10275Ssam #include <sys/types.h> 9*10275Ssam #include <sys/stat.h> 10*10275Ssam #include <sys/ioctl.h> 11*10275Ssam #include <sys/socket.h> 12*10275Ssam 13*10275Ssam #include <netinet/in.h> 14*10275Ssam 15*10275Ssam #include <stdio.h> 16*10275Ssam #include <signal.h> 17*10275Ssam #include <wait.h> 18*10275Ssam #include <pwd.h> 19*10275Ssam #include <setjmp.h> 20*10275Ssam #include <netdb.h> 21*10275Ssam 22*10275Ssam #include "ftp.h" 23*10275Ssam 24*10275Ssam extern int errno; 25*10275Ssam extern char *sys_errlist[]; 26*10275Ssam extern char *crypt(); 27*10275Ssam extern char version[]; 28*10275Ssam extern char *home; /* pointer to home directory for glob */ 29*10275Ssam extern FILE *popen(), *fopen(); 30*10275Ssam extern int pclose(), fclose(); 31*10275Ssam 32*10275Ssam struct sockaddr_in ctrl_addr; 33*10275Ssam struct sockaddr_in data_source; 34*10275Ssam struct sockaddr_in data_dest; 35*10275Ssam struct sockaddr_in his_addr; 36*10275Ssam 37*10275Ssam struct hostent *hp; 38*10275Ssam 39*10275Ssam int data; 40*10275Ssam jmp_buf errcatch; 41*10275Ssam int logged_in; 42*10275Ssam struct passwd *pw; 43*10275Ssam int debug; 44*10275Ssam int logging = 1; 45*10275Ssam int guest; 46*10275Ssam int type; 47*10275Ssam int form; 48*10275Ssam int stru; /* avoid C keyword */ 49*10275Ssam int mode; 50*10275Ssam char hostname[32]; 51*10275Ssam char *remotehost; 52*10275Ssam 53*10275Ssam int lostconn(); 54*10275Ssam FILE *getdatasock(), *dataconn(); 55*10275Ssam char *ntoa(); 56*10275Ssam 57*10275Ssam main(argc, argv) 58*10275Ssam int argc; 59*10275Ssam char *argv[]; 60*10275Ssam { 61*10275Ssam int ctrl, s, options = 0; 62*10275Ssam struct servent *sp; 63*10275Ssam union wait status; 64*10275Ssam char *cp; 65*10275Ssam 66*10275Ssam sp = getservbyname("ftp", "tcp"); 67*10275Ssam if (sp == 0) { 68*10275Ssam fprintf(stderr, "ftpd: fpt/tcp: unknown service\n"); 69*10275Ssam exit(1); 70*10275Ssam } 71*10275Ssam ctrl_addr.sin_port = sp->s_port; 72*10275Ssam data_source.sin_port = htons(ntohs(sp->s_port) - 1); 73*10275Ssam signal(SIGPIPE, lostconn); 74*10275Ssam debug = 0; 75*10275Ssam argc--, argv++; 76*10275Ssam while (argc > 0 && *argv[0] == '-') { 77*10275Ssam for (cp = &argv[0][1]; *cp; cp++) switch (*cp) { 78*10275Ssam 79*10275Ssam case 'd': 80*10275Ssam debug = 1; 81*10275Ssam options |= SO_DEBUG; 82*10275Ssam break; 83*10275Ssam 84*10275Ssam default: 85*10275Ssam fprintf(stderr, "Unknown flag -%c ignored.\n", cp); 86*10275Ssam break; 87*10275Ssam } 88*10275Ssam argc--, argv++; 89*10275Ssam } 90*10275Ssam #ifndef DEBUG 91*10275Ssam if (fork()) 92*10275Ssam exit(0); 93*10275Ssam for (s = 0; s < 10; s++) 94*10275Ssam if (s != 2) /* don't screw stderr */ 95*10275Ssam (void) close(s); 96*10275Ssam (void) open("/dev/null", 0); 97*10275Ssam (void) dup2(0, 1); 98*10275Ssam { int tt = open("/dev/tty", 2); 99*10275Ssam if (tt > 0) { 100*10275Ssam ioctl(tt, TIOCNOTTY, 0); 101*10275Ssam close(tt); 102*10275Ssam } 103*10275Ssam } 104*10275Ssam #endif 105*10275Ssam while ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 106*10275Ssam perror("ftpd: socket"); 107*10275Ssam sleep(5); 108*10275Ssam } 109*10275Ssam while (bind(s, &ctrl_addr, sizeof (ctrl_addr), 0) < 0) { 110*10275Ssam perror("ftpd: bind"); 111*10275Ssam sleep(5); 112*10275Ssam } 113*10275Ssam for (;;) { 114*10275Ssam int hisaddrlen = sizeof (his_addr); 115*10275Ssam 116*10275Ssam ctrl = accept(s, &his_addr, &hisaddrlen, 0); 117*10275Ssam if (ctrl < 0) { 118*10275Ssam perror("ftpd: accept"); 119*10275Ssam sleep(5); 120*10275Ssam continue; 121*10275Ssam } 122*10275Ssam data_dest = his_addr; 123*10275Ssam if (fork() == 0) { 124*10275Ssam if (logging) 125*10275Ssam dolog(&his_addr); 126*10275Ssam close(s); 127*10275Ssam dup2(ctrl, 0), close(ctrl), dup2(0, 1); 128*10275Ssam /* do telnet option negotiation here */ 129*10275Ssam logged_in = 0; 130*10275Ssam data = -1; 131*10275Ssam gethostname(hostname, sizeof (hostname)); 132*10275Ssam reply(220, "%s FTP server (%s) ready.", 133*10275Ssam hostname, version); 134*10275Ssam for (;;) { 135*10275Ssam setjmp(errcatch); 136*10275Ssam yyparse(); 137*10275Ssam } 138*10275Ssam } 139*10275Ssam close(ctrl); 140*10275Ssam while (wait3(status, WNOHANG, 0) > 0) 141*10275Ssam continue; 142*10275Ssam } 143*10275Ssam } 144*10275Ssam 145*10275Ssam lostconn() 146*10275Ssam { 147*10275Ssam 148*10275Ssam fatal("Connection closed."); 149*10275Ssam } 150*10275Ssam 151*10275Ssam pass(passwd) 152*10275Ssam char *passwd; 153*10275Ssam { 154*10275Ssam char *xpasswd; 155*10275Ssam 156*10275Ssam if (logged_in || pw == NULL) { 157*10275Ssam reply(503, "Login with USER first."); 158*10275Ssam return; 159*10275Ssam } 160*10275Ssam if (!guest) { /* "ftp" is only account allowed no password */ 161*10275Ssam xpasswd = crypt(passwd, pw->pw_passwd); 162*10275Ssam if (strcmp(xpasswd, pw->pw_passwd) != 0) { 163*10275Ssam reply(530, "Login incorrect."); 164*10275Ssam pw = NULL; 165*10275Ssam return; 166*10275Ssam } 167*10275Ssam } 168*10275Ssam home = pw->pw_dir; /* home dir for globbing */ 169*10275Ssam setreuid(-1, pw->pw_uid); 170*10275Ssam setregid(-1, pw->pw_gid); 171*10275Ssam initgroups(pw->pw_name, pw->pw_gid); 172*10275Ssam if (chdir(pw->pw_dir)) { 173*10275Ssam reply(550, "User %s: can't change directory to $s.", 174*10275Ssam pw->pw_name, pw->pw_dir); 175*10275Ssam pw = NULL; 176*10275Ssam return; 177*10275Ssam } 178*10275Ssam if (guest && chroot(pw->pw_dir) < 0){ 179*10275Ssam reply(550, "Can't set guest privileges."); 180*10275Ssam pw = NULL; 181*10275Ssam return; 182*10275Ssam } 183*10275Ssam if (!guest) 184*10275Ssam reply(230, "User %s logged in.", pw->pw_name); 185*10275Ssam else 186*10275Ssam reply(230, "Guest login ok, access restrictions apply."); 187*10275Ssam logged_in = 1; 188*10275Ssam } 189*10275Ssam 190*10275Ssam retrieve(cmd, name) 191*10275Ssam char *cmd, *name; 192*10275Ssam { 193*10275Ssam FILE *fin, *dout; 194*10275Ssam struct stat st; 195*10275Ssam int (*closefunc)(); 196*10275Ssam 197*10275Ssam if (cmd == 0) { 198*10275Ssam if (*name == '!') 199*10275Ssam fin = popen(name + 1, "r"), closefunc = pclose; 200*10275Ssam else 201*10275Ssam fin = fopen(name, "r"), closefunc = fclose; 202*10275Ssam } else { 203*10275Ssam char line[BUFSIZ]; 204*10275Ssam 205*10275Ssam sprintf(line, cmd, name); 206*10275Ssam fin = popen(line, "r"), closefunc = pclose; 207*10275Ssam } 208*10275Ssam if (fin == NULL) { 209*10275Ssam reply(550, "%s: %s.", name, sys_errlist[errno]); 210*10275Ssam return; 211*10275Ssam } 212*10275Ssam st.st_size = 0; 213*10275Ssam if (cmd == 0 && 214*10275Ssam (stat(name, &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG)) { 215*10275Ssam reply(550, "%s: not a plain file.", name); 216*10275Ssam goto done; 217*10275Ssam } 218*10275Ssam dout = dataconn(name, st.st_size, "w"); 219*10275Ssam if (dout == NULL) 220*10275Ssam goto done; 221*10275Ssam if (!send_data(fin, dout) || ferror(dout)) 222*10275Ssam reply(550, "%s: %s.", name, sys_errlist[errno]); 223*10275Ssam else 224*10275Ssam reply(226, "Transfer complete."); 225*10275Ssam if (mode == MODE_S) 226*10275Ssam /* indicate EOF by closing connection */ 227*10275Ssam fclose(dout), data = -1; 228*10275Ssam done: 229*10275Ssam (*closefunc)(fin); 230*10275Ssam } 231*10275Ssam 232*10275Ssam store(name, mode) 233*10275Ssam char *name, *mode; 234*10275Ssam { 235*10275Ssam FILE *fout, *din; 236*10275Ssam int (*closefunc)(); 237*10275Ssam 238*10275Ssam if (name[0] == '!') 239*10275Ssam fout = popen(&name[1], "w"), closefunc = pclose; 240*10275Ssam else 241*10275Ssam fout = fopen(name, mode), closefunc = fclose; 242*10275Ssam if (fout == NULL) { 243*10275Ssam reply(550, "%s: %s.", name, sys_errlist[errno]); 244*10275Ssam return; 245*10275Ssam } 246*10275Ssam din = dataconn(name, -1, "r"); 247*10275Ssam if (din == NULL) 248*10275Ssam goto done; 249*10275Ssam if (!receive_data(din, fout) || ferror(fout)) 250*10275Ssam reply(550, "%s: %s.", name, sys_errlist[errno]); 251*10275Ssam else 252*10275Ssam reply(226, "Transfer complete."); 253*10275Ssam fclose(din), data = -1; 254*10275Ssam done: 255*10275Ssam (*closefunc)(fout); 256*10275Ssam } 257*10275Ssam 258*10275Ssam FILE * 259*10275Ssam getdatasock(mode) 260*10275Ssam char *mode; 261*10275Ssam { 262*10275Ssam int retrytime, s; 263*10275Ssam 264*10275Ssam if (data >= 0) 265*10275Ssam return (fdopen(data, mode)); 266*10275Ssam retrytime = 1; 267*10275Ssam while ((s = socket(AF_INET, SOCK_STREAM, 0, 0)) < 0) { 268*10275Ssam if (retrytime < 5) { 269*10275Ssam sleep(retrytime); 270*10275Ssam retrytime <<= 1; 271*10275Ssam continue; 272*10275Ssam } 273*10275Ssam return (NULL); 274*10275Ssam } 275*10275Ssam retrytime = 1; 276*10275Ssam seteuid(0); 277*10275Ssam while (bind(s, &data_source, sizeof (data_source), 0) < 0) { 278*10275Ssam if (retrytime < 5) { 279*10275Ssam sleep(retrytime); 280*10275Ssam retrytime <<= 1; 281*10275Ssam continue; 282*10275Ssam } 283*10275Ssam seteuid(0); 284*10275Ssam close(s); 285*10275Ssam return (NULL); 286*10275Ssam } 287*10275Ssam seteuid(0); 288*10275Ssam return (fdopen(s, mode)); 289*10275Ssam } 290*10275Ssam 291*10275Ssam FILE * 292*10275Ssam dataconn(name, size, mode) 293*10275Ssam char *name; 294*10275Ssam int size; 295*10275Ssam char *mode; 296*10275Ssam { 297*10275Ssam char sizebuf[32]; 298*10275Ssam FILE *file; 299*10275Ssam 300*10275Ssam if (size >= 0) 301*10275Ssam sprintf(sizebuf, " (%d bytes)", size); 302*10275Ssam else 303*10275Ssam (void) strcpy(sizebuf, ""); 304*10275Ssam if (data >= 0) { 305*10275Ssam reply(125, "Using existing data connection for %s%s.", 306*10275Ssam name, sizebuf); 307*10275Ssam return (fdopen(data, mode)); 308*10275Ssam } 309*10275Ssam reply(150, "Opening data connection for %s (%s,%d)%s.", 310*10275Ssam name, ntoa(data_dest.sin_addr.s_addr), 311*10275Ssam ntohs(data_dest.sin_port), sizebuf); 312*10275Ssam file = getdatasock(mode); 313*10275Ssam if (file == NULL) { 314*10275Ssam reply(425, "Can't create data socket (%s,%d): %s.", 315*10275Ssam ntoa(data_source.sin_addr), 316*10275Ssam ntohs(data_source.sin_port), 317*10275Ssam sys_errlist[errno]); 318*10275Ssam return (NULL); 319*10275Ssam } 320*10275Ssam data = fileno(file); 321*10275Ssam if (connect(data, &data_dest, sizeof (data_dest), 0) < 0) { 322*10275Ssam reply(425, "Can't build data connection: %s.", 323*10275Ssam sys_errlist[errno]); 324*10275Ssam (void) fclose(file); 325*10275Ssam data = -1; 326*10275Ssam return (NULL); 327*10275Ssam } 328*10275Ssam return (file); 329*10275Ssam } 330*10275Ssam 331*10275Ssam /* 332*10275Ssam * Tranfer the contents of "instr" to 333*10275Ssam * "outstr" peer using the appropriate 334*10275Ssam * encapulation of the date subject 335*10275Ssam * to Mode, Structure, and Type. 336*10275Ssam * 337*10275Ssam * NB: Form isn't handled. 338*10275Ssam */ 339*10275Ssam send_data(instr, outstr) 340*10275Ssam FILE *instr, *outstr; 341*10275Ssam { 342*10275Ssam register int c; 343*10275Ssam int netfd, filefd, cnt; 344*10275Ssam char buf[BUFSIZ]; 345*10275Ssam 346*10275Ssam switch (type) { 347*10275Ssam 348*10275Ssam case TYPE_A: 349*10275Ssam while ((c = getc(instr)) != EOF) { 350*10275Ssam if (c == '\n') 351*10275Ssam putc('\r', outstr); 352*10275Ssam if (putc(c, outstr) == EOF) 353*10275Ssam return (1); 354*10275Ssam } 355*10275Ssam return (0); 356*10275Ssam 357*10275Ssam case TYPE_I: 358*10275Ssam case TYPE_L: 359*10275Ssam netfd = fileno(outstr); 360*10275Ssam filefd = fileno(instr); 361*10275Ssam 362*10275Ssam while ((cnt = read(filefd, buf, sizeof buf)) > 0) 363*10275Ssam if (write(netfd, buf, cnt) < 0) 364*10275Ssam return (1); 365*10275Ssam return (cnt < 0); 366*10275Ssam } 367*10275Ssam reply(504,"Unimplemented TYPE %d in send_data", type); 368*10275Ssam return (1); 369*10275Ssam } 370*10275Ssam 371*10275Ssam /* 372*10275Ssam * Transfer data from peer to 373*10275Ssam * "outstr" using the appropriate 374*10275Ssam * encapulation of the data subject 375*10275Ssam * to Mode, Structure, and Type. 376*10275Ssam * 377*10275Ssam * N.B.: Form isn't handled. 378*10275Ssam */ 379*10275Ssam receive_data(instr, outstr) 380*10275Ssam FILE *instr, *outstr; 381*10275Ssam { 382*10275Ssam register int c; 383*10275Ssam int cr, escape, eof; 384*10275Ssam int netfd, filefd, cnt; 385*10275Ssam char buf[BUFSIZ]; 386*10275Ssam 387*10275Ssam 388*10275Ssam switch (type) { 389*10275Ssam 390*10275Ssam case TYPE_I: 391*10275Ssam case TYPE_L: 392*10275Ssam netfd = fileno(instr); 393*10275Ssam netfd = fileno(outstr); 394*10275Ssam while ((cnt = read(netfd, buf, sizeof buf)) > 0) 395*10275Ssam if (write(filefd, buf, cnt) < 0) 396*10275Ssam return (1); 397*10275Ssam return (cnt < 0); 398*10275Ssam 399*10275Ssam case TYPE_E: 400*10275Ssam reply(504, "TYPE E not implemented."); 401*10275Ssam return (1); 402*10275Ssam 403*10275Ssam case TYPE_A: 404*10275Ssam cr = 0; 405*10275Ssam while ((c = getc(instr)) != EOF) { 406*10275Ssam if (cr) { 407*10275Ssam if (c != '\r' && c != '\n') 408*10275Ssam putc('\r', outstr); 409*10275Ssam putc(c, outstr); 410*10275Ssam cr = c == '\r'; 411*10275Ssam continue; 412*10275Ssam } 413*10275Ssam if (c == '\r') { 414*10275Ssam cr = 1; 415*10275Ssam continue; 416*10275Ssam } 417*10275Ssam putc(c, outstr); 418*10275Ssam } 419*10275Ssam if (cr) 420*10275Ssam putc('\r', outstr); 421*10275Ssam return (0); 422*10275Ssam } 423*10275Ssam fatal("Unknown type in receive_data."); 424*10275Ssam /*NOTREACHED*/ 425*10275Ssam } 426*10275Ssam 427*10275Ssam fatal(s) 428*10275Ssam char *s; 429*10275Ssam { 430*10275Ssam reply(451, "Error in server: %s\n", s); 431*10275Ssam reply(221, "Closing connection due to server error."); 432*10275Ssam exit(0); 433*10275Ssam } 434*10275Ssam 435*10275Ssam reply(n, s, args) 436*10275Ssam int n; 437*10275Ssam char *s; 438*10275Ssam { 439*10275Ssam 440*10275Ssam printf("%d ", n); 441*10275Ssam _doprnt(s, &args, stdout); 442*10275Ssam printf("\r\n"); 443*10275Ssam fflush(stdout); 444*10275Ssam if (debug) { 445*10275Ssam fprintf(stderr, "<--- %d ", n); 446*10275Ssam _doprnt(s, &args, stderr); 447*10275Ssam fprintf(stderr, "\n"); 448*10275Ssam fflush(stderr); 449*10275Ssam } 450*10275Ssam } 451*10275Ssam 452*10275Ssam lreply(n, s, args) 453*10275Ssam int n; 454*10275Ssam char *s; 455*10275Ssam { 456*10275Ssam printf("%d-", n); 457*10275Ssam _doprnt(s, &args, stdout); 458*10275Ssam printf("\r\n"); 459*10275Ssam fflush(stdout); 460*10275Ssam if (debug) { 461*10275Ssam fprintf(stderr, "<--- %d-", n); 462*10275Ssam _doprnt(s, &args, stderr); 463*10275Ssam fprintf(stderr, "\n"); 464*10275Ssam } 465*10275Ssam } 466*10275Ssam 467*10275Ssam replystr(s) 468*10275Ssam char *s; 469*10275Ssam { 470*10275Ssam printf("%s\r\n", s); 471*10275Ssam fflush(stdout); 472*10275Ssam if (debug) 473*10275Ssam fprintf(stderr, "<--- %s\n", s); 474*10275Ssam } 475*10275Ssam 476*10275Ssam ack(s) 477*10275Ssam char *s; 478*10275Ssam { 479*10275Ssam reply(200, "%s command okay.", s); 480*10275Ssam } 481*10275Ssam 482*10275Ssam nack(s) 483*10275Ssam char *s; 484*10275Ssam { 485*10275Ssam reply(502, "%s command not implemented.", s); 486*10275Ssam } 487*10275Ssam 488*10275Ssam yyerror() 489*10275Ssam { 490*10275Ssam reply(500, "Command not understood."); 491*10275Ssam } 492*10275Ssam 493*10275Ssam delete(name) 494*10275Ssam char *name; 495*10275Ssam { 496*10275Ssam struct stat st; 497*10275Ssam 498*10275Ssam if (stat(name, &st) < 0) { 499*10275Ssam reply(550, "%s: %s.", name, sys_errlist[errno]); 500*10275Ssam return; 501*10275Ssam } 502*10275Ssam if ((st.st_mode&S_IFMT) == S_IFDIR) { 503*10275Ssam if (rmdir(name) < 0) { 504*10275Ssam reply(550, "%s: %s.", name, sys_errlist[errno]); 505*10275Ssam return; 506*10275Ssam } 507*10275Ssam goto done; 508*10275Ssam } 509*10275Ssam if (unlink(name) < 0) { 510*10275Ssam reply(550, "%s: %s.", name, sys_errlist[errno]); 511*10275Ssam return; 512*10275Ssam } 513*10275Ssam done: 514*10275Ssam ack("DELE"); 515*10275Ssam } 516*10275Ssam 517*10275Ssam cwd(path) 518*10275Ssam char *path; 519*10275Ssam { 520*10275Ssam 521*10275Ssam if (chdir(path) < 0) { 522*10275Ssam reply(550, "%s: %s.", path, sys_errlist[errno]); 523*10275Ssam return; 524*10275Ssam } 525*10275Ssam ack("CWD"); 526*10275Ssam } 527*10275Ssam 528*10275Ssam do_mkdir(name) 529*10275Ssam char *name; 530*10275Ssam { 531*10275Ssam 532*10275Ssam if (mkdir(name, 0777) < 0) { 533*10275Ssam reply(550, "%s: %s.", name, sys_errlist[errno]); 534*10275Ssam return; 535*10275Ssam } 536*10275Ssam ack("MKDIR"); 537*10275Ssam } 538*10275Ssam 539*10275Ssam do_rmdir(name) 540*10275Ssam char *name; 541*10275Ssam { 542*10275Ssam 543*10275Ssam if (rmdir(name) < 0) { 544*10275Ssam reply(550, "%s: %s.", name, sys_errlist[errno]); 545*10275Ssam return; 546*10275Ssam } 547*10275Ssam ack("RMDIR"); 548*10275Ssam } 549*10275Ssam 550*10275Ssam do_pwd() 551*10275Ssam { 552*10275Ssam char path[1024]; 553*10275Ssam char *p; 554*10275Ssam 555*10275Ssam if (getwd(path) == NULL) { 556*10275Ssam reply(451, "%s.", path); 557*10275Ssam return; 558*10275Ssam } 559*10275Ssam reply(251, "\"%s\" is current directory.", path); 560*10275Ssam } 561*10275Ssam 562*10275Ssam char * 563*10275Ssam renamefrom(name) 564*10275Ssam char *name; 565*10275Ssam { 566*10275Ssam struct stat st; 567*10275Ssam 568*10275Ssam if (stat(name, &st) < 0) { 569*10275Ssam reply(550, "%s: %s.", name, sys_errlist[errno]); 570*10275Ssam return ((char *)0); 571*10275Ssam } 572*10275Ssam ack("RNFR"); 573*10275Ssam return (name); 574*10275Ssam } 575*10275Ssam 576*10275Ssam renamecmd(from, to) 577*10275Ssam char *from, *to; 578*10275Ssam { 579*10275Ssam 580*10275Ssam if (rename(from, to) < 0) { 581*10275Ssam reply(550, "rename: %s.", sys_errlist[errno]); 582*10275Ssam return; 583*10275Ssam } 584*10275Ssam ack("RNTO"); 585*10275Ssam } 586*10275Ssam 587*10275Ssam int guest; 588*10275Ssam /* 589*10275Ssam * Test pathname for guest-user safety. 590*10275Ssam */ 591*10275Ssam inappropriate_request(name) 592*10275Ssam char *name; 593*10275Ssam { 594*10275Ssam int bogus = 0, depth = 0, length = strlen(name); 595*10275Ssam char *p, *s; 596*10275Ssam 597*10275Ssam if (!guest) 598*10275Ssam return (0); 599*10275Ssam if (name[0] == '/' || name[0] == '|') 600*10275Ssam bogus = 1; 601*10275Ssam for (p = name; p < name+length;) { 602*10275Ssam s = p; /* start of token */ 603*10275Ssam while ( *p && *p!= '/') 604*10275Ssam p++; 605*10275Ssam *p = 0; 606*10275Ssam if (strcmp(s, "..") == 0) 607*10275Ssam depth -= 1; /* backing up */ 608*10275Ssam else if (strcmp(s, ".") == 0) 609*10275Ssam depth += 0; /* no change */ 610*10275Ssam else 611*10275Ssam depth += 1; /* descending */ 612*10275Ssam if (depth < 0) { 613*10275Ssam bogus = 1; 614*10275Ssam break; 615*10275Ssam } 616*10275Ssam } 617*10275Ssam if (bogus) 618*10275Ssam reply(553, "%s: pathname disallowed guest users", name); 619*10275Ssam return (bogus); 620*10275Ssam } 621*10275Ssam 622*10275Ssam /* 623*10275Ssam * Convert network-format internet address 624*10275Ssam * to base 256 d.d.d.d representation. 625*10275Ssam */ 626*10275Ssam char * 627*10275Ssam ntoa(in) 628*10275Ssam struct in_addr in; 629*10275Ssam { 630*10275Ssam static char b[18]; 631*10275Ssam register char *p; 632*10275Ssam 633*10275Ssam in.s_addr = ntohl(in.s_addr); 634*10275Ssam p = (char *)∈ 635*10275Ssam #define UC(b) (((int)b)&0xff) 636*10275Ssam sprintf(b, "%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3])); 637*10275Ssam return (b); 638*10275Ssam } 639*10275Ssam 640*10275Ssam dolog(sin) 641*10275Ssam struct sockaddr_in *sin; 642*10275Ssam { 643*10275Ssam struct hostent *hp = gethostbyaddr(&sin->sin_addr, 644*10275Ssam sizeof (struct in_addr), AF_INET); 645*10275Ssam char *remotehost; 646*10275Ssam time_t t; 647*10275Ssam 648*10275Ssam if (hp) 649*10275Ssam remotehost = hp->h_name; 650*10275Ssam else 651*10275Ssam remotehost = "UNKNOWNHOST"; 652*10275Ssam t = time(0); 653*10275Ssam fprintf(stderr,"FTP %d: connection from %s at %s", 654*10275Ssam getpid(), remotehost, ctime(&t)); 655*10275Ssam fflush(stderr); 656*10275Ssam } 657