/***************************************************************************/
/***************************************************************************/
/* */
/* (c) 1995-1999. The Regents of the University of California. All */
/* rights reserved. */
/* */
/* This work was produced at the University of California, Lawrence */
/* Livermore National Laboratory (UC LLNL) under contract no. */
/* W-7405-ENG-48 (Contract 48) between the U.S. Department of Energy */
/* (DOE) and The Regents of the University of California (University) */
/* for the operation of UC LLNL. Copyright is reserved to the */
/* University for purposes of controlled dissemination, */
/* commercialization through formal licensing, or other disposition */
/* under terms of Contract 48; DOE policies, regulations and orders; */
/* and U.S. statutes. The rights of the Federal Government are */
/* reserved under Contract 48 subject to the restrictions agreed upon */
/* by the DOE and University. */
/* */
/* */
/* DISCLAIMER */
/* */
/* This software was prepared as an account of work sponsored by an */
/* agency of the United States Government. Neither the United States */
/* Government nor the University of California nor any of their */
/* employees, makes any warranty, express or implied, or assumes any */
/* liability or responsibility for the accuracy, completeness, or */
/* usefulness of any information, apparatus, product, or process */
/* disclosed, or represents that its specific commercial products, */
/* process, or service by trade name, trademark, manufacturer, or */
/* otherwise, does not necessarily constitute or imply its */
/* endorsement, recommendation, or favoring by the United States */
/* Government or the University of California. The views and opinions */
/* of the authors expressed herein do not necessarily state or reflect */
/* those of the United States Government or the University of */
/* California, and shall not be used for advertising or product */
/* endorsement purposes. */
/* */
/* Permission to use, copy, modify and distribute this software and its */
/* documentation for any non-commercial purpose, without fee, is */
/* hereby granted, provided that the above copyright notice and this */
/* permission notice appear in all copies of the software and */
/* supporting documentation, and that all UC LLNL identification in */
/* the user interface remain unchanged. The title to copyright LLNL */
/* XDIR shall at all times remain with The Regents of the University */
/* of California and users agree to preserve same. Users seeking the */
/* right to make derivative works with LLNL XDIR for commercial */
/* purposes may obtain a license from the Lawrence Livermore National */
/* Laboratory's Technology Transfer Office, P.O. Box 808, L-795, */
/* Livermore, CA 94550. */
/* */
/***************************************************************************/
/***************************************************************************/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <ctype.h>
#include <X11/Intrinsic.h>
#ifdef KERBEROS
#include <krb5/krb5.h>
#include <krb5/asn1.h>
#endif
#include "xdir.h"
#include "str.h"
#ifndef FNDELAY
#define FNDELAY O_NDELAY
#endif
extern struct st_host_info hinfo[];
extern int diagnostics;
extern int maxt;
/*
* ftp_open - Open a control connection with the ftp server specified
* by "hostname" and "port". "host" is index host structure array.
* If successful, the function value is 0 and hinfo[host].ctrl_fd
* is set to the file descriptor used for the control connection
* socket; returns -6 for stop button pressed; else -1 is returned.
* If successful, updates hinfo[host].system and hinfo[host].server.
*/
ftp_open(host, hostname, port)
int host;
char *hostname;
int port;
{
int ctrl_fd;
struct sockaddr_in remote;
int code;
char reply[MAXFTPREPLY];
struct hostent *hostptr;
char msg[50];
int scode;
unsigned long temp;
/* Form destination address */
bzero(&remote, (int)sizeof(remote));
temp = inet_addr(hostname);
if (temp == ~0L || (sizeof(int) >= 4 && (unsigned int)temp == ~0)) {
if ((hostptr = gethostbyname(hostname)) == NULL)
return -1;
if (hostptr->h_addrtype != AF_INET)
return -1;
remote.sin_addr.s_addr =
((struct in_addr*)hostptr->h_addr_list[0])->s_addr;
} else
remote.sin_addr.s_addr = temp;
remote.sin_family = AF_INET;
remote.sin_port = htons((short)port);
if (diagnostics == DEBUG) {
sprintf(msg, "*** dest_addr = %lx\n",
(unsigned long)remote.sin_addr.s_addr);
write_log(msg);
}
/* Create socket */
if ((ctrl_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
report_perror("Opening socket stream");
return -1;
}
/* Make socket nonblocking */
#if !defined(UMAXV) && !defined(SOCKS)
if (fcntl(ctrl_fd, F_SETFL, FNDELAY) == -1) {
report_perror("Making socket stream nonblocking");
close(ctrl_fd);
return -1;
}
#endif
/* Connect socket */
if (diagnostics == DEBUG)
write_log("*** Will try to connect to remote\n");
if (iconnect(ctrl_fd, (struct sockaddr *)&remote,(int)sizeof(remote)) < 0) {
if (errno != EINPROGRESS) {
report_perror("Connecting socket stream");
close(ctrl_fd);
return -1;
}
switch (select_on_write(ctrl_fd, maxt)) {
case -6:
close(ctrl_fd);
return -6;
case 0:
write_log("Timed out while trying to establish connection\n");
case -1:
close(ctrl_fd);
return -1;
}
}
hinfo[host].ctrl_fd = ctrl_fd;
/* Get response from FTP server */
if (diagnostics == DEBUG)
write_log("*** Will try to receive welcome message from remote host\n");
scode = get_ftp_reply(host, reply, MAXFTPREPLY, &code, maxt);
switch (scode) {
case -6:
close(hinfo[host].ctrl_fd);
return -6;
case 2:
determine_server_from_open(host, reply);
return 0;
case -2:
report_client_timeout(host);
default:
close(hinfo[host].ctrl_fd);
if (scode > 0 && diagnostics < VERBOSE)
report_ftp_reply(host, reply);
return -1;
}
}
/*
* ftp_user - Sends USER command to FTP server. "host" is the host id.
* Returns 0 if successful, 1 if successful but a password is
* required, 2 if successful but a password or a Kerberos
* ticket is required, -3 for broken connection, -6 for stop
* button pressed, and -1 for other errors.
*/
ftp_user(host, username)
int host;
char *username;
{
char cmd[100];
char reply[MAXFTPREPLY];
int code;
int retval;
/* Send USER command to FTP server */
sprintf(cmd, "USER %s", username);
if ((retval = send_ftp_cmd(host, cmd)) == -2) {
report_client_timeout(host);
return -1;
} else if (retval < 0)
return retval;
/* Process reply */
retval = get_ftp_reply(host, reply, MAXFTPREPLY, &code, maxt);
switch (retval) {
case 2:
return 0;
case 3:
#ifdef KERBEROS
if (code == 332)
return 2;
#endif
return 1;
case -2:
report_client_timeout(host);
return -1;
case -6:
abort_ftp_cmd(host);
return -6;
default:
if (retval > 0 && diagnostics < VERBOSE)
report_ftp_reply(host, reply);
return retval;
}
}
/*
* ftp_password - Sends PASS command to FTP server. "host" is the host
* id. Returns 0 if successful, 1 if successful but an
* account is required, -3 for broken connection, -6 for
* stop button pressed, and -1 for other errors.
*/
ftp_password(host, password)
int host;
char *password;
{
char cmd[100];
char reply[MAXFTPREPLY];
int code;
int retval;
int scode;
/* Send PASS command to FTP server */
sprintf(cmd, "PASS %s", password);
retval = send_ftp_cmd(host, cmd);
bzero(cmd, (int)strlen(cmd));
if (retval == -2) {
report_client_timeout(host);
return -1;
} else if (retval < 0)
return retval;
/* Process reply */
scode = get_ftp_reply(host, reply, MAXFTPREPLY, &code, maxt);
switch (scode) {
case 2:
return 0;
case 3:
return 1;
case -3:
return -3;
case -6:
abort_ftp_cmd(host);
return -6;
case -2:
report_client_timeout(host);
default:
if (scode > 0 && diagnostics < VERBOSE)
report_ftp_reply(host, reply);
return -1;
}
}
/*
* ftp_account - Sends ACCT command to FTP server. "host" is the host id.
* Returns 0 if successful, -3 for broken connection, -6 for
* stop button pressed, and -1 for other errors.
*/
ftp_account(host, account)
int host;
char *account;
{
char cmd[100];
char reply[MAXFTPREPLY];
int code;
int retval;
int scode;
/* Send ACCT command to FTP server */
sprintf(cmd, "ACCT %s", account);
if ((retval = send_ftp_cmd(host, cmd)) == -2) {
report_client_timeout(host);
return -1;
} else if (retval < 0)
return retval;
/* Process reply */
scode = get_ftp_reply(host, reply, MAXFTPREPLY, &code, maxt);
switch (scode) {
case 2:
return 0;
case -3:
return -3;
case -6:
abort_ftp_cmd(host);
return -6;
case -2:
report_client_timeout(host);
default:
if (scode > 0 && diagnostics < VERBOSE)
report_ftp_reply(host, reply);
return -1;
}
}
/*
* ftp_passive - Tell server to enter passive mode. If successful,
* returns pointer to string containing port address
* returned by server in "port", else "port" is undefined.
* "host" is the host id. Use XtFree() to release
* memory pointed to by "port". Returns 0 if successful,
* -3 for broken connection, -6 for stop button pushed,
* and -1 for other errors.
*/
ftp_passive(host, port)
int host;
char **port;
{
char reply[MAXFTPREPLY];
int code;
int nbytes;
char *start;
char *end;
int retval;
/* Send PASV command to FTP server */
if ((retval = send_ftp_cmd(host, "PASV")) == -2) {
report_client_timeout(host);
return -1;
} else if (retval < 0)
return retval;
/* Get response from FTP server */
retval = get_ftp_reply(host, reply, MAXFTPREPLY, &code, maxt);
switch (retval) {
case 2:
break;
case -2:
report_client_timeout(host);
return -1;
case -3:
return -3;
case -6:
abort_ftp_cmd(host);
return -6;
default:
return -1;
}
/* Extract port address */
if ((start = strchr(reply, '(')) == NULL)
return -1;
start++;
if ((end = strrchr(start, ')')) == NULL)
return -1;
if ((nbytes = end-start) <= 0)
return -1;
*port = XtMalloc(nbytes+1);
bcopy(start, *port, nbytes);
(*port)[nbytes] = '\0';
return 0;
}
/*
* ftp_type - Set file tranfer mode. "host" is the host id. Valid values
* for "mode" are ASCII and BINARY. Returns 0 for success,
* -3 for broken connection, -6 for stop button pressed, and -1
* for other errors.
*/
ftp_type(host, mode)
int host;
int mode;
{
char reply[MAXFTPREPLY];
char cmd[7];
int code;
int retval;
char type;
int scode;
/* Send TYPE command to FTP server */
if (mode == ASCII)
type = 'A';
else if (mode == BINARY)
type = 'I';
else
return -1;
sprintf(cmd, "TYPE %c", (char)type);
if ((retval = send_ftp_cmd(host, cmd)) == -2) {
report_client_timeout(host);
return -1;
} else if (retval < 0)
return retval;
/* Get response from FTP server */
scode = get_ftp_reply(host, reply, MAXFTPREPLY, &code, maxt);
switch (scode) {
case 2:
return 0;
case -3:
return -3;
case -6:
abort_ftp_cmd(host);
return -6;
case -2:
report_client_timeout(host);
default:
if (scode > 0 && diagnostics < VERBOSE)
report_ftp_reply(host, reply);
return -1;
}
}
/*
* ftp_port - Set the data port to be used in data connection to the
* specified value. "hostport" is a string of the form
* h1,h2,h3,h4,p1,p2 where the hi's are the decimal-
* valued bytes of the host's Internet address, and the pi's
* are the decimal valued bytes of the port's address.
* "host" is the host id. Returns 0 if successful, -3 for
* broken connection, -6 for stop button pressed, and -1 for
* other errors.
*/
ftp_port(host, hostport)
int host;
char *hostport;
{
char reply[MAXFTPREPLY];
char cmd[37];
int code;
int retval;
int scode;
/* Send PORT command to FTP server */
sprintf(cmd, "PORT %s", hostport);
if ((retval = send_ftp_cmd(host, cmd)) == -2) {
report_client_timeout(host);
return -1;
} else if (retval < 0)
return retval;
/* Get response from FTP server */
scode = get_ftp_reply(host, reply, MAXFTPREPLY, &code, maxt);
switch (scode) {
case 2:
return 0;
case -3:
return -3;
case -6:
abort_ftp_cmd(host);
return -6;
case -2:
report_client_timeout(host);
default:
if (scode > 0 && diagnostics < VERBOSE)
report_ftp_reply(host, reply);
return -1;
}
}
/*
* ftp_system - Tries to determine the type of system and server the
* remote host has by using the low-level SYST command.
* Set "print_error_msg" to True if FTP-generated error
* messages are to be written to the log when not in verbose
* mode. Returns 0 for success, -3 for broken connection,
* -6 for stop button pressed, and -1 for other errors.
* If successful, and if enough information is returned,
* hinfo[host].system and hinfo[host].server are set.
*/
ftp_system(host, print_error_msg)
int host;
int print_error_msg;
{
char reply[MAXFTPREPLY];
int code;
int retval;
int scode;
/* Send SYST command to FTP server */
if ((retval = send_ftp_cmd(host, "SYST")) == -2) {
report_client_timeout(host);
return -1;
} else if (retval < 0)
return retval;
/* Get response from FTP server */
scode = get_ftp_reply(host, reply, MAXFTPREPLY, &code, maxt);
switch (scode) {
case 2:
determine_server_from_syst(host, reply);
return 0;
case -3:
return -3;
case -6:
abort_ftp_cmd(host);
return -6;
case -2:
report_client_timeout(host);
default:
if (scode > 0 && diagnostics < VERBOSE && print_error_msg)
report_ftp_reply(host, reply);
return -1;
}
}
/*
* ftp_allocate - Tell the server to reserve "size" bytes of space for a
* subsequent store command. Returns 0 if successful,
* -3 for broken connection, -6 for stop button pushed,
* and -1 for other errors. "host" is the host id.
*/
ftp_allocate(host, size)
int host;
long size;
{
char cmd[100];
char reply[MAXFTPREPLY];
int code;
int scode;
int retval;
/* Send ALLO command to FTP server */
if (hinfo[host].server == SERVER_UNIX_HPSS)
sprintf(cmd, "ALLO64 %ld", size);
else
sprintf(cmd, "ALLO %ld", size);
if ((retval = send_ftp_cmd(host, cmd)) == -2) {
report_client_timeout(host);
return -1;
} else if (retval < 0)
return retval;
/* Get response from FTP server */
scode = get_ftp_reply(host, reply, MAXFTPREPLY, &code, maxt);
switch (scode) {
case 2:
return 0;
case -3:
return -3;
case -6:
abort_ftp_cmd(host);
return -6;
case -2:
report_client_timeout(host);
default:
if (scode > 0 && diagnostics < VERBOSE)
report_ftp_reply(host, reply);
return -1;
}
}
/*
* ftp_kerberos_ticket - Sends TKT command to FTP server. "host" is the
* host id. Returns 0 if successful, 1 if successful
* but an account is required, -3 for broken
* connection, -6 for stop button pressed, and -1 for
* other errors. Assumes hinfo[host].hostname has
* been set.
*/
#ifdef KERBEROS
ftp_kerberos_ticket(host)
int host;
{
char reply[MAXFTPREPLY];
int code;
int retval;
int scode;
int port_part;
char *host_part;
krb5_error_code status;
krb5_principal server;
krb5_principal client;
krb5_ccache ccdef;
krb5_ap_rep_enc_part *rep_ret;
/* Send TKT command to FTP server */
if ((retval = send_ftp_cmd(host, "TKT")) == -2) {
report_client_timeout(host);
return -1;
} else if (retval < 0)
return retval;
/* Process reply */
scode = get_ftp_reply(host, reply, MAXFTPREPLY, &code, maxt);
switch (scode) {
case 2:
return 0;
case 3:
if (code == 333)
break;
else
return -1;
case -3:
return -3;
case -6:
abort_ftp_cmd(host);
return -6;
case -2:
report_client_timeout(host);
default:
if (scode > 0 && diagnostics < VERBOSE)
report_ftp_reply(host, reply);
return -1;
}
/* Send authorization request to Kerberos */
krb5_init_ets();
if (parse_hostname(hinfo[host].hostname, &host_part, &port_part))
fatal_error("Bug in ftp_kerberos_ticket()");
krb5_sname_to_principal(host_part, "ftp", KRB5_NT_SRV_HST,
&server);
XtFree(host_part);
if ((status = krb5_cc_default(&ccdef))) {
if (diagnostics == DEBUG) {
write_log("*** Cannot open credential cache: ");
write_log(error_message(status));
write_log("\n");
}
return -1;
}
if ((status = krb5_cc_get_principal( ccdef, &client))){
if (diagnostics == DEBUG) {
write_log("*** Cannot get client principal: ");
write_log(error_message(status));
write_log("\n");
}
return -1;
}
status = krb5_sendauth((krb5_pointer)&hinfo[host].ctrl_fd, "FTP_V5",
client, server, AP_OPTS_MUTUAL_REQUIRED, 0, 0, ccdef, 0, 0, 0,
&rep_ret);
if (status) {
if (diagnostics == DEBUG) {
write_log("*** Kerberos authentication failure: ");
write_log(error_message(status));
write_log("\n");
}
return -1;
}
krb5_free_ap_rep_enc_part(rep_ret);
/* Process reply */
scode = get_ftp_reply(host, reply, MAXFTPREPLY, &code, maxt);
switch (scode) {
case 2:
return 0;
case 3:
return 1;
case -3:
return -3;
case -6:
abort_ftp_cmd(host);
return -6;
case -2:
report_client_timeout(host);
default:
if (scode > 0 && diagnostics < VERBOSE)
report_ftp_reply(host, reply);
return -1;
}
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1