226 lines
4.7 KiB
C
226 lines
4.7 KiB
C
#include "miscfn.h"
|
|
|
|
#include <fcntl.h>
|
|
#include <pwd.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
|
|
#if HAVE_ALLOCA_H
|
|
# include <alloca.h>
|
|
#endif
|
|
|
|
#include "ftp.h"
|
|
#include "messages.h"
|
|
#include "miscfn.h"
|
|
#include "rpmlib.h"
|
|
#include "url.h"
|
|
|
|
struct pwcacheEntry {
|
|
char * machine;
|
|
char * account;
|
|
char * pw;
|
|
} ;
|
|
|
|
static char * getFtpPassword(char * machine, char * account, int mustAsk);
|
|
static int urlFtpLogin(char * url, char ** fileNamePtr);
|
|
static int urlFtpSplit(char * url, char ** user, char ** pw, char ** host,
|
|
char ** path);
|
|
|
|
static char * getFtpPassword(char * machine, char * account, int mustAsk) {
|
|
static struct pwcacheEntry * pwCache = NULL;
|
|
static int pwCount = 0;
|
|
int i;
|
|
char * prompt;
|
|
|
|
for (i = 0; i < pwCount; i++) {
|
|
if (!strcmp(pwCache[i].machine, machine) &&
|
|
!strcmp(pwCache[i].account, account))
|
|
break;
|
|
}
|
|
|
|
if (i < pwCount && !mustAsk) {
|
|
return pwCache[i].pw;
|
|
} else if (i == pwCount) {
|
|
pwCount++;
|
|
if (pwCache)
|
|
pwCache = realloc(pwCache, sizeof(*pwCache) * pwCount);
|
|
else
|
|
pwCache = malloc(sizeof(*pwCache));
|
|
|
|
pwCache[i].machine = strdup(machine);
|
|
pwCache[i].account = strdup(account);
|
|
} else
|
|
free(pwCache[i].pw);
|
|
|
|
prompt = alloca(strlen(machine) + strlen(account) + 50);
|
|
sprintf(prompt, "Password for %s@%s: ", account, machine);
|
|
|
|
pwCache[i].pw = strdup(getpass(prompt));
|
|
|
|
return pwCache[i].pw;
|
|
}
|
|
|
|
static int urlFtpSplit(char * url, char ** user, char ** pw, char ** host,
|
|
char ** path) {
|
|
char * chptr, * machineName, * fileName;
|
|
char * userName = NULL;
|
|
char * password = NULL;
|
|
|
|
url += 6; /* skip ftp:// */
|
|
|
|
chptr = url;
|
|
while (*chptr && (*chptr != '/')) chptr++;
|
|
if (!*chptr) return -1;
|
|
|
|
machineName = url; /* could still have user:pass@ though */
|
|
fileName = chptr;
|
|
|
|
*path = strdup(chptr);
|
|
|
|
*chptr = '\0';
|
|
|
|
chptr = fileName;
|
|
while (chptr > url && *chptr != '@') chptr--;
|
|
if (chptr > url) { /* we have a username */
|
|
*chptr = '\0';
|
|
userName = machineName;
|
|
machineName = chptr + 1;
|
|
|
|
chptr = userName;
|
|
while (*chptr && *chptr != ':') chptr++;
|
|
if (*chptr) { /* we have a password */
|
|
*chptr = '\0';
|
|
password = chptr + 1;
|
|
}
|
|
}
|
|
|
|
if (userName && !password) {
|
|
password = getFtpPassword(machineName, userName, 0);
|
|
}
|
|
|
|
if (userName)
|
|
*user = strdup(userName);
|
|
|
|
if (password)
|
|
*pw = strdup(password);
|
|
|
|
*host = strdup(machineName);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int urlFtpLogin(char * url, char ** fileNamePtr) {
|
|
char * buf;
|
|
char * machineName, * fileName;
|
|
char * userName = NULL;
|
|
char * password = NULL;
|
|
char * proxy;
|
|
char * portStr, * endPtr;
|
|
int port;
|
|
int ftpconn;
|
|
|
|
rpmMessage(RPMMESS_DEBUG, "getting %s via anonymous ftp\n", url);
|
|
|
|
buf = alloca(strlen(url) + 1);
|
|
strcpy(buf, url);
|
|
|
|
urlFtpSplit(buf, &userName, &password, &machineName, &fileName);
|
|
|
|
rpmMessage(RPMMESS_DEBUG, "logging into %s as %s, pw %s\n", machineName,
|
|
userName ? userName : "ftp",
|
|
password ? password : "(username)");
|
|
|
|
proxy = rpmGetVar(RPMVAR_FTPPROXY);
|
|
portStr = rpmGetVar(RPMVAR_FTPPORT);
|
|
if (!portStr) {
|
|
port = -1;
|
|
} else {
|
|
port = strtol(portStr, &endPtr, 0);
|
|
if (*endPtr) {
|
|
fprintf(stderr, "error: ftpport must be a number\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
ftpconn = ftpOpen(machineName, userName, password, proxy, port);
|
|
|
|
free(machineName);
|
|
free(userName);
|
|
free(password);
|
|
|
|
if (ftpconn < 0) {
|
|
free(fileName);
|
|
return ftpconn;
|
|
}
|
|
|
|
*fileNamePtr = fileName;
|
|
|
|
return ftpconn;
|
|
}
|
|
|
|
int urlGetFd(char * url, struct urlContext * context) {
|
|
char * fileName;
|
|
int fd;
|
|
|
|
rpmMessage(RPMMESS_DEBUG, "getting %s via anonymous ftp\n", url);
|
|
|
|
if ((context->ftpControl = urlFtpLogin(url, &fileName)) < 0)
|
|
return context->ftpControl;
|
|
|
|
fd = ftpGetFileDesc(context->ftpControl, fileName);
|
|
|
|
free(fileName);
|
|
|
|
if (fd < 0) ftpClose(context->ftpControl);
|
|
|
|
return fd;
|
|
}
|
|
|
|
int urlFinishedFd(struct urlContext * context) {
|
|
ftpClose(context->ftpControl);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int urlGetFile(char * url, char * dest) {
|
|
char * fileName;
|
|
int ftpconn;
|
|
int rc;
|
|
int fd;
|
|
|
|
rpmMessage(RPMMESS_DEBUG, "getting %s via anonymous ftp\n", url);
|
|
|
|
if ((ftpconn = urlFtpLogin(url, &fileName)) < 0) return ftpconn;
|
|
|
|
fd = creat(dest, 0600);
|
|
|
|
if (fd < 0) {
|
|
rpmMessage(RPMMESS_DEBUG, "failed to create %s\n", dest);
|
|
ftpClose(ftpconn);
|
|
free(fileName);
|
|
return FTPERR_UNKNOWN;
|
|
}
|
|
|
|
if ((rc = ftpGetFile(ftpconn, fileName, fd))) {
|
|
free(fileName);
|
|
unlink(dest);
|
|
close(fd);
|
|
ftpClose(ftpconn);
|
|
return rc;
|
|
}
|
|
|
|
free(fileName);
|
|
|
|
ftpClose(ftpconn);
|
|
|
|
return rc;
|
|
}
|
|
|
|
int urlIsURL(char * url) {
|
|
if (!strncmp(url, "ftp://", 6)) return 1;
|
|
|
|
return 0;
|
|
}
|