PageRenderTime 250ms CodeModel.GetById 31ms RepoModel.GetById 1ms app.codeStats 0ms

/amanda/tags/3_2_0/common-src/util.c

#
C | 1530 lines | 1262 code | 133 blank | 135 comment | 249 complexity | e6f2202c82b233d9557acb901de01452 MD5 | raw file
  1. /*
  2. * Amanda, The Advanced Maryland Automatic Network Disk Archiver
  3. * Copyright (c) 1999 University of Maryland at College Park
  4. * All Rights Reserved.
  5. *
  6. * Permission to use, copy, modify, distribute, and sell this software and its
  7. * documentation for any purpose is hereby granted without fee, provided that
  8. * the above copyright notice appear in all copies and that both that
  9. * copyright notice and this permission notice appear in supporting
  10. * documentation, and that the name of U.M. not be used in advertising or
  11. * publicity pertaining to distribution of the software without specific,
  12. * written prior permission. U.M. makes no representations about the
  13. * suitability of this software for any purpose. It is provided "as is"
  14. * without express or implied warranty.
  15. *
  16. * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
  18. * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  19. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  20. * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  21. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22. *
  23. * Authors: the Amanda Development Team. Its members are listed in a
  24. * file named AUTHORS, in the root directory of this distribution.
  25. */
  26. /*
  27. * $Id: util.c,v 1.42 2006/08/24 01:57:15 paddy_s Exp $
  28. */
  29. #include "amanda.h"
  30. #include "util.h"
  31. #include "match.h"
  32. #include <regex.h>
  33. #include "arglist.h"
  34. #include "clock.h"
  35. #include "sockaddr-util.h"
  36. #include "conffile.h"
  37. #include "base64.h"
  38. #include "stream.h"
  39. #include "pipespawn.h"
  40. #include <glib.h>
  41. #include <string.h>
  42. static int make_socket(sa_family_t family);
  43. static int connect_port(sockaddr_union *addrp, in_port_t port, char *proto,
  44. sockaddr_union *svaddr, int nonblock);
  45. static int
  46. make_socket(
  47. sa_family_t family)
  48. {
  49. int s;
  50. int save_errno;
  51. #if defined(SO_KEEPALIVE) || defined(USE_REUSEADDR)
  52. int on=1;
  53. int r;
  54. #endif
  55. g_debug("make_socket opening socket with family %d", family);
  56. s = socket(family, SOCK_STREAM, 0);
  57. if (s == -1) {
  58. save_errno = errno;
  59. dbprintf(_("make_socket: socket() failed: %s\n"), strerror(save_errno));
  60. errno = save_errno;
  61. return -1;
  62. }
  63. if (s < 0 || s >= (int)FD_SETSIZE) {
  64. aclose(s);
  65. errno = EMFILE; /* out of range */
  66. return -1;
  67. }
  68. #ifdef USE_REUSEADDR
  69. r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
  70. if (r < 0) {
  71. save_errno = errno;
  72. dbprintf(_("make_socket: setsockopt(SO_REUSEADDR) failed: %s\n"),
  73. strerror(errno));
  74. errno = save_errno;
  75. }
  76. #endif
  77. #ifdef SO_KEEPALIVE
  78. r = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
  79. (void *)&on, SIZEOF(on));
  80. if (r == -1) {
  81. save_errno = errno;
  82. dbprintf(_("make_socket: setsockopt() failed: %s\n"),
  83. strerror(save_errno));
  84. aclose(s);
  85. errno = save_errno;
  86. return -1;
  87. }
  88. #endif
  89. return s;
  90. }
  91. GQuark am_util_error_quark(void)
  92. {
  93. return g_quark_from_static_string("am-util-error-quark");
  94. }
  95. /* addrp is my address */
  96. /* svaddr is the address of the remote machine */
  97. /* return socket on success */
  98. /* return -1 on failure */
  99. int
  100. connect_portrange(
  101. sockaddr_union *addrp,
  102. in_port_t first_port,
  103. in_port_t last_port,
  104. char * proto,
  105. sockaddr_union *svaddr,
  106. int nonblock)
  107. {
  108. int s;
  109. in_port_t port;
  110. static in_port_t port_in_use[1024];
  111. static int nb_port_in_use = 0;
  112. int i;
  113. int save_errno = EAGAIN;
  114. assert(first_port <= last_port);
  115. /* Try a port already used */
  116. for(i=0; i < nb_port_in_use; i++) {
  117. port = port_in_use[i];
  118. if(port >= first_port && port <= last_port) {
  119. s = connect_port(addrp, port, proto, svaddr, nonblock);
  120. if(s == -2) return -1;
  121. if(s > 0) {
  122. return s;
  123. }
  124. if (errno != EAGAIN && errno != EBUSY)
  125. save_errno = errno;
  126. }
  127. }
  128. /* Try a port in the range */
  129. for (port = first_port; port <= last_port; port++) {
  130. s = connect_port(addrp, port, proto, svaddr, nonblock);
  131. if(s == -2) return -1;
  132. if(s > 0) {
  133. port_in_use[nb_port_in_use++] = port;
  134. return s;
  135. }
  136. if (errno != EAGAIN && errno != EBUSY)
  137. save_errno = errno;
  138. }
  139. dbprintf(_("connect_portrange: All ports between %d and %d are busy.\n"),
  140. first_port,
  141. last_port);
  142. errno = save_errno;
  143. return -1;
  144. }
  145. /* addrp is my address */
  146. /* svaddr is the address of the remote machine */
  147. /* return -2: Don't try again */
  148. /* return -1: Try with another port */
  149. /* return >0: this is the connected socket */
  150. int
  151. connect_port(
  152. sockaddr_union *addrp,
  153. in_port_t port,
  154. char * proto,
  155. sockaddr_union *svaddr,
  156. int nonblock)
  157. {
  158. int save_errno;
  159. struct servent * servPort;
  160. socklen_t_equiv len;
  161. socklen_t_equiv socklen;
  162. int s;
  163. servPort = getservbyport((int)htons(port), proto);
  164. if (servPort != NULL && !strstr(servPort->s_name, "amanda")) {
  165. dbprintf(_("connect_port: Skip port %d: owned by %s.\n"),
  166. port, servPort->s_name);
  167. errno = EBUSY;
  168. return -1;
  169. }
  170. if ((s = make_socket(SU_GET_FAMILY(addrp))) == -1) return -2;
  171. SU_SET_PORT(addrp, port);
  172. socklen = SS_LEN(addrp);
  173. if (bind(s, (struct sockaddr *)addrp, socklen) != 0) {
  174. save_errno = errno;
  175. aclose(s);
  176. if(servPort == NULL) {
  177. dbprintf(_("connect_port: Try port %d: available - %s\n"),
  178. port, strerror(errno));
  179. } else {
  180. dbprintf(_("connect_port: Try port %d: owned by %s - %s\n"),
  181. port, servPort->s_name, strerror(errno));
  182. }
  183. if (save_errno != EADDRINUSE) {
  184. errno = save_errno;
  185. return -2;
  186. }
  187. errno = save_errno;
  188. return -1;
  189. }
  190. if(servPort == NULL) {
  191. dbprintf(_("connect_port: Try port %d: available - Success\n"), port);
  192. } else {
  193. dbprintf(_("connect_port: Try port %d: owned by %s - Success\n"),
  194. port, servPort->s_name);
  195. }
  196. /* find out what port was actually used */
  197. len = sizeof(*addrp);
  198. if (getsockname(s, (struct sockaddr *)addrp, &len) == -1) {
  199. save_errno = errno;
  200. dbprintf(_("connect_port: getsockname() failed: %s\n"),
  201. strerror(save_errno));
  202. aclose(s);
  203. errno = save_errno;
  204. return -1;
  205. }
  206. if (nonblock)
  207. fcntl(s, F_SETFL, fcntl(s, F_GETFL, 0)|O_NONBLOCK);
  208. if (connect(s, (struct sockaddr *)svaddr, SS_LEN(svaddr)) == -1 && !nonblock) {
  209. save_errno = errno;
  210. dbprintf(_("connect_portrange: Connect from %s failed: %s\n"),
  211. str_sockaddr(addrp),
  212. strerror(save_errno));
  213. dbprintf(_("connect_portrange: connect to %s failed: %s\n"),
  214. str_sockaddr(svaddr),
  215. strerror(save_errno));
  216. aclose(s);
  217. errno = save_errno;
  218. if (save_errno == ECONNREFUSED ||
  219. save_errno == EHOSTUNREACH ||
  220. save_errno == ENETUNREACH ||
  221. save_errno == ETIMEDOUT) {
  222. return -2 ;
  223. }
  224. return -1;
  225. }
  226. dbprintf(_("connected to %s\n"),
  227. str_sockaddr(svaddr));
  228. dbprintf(_("our side is %s\n"),
  229. str_sockaddr(addrp));
  230. return s;
  231. }
  232. /*
  233. * Bind to a port in the given range. Takes a begin,end pair of port numbers.
  234. *
  235. * Returns negative on error (EGAIN if all ports are in use). Returns 0
  236. * on success.
  237. */
  238. int
  239. bind_portrange(
  240. int s,
  241. sockaddr_union *addrp,
  242. in_port_t first_port,
  243. in_port_t last_port,
  244. char * proto)
  245. {
  246. in_port_t port;
  247. in_port_t cnt;
  248. socklen_t_equiv socklen;
  249. struct servent *servPort;
  250. const in_port_t num_ports = (in_port_t)(last_port - first_port + 1);
  251. int save_errno = EAGAIN;
  252. assert(first_port <= last_port);
  253. /*
  254. * We pick a different starting port based on our pid and the current
  255. * time to avoid always picking the same reserved port twice.
  256. */
  257. port = (in_port_t)(((getpid() + time(0)) % num_ports) + first_port);
  258. /*
  259. * Scan through the range, trying all available ports that are either
  260. * not taken in /etc/services or registered for *amanda*. Wrap around
  261. * if we don't happen to start at the beginning.
  262. */
  263. for (cnt = 0; cnt < num_ports; cnt++) {
  264. servPort = getservbyport((int)htons(port), proto);
  265. if ((servPort == NULL) || strstr(servPort->s_name, "amanda")) {
  266. SU_SET_PORT(addrp, port);
  267. socklen = SS_LEN(addrp);
  268. if (bind(s, (struct sockaddr *)addrp, socklen) >= 0) {
  269. if (servPort == NULL) {
  270. g_debug(_("bind_portrange2: Try port %d: Available - Success"), port);
  271. } else {
  272. g_debug(_("bind_portrange2: Try port %d: Owned by %s - Success."), port, servPort->s_name);
  273. }
  274. return 0;
  275. }
  276. if (errno != EAGAIN && errno != EBUSY)
  277. save_errno = errno;
  278. if (servPort == NULL) {
  279. g_debug(_("bind_portrange2: Try port %d: Available - %s"),
  280. port, strerror(errno));
  281. } else {
  282. g_debug(_("bind_portrange2: Try port %d: Owned by %s - %s"),
  283. port, servPort->s_name, strerror(errno));
  284. }
  285. } else {
  286. g_debug(_("bind_portrange2: Skip port %d: Owned by %s."),
  287. port, servPort->s_name);
  288. }
  289. if (++port > last_port)
  290. port = first_port;
  291. }
  292. g_debug(_("bind_portrange: all ports between %d and %d busy"),
  293. first_port,
  294. last_port);
  295. errno = save_errno;
  296. return -1;
  297. }
  298. int
  299. interruptible_accept(
  300. int sock,
  301. struct sockaddr *addr,
  302. socklen_t *addrlen,
  303. gboolean (*prolong)(gpointer data),
  304. gpointer prolong_data)
  305. {
  306. SELECT_ARG_TYPE readset;
  307. struct timeval tv;
  308. int nfound;
  309. if (sock < 0 || sock >= FD_SETSIZE) {
  310. g_debug("interruptible_accept: bad socket %d", sock);
  311. return EBADF;
  312. }
  313. memset(&readset, 0, SIZEOF(readset));
  314. while (1) {
  315. if (!prolong(prolong_data)) {
  316. errno = 0;
  317. return -1;
  318. }
  319. FD_ZERO(&readset);
  320. FD_SET(sock, &readset);
  321. /* try accepting for 1s */
  322. memset(&tv, 0, SIZEOF(tv));
  323. tv.tv_sec = 1;
  324. nfound = select(sock+1, &readset, NULL, NULL, &tv);
  325. if (nfound < 0) {
  326. return -1;
  327. } else if (nfound == 0) {
  328. continue;
  329. } else if (!FD_ISSET(sock, &readset)) {
  330. g_debug("interruptible_accept: select malfunction");
  331. errno = EBADF;
  332. return -1;
  333. } else {
  334. int rv = accept(sock, addr, addrlen);
  335. if (rv < 0 && errno == EAGAIN)
  336. continue;
  337. return rv;
  338. }
  339. }
  340. }
  341. /*
  342. * Writes out the entire iovec
  343. */
  344. ssize_t
  345. full_writev(
  346. int fd,
  347. struct iovec * iov,
  348. int iovcnt)
  349. {
  350. ssize_t delta, n, total;
  351. assert(iov != NULL);
  352. total = 0;
  353. while (iovcnt > 0) {
  354. /*
  355. * Write the iovec
  356. */
  357. n = writev(fd, iov, iovcnt);
  358. if (n < 0) {
  359. if (errno != EINTR)
  360. return (-1);
  361. }
  362. else if (n == 0) {
  363. errno = EIO;
  364. return (-1);
  365. } else {
  366. total += n;
  367. /*
  368. * Iterate through each iov. Figure out what we still need
  369. * to write out.
  370. */
  371. for (; n > 0; iovcnt--, iov++) {
  372. /* 'delta' is the bytes written from this iovec */
  373. delta = ((size_t)n < (size_t)iov->iov_len) ? n : (ssize_t)iov->iov_len;
  374. /* subtract from the total num bytes written */
  375. n -= delta;
  376. assert(n >= 0);
  377. /* subtract from this iovec */
  378. iov->iov_len -= delta;
  379. iov->iov_base = (char *)iov->iov_base + delta;
  380. /* if this iovec isn't empty, run the writev again */
  381. if (iov->iov_len > 0)
  382. break;
  383. }
  384. }
  385. }
  386. return (total);
  387. }
  388. /*
  389. * For backward compatibility we are trying for minimal quoting. Unless ALWAYS
  390. * is true, we only quote a string if it contains whitespace or is misquoted...
  391. */
  392. char *
  393. quote_string_maybe(
  394. const char *str,
  395. gboolean always)
  396. {
  397. char * s;
  398. char * ret;
  399. if ((str == NULL) || (*str == '\0')) {
  400. ret = stralloc("\"\"");
  401. } else if (!always && (match("[:\'\\\"[:space:][:cntrl:]]", str)) == 0) {
  402. /*
  403. * String does not need to be quoted since it contains
  404. * neither whitespace, control or quote characters.
  405. */
  406. ret = stralloc(str);
  407. } else {
  408. /*
  409. * Allocate maximum possible string length.
  410. * (a string of all quotes plus room for leading ", trailing " and NULL)
  411. */
  412. ret = s = alloc((strlen(str) * 2) + 2 + 1);
  413. *(s++) = '"';
  414. while (*str != '\0') {
  415. if (*str == '\t') {
  416. *(s++) = '\\';
  417. *(s++) = 't';
  418. str++;
  419. continue;
  420. } else if (*str == '\n') {
  421. *(s++) = '\\';
  422. *(s++) = 'n';
  423. str++;
  424. continue;
  425. } else if (*str == '\r') {
  426. *(s++) = '\\';
  427. *(s++) = 'r';
  428. str++;
  429. continue;
  430. } else if (*str == '\f') {
  431. *(s++) = '\\';
  432. *(s++) = 'f';
  433. str++;
  434. continue;
  435. } else if (*str == '\\') {
  436. *(s++) = '\\';
  437. *(s++) = '\\';
  438. str++;
  439. continue;
  440. }
  441. if (*str == '"')
  442. *(s++) = '\\';
  443. *(s++) = *(str++);
  444. }
  445. *(s++) = '"';
  446. *s = '\0';
  447. }
  448. return (ret);
  449. }
  450. char *
  451. unquote_string(
  452. const char *str)
  453. {
  454. char * ret;
  455. if ((str == NULL) || (*str == '\0')) {
  456. ret = stralloc("");
  457. } else {
  458. char * in;
  459. char * out;
  460. ret = in = out = stralloc(str);
  461. while (*in != '\0') {
  462. if (*in == '"') {
  463. in++;
  464. continue;
  465. }
  466. if (*in == '\\') {
  467. in++;
  468. if (*in == 'n') {
  469. in++;
  470. *(out++) = '\n';
  471. continue;
  472. } else if (*in == 't') {
  473. in++;
  474. *(out++) = '\t';
  475. continue;
  476. } else if (*in == 'r') {
  477. in++;
  478. *(out++) = '\r';
  479. continue;
  480. } else if (*in == 'f') {
  481. in++;
  482. *(out++) = '\f';
  483. continue;
  484. } else if (*in >= '0' && *in <= '7') {
  485. char c = 0;
  486. int i = 0;
  487. while (i < 3 && *in >= '0' && *in <= '7') {
  488. c = (c << 3) + *(in++) - '0';
  489. i++;
  490. }
  491. if (c)
  492. *(out++) = c;
  493. } else if (*in == '\0') {
  494. /* trailing backslash -- ignore */
  495. break;
  496. }
  497. }
  498. *(out++) = *(in++);
  499. }
  500. *out = '\0';
  501. }
  502. return (ret);
  503. }
  504. gchar **
  505. split_quoted_strings(
  506. const gchar *string)
  507. {
  508. char *local;
  509. char *start;
  510. char *p;
  511. char **result;
  512. GPtrArray *strs;
  513. int iq = 0;
  514. if (!string)
  515. return NULL;
  516. p = start = local = g_strdup(string);
  517. strs = g_ptr_array_new();
  518. while (*p) {
  519. if (!iq && *p == ' ') {
  520. *p = '\0';
  521. g_ptr_array_add(strs, unquote_string(start));
  522. start = p+1;
  523. } else if (*p == '\\') {
  524. /* next character is taken literally; if it's a multicharacter
  525. * escape (e.g., \171), that doesn't bother us here */
  526. p++;
  527. if (!*p) break;
  528. } else if (*p == '\"') {
  529. iq = ! iq;
  530. }
  531. p++;
  532. }
  533. if (start != string)
  534. g_ptr_array_add(strs, unquote_string(start));
  535. /* now convert strs into a strv, by stealing its references to the underlying
  536. * strings */
  537. result = g_new0(char *, strs->len + 1);
  538. memmove(result, strs->pdata, sizeof(char *) * strs->len);
  539. g_ptr_array_free(strs, TRUE); /* TRUE => free pdata, strings are not freed */
  540. g_free(local);
  541. return result;
  542. }
  543. char *
  544. strquotedstr(char **saveptr)
  545. {
  546. char * tok = strtok_r(NULL, " ", saveptr);
  547. size_t len;
  548. int in_quote;
  549. int in_backslash;
  550. char *p, *t;
  551. if (!tok)
  552. return tok;
  553. len = strlen(tok);
  554. in_quote = 0;
  555. in_backslash = 0;
  556. p = tok;
  557. while (in_quote || in_backslash || *p != '\0') {
  558. if (*p == '\0') {
  559. /* append a new token */
  560. t = strtok_r(NULL, " ", saveptr);
  561. if (!t)
  562. return NULL;
  563. tok[len] = ' ';
  564. len = strlen(tok);
  565. }
  566. if (!in_backslash) {
  567. if (*p == '"')
  568. in_quote = !in_quote;
  569. else if (*p == '\\') {
  570. in_backslash = 1;
  571. }
  572. } else {
  573. in_backslash = 0;
  574. }
  575. p++;
  576. }
  577. return tok;
  578. }
  579. char *
  580. sanitize_string(
  581. const char *str)
  582. {
  583. char * s;
  584. char * ret;
  585. if ((str == NULL) || (*str == '\0')) {
  586. ret = stralloc("");
  587. } else {
  588. ret = stralloc(str);
  589. for (s = ret; *s != '\0'; s++) {
  590. if (iscntrl((int)*s))
  591. *s = '?';
  592. }
  593. }
  594. return (ret);
  595. }
  596. char *hexencode_string(const char *str)
  597. {
  598. size_t orig_len, new_len, i;
  599. GString *s;
  600. gchar *ret;
  601. if (!str) {
  602. s = g_string_sized_new(0);
  603. goto cleanup;
  604. }
  605. new_len = orig_len = strlen(str);
  606. for (i = 0; i < orig_len; i++) {
  607. if (!g_ascii_isalnum(str[i])) {
  608. new_len += 2;
  609. }
  610. }
  611. s = g_string_sized_new(new_len);
  612. for (i = 0; i < orig_len; i++) {
  613. if (g_ascii_isalnum(str[i])) {
  614. g_string_append_c(s, str[i]);
  615. } else {
  616. g_string_append_printf(s, "%%%02hhx", str[i]);
  617. }
  618. }
  619. cleanup:
  620. ret = s->str;
  621. g_string_free(s, FALSE);
  622. return ret;
  623. }
  624. char *hexdecode_string(const char *str, GError **err)
  625. {
  626. size_t orig_len, new_len, i;
  627. GString *s;
  628. gchar *ret;
  629. if (!str) {
  630. s = g_string_sized_new(0);
  631. goto cleanup;
  632. }
  633. new_len = orig_len = strlen(str);
  634. for (i = 0; i < orig_len; i++) {
  635. if (str[i] == '%') {
  636. new_len -= 2;
  637. }
  638. }
  639. s = g_string_sized_new(new_len);
  640. for (i = 0; (orig_len > 2) && (i < orig_len-2); i++) {
  641. if (str[i] == '%') {
  642. gchar tmp = 0;
  643. size_t j;
  644. for (j = 1; j < 3; j++) {
  645. tmp <<= 4;
  646. if (str[i+j] >= '0' && str[i+j] <= '9') {
  647. tmp += str[i+j] - '0';
  648. } else if (str[i+j] >= 'a' && str[i+j] <= 'f') {
  649. tmp += str[i+j] - 'a' + 10;
  650. } else if (str[i+j] >= 'A' && str[i+j] <= 'F') {
  651. tmp += str[i+j] - 'A' + 10;
  652. } else {
  653. /* error */
  654. g_set_error(err, am_util_error_quark(), AM_UTIL_ERROR_HEXDECODEINVAL,
  655. "Illegal character (non-hex) 0x%02hhx at offset %zd", str[i+j], i+j);
  656. g_string_truncate(s, 0);
  657. goto cleanup;
  658. }
  659. }
  660. if (!tmp) {
  661. g_set_error(err, am_util_error_quark(), AM_UTIL_ERROR_HEXDECODEINVAL,
  662. "Encoded NULL at starting offset %zd", i);
  663. g_string_truncate(s, 0);
  664. goto cleanup;
  665. }
  666. g_string_append_c(s, tmp);
  667. i += 2;
  668. } else {
  669. g_string_append_c(s, str[i]);
  670. }
  671. }
  672. for ( /*nothing*/; i < orig_len; i++) {
  673. if (str[i] == '%') {
  674. g_set_error(err, am_util_error_quark(), AM_UTIL_ERROR_HEXDECODEINVAL,
  675. "'%%' found at offset %zd, but fewer than two characters follow it (%zd)", i, orig_len-i-1);
  676. g_string_truncate(s, 0);
  677. goto cleanup;
  678. } else {
  679. g_string_append_c(s, str[i]);
  680. }
  681. }
  682. cleanup:
  683. ret = s->str;
  684. g_string_free(s, FALSE);
  685. return ret;
  686. }
  687. /* Helper for parse_braced_component; this will turn a single element array
  688. * matching /^\d+\.\.\d+$/ into a sequence of numbered array elements. */
  689. static GPtrArray *
  690. expand_braced_sequence(GPtrArray *arr)
  691. {
  692. char *elt, *p;
  693. char *l, *r;
  694. int ldigits, rdigits, ndigits;
  695. guint64 start, end;
  696. gboolean leading_zero;
  697. /* check whether the element matches the pattern */
  698. /* expand last element of the array only */
  699. elt = g_ptr_array_index(arr, arr->len-1);
  700. ldigits = 0;
  701. for (l = p = elt; *p && g_ascii_isdigit(*p); p++)
  702. ldigits++;
  703. if (ldigits == 0)
  704. return arr;
  705. if (*(p++) != '.')
  706. return arr;
  707. if (*(p++) != '.')
  708. return arr;
  709. rdigits = 0;
  710. for (r = p; *p && g_ascii_isdigit(*p); p++)
  711. rdigits++;
  712. if (rdigits == 0)
  713. return arr;
  714. if (*p)
  715. return arr;
  716. /* we have a match, so extract start and end */
  717. start = g_ascii_strtoull(l, NULL, 10);
  718. end = g_ascii_strtoull(r, NULL, 10);
  719. leading_zero = *l == '0';
  720. ndigits = MAX(ldigits, rdigits);
  721. if (start > end)
  722. return arr;
  723. /* sanity check.. */
  724. if (end - start > 100000)
  725. return arr;
  726. /* remove last from the array */
  727. g_ptr_array_remove_index(arr, arr->len - 1);
  728. /* Add new elements */
  729. while (start <= end) {
  730. if (leading_zero) {
  731. g_ptr_array_add(arr, g_strdup_printf("%0*ju",
  732. ndigits, (uintmax_t)start));
  733. } else {
  734. g_ptr_array_add(arr, g_strdup_printf("%ju", (uintmax_t)start));
  735. }
  736. start++;
  737. }
  738. return arr;
  739. }
  740. /* Helper for expand_braced_alternates; returns a list of un-escaped strings
  741. * for the first "component" of str, where a component is a plain string or a
  742. * brace-enclosed set of alternatives. str is pointing to the first character
  743. * of the next component on return. */
  744. static GPtrArray *
  745. parse_braced_component(char **str)
  746. {
  747. GPtrArray *result = g_ptr_array_new();
  748. if (**str == '{') {
  749. char *p = (*str)+1;
  750. char *local = g_malloc(strlen(*str)+1);
  751. char *current = local;
  752. char *c = current;
  753. while (1) {
  754. if (*p == '\0' || *p == '{') {
  755. /* unterminated { .. } or extra '{' */
  756. amfree(local);
  757. g_ptr_array_free(result, TRUE);
  758. return NULL;
  759. }
  760. if (*p == '}' || *p == ',') {
  761. *c = '\0';
  762. g_ptr_array_add(result, g_strdup(current));
  763. result = expand_braced_sequence(result);
  764. current = ++c;
  765. if (*p == '}')
  766. break;
  767. else
  768. p++;
  769. }
  770. if (*p == '\\') {
  771. if (*(p+1) == '{' || *(p+1) == '}' || *(p+1) == '\\' || *(p+1) == ',')
  772. p++;
  773. }
  774. *(c++) = *(p++);
  775. }
  776. amfree(local);
  777. if (*p)
  778. *str = p+1;
  779. else
  780. *str = p;
  781. } else {
  782. /* no braces -- just un-escape a plain string */
  783. char *local = g_malloc(strlen(*str)+1);
  784. char *r = local;
  785. char *p = *str;
  786. while (*p && *p != '{') {
  787. if (*p == '\\') {
  788. if (*(p+1) == '{' || *(p+1) == '}' || *(p+1) == '\\' || *(p+1) == ',')
  789. p++;
  790. }
  791. *(r++) = *(p++);
  792. }
  793. *r = '\0';
  794. g_ptr_array_add(result, local);
  795. *str = p;
  796. }
  797. return result;
  798. }
  799. GPtrArray *
  800. expand_braced_alternates(
  801. char * source)
  802. {
  803. GPtrArray *rval = g_ptr_array_new();
  804. g_ptr_array_add(rval, g_strdup(""));
  805. while (*source) {
  806. GPtrArray *new_components;
  807. GPtrArray *new_rval;
  808. guint i, j;
  809. new_components = parse_braced_component(&source);
  810. if (!new_components) {
  811. /* parse error */
  812. g_ptr_array_free(rval, TRUE);
  813. return NULL;
  814. }
  815. new_rval = g_ptr_array_new();
  816. /* do a cartesian join of rval and new_components */
  817. for (i = 0; i < rval->len; i++) {
  818. for (j = 0; j < new_components->len; j++) {
  819. g_ptr_array_add(new_rval, g_strconcat(
  820. g_ptr_array_index(rval, i),
  821. g_ptr_array_index(new_components, j),
  822. NULL));
  823. }
  824. }
  825. g_ptr_array_free(rval, TRUE);
  826. g_ptr_array_free(new_components, TRUE);
  827. rval = new_rval;
  828. }
  829. return rval;
  830. }
  831. char *
  832. collapse_braced_alternates(
  833. GPtrArray *source)
  834. {
  835. GString *result = NULL;
  836. guint i;
  837. result = g_string_new("{");
  838. for (i = 0; i < source->len; i ++) {
  839. const char *str = g_ptr_array_index(source, i);
  840. char *qstr = NULL;
  841. if (strchr(str, ',') || strchr(str, '\\') ||
  842. strchr(str, '{') || strchr(str, '}')) {
  843. const char *s;
  844. char *d;
  845. s = str;
  846. qstr = d = g_malloc(strlen(str)*2+1);
  847. while (*s) {
  848. if (*s == ',' || *s == '\\' || *s == '{' || *s == '}')
  849. *(d++) = '\\';
  850. *(d++) = *(s++);
  851. }
  852. *(d++) = '\0';
  853. }
  854. g_string_append_printf(result, "%s%s", qstr? qstr : str,
  855. (i < source->len-1)? "," : "");
  856. if (qstr)
  857. g_free(qstr);
  858. }
  859. g_string_append(result, "}");
  860. return g_string_free(result, FALSE);
  861. }
  862. /*
  863. Return 0 if the following characters are present
  864. * ( ) < > [ ] , ; : ! $ \ / "
  865. else returns 1
  866. */
  867. int
  868. validate_mailto(
  869. const char *mailto)
  870. {
  871. return !match("\\*|<|>|\\(|\\)|\\[|\\]|,|;|:|\\\\|/|\"|\\!|\\$|\\|", mailto);
  872. }
  873. int copy_file(
  874. char *dst,
  875. char *src,
  876. char **errmsg)
  877. {
  878. int infd, outfd;
  879. int save_errno;
  880. size_t nb;
  881. char buf[32768];
  882. char *quoted;
  883. if ((infd = open(src, O_RDONLY)) == -1) {
  884. save_errno = errno;
  885. quoted = quote_string(src);
  886. *errmsg = vstrallocf(_("Can't open file '%s' for reading: %s"),
  887. quoted, strerror(save_errno));
  888. amfree(quoted);
  889. return -1;
  890. }
  891. if ((outfd = open(dst, O_WRONLY|O_CREAT, 0600)) == -1) {
  892. save_errno = errno;
  893. quoted = quote_string(dst);
  894. *errmsg = vstrallocf(_("Can't open file '%s' for writting: %s"),
  895. quoted, strerror(save_errno));
  896. amfree(quoted);
  897. close(infd);
  898. return -1;
  899. }
  900. while((nb=read(infd, &buf, SIZEOF(buf))) > 0) {
  901. if(full_write(outfd,&buf,nb) < nb) {
  902. save_errno = errno;
  903. quoted = quote_string(dst);
  904. *errmsg = vstrallocf(_("Error writing to '%s': %s"),
  905. quoted, strerror(save_errno));
  906. amfree(quoted);
  907. close(infd);
  908. close(outfd);
  909. return -1;
  910. }
  911. }
  912. if (errno != 0) {
  913. save_errno = errno;
  914. quoted = quote_string(src);
  915. *errmsg = vstrallocf(_("Error reading from '%s': %s"),
  916. quoted, strerror(save_errno));
  917. amfree(quoted);
  918. close(infd);
  919. close(outfd);
  920. return -1;
  921. }
  922. close(infd);
  923. close(outfd);
  924. return 0;
  925. }
  926. #ifndef HAVE_READLINE
  927. /*
  928. * simple readline() replacements, used when we don't have readline
  929. * support from the system.
  930. */
  931. char *
  932. readline(
  933. const char *prompt)
  934. {
  935. g_printf("%s", prompt);
  936. fflush(stdout);
  937. fflush(stderr);
  938. return agets(stdin);
  939. }
  940. void
  941. add_history(
  942. const char *line)
  943. {
  944. (void)line; /* Quiet unused parameter warning */
  945. }
  946. #endif
  947. /* Order of preference: readdir64(), readdir(). */
  948. #if HAVE_DECL_READDIR64
  949. # define USE_DIRENT64
  950. # define USE_READDIR64
  951. #elif HAVE_DECL_READDIR
  952. # define USE_READDIR
  953. #else
  954. # error No readdir() or readdir64() available!
  955. #endif
  956. char * portable_readdir(DIR* handle) {
  957. #ifdef USE_DIRENT64
  958. struct dirent64 *entry_p;
  959. #else
  960. struct dirent *entry_p;
  961. #endif
  962. static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
  963. g_static_mutex_lock(&mutex);
  964. #ifdef USE_READDIR
  965. entry_p = readdir(handle);
  966. #endif
  967. #ifdef USE_READDIR64
  968. entry_p = readdir64(handle);
  969. #endif
  970. g_static_mutex_unlock(&mutex);
  971. if (entry_p == NULL)
  972. return NULL;
  973. /* FIXME: According to glibc documentation, d_name may not be
  974. null-terminated in some cases on some very old platforms. Not
  975. sure what to do about that case. */
  976. return strdup(entry_p->d_name);
  977. }
  978. int search_directory(DIR * handle, const char * regex,
  979. SearchDirectoryFunctor functor, gpointer user_data) {
  980. int rval = 0;
  981. regex_t compiled_regex;
  982. gboolean done = FALSE;
  983. if (regcomp(&compiled_regex, regex, REG_EXTENDED | REG_NOSUB) != 0) {
  984. regfree(&compiled_regex);
  985. return -1;
  986. }
  987. rewinddir(handle);
  988. while (!done) {
  989. char * read_name;
  990. int result;
  991. read_name = portable_readdir(handle);
  992. if (read_name == NULL) {
  993. regfree(&compiled_regex);
  994. return rval;
  995. }
  996. result = regexec(&compiled_regex, read_name, 0, NULL, 0);
  997. if (result == 0) {
  998. rval ++;
  999. done = !functor(read_name, user_data);
  1000. }
  1001. amfree(read_name);
  1002. }
  1003. regfree(&compiled_regex);
  1004. return rval;
  1005. }
  1006. char* find_regex_substring(const char* base_string, const regmatch_t match) {
  1007. char * rval;
  1008. int size;
  1009. size = match.rm_eo - match.rm_so;
  1010. rval = malloc(size+1);
  1011. memcpy(rval, base_string + match.rm_so, size);
  1012. rval[size] = '\0';
  1013. return rval;
  1014. }
  1015. int compare_possibly_null_strings(const char * a, const char * b) {
  1016. if (a == b) {
  1017. /* NULL or otherwise, they're the same. */
  1018. return 0;
  1019. } else if (a == NULL) {
  1020. /* b != NULL */
  1021. return -1;
  1022. } else if (b == NULL) {
  1023. /* a != NULL */
  1024. return 1;
  1025. } else {
  1026. /* a != NULL != b */
  1027. return strcmp(a, b);
  1028. }
  1029. }
  1030. int
  1031. resolve_hostname(const char *hostname,
  1032. int socktype,
  1033. struct addrinfo **res,
  1034. char **canonname)
  1035. {
  1036. struct addrinfo hints;
  1037. struct addrinfo *myres;
  1038. int flags = 0;
  1039. int result;
  1040. if (res) *res = NULL;
  1041. if (canonname) {
  1042. *canonname = NULL;
  1043. flags = AI_CANONNAME;
  1044. }
  1045. #ifdef AI_ADDRCONFIG
  1046. flags |= AI_ADDRCONFIG;
  1047. #endif
  1048. memset(&hints, 0, sizeof(hints));
  1049. #ifdef WORKING_IPV6
  1050. /* get any kind of addresss */
  1051. hints.ai_family = AF_UNSPEC;
  1052. #else
  1053. /* even if getaddrinfo supports IPv6, don't let it return
  1054. * such an address */
  1055. hints.ai_family = AF_INET;
  1056. #endif
  1057. hints.ai_flags = flags;
  1058. hints.ai_socktype = socktype;
  1059. result = getaddrinfo(hostname, NULL, &hints, &myres);
  1060. if (result != 0) {
  1061. return result;
  1062. }
  1063. if (canonname && myres && myres->ai_canonname) {
  1064. *canonname = stralloc(myres->ai_canonname);
  1065. }
  1066. if (res) {
  1067. *res = myres;
  1068. } else {
  1069. freeaddrinfo(myres);
  1070. }
  1071. return result;
  1072. }
  1073. char *
  1074. _str_exit_status(
  1075. char *subject,
  1076. amwait_t status)
  1077. {
  1078. if (WIFEXITED(status)) {
  1079. int exitstatus = WEXITSTATUS(status);
  1080. if (exitstatus == 0)
  1081. return vstrallocf(_("%s exited normally"), subject);
  1082. else
  1083. return vstrallocf(_("%s exited with status %d"), subject, exitstatus);
  1084. }
  1085. if (WIFSIGNALED(status)) {
  1086. int signal = WTERMSIG(status);
  1087. #ifdef WCOREDUMP
  1088. if (WCOREDUMP(status))
  1089. return vstrallocf(_("%s exited after receiving signal %d (core dumped)"),
  1090. subject, signal);
  1091. else
  1092. #endif
  1093. return vstrallocf(_("%s exited after receiving signal %d"),
  1094. subject, signal);
  1095. }
  1096. if (WIFSTOPPED(status)) {
  1097. int signal = WSTOPSIG(status);
  1098. return vstrallocf(_("%s stopped temporarily after receiving signal %d"),
  1099. subject, signal);
  1100. }
  1101. #ifdef WIFCONTINUED
  1102. if (WIFCONTINUED(status)) {
  1103. return vstrallocf(_("%s was resumed"), subject);
  1104. }
  1105. #endif
  1106. return vstrallocf(_("%s exited in unknown circumstances"), subject);
  1107. }
  1108. void
  1109. check_running_as(running_as_flags who)
  1110. {
  1111. #ifdef CHECK_USERID
  1112. struct passwd *pw;
  1113. uid_t uid_me;
  1114. uid_t uid_target;
  1115. char *uname_me = NULL;
  1116. char *uname_target = NULL;
  1117. char *dumpuser;
  1118. uid_me = getuid();
  1119. if ((pw = getpwuid(uid_me)) == NULL) {
  1120. error(_("current userid %ld not found in password database"), (long)uid_me);
  1121. /* NOTREACHED */
  1122. }
  1123. uname_me = stralloc(pw->pw_name);
  1124. #ifndef SINGLE_USERID
  1125. if (!(who & RUNNING_AS_UID_ONLY) && uid_me != geteuid()) {
  1126. error(_("euid (%lld) does not match uid (%lld); is this program setuid-root when it shouldn't be?"),
  1127. (long long int)geteuid(), (long long int)uid_me);
  1128. /* NOTREACHED */
  1129. }
  1130. #endif
  1131. switch (who & RUNNING_AS_USER_MASK) {
  1132. case RUNNING_AS_ANY:
  1133. uid_target = uid_me;
  1134. uname_target = uname_me;
  1135. amfree(uname_me);
  1136. return;
  1137. case RUNNING_AS_ROOT:
  1138. uid_target = 0;
  1139. uname_target = "root";
  1140. break;
  1141. case RUNNING_AS_DUMPUSER_PREFERRED:
  1142. dumpuser = getconf_str(CNF_DUMPUSER);
  1143. if ((pw = getpwnam(dumpuser)) != NULL &&
  1144. uid_me != pw->pw_uid) {
  1145. if ((pw = getpwnam(CLIENT_LOGIN)) != NULL &&
  1146. uid_me == pw->pw_uid) {
  1147. /* uid == CLIENT_LOGIN: not ideal, but OK */
  1148. dbprintf(_("NOTE: running as '%s', which is the client"
  1149. " user, not the dumpuser ('%s'); forging"
  1150. " on anyway\n"),
  1151. CLIENT_LOGIN, dumpuser);
  1152. uid_target = uid_me; /* force success below */
  1153. break;
  1154. }
  1155. }
  1156. /* FALLTHROUGH */
  1157. case RUNNING_AS_DUMPUSER:
  1158. uname_target = getconf_str(CNF_DUMPUSER);
  1159. if ((pw = getpwnam(uname_target)) == NULL) {
  1160. error(_("cannot look up dumpuser \"%s\""), uname_target);
  1161. /*NOTREACHED*/
  1162. }
  1163. uid_target = pw->pw_uid;
  1164. break;
  1165. case RUNNING_AS_CLIENT_LOGIN:
  1166. uname_target = CLIENT_LOGIN;
  1167. if ((pw = getpwnam(uname_target)) == NULL) {
  1168. error(_("cannot look up client user \"%s\""), uname_target);
  1169. /*NOTREACHED*/
  1170. }
  1171. uid_target = pw->pw_uid;
  1172. break;
  1173. default:
  1174. error(_("Unknown check_running_as() call"));
  1175. /* NOTREACHED */
  1176. }
  1177. if (uid_me != uid_target) {
  1178. error(_("running as user \"%s\" instead of \"%s\""), uname_me, uname_target);
  1179. /*NOTREACHED*/
  1180. }
  1181. amfree(uname_me);
  1182. #else
  1183. /* Quiet unused variable warning */
  1184. (void)who;
  1185. #endif
  1186. }
  1187. int
  1188. set_root_privs(int need_root)
  1189. {
  1190. #ifndef SINGLE_USERID
  1191. static gboolean first_call = TRUE;
  1192. static uid_t unpriv = 1;
  1193. if (first_call) {
  1194. /* save the original real userid (that of our invoker) */
  1195. unpriv = getuid();
  1196. /* and set all of our userids (including, importantly, the saved
  1197. * userid) to 0 */
  1198. setuid(0);
  1199. /* don't need to do this next time */
  1200. first_call = FALSE;
  1201. }
  1202. if (need_root == 1) {
  1203. if (geteuid() == 0) return 1; /* already done */
  1204. if (seteuid(0) == -1) return 0;
  1205. /* (we don't switch the group back) */
  1206. } else if (need_root == -1) {
  1207. /* make sure the euid is 0 so that we can set the uid */
  1208. if (geteuid() != 0) {
  1209. if (seteuid(0) == -1) return 0;
  1210. }
  1211. /* now set the uid to the unprivileged userid */
  1212. if (setuid(unpriv) == -1) return 0;
  1213. } else {
  1214. if (geteuid() != 0) return 1; /* already done */
  1215. /* set the *effective* userid only */
  1216. if (seteuid(unpriv) == -1) return 0;
  1217. if (setegid(getgid()) == -1) return 0;
  1218. }
  1219. #else
  1220. (void)need_root; /* Quiet unused variable warning */
  1221. #endif
  1222. return 1;
  1223. }
  1224. int
  1225. become_root(void)
  1226. {
  1227. #ifndef SINGLE_USERID
  1228. /* first, set the effective userid to 0 */
  1229. if (seteuid(0) == -1) return 0;
  1230. /* then, set all of the userids to 0 */
  1231. if (setuid(0) == -1) return 0;
  1232. #endif
  1233. return 1;
  1234. }
  1235. char *
  1236. base64_decode_alloc_string(
  1237. char *in)
  1238. {
  1239. char *out;
  1240. size_t in_len = strlen(in);
  1241. size_t out_len = 3 * (in_len / 4) + 3;
  1242. out = malloc(out_len);
  1243. if (!base64_decode(in, in_len, out, &out_len)) {
  1244. amfree(out);
  1245. return NULL;
  1246. }
  1247. out[out_len] = '\0';
  1248. return out;
  1249. }
  1250. /* A GHFunc (callback for g_hash_table_foreach),
  1251. * Store a property and it's value in an ARGV.
  1252. *
  1253. * @param key_p: (char *) property name.
  1254. * @param value_p: (GSList *) property values list.
  1255. * @param user_data_p: (char ***) pointer to ARGV.
  1256. */
  1257. static void
  1258. proplist_add_to_argv(
  1259. gpointer key_p,
  1260. gpointer value_p,
  1261. gpointer user_data_p)
  1262. {
  1263. char *property_s = key_p;
  1264. property_t *value_s = value_p;
  1265. GPtrArray *argv_ptr = user_data_p;
  1266. GSList *value;
  1267. char *q, *w, *qprop;
  1268. q = stralloc(property_s);
  1269. /* convert to lower case */
  1270. for (w=q; *w != '\0'; w++) {
  1271. *w = tolower(*w);
  1272. if (*w == '_')
  1273. *w = '-';
  1274. }
  1275. qprop = stralloc2("--", q);
  1276. amfree(q);
  1277. for(value=value_s->values; value != NULL; value = value->next) {
  1278. g_ptr_array_add(argv_ptr, stralloc(qprop));
  1279. g_ptr_array_add(argv_ptr, stralloc((char *)value->data));
  1280. }
  1281. amfree(qprop);
  1282. }
  1283. void
  1284. property_add_to_argv(
  1285. GPtrArray *argv_ptr,
  1286. GHashTable *proplist)
  1287. {
  1288. g_hash_table_foreach(proplist, &proplist_add_to_argv, argv_ptr);
  1289. }
  1290. /*
  1291. * Process parameters
  1292. */
  1293. static char *pname = NULL;
  1294. static char *ptype = NULL;
  1295. static pcontext_t pcontext = CONTEXT_DEFAULT;
  1296. void
  1297. set_pname(char *p)
  1298. {
  1299. pname = newstralloc(pname, p);
  1300. }
  1301. char *
  1302. get_pname(void)
  1303. {
  1304. if (!pname) pname = stralloc("unknown");
  1305. return pname;
  1306. }
  1307. void
  1308. set_ptype(char *p)
  1309. {
  1310. ptype = newstralloc(ptype, p);
  1311. }
  1312. char *
  1313. get_ptype(void)
  1314. {
  1315. if (!ptype) ptype = stralloc("unknown");
  1316. return ptype;
  1317. }
  1318. void
  1319. set_pcontext(pcontext_t pc)
  1320. {
  1321. pcontext = pc;
  1322. }
  1323. pcontext_t
  1324. get_pcontext(void)
  1325. {
  1326. return pcontext;
  1327. }
  1328. #ifdef __OpenBSD__
  1329. void
  1330. openbsd_fd_inform(void)
  1331. {
  1332. int i;
  1333. for (i = DATA_FD_OFFSET; i < DATA_FD_OFFSET + DATA_FD_COUNT*2; i++) {
  1334. /* a simple fcntl() will cause the library to "look" at this file
  1335. * descriptor, which is good enough */
  1336. (void)fcntl(i, F_GETFL);
  1337. }
  1338. }
  1339. #endif
  1340. void
  1341. debug_executing(
  1342. GPtrArray *argv_ptr)
  1343. {
  1344. guint i;
  1345. char *cmdline = stralloc((char *)g_ptr_array_index(argv_ptr, 0));
  1346. for (i = 1; i < argv_ptr->len-1; i++) {
  1347. char *arg = g_shell_quote((char *)g_ptr_array_index(argv_ptr, i));
  1348. cmdline = vstrextend(&cmdline, " ", arg, NULL);
  1349. amfree(arg);
  1350. }
  1351. g_debug("Executing: %s\n", cmdline);
  1352. amfree(cmdline);
  1353. }