X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=common-src%2Futil.c;h=1c1856a94119e3bddd34cc8fbdbc83454e5c7070;hb=21170aaf9015a4c519265834456fc309932f24c0;hp=bb27cfac0618d1af986bd06eae9a231d61111a0e;hpb=ac973066bc508cb82728e46eaf499e9424d4e0f1;p=debian%2Famanda diff --git a/common-src/util.c b/common-src/util.c index bb27cfa..1c1856a 100644 --- a/common-src/util.c +++ b/common-src/util.c @@ -29,82 +29,16 @@ #include "amanda.h" #include "util.h" +#include #include "arglist.h" #include "clock.h" - -/*#define NET_READ_DEBUG*/ - -#ifdef NET_READ_DEBUG -#define netprintf(x) dbprintf(x) -#else -#define netprintf(x) -#endif +#include "sockaddr-util.h" +#include "conffile.h" +#include "base64.h" static int make_socket(sa_family_t family); -static int connect_port(struct sockaddr_storage *addrp, in_port_t port, char *proto, - struct sockaddr_storage *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 connect_port(sockaddr_union *addrp, in_port_t port, char *proto, + sockaddr_union *svaddr, int nonblock); static int make_socket( @@ -117,12 +51,11 @@ make_socket( 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; - dbprintf(("%s: make_socket: socket() failed: %s\n", - debug_prefix_time(NULL), - strerror(save_errno))); + dbprintf(_("make_socket: socket() failed: %s\n"), strerror(save_errno)); errno = save_errno; return -1; } @@ -136,9 +69,8 @@ make_socket( r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (r < 0) { save_errno = errno; - dbprintf(("%s: stream_server: setsockopt(SO_REUSEADDR) failed: %s\n", - debug_prefix_time(NULL), - strerror(errno))); + dbprintf(_("make_socket: setsockopt(SO_REUSEADDR) failed: %s\n"), + strerror(errno)); errno = save_errno; } #endif @@ -148,9 +80,8 @@ make_socket( (void *)&on, SIZEOF(on)); if (r == -1) { save_errno = errno; - dbprintf(("%s: make_socket: setsockopt() failed: %s\n", - debug_prefix_time(NULL), - strerror(save_errno))); + dbprintf(_("make_socket: setsockopt() failed: %s\n"), + strerror(save_errno)); aclose(s); errno = save_errno; return -1; @@ -166,11 +97,11 @@ make_socket( /* return -1 on failure */ int connect_portrange( - struct sockaddr_storage *addrp, + sockaddr_union *addrp, in_port_t first_port, in_port_t last_port, char * proto, - struct sockaddr_storage *svaddr, + sockaddr_union *svaddr, int nonblock) { int s; @@ -178,6 +109,7 @@ connect_portrange( static in_port_t port_in_use[1024]; static int nb_port_in_use = 0; int i; + int save_errno = EAGAIN; assert(first_port <= last_port); /* Try a port already used */ @@ -189,6 +121,8 @@ connect_portrange( if(s > 0) { return s; } + if (errno != EAGAIN && errno != EBUSY) + save_errno = errno; } } @@ -200,13 +134,14 @@ connect_portrange( port_in_use[nb_port_in_use++] = port; return s; } + if (errno != EAGAIN && errno != EBUSY) + save_errno = errno; } - dbprintf(("%s: connect_portrange: all ports between %d and %d busy\n", - debug_prefix_time(NULL), + dbprintf(_("connect_portrange: All ports between %d and %d are busy.\n"), first_port, - last_port)); - errno = EAGAIN; + last_port); + errno = save_errno; return -1; } @@ -217,58 +152,62 @@ connect_portrange( /* return >0: this is the connected socket */ int connect_port( - struct sockaddr_storage *addrp, + sockaddr_union *addrp, in_port_t port, char * proto, - struct sockaddr_storage *svaddr, + sockaddr_union *svaddr, int nonblock) { int save_errno; struct servent * servPort; - socklen_t len; - socklen_t socklen; + socklen_t_equiv len; + socklen_t_equiv socklen; int s; servPort = getservbyport((int)htons(port), proto); if (servPort != NULL && !strstr(servPort->s_name, "amanda")) { - dbprintf(("%s: connect_port: Skip port %d: Owned by %s.\n", - debug_prefix_time(NULL), port, servPort->s_name)); + dbprintf(_("connect_port: Skip port %d: owned by %s.\n"), + port, servPort->s_name); + errno = EBUSY; return -1; } - if(servPort == NULL) - dbprintf(("%s: connect_port: Try port %d: Available - \n", - debug_prefix_time(NULL), port)); - else { - dbprintf(("%s: connect_port: Try port %d: Owned by %s - \n", - debug_prefix_time(NULL), port, servPort->s_name)); - } + if ((s = make_socket(SU_GET_FAMILY(addrp))) == -1) return -2; - if ((s = make_socket(addrp->ss_family)) == -1) return -2; - - SS_SET_PORT(addrp, port); + SU_SET_PORT(addrp, port); socklen = SS_LEN(addrp); if (bind(s, (struct sockaddr *)addrp, socklen) != 0) { save_errno = errno; aclose(s); + if(servPort == NULL) { + dbprintf(_("connect_port: Try port %d: available - %s\n"), + port, strerror(errno)); + } else { + dbprintf(_("connect_port: Try port %d: owned by %s - %s\n"), + port, servPort->s_name, strerror(errno)); + } if (save_errno != EADDRINUSE) { - dbprintf(("errno %d strerror %s\n", - errno, strerror(errno))); errno = save_errno; return -2; } + errno = save_errno; return -1; } + if(servPort == NULL) { + dbprintf(_("connect_port: Try port %d: available - Success\n"), port); + } else { + dbprintf(_("connect_port: Try port %d: owned by %s - Success\n"), + port, servPort->s_name); + } /* find out what port was actually used */ len = sizeof(*addrp); if (getsockname(s, (struct sockaddr *)addrp, &len) == -1) { save_errno = errno; - dbprintf(("%s: connect_port: getsockname() failed: %s\n", - debug_prefix_time(NULL), - strerror(save_errno))); + dbprintf(_("connect_port: getsockname() failed: %s\n"), + strerror(save_errno)); aclose(s); errno = save_errno; return -1; @@ -278,14 +217,12 @@ connect_port( fcntl(s, F_SETFL, fcntl(s, F_GETFL, 0)|O_NONBLOCK); if (connect(s, (struct sockaddr *)svaddr, SS_LEN(svaddr)) == -1 && !nonblock) { save_errno = errno; - dbprintf(("%s: connect_portrange: connect from %s failed: %s\n", - debug_prefix_time(NULL), + dbprintf(_("connect_portrange: Connect from %s failed: %s\n"), str_sockaddr(addrp), - strerror(save_errno))); - dbprintf(("%s: connect_portrange: connect to %s failed: %s\n", - debug_prefix_time(NULL), + strerror(save_errno)); + dbprintf(_("connect_portrange: connect to %s failed: %s\n"), str_sockaddr(svaddr), - strerror(save_errno))); + strerror(save_errno)); aclose(s); errno = save_errno; if (save_errno == ECONNREFUSED || @@ -297,12 +234,10 @@ connect_port( return -1; } - dbprintf(("%s: connected to %s\n", - debug_prefix_time(NULL), - str_sockaddr(svaddr))); - dbprintf(("%s: our side is %s\n", - debug_prefix_time(NULL), - str_sockaddr(addrp))); + dbprintf(_("connected to %s\n"), + str_sockaddr(svaddr)); + dbprintf(_("our side is %s\n"), + str_sockaddr(addrp)); return s; } @@ -316,16 +251,17 @@ connect_port( int bind_portrange( int s, - struct sockaddr_storage *addrp, + sockaddr_union *addrp, in_port_t first_port, in_port_t last_port, char * proto) { in_port_t port; in_port_t cnt; - socklen_t socklen; + socklen_t_equiv socklen; struct servent *servPort; const in_port_t num_ports = (in_port_t)(last_port - first_port + 1); + int save_errno = EAGAIN; assert(first_port <= last_port); @@ -343,85 +279,87 @@ bind_portrange( for (cnt = 0; cnt < num_ports; cnt++) { servPort = getservbyport((int)htons(port), proto); if ((servPort == NULL) || strstr(servPort->s_name, "amanda")) { - if (servPort == NULL) { - dbprintf(("%s: bind_portrange2: Try port %d: Available - ", - debug_prefix_time(NULL), port)); - } else { - dbprintf(("%s: bind_portrange2: Try port %d: Owned by %s - ", - debug_prefix_time(NULL), port, servPort->s_name)); - } - SS_SET_PORT(addrp, port); + SU_SET_PORT(addrp, port); socklen = SS_LEN(addrp); if (bind(s, (struct sockaddr *)addrp, socklen) >= 0) { - dbprintf(("Success\n")); + if (servPort == NULL) { + dbprintf(_("bind_portrange2: Try port %d: Available - Success\n"), port); + } else { + dbprintf(_("bind_portrange2: Try port %d: Owned by %s - Success.\n"), port, servPort->s_name); + } return 0; } - dbprintf(("%s\n", strerror(errno))); + if (errno != EAGAIN && errno != EBUSY) + save_errno = errno; + if (servPort == NULL) { + dbprintf(_("bind_portrange2: Try port %d: Available - %s\n"), + port, strerror(errno)); + } else { + dbprintf(_("bind_portrange2: Try port %d: Owned by %s - %s\n"), + port, servPort->s_name, strerror(errno)); + } } else { - dbprintf(("%s: bind_portrange2: Skip port %d: Owned by %s.\n", - debug_prefix_time(NULL), port, servPort->s_name)); + dbprintf(_("bind_portrange2: Skip port %d: Owned by %s.\n"), + port, servPort->s_name); } if (++port > last_port) port = first_port; } - dbprintf(("%s: bind_portrange: all ports between %d and %d busy\n", - debug_prefix_time(NULL), + dbprintf(_("bind_portrange: all ports between %d and %d busy\n"), first_port, - last_port)); - errno = EAGAIN; + last_port); + errno = save_errno; return -1; } /* - * Construct a datestamp (YYYYMMDD) from a time_t. + * Writes out the entire iovec */ -char * -construct_datestamp( - time_t *t) +ssize_t +full_writev( + int fd, + struct iovec * iov, + int iovcnt) { - struct tm *tm; - char datestamp[3 * NUM_STR_SIZE]; - time_t when; + ssize_t delta, n, total; - if (t == NULL) { - when = time((time_t *)NULL); - } else { - when = *t; - } - tm = localtime(&when); - if (!tm) - return stralloc("19000101"); - - snprintf(datestamp, SIZEOF(datestamp), - "%04d%02d%02d", tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday); - return stralloc(datestamp); -} + assert(iov != NULL); -/* - * Construct a timestamp (YYYYMMDDHHMMSS) from a time_t. - */ -char * -construct_timestamp( - time_t *t) -{ - struct tm *tm; - char timestamp[6 * NUM_STR_SIZE]; - time_t when; - - if (t == NULL) { - when = time((time_t *)NULL); - } else { - when = *t; + 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; + } + } } - tm = localtime(&when); - if (!tm) - return stralloc("19000101000000"); - - snprintf(timestamp, SIZEOF(timestamp), - "%04d%02d%02d%02d%02d%02d", - tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); - return stralloc(timestamp); + return (total); } @@ -447,7 +385,7 @@ quote_string( if ((str == NULL) || (*str == '\0')) { ret = stralloc("\"\""); - } else if ((match("[\\\"[:space:][:cntrl:]]", str)) == 0) { + } else if ((match("[:\'\\\"[:space:][:cntrl:]]", str)) == 0) { /* * String does not need to be quoted since it contains * neither whitespace, control or quote characters. @@ -535,6 +473,19 @@ unquote_string( 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++); @@ -544,62 +495,102 @@ unquote_string( return (ret); } -char * -sanitize_string( - const char *str) +gchar ** +split_quoted_strings( + const gchar *string) { - char * s; - char * ret; - - if ((str == NULL) || (*str == '\0')) { - ret = stralloc(""); - } else { - ret = stralloc(str); - for (s = ret; *s != '\0'; s++) { - if (iscntrl(*s)) - *s = '?'; + char *local = g_strdup(string); + char *start = local; + char *p = local; + char **result; + GPtrArray *strs = g_ptr_array_new(); + int iq = 0; + + 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++; } - return (ret); + 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, FALSE); /* FALSE => don't free strings */ + g_free(local); + + return result; } char * -strquotedstr(void) +strquotedstr(char **saveptr) { - char * tok = strtok(NULL, " "); - - if ((tok != NULL) && (tok[0] == '"')) { - char * t; - size_t len; - - len = strlen(tok); - do { - t = strtok(NULL, " "); + 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); - } while ((t != NULL) && - (tok[len - 1] != '"') && (tok[len - 2] != '\\')); + } + if (!in_backslash) { + if (*p == '"') + in_quote = !in_quote; + else if (*p == '\\') { + in_backslash = 1; + } + } else { + in_backslash = 0; + } + p++; } return tok; } -ssize_t -hexdump( - const char *buffer, - size_t len) +char * +sanitize_string( + const char *str) { - ssize_t rc = -1; + char * s; + char * ret; - FILE *stream = popen("od -c -x -", "w"); - - if (stream != NULL) { - fflush(stdout); - rc = (ssize_t)fwrite(buffer, len, 1, stream); - if (ferror(stream)) - rc = -1; - pclose(stream); + if ((str == NULL) || (*str == '\0')) { + ret = stralloc(""); + } else { + ret = stralloc(str); + for (s = ret; *s != '\0'; s++) { + if (iscntrl((int)*s)) + *s = '?'; + } } - return rc; + return (ret); } /* @@ -615,138 +606,6 @@ validate_mailto( return !match("\\*|<|>|\\(|\\)|\\[|\\]|,|;|:|\\\\|/|\"|\\!|\\$|\\|", mailto); } - -void -dump_sockaddr( - struct sockaddr_storage *sa) -{ -#ifdef WORKING_IPV6 - char ipstr[INET6_ADDRSTRLEN]; -#else - char ipstr[INET_ADDRSTRLEN]; -#endif - int port; - - port = SS_GET_PORT(sa); -#ifdef WORKING_IPV6 - if ( sa->ss_family == (sa_family_t)AF_INET6) { - inet_ntop(AF_INET6, &((struct sockaddr_in6 *)sa)->sin6_addr, - ipstr, sizeof(ipstr)); - dbprintf(("%s: (sockaddr_in6 *)%p = { %d, %d, %s }\n", - debug_prefix_time(NULL), sa, - ((struct sockaddr_in6 *)sa)->sin6_family, - port, - ipstr)); - } else -#endif - { - inet_ntop(AF_INET, &((struct sockaddr_in *)sa)->sin_addr, ipstr, - sizeof(ipstr)); - dbprintf(("%s: (sockaddr_in *)%p = { %d, %d, %s }\n", - debug_prefix_time(NULL), sa, - ((struct sockaddr_in *)sa)->sin_family, - port, - ipstr)); - } -} - - -#ifdef WORKING_IPV6 -static char mystr_sockaddr[INET6_ADDRSTRLEN + 20]; -#else -static char mystr_sockaddr[INET_ADDRSTRLEN + 20]; -#endif - -char * -str_sockaddr( - struct sockaddr_storage *sa) -{ -#ifdef WORKING_IPV6 - char ipstr[INET6_ADDRSTRLEN]; -#else - char ipstr[INET_ADDRSTRLEN]; -#endif - int port; - - port = SS_GET_PORT(sa); -#ifdef WORKING_IPV6 - if ( sa->ss_family == (sa_family_t)AF_INET6) { - inet_ntop(AF_INET6, &((struct sockaddr_in6 *)sa)->sin6_addr, - ipstr, sizeof(ipstr)); - } else -#endif - { - inet_ntop(AF_INET, &((struct sockaddr_in *)sa)->sin_addr, ipstr, - sizeof(ipstr)); - } - snprintf(mystr_sockaddr,sizeof(mystr_sockaddr),"%s.%d", ipstr, port); - return mystr_sockaddr; -} - - -int -cmp_sockaddr( - struct sockaddr_storage *ss1, - struct sockaddr_storage *ss2, - int addr_only) -{ - /* if addresses are v4mapped, "unmap" them */ -#ifdef WORKING_IPV6 -#ifdef IN6_IS_ADDR_V4MAPPED - struct sockaddr_in ss1_v4; - struct sockaddr_in ss2_v4; - - if (ss1->ss_family == AF_INET6 && - IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss1)->sin6_addr)) { - memset(&ss1_v4, 0, sizeof(struct sockaddr_in)); - memcpy(&ss1_v4.sin_addr.s_addr, - &(((struct sockaddr_in6 *)ss1)->sin6_addr.s6_addr[12]), - sizeof(struct in_addr)); - ss1_v4.sin_family = AF_INET; - SS_SET_PORT((struct sockaddr_storage *)&ss1_v4, SS_GET_PORT(ss1)); - ss1 = (struct sockaddr_storage *)&ss1_v4; - } - - if (ss2->ss_family == AF_INET6 && - IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss2)->sin6_addr)) { - memset(&ss2_v4, 0, sizeof(struct sockaddr_in)); - memcpy(&ss2_v4.sin_addr.s_addr, - &(((struct sockaddr_in6 *)ss2)->sin6_addr.s6_addr[12]), - sizeof(struct in_addr)); - ss2_v4.sin_family = AF_INET; - SS_SET_PORT((struct sockaddr_storage *)&ss2_v4, SS_GET_PORT(ss2)); - ss2 = (struct sockaddr_storage *)&ss2_v4; - } -#endif -#endif - - if (ss1->ss_family == ss2->ss_family) { - if (addr_only) { -#ifdef WORKING_IPV6 - if(ss1->ss_family == (sa_family_t)AF_INET6) - return memcmp( - &((struct sockaddr_in6 *)ss1)->sin6_addr, - &((struct sockaddr_in6 *)ss2)->sin6_addr, - sizeof(((struct sockaddr_in6 *)ss1)->sin6_addr)); - else -#endif - return memcmp( - &((struct sockaddr_in *)ss1)->sin_addr, - &((struct sockaddr_in *)ss2)->sin_addr, - sizeof(((struct sockaddr_in *)ss1)->sin_addr)); - } else { - return memcmp(ss1, ss2, SS_LEN(ss1)); - } - } else { - /* compare families to give a total order */ - if (ss1->ss_family < ss2->ss_family) - return -1; - else - return 1; - } -} - - int copy_file( char *dst, char *src, @@ -754,15 +613,15 @@ int copy_file( { int infd, outfd; int save_errno; - ssize_t nb; + size_t nb; char buf[32768]; char *quoted; if ((infd = open(src, O_RDONLY)) == -1) { save_errno = errno; quoted = quote_string(src); - *errmsg = vstralloc("Can't open file ", quoted, " for reading: %s", - strerror(save_errno), NULL); + *errmsg = vstrallocf(_("Can't open file '%s' for reading: %s"), + quoted, strerror(save_errno)); amfree(quoted); return -1; } @@ -770,19 +629,19 @@ int copy_file( if ((outfd = open(dst, O_WRONLY|O_CREAT, 0600)) == -1) { save_errno = errno; quoted = quote_string(dst); - *errmsg = vstralloc("Can't open file ", quoted, " for writting: %s", - strerror(save_errno), NULL); + *errmsg = vstrallocf(_("Can't open file '%s' for writting: %s"), + quoted, strerror(save_errno)); amfree(quoted); close(infd); return -1; } 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 = vstralloc("Error writing to \"", quoted, "\":", - strerror(save_errno), NULL); + *errmsg = vstrallocf(_("Error writing to '%s': %s"), + quoted, strerror(save_errno)); amfree(quoted); close(infd); close(outfd); @@ -790,11 +649,11 @@ int copy_file( } } - if (nb < 0) { + if (errno != 0) { save_errno = errno; quoted = quote_string(src); - *errmsg = vstralloc("Error reading from \"", quoted, "\":", - strerror(save_errno), NULL); + *errmsg = vstrallocf(_("Error reading from '%s': %s"), + quoted, strerror(save_errno)); amfree(quoted); close(infd); close(outfd); @@ -805,16 +664,18 @@ int copy_file( close(outfd); return 0; } -#ifndef HAVE_LIBREADLINE + +#ifndef HAVE_READLINE /* - * simple readline() replacements + * simple readline() replacements, used when we don't have readline + * support from the system. */ char * readline( const char *prompt) { - printf("%s", prompt); + g_printf("%s", prompt); fflush(stdout); fflush(stderr); return agets(stdin); @@ -824,6 +685,428 @@ void add_history( const char *line) { - (void)line; /* Quite unused parameter warning */ + (void)line; /* Quiet unused parameter warning */ +} + +#endif + +/* Order of preference: readdir64(), readdir(). */ +#if HAVE_DECL_READDIR64 +# define USE_DIRENT64 +# define USE_READDIR64 +#elif HAVE_DECL_READDIR +# define USE_READDIR +#else +# error No readdir() or readdir64() available! +#endif + +char * portable_readdir(DIR* handle) { + +#ifdef USE_DIRENT64 + struct dirent64 *entry_p; +#else + struct dirent *entry_p; +#endif + + static GStaticMutex mutex = G_STATIC_MUTEX_INIT; + + g_static_mutex_lock(&mutex); + +#ifdef USE_READDIR + entry_p = readdir(handle); +#endif +#ifdef USE_READDIR64 + entry_p = readdir64(handle); +#endif + + g_static_mutex_unlock(&mutex); + + if (entry_p == NULL) + return NULL; + + /* FIXME: According to glibc documentation, d_name may not be + null-terminated in some cases on some very old platforms. Not + sure what to do about that case. */ + return strdup(entry_p->d_name); +} + +int search_directory(DIR * handle, const char * regex, + SearchDirectoryFunctor functor, gpointer user_data) { + int rval = 0; + regex_t compiled_regex; + gboolean done = FALSE; + + if (regcomp(&compiled_regex, regex, REG_EXTENDED | REG_NOSUB) != 0) { + regfree(&compiled_regex); + return -1; + } + + rewinddir(handle); + + while (!done) { + char * read_name; + int result; + read_name = portable_readdir(handle); + if (read_name == NULL) { + regfree(&compiled_regex); + return rval; + } + result = regexec(&compiled_regex, read_name, 0, NULL, 0); + if (result == 0) { + rval ++; + done = !functor(read_name, user_data); + } + amfree(read_name); + } + regfree(&compiled_regex); + return rval; +} + +char* find_regex_substring(const char* base_string, const regmatch_t match) { + char * rval; + int size; + + size = match.rm_eo - match.rm_so; + rval = malloc(size+1); + memcpy(rval, base_string + match.rm_so, size); + rval[size] = '\0'; + + return rval; +} + +int compare_possibly_null_strings(const char * a, const char * b) { + if (a == b) { + /* NULL or otherwise, they're the same. */ + return 0; + } else if (a == NULL) { + /* b != NULL */ + return -1; + } else if (b == NULL) { + /* a != NULL */ + return 1; + } else { + /* a != NULL != b */ + return strcmp(a, b); + } +} + +int +resolve_hostname(const char *hostname, + int socktype, + struct addrinfo **res, + char **canonname) +{ + struct addrinfo hints; + struct addrinfo *myres; + int flags = 0; + int result; + + if (res) *res = NULL; + if (canonname) { + *canonname = NULL; + flags = AI_CANONNAME; + } + +#ifdef AI_ADDRCONFIG + flags |= AI_ADDRCONFIG; +#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); + if (result != 0) { + return result; + } + + if (canonname && myres && myres->ai_canonname) { + *canonname = stralloc(myres->ai_canonname); + } + + if (res) { + *res = myres; + } else { + freeaddrinfo(myres); + } + + return result; +} + +char * +_str_exit_status( + char *subject, + amwait_t status) +{ + if (WIFEXITED(status)) { + int exitstatus = WEXITSTATUS(status); + if (exitstatus == 0) + return vstrallocf(_("%s exited normally"), subject); + else + return vstrallocf(_("%s exited with status %d"), subject, exitstatus); + } + + if (WIFSIGNALED(status)) { + int signal = WTERMSIG(status); +#ifdef WCOREDUMP + if (WCOREDUMP(status)) + return vstrallocf(_("%s exited after receiving signal %d (core dumped)"), + subject, signal); + else +#endif + return vstrallocf(_("%s exited after receiving signal %d"), + subject, signal); + } + + if (WIFSTOPPED(status)) { + int signal = WSTOPSIG(status); + return vstrallocf(_("%s stopped temporarily after receiving signal %d"), + subject, signal); + } + +#ifdef WIFCONTINUED + if (WIFCONTINUED(status)) { + return vstrallocf(_("%s was resumed"), subject); + } +#endif + + return vstrallocf(_("%s exited in unknown circumstances"), subject); +} + +void +check_running_as(running_as_flags who) +{ +#ifdef CHECK_USERID + struct passwd *pw; + uid_t uid_me; + uid_t uid_target; + char *uname_me = NULL; + char *uname_target = NULL; + char *dumpuser; + + uid_me = getuid(); + if ((pw = getpwuid(uid_me)) == NULL) { + error(_("current userid %ld not found in password database"), (long)uid_me); + /* NOTREACHED */ + } + uname_me = stralloc(pw->pw_name); + +#ifndef SINGLE_USERID + if (!(who & RUNNING_AS_UID_ONLY) && uid_me != geteuid()) { + error(_("euid (%lld) does not match uid (%lld); is this program setuid-root when it shouldn't be?"), + (long long int)geteuid(), (long long int)uid_me); + /* NOTREACHED */ + } +#endif + + switch (who & RUNNING_AS_USER_MASK) { + case RUNNING_AS_ANY: + uid_target = uid_me; + uname_target = uname_me; + return; + + case RUNNING_AS_ROOT: + uid_target = 0; + uname_target = "root"; + break; + + case RUNNING_AS_DUMPUSER_PREFERRED: + dumpuser = getconf_str(CNF_DUMPUSER); + if ((pw = getpwnam(dumpuser)) != NULL && + uid_me != pw->pw_uid) { + if ((pw = getpwnam(CLIENT_LOGIN)) != NULL && + uid_me == pw->pw_uid) { + /* uid == CLIENT_LOGIN: not ideal, but OK */ + dbprintf(_("NOTE: running as '%s', which is the client" + " user, not the dumpuser ('%s'); forging" + " on anyway\n"), + CLIENT_LOGIN, dumpuser); + uid_target = uid_me; /* force success below */ + break; + } + } + /* FALLTHROUGH */ + + case RUNNING_AS_DUMPUSER: + uname_target = getconf_str(CNF_DUMPUSER); + if ((pw = getpwnam(uname_target)) == NULL) { + error(_("cannot look up dumpuser \"%s\""), uname_target); + /*NOTREACHED*/ + } + uid_target = pw->pw_uid; + break; + + case RUNNING_AS_CLIENT_LOGIN: + uname_target = CLIENT_LOGIN; + if ((pw = getpwnam(uname_target)) == NULL) { + error(_("cannot look up client user \"%s\""), uname_target); + /*NOTREACHED*/ + } + uid_target = pw->pw_uid; + break; + + default: + error(_("Unknown check_running_as() call")); + /* NOTREACHED */ + } + + if (uid_me != uid_target) { + error(_("running as user \"%s\" instead of \"%s\""), uname_me, uname_target); + /*NOTREACHED*/ + } + amfree(uname_me); + +#else + /* Quiet unused variable warning */ + (void)who; +#endif +} + +int +set_root_privs(int need_root) +{ +#ifndef SINGLE_USERID + if (need_root) { + if (seteuid(0) == -1) return 0; + /* (we don't switch the group back) */ + } else { + if (geteuid() != 0) return 0; + if (seteuid(getuid()) == -1) return 0; + if (setegid(getgid()) == -1) return 0; + } +#else + (void)need_root; /* Quiet unused variable warning */ +#endif + return 1; } + +int +become_root(void) +{ +#ifndef SINGLE_USERID + // if euid !=0, it set only euid + if (setuid(0) == -1) return 0; + // will set ruid because euid == 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) */ +void count_proplist( + gpointer key_p G_GNUC_UNUSED, + gpointer value_p, + gpointer user_data_p) +{ + property_t *value_s = value_p; + int *nb = user_data_p; + GSList *value; + + for(value=value_s->values; value != NULL; value = value->next) { + (*nb)++; + } +} + +/* A GHFunc (callback for g_hash_table_foreach) */ +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; + char ***argv = 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) { + **argv = stralloc(qprop); + (*argv)++; + **argv = stralloc((char *)value->data); + (*argv)++; + } + amfree(qprop); +} + + +/* + * Process parameters + */ + +static char *pname = NULL; +static char *ptype = NULL; +static pcontext_t pcontext = CONTEXT_DEFAULT; + +void +set_pname(char *p) +{ + 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; +}