From 00e6c3c3ed06a258a02943fc49fa7c528025d747 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Thu, 31 Dec 2015 13:59:18 +0200 Subject: Command-line control interface. * configure.ac (DEFAULT_CONTROL_URL): New subst variable. * grecs: Upgrade. * ident/pam.c (overwrite_and_free): Free ptr. * lib/Makefile.am: Add new sources. * src/addrfmt.c: Move to lib/addrfmt.c * lib/grecsasrt.c: New file. * lib/grecsasrt.h: New file. * lib/mkfilename.c: New file. * lib/netrc.c: New file. * lib/pp.c: New file. * lib/split3.c: New file. * src/url.c: Move from lib/url.c (pies_url_free_user, pies_url_free_passwd): New finctions. * lib/libpies.h (strsplit3): New proto. (pies_url_create, pies_url_destroy) (pies_url_get_arg, pies_url_copy) (pies_url_free_user, pies_url_free_passwd) (netrc_scan) (pp_add_option, pp_command_line, mkfilename) (sockaddr_to_str, sockaddr_to_astr): New protos * src/Makefile.am (bin_PROGRAMS): New program: piesctl (pies_SOURCES): Remove addrfmt.c and url.c. (noinst_HEADERS, BUILT_SOURCES): Add piesctl-cl.h * src/cmdline.opt: Use pp_* function family to build preprocessor command line. * src/ctl.c (http_header_hash): Use case-insensitive hashing. (ctlio_finalize_reply): Don't close connection after sending 401 response. (input): Remove ws and wsflags. All uses changed. (input_append): Use strsplit3 to parse the request line. * src/pies.c: Use pp_* function family to build preprocessor command line. Move assert_, mkfilename and _cb+_url functions into libpies. * src/pies.h (pies_sockaddr_storage): Move to libpies.h * src/piesctl.c: New file. * src/piesctl-cl.opt: New file. --- lib/url.c | 360 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 360 insertions(+) create mode 100644 lib/url.c (limited to 'lib/url.c') diff --git a/lib/url.c b/lib/url.c new file mode 100644 index 0000000..41f5c04 --- /dev/null +++ b/lib/url.c @@ -0,0 +1,360 @@ +/* This file is part of GNU Pies + Copyright (C) 2009, 2010, 2013, 2015 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 +#include +#include +#include +#include "libpies.h" +#include + +/* scheme://[user[:password]@][host[:port]/]path[;arg=str[;arg=str...] +*/ + +static int +alloc_string_len (char **sptr, const char *start, size_t len) +{ + *sptr = malloc (len + 1); + if (!*sptr) + return 1; + memcpy (*sptr, start, len); + (*sptr)[len] = 0; + return 0; +} + +static int +alloc_string (char **sptr, const char *start, const char *end) +{ + size_t len = end ? end - start : strlen (start); + return alloc_string_len (sptr, start, len); +} + +static int +url_parse_args (struct pies_url *url, char **str) +{ + struct wordsplit ws; + + ws.ws_delim = ";"; + if (wordsplit (*str, &ws, WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_DELIM)) + return 1; + url->argc = ws.ws_wordc; + url->argv = ws.ws_wordv; + return 0; +} + +static int +url_parse_path (struct pies_url *url, char **str) +{ + char *p; + + p = strchr (*str, ';'); + if (!p) + p = *str + strlen (*str); + if (alloc_string (&url->path, *str, p)) + return 1; + *str = p; + if (*p) + ++*str; + return url_parse_args (url, str); +} + +/* On input str points at the beginning of host part */ +static int +url_parse_host (struct pies_url *url, char **str) +{ + char *s = *str; + size_t len = strcspn (s, "/:"); + + if (s[len] == ':') + { + char *start = s + len + 1; + char *q; + unsigned long n = strtoul (start, &q, 10); + if (n > USHRT_MAX) + return 1; + if ((*q && !strchr ("/;", *q))) + { + char *proto = url->proto_s ? url->proto_s : "tcp"; + size_t size = strcspn (start, "/;"); + struct servent *serv; + + alloc_string_len (&url->port_s, start, size); + serv = getservbyname (url->port_s, proto); + if (!serv) + return 1; + url->port = ntohs (serv->s_port); + *str = start + size; + } + else + { + alloc_string_len (&url->port_s, start, q - start); + url->port = n; + *str = q; + } + } + else + *str = s + len; + if (alloc_string_len (&url->host, s, len)) + return 1; + if (**str) + { + if (*(*str)++ == '/') + return url_parse_path (url, str); + else + return url_parse_args (url, str); + } + return 0; +} + +/* On input str points past the mech:// part */ +static int +url_parse_user (struct pies_url *url, char **str) +{ + if (**str == '/') + return url_parse_path (url, str); + else + { + size_t len = strcspn (*str, ":;@/"); + char *p = *str + len; + + switch (*p) + { + case ';': + case ':': + len = strcspn (p + 1, "@/:"); + if (p[len + 1] == '@') + { + if (alloc_string_len (&url->passwd, p + 1, len)) + return 1; + if (alloc_string (&url->user, *str, p)) + return 1; + *str = p + len + 2; + } + break; + + case '@': + if (alloc_string (&url->user, *str, p)) + return 1; + url->passwd = NULL; + *str = p + 1; + } + return url_parse_host (url, str); + } +} + +static int +url_parse_scheme (struct pies_url *url, const char *str) +{ + size_t len; + char *p; + + if (!str) + { + errno = EINVAL; + return 1; + } + + len = strcspn (str, ":+"); + if (!str[len]) + { + errno = EINVAL; + return 1; + } + + alloc_string_len (&url->scheme, str, len); + + str += len; + + if (*str == '+') + { + struct protoent *proto; + + len = strcspn (++str, ":"); + if (str[len] == 0) + { + errno = EINVAL; + return 1; + } + alloc_string_len (&url->proto_s, str, len); + str += len; + proto = getprotobyname (url->proto_s); + if (!proto) + { + errno = EINVAL; + return 1; + } + url->proto = proto->p_proto; + } + else + url->proto = 0; + + /* Skip slashes */ + p = (char*) str + 1; + if (memcmp (p, "//", 2)) + { + errno = EINVAL; + return 1; + } + p += 2; + return url_parse_user (url, &p); +} + +void +pies_url_free_user (struct pies_url *url) +{ + if (url->user) + { + free (url->user); + url->user = NULL; + } +} + +void +pies_url_free_passwd (struct pies_url *url) +{ + if (url->passwd) + { + memset (url->passwd, 0, strlen (url->passwd)); + free (url->passwd); + url->passwd = NULL; + } +} + +void +pies_url_destroy (struct pies_url **purl) +{ + int i; + if (purl && *purl) + { + struct pies_url *url = *purl; + + free (url->string); + free (url->scheme); + free (url->host); + free (url->port_s); + free (url->proto_s); + free (url->path); + pies_url_free_user (url); + pies_url_free_passwd (url); + for (i = 0; i < url->argc; i++) + free (url->argv[i]); + free (url->argv); + free (url); + *purl = NULL; + } +} + +static int +strasgn (char **dst, char *src) +{ + if (!src) + *dst = NULL; + else + { + *dst = strdup (src); + if (!*dst) + return 1; + } + return 0; +} + +static int +do_url_copy (struct pies_url *dest, struct pies_url *src) +{ +#define STRASGN(a,b) if (strasgn (a, b)) return -1; + size_t i; + + STRASGN (&dest->string, src->string); + STRASGN (&dest->scheme, src->scheme); + STRASGN (&dest->host, src->host); + STRASGN (&dest->port_s, src->port_s); + dest->port = src->port; + STRASGN (&dest->proto_s, src->proto_s); + dest->proto = src->proto; + STRASGN (&dest->path, src->path); + STRASGN (&dest->user, src->user); + STRASGN (&dest->passwd, src->passwd); + dest->argv = calloc (src->argc + 1, sizeof (dest->argv[0])); + if (!dest->argv) + return -1; + for (i = 0; i < src->argc; i++) + { + if (!(dest->argv[i] = strdup (src->argv[0]))) + { + dest->argc = i; + return -1; + } + } + dest->argv[i] = NULL; + dest->argc = i; + return 0; +#undef STRASGN +} + +int +pies_url_copy (struct pies_url **purl, struct pies_url *src) +{ + struct pies_url *dest = malloc (sizeof (*dest)); + + if (!dest) + return -1; + memset (dest, 0, sizeof (*dest)); + if (do_url_copy (dest, src)) + { + pies_url_destroy (&dest); + return -1; + } + *purl = dest; + return 0; +} + +int +pies_url_create (struct pies_url **purl, const char *str) +{ + int rc; + struct pies_url *url; + + url = malloc (sizeof (*url)); + if (!url) + return 1; + memset (url, 0, sizeof (*url)); + rc = url_parse_scheme (url, str); + if (rc) + pies_url_destroy (&url); + else + { + url->string = strdup (str); + *purl = url; + } + return rc; +} + +const char * +pies_url_get_arg (struct pies_url *url, const char *argname) +{ + int i; + size_t arglen = strlen (argname); + for (i = 0; i < url->argc; i++) + { + size_t len = strcspn (url->argv[i], "="); + if (len == arglen && memcmp (url->argv[i], argname, arglen) == 0) + return url->argv[i] + len + 1; + } + return NULL; +} -- cgit v1.2.1