/* This file is part of GNU Pies Copyright (C) 2015, 2017 Sergey Poznyakoff GNU Pies is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNU Pies is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Pies. If not, see . */ #ifdef HAVE_CONFIG_H # include #endif #include "libpies.h" #include #include #include #include #include #include /* Compare two hostnames. Return 0 if they have the same address type, address length *and* at least one of the addresses of A matches B */ static int hostcmp (const char *a, const char *b) { struct hostent *hp = gethostbyname (a); char **addrlist; char *dptr; char **addr; size_t i, count; size_t entry_length; int entry_type; if (!hp) return 1; for (count = 1, addr = hp->h_addr_list; *addr; addr++) count++; addrlist = grecs_malloc (count * (sizeof *addrlist + hp->h_length) - hp->h_length); dptr = (char *) (addrlist + count); for (i = 0; i < count - 1; i++) { memcpy (dptr, hp->h_addr_list[i], hp->h_length); addrlist[i] = dptr; dptr += hp->h_length; } addrlist[i] = NULL; entry_length = hp->h_length; entry_type = hp->h_addrtype; hp = gethostbyname (b); if (!hp || entry_length != hp->h_length || entry_type != hp->h_addrtype) { grecs_free (addrlist); return 1; } for (addr = addrlist; *addr; addr++) { char **p; for (p = hp->h_addr_list; *p; p++) { if (memcmp (*addr, *p, entry_length) == 0) { grecs_free (addrlist); return 0; } } } grecs_free (addrlist); return 1; } static int match_url (size_t argc, char **argv, struct pies_url *url) { if (hostcmp (argv[1], url->host ? url->host : "localhost") == 0) { if (argc >= 4 && strcmp (argv[2], "port") == 0) { unsigned long n = strtoul (argv[3], NULL, 10); if (n == url->port) return 1; } else return 1; } return 0; } static void parse_args (struct grecs_locus *loc, char **argv, char **username, char **password) { if (*username) { grecs_free (*username); *username = NULL; } if (*password) { grecs_free (*password); *password = NULL; } while (*argv) { if (!argv[1]) { grecs_error (loc, 0, _("incomplete sentence")); break; } if (strcmp (*argv, "login") == 0) *username = grecs_strdup (argv[1]); else if (strcmp (*argv, "password") == 0) *password = grecs_strdup (argv[1]); argv += 2; } } /* Parse traditional .netrc file. Set up auth_args fields in accordance with it. */ void netrc_scan_file (FILE *fp, struct grecs_locus *loc, struct pies_url *url) { char *buf = NULL; size_t n = 0; struct wordsplit ws; int wsflags = WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_QUOTE | WRDSF_SQUEEZE_DELIMS; char *username = NULL; char *password = NULL; while (grecs_getline (&buf, &n, fp) > 0) { loc->beg.line++; if (wordsplit (buf, &ws, wsflags)) { grecs_error (loc, 0, "wordsplit: %s", wordsplit_strerror (&ws)); continue; } wsflags |= WRDSF_REUSE; if (ws.ws_wordc == 0) continue; if (strcmp (ws.ws_wordv[0], "machine") == 0) { if (match_url (ws.ws_wordc, ws.ws_wordv, url)) { parse_args (loc, ws.ws_wordv + 2, &username, &password); break; } } else if (strcmp (ws.ws_wordv[0], "default") == 0) parse_args (loc, ws.ws_wordv + 1, &username, &password); else grecs_error (loc, 0, _("ignoring unrecognized line")); } grecs_free (buf); if (wsflags & WRDSF_REUSE) wordsplit_free (&ws); url->user = username; url->passwd = password; } void netrc_scan (struct pies_url *url) { FILE *fp; struct grecs_locus loc; char *filename; char *homedir; if (url->user) return; homedir = getenv ("HOME"); if (!homedir) { struct passwd *pwd = getpwuid (getuid ()); if (!pwd) return; homedir = pwd->pw_dir; } filename = mkfilename (homedir, ".netrc", NULL); fp = fopen (filename, "r"); if (!fp) { if (errno != ENOENT) grecs_error (NULL, 0, _("cannot open configuration file %s: %s"), filename, strerror (errno)); free (filename); return; } loc.beg.file = loc.end.file = (char*) filename; loc.beg.col = loc.end.col = 0; loc.beg.line = 0; netrc_scan_file (fp, &loc, url); fclose (fp); free (filename); }