#include "amanda.h"
#include "util.h"
+#include "match.h"
#include <regex.h>
#include "arglist.h"
#include "clock.h"
#include "sockaddr-util.h"
#include "conffile.h"
-
-#ifdef HAVE_LIBCURL
-#include <curl/curl.h>
-#endif
+#include "base64.h"
+#include "stream.h"
+#include "pipespawn.h"
+#include <glib.h>
+#include <string.h>
static int make_socket(sa_family_t family);
static int connect_port(sockaddr_union *addrp, in_port_t port, char *proto,
sockaddr_union *svaddr, int nonblock);
-/*
- * Keep calling read() until we've read buflen's worth of data, or EOF,
- * or we get an error.
- *
- * Returns the number of bytes read, 0 on EOF, or negative on error.
- */
-ssize_t
-fullread(
- int fd,
- void * vbuf,
- size_t buflen)
-{
- ssize_t nread, tot = 0;
- char *buf = vbuf; /* cast to char so we can ++ it */
-
- while (buflen > 0) {
- nread = read(fd, buf, buflen);
- if (nread < 0) {
- if ((errno == EINTR) || (errno == EAGAIN))
- continue;
- return ((tot > 0) ? tot : -1);
- }
-
- if (nread == 0)
- break;
-
- tot += nread;
- buf += nread;
- buflen -= nread;
- }
- return (tot);
-}
-
-/*
- * Keep calling write() until we've written buflen's worth of data,
- * or we get an error.
- *
- * Returns the number of bytes written, or negative on error.
- */
-ssize_t
-fullwrite(
- int fd,
- const void *vbuf,
- size_t buflen)
-{
- ssize_t nwritten, tot = 0;
- const char *buf = vbuf; /* cast to char so we can ++ it */
-
- while (buflen > 0) {
- nwritten = write(fd, buf, buflen);
- if (nwritten < 0) {
- if ((errno == EINTR) || (errno == EAGAIN))
- continue;
- return ((tot > 0) ? tot : -1);
- }
- tot += nwritten;
- buf += nwritten;
- buflen -= nwritten;
- }
- return (tot);
-}
-
static int
make_socket(
sa_family_t family)
int r;
#endif
+ g_debug("make_socket opening socket with family %d", family);
s = socket(family, SOCK_STREAM, 0);
if (s == -1) {
save_errno = errno;
return s;
}
+GQuark am_util_error_quark(void)
+{
+ return g_quark_from_static_string("am-util-error-quark");
+}
+
/* addrp is my address */
/* svaddr is the address of the remote machine */
/* return socket on success */
socklen = SS_LEN(addrp);
if (bind(s, (struct sockaddr *)addrp, socklen) >= 0) {
if (servPort == NULL) {
- dbprintf(_("bind_portrange2: Try port %d: Available - Success\n"), port);
+ g_debug(_("bind_portrange2: Try port %d: Available - Success"), port);
} else {
- dbprintf(_("bind_portrange2: Try port %d: Owned by %s - Success.\n"), port, servPort->s_name);
+ g_debug(_("bind_portrange2: Try port %d: Owned by %s - Success."), port, servPort->s_name);
}
return 0;
}
if (errno != EAGAIN && errno != EBUSY)
save_errno = errno;
if (servPort == NULL) {
- dbprintf(_("bind_portrange2: Try port %d: Available - %s\n"),
+ g_debug(_("bind_portrange2: Try port %d: Available - %s"),
port, strerror(errno));
} else {
- dbprintf(_("bind_portrange2: Try port %d: Owned by %s - %s\n"),
+ g_debug(_("bind_portrange2: Try port %d: Owned by %s - %s"),
port, servPort->s_name, strerror(errno));
}
} else {
- dbprintf(_("bind_portrange2: Skip port %d: Owned by %s.\n"),
+ g_debug(_("bind_portrange2: Skip port %d: Owned by %s."),
port, servPort->s_name);
}
if (++port > last_port)
port = first_port;
}
- dbprintf(_("bind_portrange: all ports between %d and %d busy\n"),
+ g_debug(_("bind_portrange: all ports between %d and %d busy"),
first_port,
last_port);
errno = save_errno;
return -1;
}
-
int
-needs_quotes(
- const char * str)
+interruptible_accept(
+ int sock,
+ struct sockaddr *addr,
+ socklen_t *addrlen,
+ gboolean (*prolong)(gpointer data),
+ gpointer prolong_data)
{
- return (match("[ \t\f\r\n\"]", str) != 0);
+ SELECT_ARG_TYPE readset;
+ struct timeval tv;
+ int nfound;
+
+ if (sock < 0 || sock >= FD_SETSIZE) {
+ g_debug("interruptible_accept: bad socket %d", sock);
+ return EBADF;
+ }
+
+ memset(&readset, 0, SIZEOF(readset));
+
+ while (1) {
+ if (!prolong(prolong_data)) {
+ errno = 0;
+ return -1;
+ }
+
+ FD_ZERO(&readset);
+ FD_SET(sock, &readset);
+
+ /* try accepting for 1s */
+ memset(&tv, 0, SIZEOF(tv));
+ tv.tv_sec = 1;
+
+ nfound = select(sock+1, &readset, NULL, NULL, &tv);
+ if (nfound < 0) {
+ return -1;
+ } else if (nfound == 0) {
+ continue;
+ } else if (!FD_ISSET(sock, &readset)) {
+ g_debug("interruptible_accept: select malfunction");
+ errno = EBADF;
+ return -1;
+ } else {
+ int rv = accept(sock, addr, addrlen);
+ if (rv < 0 && errno == EAGAIN)
+ continue;
+ return rv;
+ }
+ }
+}
+
+/*
+ * Writes out the entire iovec
+ */
+ssize_t
+full_writev(
+ int fd,
+ struct iovec * iov,
+ int iovcnt)
+{
+ ssize_t delta, n, total;
+
+ assert(iov != NULL);
+
+ total = 0;
+ while (iovcnt > 0) {
+ /*
+ * Write the iovec
+ */
+ n = writev(fd, iov, iovcnt);
+ if (n < 0) {
+ if (errno != EINTR)
+ return (-1);
+ }
+ else if (n == 0) {
+ errno = EIO;
+ return (-1);
+ } else {
+ total += n;
+ /*
+ * Iterate through each iov. Figure out what we still need
+ * to write out.
+ */
+ for (; n > 0; iovcnt--, iov++) {
+ /* 'delta' is the bytes written from this iovec */
+ delta = ((size_t)n < (size_t)iov->iov_len) ? n : (ssize_t)iov->iov_len;
+ /* subtract from the total num bytes written */
+ n -= delta;
+ assert(n >= 0);
+ /* subtract from this iovec */
+ iov->iov_len -= delta;
+ iov->iov_base = (char *)iov->iov_base + delta;
+ /* if this iovec isn't empty, run the writev again */
+ if (iov->iov_len > 0)
+ break;
+ }
+ }
+ }
+ return (total);
}
/*
- * For backward compatibility we are trying for minimal quoting.
- * We only quote a string if it contains whitespace or is misquoted...
+ * For backward compatibility we are trying for minimal quoting. Unless ALWAYS
+ * is true, we only quote a string if it contains whitespace or is misquoted...
*/
char *
-quote_string(
- const char *str)
+quote_string_maybe(
+ const char *str,
+ gboolean always)
{
char * s;
char * ret;
if ((str == NULL) || (*str == '\0')) {
ret = stralloc("\"\"");
- } else if ((match("[:\'\\\"[:space:][:cntrl:]]", str)) == 0) {
- /*
- * String does not need to be quoted since it contains
- * neither whitespace, control or quote characters.
- */
- ret = stralloc(str);
} else {
- /*
- * Allocate maximum possible string length.
- * (a string of all quotes plus room for leading ", trailing " and NULL)
- */
- ret = s = alloc((strlen(str) * 2) + 2 + 1);
- *(s++) = '"';
- while (*str != '\0') {
- if (*str == '\t') {
- *(s++) = '\\';
- *(s++) = 't';
- str++;
- continue;
- } else if (*str == '\n') {
- *(s++) = '\\';
- *(s++) = 'n';
- str++;
- continue;
- } else if (*str == '\r') {
- *(s++) = '\\';
- *(s++) = 'r';
- str++;
- continue;
- } else if (*str == '\f') {
- *(s++) = '\\';
- *(s++) = 'f';
- str++;
- continue;
- } else if (*str == '\\') {
- *(s++) = '\\';
- *(s++) = '\\';
- str++;
- continue;
- }
- if (*str == '"')
- *(s++) = '\\';
- *(s++) = *(str++);
+ const char *r;
+ for (r = str; *r; r++) {
+ if (*r == ':' || *r == '\'' || *r == '\\' || *r == '\"' ||
+ *r <= ' ' || *r == 0x7F )
+ always = 1;
+ }
+ if (!always) {
+ /*
+ * String does not need to be quoted since it contains
+ * neither whitespace, control or quote characters.
+ */
+ ret = stralloc(str);
+ } else {
+ /*
+ * Allocate maximum possible string length.
+ * (a string of all quotes plus room for leading ", trailing " and
+ * NULL)
+ */
+ ret = s = alloc((strlen(str) * 2) + 2 + 1);
+ *(s++) = '"';
+ while (*str != '\0') {
+ if (*str == '\t') {
+ *(s++) = '\\';
+ *(s++) = 't';
+ str++;
+ continue;
+ } else if (*str == '\n') {
+ *(s++) = '\\';
+ *(s++) = 'n';
+ str++;
+ continue;
+ } else if (*str == '\r') {
+ *(s++) = '\\';
+ *(s++) = 'r';
+ str++;
+ continue;
+ } else if (*str == '\f') {
+ *(s++) = '\\';
+ *(s++) = 'f';
+ str++;
+ continue;
+ } else if (*str == '\\') {
+ *(s++) = '\\';
+ *(s++) = '\\';
+ str++;
+ continue;
+ }
+ if (*str == '"')
+ *(s++) = '\\';
+ *(s++) = *(str++);
+ }
+ *(s++) = '"';
+ *s = '\0';
}
- *(s++) = '"';
- *s = '\0';
+ }
+ return (ret);
+}
+
+
+int
+len_quote_string_maybe(
+ const char *str,
+ gboolean always)
+{
+ int ret;
+
+ if ((str == NULL) || (*str == '\0')) {
+ ret = 0;
+ } else {
+ const char *r;
+ for (r = str; *r; r++) {
+ if (*r == ':' || *r == '\'' || *r == '\\' || *r == '\"' ||
+ *r <= ' ' || *r == 0x7F )
+ always = 1;
+ }
+ if (!always) {
+ /*
+ * String does not need to be quoted since it contains
+ * neither whitespace, control or quote characters.
+ */
+ ret = strlen(str);
+ } else {
+ /*
+ * Allocate maximum possible string length.
+ * (a string of all quotes plus room for leading ", trailing " and
+ * NULL)
+ */
+ ret = 1;
+ while (*str != '\0') {
+ if (*str == '\t') {
+ ret++;
+ ret++;
+ str++;
+ continue;
+ } else if (*str == '\n') {
+ ret++;
+ ret++;
+ str++;
+ continue;
+ } else if (*str == '\r') {
+ ret++;
+ ret++;
+ str++;
+ continue;
+ } else if (*str == '\f') {
+ ret++;
+ ret++;
+ str++;
+ continue;
+ } else if (*str == '\\') {
+ ret++;
+ ret++;
+ str++;
+ continue;
+ }
+ if (*str == '"')
+ ret++;
+ ret++;
+ str++;
+ }
+ ret++;
+ }
}
return (ret);
}
in++;
*(out++) = '\f';
continue;
+ } else if (*in >= '0' && *in <= '7') {
+ char c = 0;
+ int i = 0;
+
+ while (i < 3 && *in >= '0' && *in <= '7') {
+ c = (c << 3) + *(in++) - '0';
+ i++;
+ }
+ if (c)
+ *(out++) = c;
+ } else if (*in == '\0') {
+ /* trailing backslash -- ignore */
+ break;
}
}
*(out++) = *(in++);
return (ret);
}
+gchar **
+split_quoted_strings(
+ const gchar *string)
+{
+ char *local;
+ char *start;
+ char *p;
+ char **result;
+ GPtrArray *strs;
+ int iq = 0;
+
+ if (!string)
+ return NULL;
+
+ p = start = local = g_strdup(string);
+ strs = g_ptr_array_new();
+
+ while (*p) {
+ if (!iq && *p == ' ') {
+ *p = '\0';
+ g_ptr_array_add(strs, unquote_string(start));
+ start = p+1;
+ } else if (*p == '\\') {
+ /* next character is taken literally; if it's a multicharacter
+ * escape (e.g., \171), that doesn't bother us here */
+ p++;
+ if (!*p) break;
+ } else if (*p == '\"') {
+ iq = ! iq;
+ }
+
+ p++;
+ }
+ if (start != string)
+ g_ptr_array_add(strs, unquote_string(start));
+
+ /* now convert strs into a strv, by stealing its references to the underlying
+ * strings */
+ result = g_new0(char *, strs->len + 1);
+ memmove(result, strs->pdata, sizeof(char *) * strs->len);
+
+ g_ptr_array_free(strs, TRUE); /* TRUE => free pdata, strings are not freed */
+ g_free(local);
+
+ return result;
+}
+
+char *
+strquotedstr(char **saveptr)
+{
+ char * tok = strtok_r(NULL, " ", saveptr);
+ size_t len;
+ int in_quote;
+ int in_backslash;
+ char *p, *t;
+
+ if (!tok)
+ return tok;
+ len = strlen(tok);
+ in_quote = 0;
+ in_backslash = 0;
+ p = tok;
+ while (in_quote || in_backslash || *p != '\0') {
+ if (*p == '\0') {
+ /* append a new token */
+ t = strtok_r(NULL, " ", saveptr);
+ if (!t)
+ return NULL;
+ tok[len] = ' ';
+ len = strlen(tok);
+ }
+ if (!in_backslash) {
+ if (*p == '"')
+ in_quote = !in_quote;
+ else if (*p == '\\') {
+ in_backslash = 1;
+ }
+ } else {
+ in_backslash = 0;
+ }
+ p++;
+ }
+ return tok;
+}
+
char *
sanitize_string(
const char *str)
return (ret);
}
+char *hexencode_string(const char *str)
+{
+ size_t orig_len, new_len, i;
+ GString *s;
+ gchar *ret;
+ if (!str) {
+ s = g_string_sized_new(0);
+ goto cleanup;
+ }
+ new_len = orig_len = strlen(str);
+ for (i = 0; i < orig_len; i++) {
+ if (!g_ascii_isalnum(str[i])) {
+ new_len += 2;
+ }
+ }
+ s = g_string_sized_new(new_len);
+
+ for (i = 0; i < orig_len; i++) {
+ if (g_ascii_isalnum(str[i])) {
+ g_string_append_c(s, str[i]);
+ } else {
+ g_string_append_printf(s, "%%%02hhx", str[i]);
+ }
+ }
+
+cleanup:
+ ret = s->str;
+ g_string_free(s, FALSE);
+ return ret;
+}
+
+char *hexdecode_string(const char *str, GError **err)
+{
+ size_t orig_len, new_len, i;
+ GString *s;
+ gchar *ret;
+ if (!str) {
+ s = g_string_sized_new(0);
+ goto cleanup;
+ }
+ new_len = orig_len = strlen(str);
+ for (i = 0; i < orig_len; i++) {
+ if (str[i] == '%') {
+ new_len -= 2;
+ }
+ }
+ s = g_string_sized_new(new_len);
+
+ for (i = 0; (orig_len > 2) && (i < orig_len-2); i++) {
+ if (str[i] == '%') {
+ gchar tmp = 0;
+ size_t j;
+ for (j = 1; j < 3; j++) {
+ tmp <<= 4;
+ if (str[i+j] >= '0' && str[i+j] <= '9') {
+ tmp += str[i+j] - '0';
+ } else if (str[i+j] >= 'a' && str[i+j] <= 'f') {
+ tmp += str[i+j] - 'a' + 10;
+ } else if (str[i+j] >= 'A' && str[i+j] <= 'F') {
+ tmp += str[i+j] - 'A' + 10;
+ } else {
+ /* error */
+ g_set_error(err, am_util_error_quark(), AM_UTIL_ERROR_HEXDECODEINVAL,
+ "Illegal character (non-hex) 0x%02hhx at offset %zd", str[i+j], i+j);
+ g_string_truncate(s, 0);
+ goto cleanup;
+ }
+ }
+ if (!tmp) {
+ g_set_error(err, am_util_error_quark(), AM_UTIL_ERROR_HEXDECODEINVAL,
+ "Encoded NULL at starting offset %zd", i);
+ g_string_truncate(s, 0);
+ goto cleanup;
+ }
+ g_string_append_c(s, tmp);
+ i += 2;
+ } else {
+ g_string_append_c(s, str[i]);
+ }
+ }
+ for ( /*nothing*/; i < orig_len; i++) {
+ if (str[i] == '%') {
+ g_set_error(err, am_util_error_quark(), AM_UTIL_ERROR_HEXDECODEINVAL,
+ "'%%' found at offset %zd, but fewer than two characters follow it (%zd)", i, orig_len-i-1);
+ g_string_truncate(s, 0);
+ goto cleanup;
+ } else {
+ g_string_append_c(s, str[i]);
+ }
+ }
+
+cleanup:
+ ret = s->str;
+ g_string_free(s, FALSE);
+ return ret;
+}
+
+/* Helper for parse_braced_component; this will turn a single element array
+ * matching /^\d+\.\.\d+$/ into a sequence of numbered array elements. */
+static GPtrArray *
+expand_braced_sequence(GPtrArray *arr)
+{
+ char *elt, *p;
+ char *l, *r;
+ int ldigits, rdigits, ndigits;
+ guint64 start, end;
+ gboolean leading_zero;
+
+ /* check whether the element matches the pattern */
+ /* expand last element of the array only */
+ elt = g_ptr_array_index(arr, arr->len-1);
+ ldigits = 0;
+ for (l = p = elt; *p && g_ascii_isdigit(*p); p++)
+ ldigits++;
+ if (ldigits == 0)
+ return arr;
+ if (*(p++) != '.')
+ return arr;
+ if (*(p++) != '.')
+ return arr;
+ rdigits = 0;
+ for (r = p; *p && g_ascii_isdigit(*p); p++)
+ rdigits++;
+ if (rdigits == 0)
+ return arr;
+ if (*p)
+ return arr;
+
+ /* we have a match, so extract start and end */
+ start = g_ascii_strtoull(l, NULL, 10);
+ end = g_ascii_strtoull(r, NULL, 10);
+ leading_zero = *l == '0';
+ ndigits = MAX(ldigits, rdigits);
+ if (start > end)
+ return arr;
+
+ /* sanity check.. */
+ if (end - start > 100000)
+ return arr;
+
+ /* remove last from the array */
+ g_ptr_array_remove_index(arr, arr->len - 1);
+
+ /* Add new elements */
+ while (start <= end) {
+ if (leading_zero) {
+ g_ptr_array_add(arr, g_strdup_printf("%0*ju",
+ ndigits, (uintmax_t)start));
+ } else {
+ g_ptr_array_add(arr, g_strdup_printf("%ju", (uintmax_t)start));
+ }
+ start++;
+ }
+
+ return arr;
+}
+
+/* Helper for expand_braced_alternates; returns a list of un-escaped strings
+ * for the first "component" of str, where a component is a plain string or a
+ * brace-enclosed set of alternatives. str is pointing to the first character
+ * of the next component on return. */
+static GPtrArray *
+parse_braced_component(char **str)
+{
+ GPtrArray *result = g_ptr_array_new();
+
+ if (**str == '{') {
+ char *p = (*str)+1;
+ char *local = g_malloc(strlen(*str)+1);
+ char *current = local;
+ char *c = current;
+
+ while (1) {
+ if (*p == '\0' || *p == '{') {
+ /* unterminated { .. } or extra '{' */
+ amfree(local);
+ g_ptr_array_free(result, TRUE);
+ return NULL;
+ }
+
+ if (*p == '}' || *p == ',') {
+ *c = '\0';
+ g_ptr_array_add(result, g_strdup(current));
+ result = expand_braced_sequence(result);
+ current = ++c;
+
+ if (*p == '}')
+ break;
+ else
+ p++;
+ }
+
+ if (*p == '\\') {
+ if (*(p+1) == '{' || *(p+1) == '}' || *(p+1) == '\\' || *(p+1) == ',')
+ p++;
+ }
+ *(c++) = *(p++);
+ }
+
+ amfree(local);
+
+ if (*p)
+ *str = p+1;
+ else
+ *str = p;
+ } else {
+ /* no braces -- just un-escape a plain string */
+ char *local = g_malloc(strlen(*str)+1);
+ char *r = local;
+ char *p = *str;
+
+ while (*p && *p != '{') {
+ if (*p == '\\') {
+ if (*(p+1) == '{' || *(p+1) == '}' || *(p+1) == '\\' || *(p+1) == ',')
+ p++;
+ }
+ *(r++) = *(p++);
+ }
+ *r = '\0';
+ g_ptr_array_add(result, local);
+ *str = p;
+ }
+
+ return result;
+}
+
+GPtrArray *
+expand_braced_alternates(
+ char * source)
+{
+ GPtrArray *rval = g_ptr_array_new();
+
+ g_ptr_array_add(rval, g_strdup(""));
+
+ while (*source) {
+ GPtrArray *new_components;
+ GPtrArray *new_rval;
+ guint i, j;
+
+ new_components = parse_braced_component(&source);
+ if (!new_components) {
+ /* parse error */
+ g_ptr_array_free(rval, TRUE);
+ return NULL;
+ }
+
+ new_rval = g_ptr_array_new();
+
+ /* do a cartesian join of rval and new_components */
+ for (i = 0; i < rval->len; i++) {
+ for (j = 0; j < new_components->len; j++) {
+ g_ptr_array_add(new_rval, g_strconcat(
+ g_ptr_array_index(rval, i),
+ g_ptr_array_index(new_components, j),
+ NULL));
+ }
+ }
+
+ g_ptr_array_free(rval, TRUE);
+ g_ptr_array_free(new_components, TRUE);
+ rval = new_rval;
+ }
+
+ return rval;
+}
+
+char *
+collapse_braced_alternates(
+ GPtrArray *source)
+{
+ GString *result = NULL;
+ guint i;
+
+ result = g_string_new("{");
+
+ for (i = 0; i < source->len; i ++) {
+ const char *str = g_ptr_array_index(source, i);
+ char *qstr = NULL;
+
+ if (strchr(str, ',') || strchr(str, '\\') ||
+ strchr(str, '{') || strchr(str, '}')) {
+ const char *s;
+ char *d;
+
+ s = str;
+ qstr = d = g_malloc(strlen(str)*2+1);
+ while (*s) {
+ if (*s == ',' || *s == '\\' || *s == '{' || *s == '}')
+ *(d++) = '\\';
+ *(d++) = *(s++);
+ }
+ *(d++) = '\0';
+ }
+ g_string_append_printf(result, "%s%s", qstr? qstr : str,
+ (i < source->len-1)? "," : "");
+ if (qstr)
+ g_free(qstr);
+ }
+
+ g_string_append(result, "}");
+ return g_string_free(result, FALSE);
+}
+
/*
Return 0 if the following characters are present
* ( ) < > [ ] , ; : ! $ \ / "
{
int infd, outfd;
int save_errno;
- ssize_t nb;
+ size_t nb;
char buf[32768];
char *quoted;
}
while((nb=read(infd, &buf, SIZEOF(buf))) > 0) {
- if(fullwrite(outfd,&buf,(size_t)nb) < nb) {
+ if(full_write(outfd,&buf,nb) < nb) {
save_errno = errno;
quoted = quote_string(dst);
*errmsg = vstrallocf(_("Error writing to '%s': %s"),
}
}
- if (nb < 0) {
+ if (errno != 0) {
save_errno = errno;
quoted = quote_string(src);
*errmsg = vstrallocf(_("Error reading from '%s': %s"),
return 0;
}
-#ifndef HAVE_READLINE
+#ifndef HAVE_LIBREADLINE
/*
* simple readline() replacements, used when we don't have readline
* support from the system.
}
}
-gboolean amanda_thread_init(void) {
- gboolean success = FALSE;
-#ifdef HAVE_LIBCURL
- static gboolean did_curl_init = FALSE;
- if (!did_curl_init) {
-# ifdef G_THREADS_ENABLED
- g_assert(!g_thread_supported());
-# endif
- g_assert(curl_global_init(CURL_GLOBAL_ALL) == 0);
- did_curl_init = TRUE;
- }
-#endif
-#if defined(G_THREADS_ENABLED) && !defined(G_THREADS_IMPL_NONE)
- if (g_thread_supported()) {
- return TRUE;
- }
- g_thread_init(NULL);
- success = TRUE;
-#endif
- return success;
-}
-
int
resolve_hostname(const char *hostname,
int socktype,
#endif
memset(&hints, 0, sizeof(hints));
+#ifdef WORKING_IPV6
+ /* get any kind of addresss */
hints.ai_family = AF_UNSPEC;
+#else
+ /* even if getaddrinfo supports IPv6, don't let it return
+ * such an address */
+ hints.ai_family = AF_INET;
+#endif
hints.ai_flags = flags;
hints.ai_socktype = socktype;
result = getaddrinfo(hostname, NULL, &hints, &myres);
#endif
switch (who & RUNNING_AS_USER_MASK) {
+ case RUNNING_AS_ANY:
+ uid_target = uid_me;
+ uname_target = uname_me;
+ amfree(uname_me);
+ return;
+
case RUNNING_AS_ROOT:
uid_target = 0;
uname_target = "root";
set_root_privs(int need_root)
{
#ifndef SINGLE_USERID
- if (need_root) {
+ static gboolean first_call = TRUE;
+ static uid_t unpriv = 1;
+
+ if (first_call) {
+ /* save the original real userid (that of our invoker) */
+ unpriv = getuid();
+
+ /* and set all of our userids (including, importantly, the saved
+ * userid) to 0 */
+ setuid(0);
+
+ /* don't need to do this next time */
+ first_call = FALSE;
+ }
+
+ if (need_root == 1) {
+ if (geteuid() == 0) return 1; /* already done */
+
if (seteuid(0) == -1) return 0;
/* (we don't switch the group back) */
+ } else if (need_root == -1) {
+ /* make sure the euid is 0 so that we can set the uid */
+ if (geteuid() != 0) {
+ if (seteuid(0) == -1) return 0;
+ }
+
+ /* now set the uid to the unprivileged userid */
+ if (setuid(unpriv) == -1) return 0;
} else {
- if (geteuid() != 0) return 0;
- if (seteuid(getuid()) == -1) return 0;
+ if (geteuid() != 0) return 1; /* already done */
+
+ /* set the *effective* userid only */
+ if (seteuid(unpriv) == -1) return 0;
if (setegid(getgid()) == -1) return 0;
}
#else
become_root(void)
{
#ifndef SINGLE_USERID
+ /* first, set the effective userid to 0 */
+ if (seteuid(0) == -1) return 0;
+
+ /* then, set all of the userids to 0 */
if (setuid(0) == -1) return 0;
#endif
return 1;
}
+char *
+base64_decode_alloc_string(
+ char *in)
+{
+ char *out;
+ size_t in_len = strlen(in);
+ size_t out_len = 3 * (in_len / 4) + 3;
+
+ out = malloc(out_len);
+ if (!base64_decode(in, in_len, out, &out_len)) {
+ amfree(out);
+ return NULL;
+ }
+ out[out_len] = '\0';
+
+ return out;
+}
+
+
+/* A GHFunc (callback for g_hash_table_foreach),
+ * Store a property and it's value in an ARGV.
+ *
+ * @param key_p: (char *) property name.
+ * @param value_p: (GSList *) property values list.
+ * @param user_data_p: (char ***) pointer to ARGV.
+ */
+static void
+proplist_add_to_argv(
+ gpointer key_p,
+ gpointer value_p,
+ gpointer user_data_p)
+{
+ char *property_s = key_p;
+ property_t *value_s = value_p;
+ GPtrArray *argv_ptr = user_data_p;
+ GSList *value;
+ char *q, *w, *qprop;
+
+ q = stralloc(property_s);
+ /* convert to lower case */
+ for (w=q; *w != '\0'; w++) {
+ *w = tolower(*w);
+ if (*w == '_')
+ *w = '-';
+ }
+ qprop = stralloc2("--", q);
+ amfree(q);
+ for(value=value_s->values; value != NULL; value = value->next) {
+ g_ptr_array_add(argv_ptr, stralloc(qprop));
+ g_ptr_array_add(argv_ptr, stralloc((char *)value->data));
+ }
+ amfree(qprop);
+}
+
+void
+property_add_to_argv(
+ GPtrArray *argv_ptr,
+ GHashTable *proplist)
+{
+ g_hash_table_foreach(proplist, &proplist_add_to_argv, argv_ptr);
+}
+
+
/*
* Process parameters
*/
-/* current process name */
-#define MAX_PNAME 128
-static char pname[MAX_PNAME] = "unknown";
+static char *pname = NULL;
+static char *ptype = NULL;
+static pcontext_t pcontext = CONTEXT_DEFAULT;
void
set_pname(char *p)
{
- g_strlcpy(pname, p, sizeof(pname));
+ pname = newstralloc(pname, p);
}
char *
get_pname(void)
{
+ if (!pname) pname = stralloc("unknown");
return pname;
}
+void
+set_ptype(char *p)
+{
+ ptype = newstralloc(ptype, p);
+}
+
+char *
+get_ptype(void)
+{
+ if (!ptype) ptype = stralloc("unknown");
+ return ptype;
+}
+
+void
+set_pcontext(pcontext_t pc)
+{
+ pcontext = pc;
+}
+
+pcontext_t
+get_pcontext(void)
+{
+ return pcontext;
+}
+
+#ifdef __OpenBSD__
+void
+openbsd_fd_inform(void)
+{
+ int i;
+ for (i = DATA_FD_OFFSET; i < DATA_FD_OFFSET + DATA_FD_COUNT*2; i++) {
+ /* a simple fcntl() will cause the library to "look" at this file
+ * descriptor, which is good enough */
+ (void)fcntl(i, F_GETFL);
+ }
+}
+#endif
+
+void
+debug_executing(
+ GPtrArray *argv_ptr)
+{
+ guint i;
+ char *cmdline = stralloc((char *)g_ptr_array_index(argv_ptr, 0));
+
+ for (i = 1; i < argv_ptr->len-1; i++) {
+ char *arg = g_shell_quote((char *)g_ptr_array_index(argv_ptr, i));
+ cmdline = vstrextend(&cmdline, " ", arg, NULL);
+ amfree(arg);
+ }
+ g_debug("Executing: %s\n", cmdline);
+ amfree(cmdline);
+}
+
+char *
+get_first_line(
+ GPtrArray *argv_ptr)
+{
+ char *output_string = NULL;
+ int inpipe[2], outpipe[2], errpipe[2];
+ int pid;
+ FILE *out, *err;
+
+ assert(argv_ptr != NULL);
+ assert(argv_ptr->pdata != NULL);
+ assert(argv_ptr->len >= 1);
+
+ if (pipe(inpipe) == -1) {
+ error(_("error [open pipe: %s]"), strerror(errno));
+ /*NOTREACHED*/
+ }
+ if (pipe(outpipe) == -1) {
+ error(_("error [open pipe: %s]"), strerror(errno));
+ /*NOTREACHED*/
+ }
+ if (pipe(errpipe) == -1) {
+ error(_("error [open pipe: %s]"), strerror(errno));
+ /*NOTREACHED*/
+ }
+
+ fflush(stdout);
+ switch(pid = fork()) {
+ case -1:
+ error(_("error [fork: %s]"), strerror(errno));
+ /*NOTREACHED*/
+
+ default: /* parent process */
+ aclose(inpipe[0]);
+ aclose(outpipe[1]);
+ aclose(errpipe[1]);
+ break;
+
+ case 0: /* child process */
+ aclose(inpipe[1]);
+ aclose(outpipe[0]);
+ aclose(errpipe[0]);
+
+ dup2(inpipe[0], 0);
+ dup2(outpipe[1], 1);
+ dup2(errpipe[1], 2);
+
+ debug_executing(argv_ptr);
+ g_fprintf(stdout, "unknown\n");
+ execv((char *)*argv_ptr->pdata, (char **)argv_ptr->pdata);
+ error(_("error [exec %s: %s]"), (char *)*argv_ptr->pdata, strerror(errno));
+ }
+
+ aclose(inpipe[1]);
+
+ out = fdopen(outpipe[0],"r");
+ err = fdopen(errpipe[0],"r");
+
+ output_string = agets(out);
+ if (!output_string)
+ output_string = agets(err);
+
+ fclose(out);
+ fclose(err);
+
+ waitpid(pid, NULL, 0);
+
+ return output_string;
+}
+