Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

netrc: Implement .netrc parsing #244

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ conn_init(conn_t *conn)
conn->ftp->ftp_mode = FTP_PASSIVE;
conn->ftp->tcp.ai_family = conn->conf->ai_family;
if (conn->conf->use_netrc)
netrc_parse(conn->conf->netrc_filename, conn->host, conn->user, conn->pass);
netrc_parse(conn->conf->netrc_filename, conn->host, conn->user, sizeof(conn->user), conn->pass, sizeof(conn->pass));
printf("host: %s, user: %s, pass: %s\n", conn->host, conn->user, conn->pass);
if (!ftp_connect(conn->ftp, conn->proto, conn->host, conn->port,
conn->user, conn->pass,
Expand Down
126 changes: 75 additions & 51 deletions src/netrc.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,75 +41,95 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include "axel.h"
#include "netrc.h"

#define REL_NETRC "/.netrc"
#define IS_DELIM(x) (*x == ' ' || *x == '\t' || *x == '\n')

static int fd;
static size_t sz;
static char *p;
static char *s_addr;
static char *e_addr;

static size_t file_size(void)
static size_t file_size(int fd)
{
struct stat st;
fstat(fd, &st);
return st.st_size;
}

static int netrc_open(const char * const filename)
static int netrc_mmap(const char *filename)
{
int ret;
char *path;
char *netrc;
char *home;

ret = 0;
if (filename && filename[0] != '\0') {
path = strdup(filename);
} else {
if ((netrc = getenv("NETRC"))) {
path = strdup(netrc);
} else if ((home = getenv("HOME"))) {
size_t i = strlen(home) + strlen(REL_NETRC) + 1;
path = malloc(i);
snprintf(path, i, "%s%s", home, REL_NETRC);
} else {
return ret;
int fd;
size_t sz;
char *aux = NULL;
char *home = NULL;
char *path = NULL;
const char suffix[] = "/.netrc";
davidpolverari marked this conversation as resolved.
Show resolved Hide resolved

if (filename && *filename) {
aux = path = (char *)filename;
} else if ((path = getenv("NETRC"))) {
aux = path;
} else if ((home = getenv("HOME"))) {
size_t i = strlen(home);
if ((path = malloc(i + sizeof(suffix)))) {
memcpy(path, home, i);
memcpy(path+i, suffix, sizeof(suffix));
}
}
if ((fd = open(path, O_RDONLY, 0)) == -1) {
ret = 0;
if (!path)
return 0;
fd = open(path, O_RDONLY,0);
if (!aux)
free(path);
if (fd == -1) {
return 0;
} else {
sz = file_size();
sz = file_size(fd);
s_addr = mmap(NULL, sz, PROT_READ, MAP_PRIVATE | MAP_POPULATE, fd, 0);
close(fd);
e_addr = s_addr + sz;
ret = 1;
return sz;
}
free(path);
return ret;
}

static void netrc_close(void)
static void netrc_munmap(size_t sz)
{
munmap(s_addr, sz);
close(fd);
}

static int next_token(char **t)
static size_t
memspn(const char *s, const char *t, size_t len)
{
size_t sz = 0;

while (*s && len-- && strchr(t, *s++))
sz++;
return sz;
}

static size_t
memcspn(const char *s, const char *t, size_t len)
{
size_t sz = 0;

while (*s && len--)
if (strchr(t, *s))
return sz;
else
s++, sz++;
return sz;
}

static size_t next_token(char **t)
{
char *q;
int len;
size_t len;
const char *delims = " \t\n";

if (!p)
p = s_addr;
while (IS_DELIM(p) && p < e_addr)
p++;
p += memspn(p, delims, (e_addr - p));
q = p;
while (!IS_DELIM(q) && q < e_addr)
q++;
q += memcspn(q, delims, (e_addr - q));
if (q == e_addr)
return 0;
len = q-p;
Expand All @@ -118,20 +138,22 @@ static int next_token(char **t)
return len;
}

static void get_creds(char *user, char *pwd)
static void
get_creds(char *user, size_t ul, char *pwd, size_t pl)
{
int len;
size_t len;
char *tok;

while ((len = next_token(&tok))) {
if (!strncmp("login", tok, len)) {
len = next_token(&tok);
strncpy(user, tok, len);
user[len] = '\0';
/* next_token() doesn't null-terminate */
if (len <= ul)
strlcpy(user, tok, len+1);
} else if (!strncmp("password", tok, len)) {
len = next_token(&tok);
strncpy(pwd, tok, len);
pwd[len] = '\0';
if (len <= pl)
strlcpy(pwd, tok, len+1);
} else if (!strncmp("machine", tok, len) || !strncmp("default", tok, len)) {
p -= len;
break;
Expand All @@ -140,24 +162,26 @@ static void get_creds(char *user, char *pwd)
}

int
davidpolverari marked this conversation as resolved.
Show resolved Hide resolved
netrc_parse(const char *filename, const char *host, char *user, char *password)
netrc_parse(const char *filename, const char *host,
char *user, size_t ul, char *password, size_t pl)
{
davidpolverari marked this conversation as resolved.
Show resolved Hide resolved
int len;
size_t len;
size_t sz;
char *tok;

if (!netrc_open(filename))
if (!(sz = netrc_mmap(filename)))
return 0;
while ((len = next_token(&tok))) {
if (!strncmp("default", tok, len)) {
get_creds(user, password);
get_creds(user, ul, password, pl);
break;
} else if (!strncmp("machine", tok, len)) {
if ((len = next_token(&tok)) && !strncmp(host, tok, len)) {
get_creds(user, password);
get_creds(user, ul, password, pl);
break;
}
}
}
netrc_close();
return 0;
netrc_munmap(sz);
return 1;
}
2 changes: 1 addition & 1 deletion src/netrc.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,6 @@
#ifndef AXEL_NETRC_H
#define AXEL_NETRC_H

int netrc_parse(const char *filename, const char *host, char *user, char *pwd);
int netrc_parse(const char *filename, const char *host, char *user, size_t ul, char *pwd, size_t pl);

#endif /* AXEL_NETRC_H */
3 changes: 2 additions & 1 deletion src/text.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ main(int argc, char *argv[])
case 'R':
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's define a negative version, it's necessary for if there's a default in the axel config file. I'm not sure a short version is needed (I've been thinking about removing support for systems not supporting getopt_long anyway).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About negative version of the option, I don't know whether it is a good idea to make .netrc parsing default, as it may break existing users' assumptions/scripts/workflows, etc. What do you think about it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mean to make it the default, but if you have the option on the configuration file, then you need a way to disable it from the command line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I'll add it.

conf->use_netrc = 1;
if (optarg) {
if (!sscanf(optarg, "%s", conf->netrc_filename)) {
if (!strlcpy(conf->netrc_filename, optarg,
sizeof(conf->netrc_filename))) {
print_help();
goto free_conf;
}
Expand Down