PageRenderTime 50ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

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

#
C | 1419 lines | 1163 code | 127 blank | 129 comment | 237 complexity | 9f5cba5add3e037798492ded1686fb67 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. /*
  299. * Writes out the entire iovec
  300. */
  301. ssize_t
  302. full_writev(
  303. int fd,
  304. struct iovec * iov,
  305. int iovcnt)
  306. {
  307. ssize_t delta, n, total;
  308. assert(iov != NULL);
  309. total = 0;
  310. while (iovcnt > 0) {
  311. /*
  312. * Write the iovec
  313. */
  314. n = writev(fd, iov, iovcnt);
  315. if (n < 0) {
  316. if (errno != EINTR)
  317. return (-1);
  318. }
  319. else if (n == 0) {
  320. errno = EIO;
  321. return (-1);
  322. } else {
  323. total += n;
  324. /*
  325. * Iterate through each iov. Figure out what we still need
  326. * to write out.
  327. */
  328. for (; n > 0; iovcnt--, iov++) {
  329. /* 'delta' is the bytes written from this iovec */
  330. delta = ((size_t)n < (size_t)iov->iov_len) ? n : (ssize_t)iov->iov_len;
  331. /* subtract from the total num bytes written */
  332. n -= delta;
  333. assert(n >= 0);
  334. /* subtract from this iovec */
  335. iov->iov_len -= delta;
  336. iov->iov_base = (char *)iov->iov_base + delta;
  337. /* if this iovec isn't empty, run the writev again */
  338. if (iov->iov_len > 0)
  339. break;
  340. }
  341. }
  342. }
  343. return (total);
  344. }
  345. /*
  346. * For backward compatibility we are trying for minimal quoting. Unless ALWAYS
  347. * is true, we only quote a string if it contains whitespace or is misquoted...
  348. */
  349. char *
  350. quote_string_maybe(
  351. const char *str,
  352. gboolean always)
  353. {
  354. char * s;
  355. char * ret;
  356. if ((str == NULL) || (*str == '\0')) {
  357. ret = stralloc("\"\"");
  358. } else if (!always && (match("[:\'\\\"[:space:][:cntrl:]]", str)) == 0) {
  359. /*
  360. * String does not need to be quoted since it contains
  361. * neither whitespace, control or quote characters.
  362. */
  363. ret = stralloc(str);
  364. } else {
  365. /*
  366. * Allocate maximum possible string length.
  367. * (a string of all quotes plus room for leading ", trailing " and NULL)
  368. */
  369. ret = s = alloc((strlen(str) * 2) + 2 + 1);
  370. *(s++) = '"';
  371. while (*str != '\0') {
  372. if (*str == '\t') {
  373. *(s++) = '\\';
  374. *(s++) = 't';
  375. str++;
  376. continue;
  377. } else if (*str == '\n') {
  378. *(s++) = '\\';
  379. *(s++) = 'n';
  380. str++;
  381. continue;
  382. } else if (*str == '\r') {
  383. *(s++) = '\\';
  384. *(s++) = 'r';
  385. str++;
  386. continue;
  387. } else if (*str == '\f') {
  388. *(s++) = '\\';
  389. *(s++) = 'f';
  390. str++;
  391. continue;
  392. } else if (*str == '\\') {
  393. *(s++) = '\\';
  394. *(s++) = '\\';
  395. str++;
  396. continue;
  397. }
  398. if (*str == '"')
  399. *(s++) = '\\';
  400. *(s++) = *(str++);
  401. }
  402. *(s++) = '"';
  403. *s = '\0';
  404. }
  405. return (ret);
  406. }
  407. char *
  408. unquote_string(
  409. const char *str)
  410. {
  411. char * ret;
  412. if ((str == NULL) || (*str == '\0')) {
  413. ret = stralloc("");
  414. } else {
  415. char * in;
  416. char * out;
  417. ret = in = out = stralloc(str);
  418. while (*in != '\0') {
  419. if (*in == '"') {
  420. in++;
  421. continue;
  422. }
  423. if (*in == '\\') {
  424. in++;
  425. if (*in == 'n') {
  426. in++;
  427. *(out++) = '\n';
  428. continue;
  429. } else if (*in == 't') {
  430. in++;
  431. *(out++) = '\t';
  432. continue;
  433. } else if (*in == 'r') {
  434. in++;
  435. *(out++) = '\r';
  436. continue;
  437. } else if (*in == 'f') {
  438. in++;
  439. *(out++) = '\f';
  440. continue;
  441. } else if (*in >= '0' && *in <= '7') {
  442. char c = 0;
  443. int i = 0;
  444. while (i < 3 && *in >= '0' && *in <= '7') {
  445. c = (c << 3) + *(in++) - '0';
  446. i++;
  447. }
  448. if (c)
  449. *(out++) = c;
  450. } else if (*in == '\0') {
  451. /* trailing backslash -- ignore */
  452. break;
  453. }
  454. }
  455. *(out++) = *(in++);
  456. }
  457. *out = '\0';
  458. }
  459. return (ret);
  460. }
  461. gchar **
  462. split_quoted_strings(
  463. const gchar *string)
  464. {
  465. char *local;
  466. char *start;
  467. char *p;
  468. char **result;
  469. GPtrArray *strs;
  470. int iq = 0;
  471. if (!string)
  472. return NULL;
  473. p = start = local = g_strdup(string);
  474. strs = g_ptr_array_new();
  475. while (*p) {
  476. if (!iq && *p == ' ') {
  477. *p = '\0';
  478. g_ptr_array_add(strs, unquote_string(start));
  479. start = p+1;
  480. } else if (*p == '\\') {
  481. /* next character is taken literally; if it's a multicharacter
  482. * escape (e.g., \171), that doesn't bother us here */
  483. p++;
  484. if (!*p) break;
  485. } else if (*p == '\"') {
  486. iq = ! iq;
  487. }
  488. p++;
  489. }
  490. if (start != string)
  491. g_ptr_array_add(strs, unquote_string(start));
  492. /* now convert strs into a strv, by stealing its references to the underlying
  493. * strings */
  494. result = g_new0(char *, strs->len + 1);
  495. memmove(result, strs->pdata, sizeof(char *) * strs->len);
  496. g_ptr_array_free(strs, FALSE); /* FALSE => don't free strings */
  497. g_free(local);
  498. return result;
  499. }
  500. char *
  501. strquotedstr(char **saveptr)
  502. {
  503. char * tok = strtok_r(NULL, " ", saveptr);
  504. size_t len;
  505. int in_quote;
  506. int in_backslash;
  507. char *p, *t;
  508. if (!tok)
  509. return tok;
  510. len = strlen(tok);
  511. in_quote = 0;
  512. in_backslash = 0;
  513. p = tok;
  514. while (in_quote || in_backslash || *p != '\0') {
  515. if (*p == '\0') {
  516. /* append a new token */
  517. t = strtok_r(NULL, " ", saveptr);
  518. if (!t)
  519. return NULL;
  520. tok[len] = ' ';
  521. len = strlen(tok);
  522. }
  523. if (!in_backslash) {
  524. if (*p == '"')
  525. in_quote = !in_quote;
  526. else if (*p == '\\') {
  527. in_backslash = 1;
  528. }
  529. } else {
  530. in_backslash = 0;
  531. }
  532. p++;
  533. }
  534. return tok;
  535. }
  536. char *
  537. sanitize_string(
  538. const char *str)
  539. {
  540. char * s;
  541. char * ret;
  542. if ((str == NULL) || (*str == '\0')) {
  543. ret = stralloc("");
  544. } else {
  545. ret = stralloc(str);
  546. for (s = ret; *s != '\0'; s++) {
  547. if (iscntrl((int)*s))
  548. *s = '?';
  549. }
  550. }
  551. return (ret);
  552. }
  553. char *hexencode_string(const char *str)
  554. {
  555. size_t orig_len, new_len, i;
  556. GString *s;
  557. gchar *ret;
  558. if (!str) {
  559. s = g_string_sized_new(0);
  560. goto cleanup;
  561. }
  562. new_len = orig_len = strlen(str);
  563. for (i = 0; i < orig_len; i++) {
  564. if (!g_ascii_isalnum(str[i])) {
  565. new_len += 2;
  566. }
  567. }
  568. s = g_string_sized_new(new_len);
  569. for (i = 0; i < orig_len; i++) {
  570. if (g_ascii_isalnum(str[i])) {
  571. g_string_append_c(s, str[i]);
  572. } else {
  573. g_string_append_printf(s, "%%%02hhx", str[i]);
  574. }
  575. }
  576. cleanup:
  577. ret = s->str;
  578. g_string_free(s, FALSE);
  579. return ret;
  580. }
  581. char *hexdecode_string(const char *str, GError **err)
  582. {
  583. size_t orig_len, new_len, i;
  584. GString *s;
  585. gchar *ret;
  586. if (!str) {
  587. s = g_string_sized_new(0);
  588. goto cleanup;
  589. }
  590. new_len = orig_len = strlen(str);
  591. for (i = 0; i < orig_len; i++) {
  592. if (str[i] == '%') {
  593. new_len -= 2;
  594. }
  595. }
  596. s = g_string_sized_new(new_len);
  597. for (i = 0; (orig_len > 2) && (i < orig_len-2); i++) {
  598. if (str[i] == '%') {
  599. gchar tmp = 0;
  600. size_t j;
  601. for (j = 1; j < 3; j++) {
  602. tmp <<= 4;
  603. if (str[i+j] >= '0' && str[i+j] <= '9') {
  604. tmp += str[i+j] - '0';
  605. } else if (str[i+j] >= 'a' && str[i+j] <= 'f') {
  606. tmp += str[i+j] - 'a' + 10;
  607. } else if (str[i+j] >= 'A' && str[i+j] <= 'F') {
  608. tmp += str[i+j] - 'A' + 10;
  609. } else {
  610. /* error */
  611. g_set_error(err, am_util_error_quark(), AM_UTIL_ERROR_HEXDECODEINVAL,
  612. "Illegal character (non-hex) 0x%02hhx at offset %zd", str[i+j], i+j);
  613. g_string_truncate(s, 0);
  614. goto cleanup;
  615. }
  616. }
  617. if (!tmp) {
  618. g_set_error(err, am_util_error_quark(), AM_UTIL_ERROR_HEXDECODEINVAL,
  619. "Encoded NULL at starting offset %zd", i);
  620. g_string_truncate(s, 0);
  621. goto cleanup;
  622. }
  623. g_string_append_c(s, tmp);
  624. i += 2;
  625. } else {
  626. g_string_append_c(s, str[i]);
  627. }
  628. }
  629. for ( /*nothing*/; i < orig_len; i++) {
  630. if (str[i] == '%') {
  631. g_set_error(err, am_util_error_quark(), AM_UTIL_ERROR_HEXDECODEINVAL,
  632. "'%%' found at offset %zd, but fewer than two characters follow it (%zd)", i, orig_len-i-1);
  633. g_string_truncate(s, 0);
  634. goto cleanup;
  635. } else {
  636. g_string_append_c(s, str[i]);
  637. }
  638. }
  639. cleanup:
  640. ret = s->str;
  641. g_string_free(s, FALSE);
  642. return ret;
  643. }
  644. /* Helper for expand_braced_alternates; returns a list of un-escaped strings
  645. * for the first "component" of str, where a component is a plain string or a
  646. * brace-enclosed set of alternatives. str is pointing to the first character
  647. * of the next component on return. */
  648. static GPtrArray *
  649. parse_braced_component(char **str)
  650. {
  651. GPtrArray *result = g_ptr_array_new();
  652. if (**str == '{') {
  653. char *p = (*str)+1;
  654. char *local = g_malloc(strlen(*str)+1);
  655. char *current = local;
  656. char *c = current;
  657. while (1) {
  658. if (*p == '\0' || *p == '{') {
  659. /* unterminated { .. } or extra '{' */
  660. amfree(local);
  661. g_ptr_array_free(result, TRUE);
  662. return NULL;
  663. }
  664. if (*p == '}' || *p == ',') {
  665. *c = '\0';
  666. g_ptr_array_add(result, g_strdup(current));
  667. current = ++c;
  668. if (*p == '}')
  669. break;
  670. else
  671. p++;
  672. }
  673. if (*p == '\\') {
  674. if (*(p+1) == '{' || *(p+1) == '}' || *(p+1) == '\\' || *(p+1) == ',')
  675. p++;
  676. }
  677. *(c++) = *(p++);
  678. }
  679. amfree(local);
  680. if (*p)
  681. *str = p+1;
  682. else
  683. *str = p;
  684. } else {
  685. /* no braces -- just un-escape a plain string */
  686. char *local = g_malloc(strlen(*str)+1);
  687. char *r = local;
  688. char *p = *str;
  689. while (*p && *p != '{') {
  690. if (*p == '\\') {
  691. if (*(p+1) == '{' || *(p+1) == '}' || *(p+1) == '\\' || *(p+1) == ',')
  692. p++;
  693. }
  694. *(r++) = *(p++);
  695. }
  696. *r = '\0';
  697. g_ptr_array_add(result, local);
  698. *str = p;
  699. }
  700. return result;
  701. }
  702. GPtrArray *
  703. expand_braced_alternates(
  704. char * source)
  705. {
  706. GPtrArray *rval = g_ptr_array_new();
  707. g_ptr_array_add(rval, g_strdup(""));
  708. while (*source) {
  709. GPtrArray *new_components;
  710. GPtrArray *new_rval;
  711. guint i, j;
  712. new_components = parse_braced_component(&source);
  713. if (!new_components) {
  714. /* parse error */
  715. g_ptr_array_free(rval, TRUE);
  716. return NULL;
  717. }
  718. new_rval = g_ptr_array_new();
  719. /* do a cartesian join of rval and new_components */
  720. for (i = 0; i < rval->len; i++) {
  721. for (j = 0; j < new_components->len; j++) {
  722. g_ptr_array_add(new_rval, g_strconcat(
  723. g_ptr_array_index(rval, i),
  724. g_ptr_array_index(new_components, j),
  725. NULL));
  726. }
  727. }
  728. g_ptr_array_free(rval, TRUE);
  729. g_ptr_array_free(new_components, TRUE);
  730. rval = new_rval;
  731. }
  732. return rval;
  733. }
  734. char *
  735. collapse_braced_alternates(
  736. GPtrArray *source)
  737. {
  738. GString *result = NULL;
  739. guint i;
  740. result = g_string_new("{");
  741. for (i = 0; i < source->len; i ++) {
  742. const char *str = g_ptr_array_index(source, i);
  743. char *qstr = NULL;
  744. if (strchr(str, ',') || strchr(str, '\\') ||
  745. strchr(str, '{') || strchr(str, '}')) {
  746. const char *s;
  747. char *d;
  748. s = str;
  749. qstr = d = g_malloc(strlen(str)*2+1);
  750. while (*s) {
  751. if (*s == ',' || *s == '\\' || *s == '{' || *s == '}')
  752. *(d++) = '\\';
  753. *(d++) = *(s++);
  754. }
  755. *(d++) = '\0';
  756. }
  757. g_string_append_printf(result, "%s%s", qstr? qstr : str,
  758. (i < source->len-1)? "," : "");
  759. if (qstr)
  760. g_free(qstr);
  761. }
  762. g_string_append(result, "}");
  763. return g_string_free(result, FALSE);
  764. }
  765. /*
  766. Return 0 if the following characters are present
  767. * ( ) < > [ ] , ; : ! $ \ / "
  768. else returns 1
  769. */
  770. int
  771. validate_mailto(
  772. const char *mailto)
  773. {
  774. return !match("\\*|<|>|\\(|\\)|\\[|\\]|,|;|:|\\\\|/|\"|\\!|\\$|\\|", mailto);
  775. }
  776. int copy_file(
  777. char *dst,
  778. char *src,
  779. char **errmsg)
  780. {
  781. int infd, outfd;
  782. int save_errno;
  783. size_t nb;
  784. char buf[32768];
  785. char *quoted;
  786. if ((infd = open(src, O_RDONLY)) == -1) {
  787. save_errno = errno;
  788. quoted = quote_string(src);
  789. *errmsg = vstrallocf(_("Can't open file '%s' for reading: %s"),
  790. quoted, strerror(save_errno));
  791. amfree(quoted);
  792. return -1;
  793. }
  794. if ((outfd = open(dst, O_WRONLY|O_CREAT, 0600)) == -1) {
  795. save_errno = errno;
  796. quoted = quote_string(dst);
  797. *errmsg = vstrallocf(_("Can't open file '%s' for writting: %s"),
  798. quoted, strerror(save_errno));
  799. amfree(quoted);
  800. close(infd);
  801. return -1;
  802. }
  803. while((nb=read(infd, &buf, SIZEOF(buf))) > 0) {
  804. if(full_write(outfd,&buf,nb) < nb) {
  805. save_errno = errno;
  806. quoted = quote_string(dst);
  807. *errmsg = vstrallocf(_("Error writing to '%s': %s"),
  808. quoted, strerror(save_errno));
  809. amfree(quoted);
  810. close(infd);
  811. close(outfd);
  812. return -1;
  813. }
  814. }
  815. if (errno != 0) {
  816. save_errno = errno;
  817. quoted = quote_string(src);
  818. *errmsg = vstrallocf(_("Error reading from '%s': %s"),
  819. quoted, strerror(save_errno));
  820. amfree(quoted);
  821. close(infd);
  822. close(outfd);
  823. return -1;
  824. }
  825. close(infd);
  826. close(outfd);
  827. return 0;
  828. }
  829. #ifndef HAVE_READLINE
  830. /*
  831. * simple readline() replacements, used when we don't have readline
  832. * support from the system.
  833. */
  834. char *
  835. readline(
  836. const char *prompt)
  837. {
  838. g_printf("%s", prompt);
  839. fflush(stdout);
  840. fflush(stderr);
  841. return agets(stdin);
  842. }
  843. void
  844. add_history(
  845. const char *line)
  846. {
  847. (void)line; /* Quiet unused parameter warning */
  848. }
  849. #endif
  850. /* Order of preference: readdir64(), readdir(). */
  851. #if HAVE_DECL_READDIR64
  852. # define USE_DIRENT64
  853. # define USE_READDIR64
  854. #elif HAVE_DECL_READDIR
  855. # define USE_READDIR
  856. #else
  857. # error No readdir() or readdir64() available!
  858. #endif
  859. char * portable_readdir(DIR* handle) {
  860. #ifdef USE_DIRENT64
  861. struct dirent64 *entry_p;
  862. #else
  863. struct dirent *entry_p;
  864. #endif
  865. static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
  866. g_static_mutex_lock(&mutex);
  867. #ifdef USE_READDIR
  868. entry_p = readdir(handle);
  869. #endif
  870. #ifdef USE_READDIR64
  871. entry_p = readdir64(handle);
  872. #endif
  873. g_static_mutex_unlock(&mutex);
  874. if (entry_p == NULL)
  875. return NULL;
  876. /* FIXME: According to glibc documentation, d_name may not be
  877. null-terminated in some cases on some very old platforms. Not
  878. sure what to do about that case. */
  879. return strdup(entry_p->d_name);
  880. }
  881. int search_directory(DIR * handle, const char * regex,
  882. SearchDirectoryFunctor functor, gpointer user_data) {
  883. int rval = 0;
  884. regex_t compiled_regex;
  885. gboolean done = FALSE;
  886. if (regcomp(&compiled_regex, regex, REG_EXTENDED | REG_NOSUB) != 0) {
  887. regfree(&compiled_regex);
  888. return -1;
  889. }
  890. rewinddir(handle);
  891. while (!done) {
  892. char * read_name;
  893. int result;
  894. read_name = portable_readdir(handle);
  895. if (read_name == NULL) {
  896. regfree(&compiled_regex);
  897. return rval;
  898. }
  899. result = regexec(&compiled_regex, read_name, 0, NULL, 0);
  900. if (result == 0) {
  901. rval ++;
  902. done = !functor(read_name, user_data);
  903. }
  904. amfree(read_name);
  905. }
  906. regfree(&compiled_regex);
  907. return rval;
  908. }
  909. char* find_regex_substring(const char* base_string, const regmatch_t match) {
  910. char * rval;
  911. int size;
  912. size = match.rm_eo - match.rm_so;
  913. rval = malloc(size+1);
  914. memcpy(rval, base_string + match.rm_so, size);
  915. rval[size] = '\0';
  916. return rval;
  917. }
  918. int compare_possibly_null_strings(const char * a, const char * b) {
  919. if (a == b) {
  920. /* NULL or otherwise, they're the same. */
  921. return 0;
  922. } else if (a == NULL) {
  923. /* b != NULL */
  924. return -1;
  925. } else if (b == NULL) {
  926. /* a != NULL */
  927. return 1;
  928. } else {
  929. /* a != NULL != b */
  930. return strcmp(a, b);
  931. }
  932. }
  933. int
  934. resolve_hostname(const char *hostname,
  935. int socktype,
  936. struct addrinfo **res,
  937. char **canonname)
  938. {
  939. struct addrinfo hints;
  940. struct addrinfo *myres;
  941. int flags = 0;
  942. int result;
  943. if (res) *res = NULL;
  944. if (canonname) {
  945. *canonname = NULL;
  946. flags = AI_CANONNAME;
  947. }
  948. #ifdef AI_ADDRCONFIG
  949. flags |= AI_ADDRCONFIG;
  950. #endif
  951. memset(&hints, 0, sizeof(hints));
  952. #ifdef WORKING_IPV6
  953. /* get any kind of addresss */
  954. hints.ai_family = AF_UNSPEC;
  955. #else
  956. /* even if getaddrinfo supports IPv6, don't let it return
  957. * such an address */
  958. hints.ai_family = AF_INET;
  959. #endif
  960. hints.ai_flags = flags;
  961. hints.ai_socktype = socktype;
  962. result = getaddrinfo(hostname, NULL, &hints, &myres);
  963. if (result != 0) {
  964. return result;
  965. }
  966. if (canonname && myres && myres->ai_canonname) {
  967. *canonname = stralloc(myres->ai_canonname);
  968. }
  969. if (res) {
  970. *res = myres;
  971. } else {
  972. freeaddrinfo(myres);
  973. }
  974. return result;
  975. }
  976. char *
  977. _str_exit_status(
  978. char *subject,
  979. amwait_t status)
  980. {
  981. if (WIFEXITED(status)) {
  982. int exitstatus = WEXITSTATUS(status);
  983. if (exitstatus == 0)
  984. return vstrallocf(_("%s exited normally"), subject);
  985. else
  986. return vstrallocf(_("%s exited with status %d"), subject, exitstatus);
  987. }
  988. if (WIFSIGNALED(status)) {
  989. int signal = WTERMSIG(status);
  990. #ifdef WCOREDUMP
  991. if (WCOREDUMP(status))
  992. return vstrallocf(_("%s exited after receiving signal %d (core dumped)"),
  993. subject, signal);
  994. else
  995. #endif
  996. return vstrallocf(_("%s exited after receiving signal %d"),
  997. subject, signal);
  998. }
  999. if (WIFSTOPPED(status)) {
  1000. int signal = WSTOPSIG(status);
  1001. return vstrallocf(_("%s stopped temporarily after receiving signal %d"),
  1002. subject, signal);
  1003. }
  1004. #ifdef WIFCONTINUED
  1005. if (WIFCONTINUED(status)) {
  1006. return vstrallocf(_("%s was resumed"), subject);
  1007. }
  1008. #endif
  1009. return vstrallocf(_("%s exited in unknown circumstances"), subject);
  1010. }
  1011. void
  1012. check_running_as(running_as_flags who)
  1013. {
  1014. #ifdef CHECK_USERID
  1015. struct passwd *pw;
  1016. uid_t uid_me;
  1017. uid_t uid_target;
  1018. char *uname_me = NULL;
  1019. char *uname_target = NULL;
  1020. char *dumpuser;
  1021. uid_me = getuid();
  1022. if ((pw = getpwuid(uid_me)) == NULL) {
  1023. error(_("current userid %ld not found in password database"), (long)uid_me);
  1024. /* NOTREACHED */
  1025. }
  1026. uname_me = stralloc(pw->pw_name);
  1027. #ifndef SINGLE_USERID
  1028. if (!(who & RUNNING_AS_UID_ONLY) && uid_me != geteuid()) {
  1029. error(_("euid (%lld) does not match uid (%lld); is this program setuid-root when it shouldn't be?"),
  1030. (long long int)geteuid(), (long long int)uid_me);
  1031. /* NOTREACHED */
  1032. }
  1033. #endif
  1034. switch (who & RUNNING_AS_USER_MASK) {
  1035. case RUNNING_AS_ANY:
  1036. uid_target = uid_me;
  1037. uname_target = uname_me;
  1038. amfree(uname_me);
  1039. return;
  1040. case RUNNING_AS_ROOT:
  1041. uid_target = 0;
  1042. uname_target = "root";
  1043. break;
  1044. case RUNNING_AS_DUMPUSER_PREFERRED:
  1045. dumpuser = getconf_str(CNF_DUMPUSER);
  1046. if ((pw = getpwnam(dumpuser)) != NULL &&
  1047. uid_me != pw->pw_uid) {
  1048. if ((pw = getpwnam(CLIENT_LOGIN)) != NULL &&
  1049. uid_me == pw->pw_uid) {
  1050. /* uid == CLIENT_LOGIN: not ideal, but OK */
  1051. dbprintf(_("NOTE: running as '%s', which is the client"
  1052. " user, not the dumpuser ('%s'); forging"
  1053. " on anyway\n"),
  1054. CLIENT_LOGIN, dumpuser);
  1055. uid_target = uid_me; /* force success below */
  1056. break;
  1057. }
  1058. }
  1059. /* FALLTHROUGH */
  1060. case RUNNING_AS_DUMPUSER:
  1061. uname_target = getconf_str(CNF_DUMPUSER);
  1062. if ((pw = getpwnam(uname_target)) == NULL) {
  1063. error(_("cannot look up dumpuser \"%s\""), uname_target);
  1064. /*NOTREACHED*/
  1065. }
  1066. uid_target = pw->pw_uid;
  1067. break;
  1068. case RUNNING_AS_CLIENT_LOGIN:
  1069. uname_target = CLIENT_LOGIN;
  1070. if ((pw = getpwnam(uname_target)) == NULL) {
  1071. error(_("cannot look up client user \"%s\""), uname_target);
  1072. /*NOTREACHED*/
  1073. }
  1074. uid_target = pw->pw_uid;
  1075. break;
  1076. default:
  1077. error(_("Unknown check_running_as() call"));
  1078. /* NOTREACHED */
  1079. }
  1080. if (uid_me != uid_target) {
  1081. error(_("running as user \"%s\" instead of \"%s\""), uname_me, uname_target);
  1082. /*NOTREACHED*/
  1083. }
  1084. amfree(uname_me);
  1085. #else
  1086. /* Quiet unused variable warning */
  1087. (void)who;
  1088. #endif
  1089. }
  1090. int
  1091. set_root_privs(int need_root)
  1092. {
  1093. #ifndef SINGLE_USERID
  1094. static gboolean first_call = TRUE;
  1095. static uid_t unpriv = 1;
  1096. if (first_call) {
  1097. /* save the original real userid (that of our invoker) */
  1098. unpriv = getuid();
  1099. /* and set all of our userids (including, importantly, the saved
  1100. * userid) to 0 */
  1101. setuid(0);
  1102. /* don't need to do this next time */
  1103. first_call = FALSE;
  1104. }
  1105. if (need_root == 1) {
  1106. if (geteuid() == 0) return 1; /* already done */
  1107. if (seteuid(0) == -1) return 0;
  1108. /* (we don't switch the group back) */
  1109. } else if (need_root == -1) {
  1110. /* make sure the euid is 0 so that we can set the uid */
  1111. if (geteuid() != 0) {
  1112. if (seteuid(0) == -1) return 0;
  1113. }
  1114. /* now set the uid to the unprivileged userid */
  1115. if (setuid(unpriv) == -1) return 0;
  1116. } else {
  1117. if (geteuid() != 0) return 1; /* already done */
  1118. /* set the *effective* userid only */
  1119. if (seteuid(unpriv) == -1) return 0;
  1120. if (setegid(getgid()) == -1) return 0;
  1121. }
  1122. #else
  1123. (void)need_root; /* Quiet unused variable warning */
  1124. #endif
  1125. return 1;
  1126. }
  1127. int
  1128. become_root(void)
  1129. {
  1130. #ifndef SINGLE_USERID
  1131. /* first, set the effective userid to 0 */
  1132. if (seteuid(0) == -1) return 0;
  1133. /* then, set all of the userids to 0 */
  1134. if (setuid(0) == -1) return 0;
  1135. #endif
  1136. return 1;
  1137. }
  1138. char *
  1139. base64_decode_alloc_string(
  1140. char *in)
  1141. {
  1142. char *out;
  1143. size_t in_len = strlen(in);
  1144. size_t out_len = 3 * (in_len / 4) + 3;
  1145. out = malloc(out_len);
  1146. if (!base64_decode(in, in_len, out, &out_len)) {
  1147. amfree(out);
  1148. return NULL;
  1149. }
  1150. out[out_len] = '\0';
  1151. return out;
  1152. }
  1153. /* A GHFunc (callback for g_hash_table_foreach) */
  1154. void count_proplist(
  1155. gpointer key_p G_GNUC_UNUSED,
  1156. gpointer value_p,
  1157. gpointer user_data_p)
  1158. {
  1159. property_t *value_s = value_p;
  1160. int *nb = user_data_p;
  1161. GSList *value;
  1162. for(value=value_s->values; value != NULL; value = value->next) {
  1163. (*nb)++;
  1164. }
  1165. }
  1166. /* A GHFunc (callback for g_hash_table_foreach) */
  1167. void proplist_add_to_argv(
  1168. gpointer key_p,
  1169. gpointer value_p,
  1170. gpointer user_data_p)
  1171. {
  1172. char *property_s = key_p;
  1173. property_t *value_s = value_p;
  1174. GPtrArray *argv_ptr = user_data_p;
  1175. GSList *value;
  1176. char *q, *w, *qprop;
  1177. q = stralloc(property_s);
  1178. /* convert to lower case */
  1179. for (w=q; *w != '\0'; w++) {
  1180. *w = tolower(*w);
  1181. if (*w == '_')
  1182. *w = '-';
  1183. }
  1184. qprop = stralloc2("--", q);
  1185. amfree(q);
  1186. for(value=value_s->values; value != NULL; value = value->next) {
  1187. g_ptr_array_add(argv_ptr, stralloc(qprop));
  1188. g_ptr_array_add(argv_ptr, stralloc((char *)value->data));
  1189. }
  1190. amfree(qprop);
  1191. }
  1192. /*
  1193. * Process parameters
  1194. */
  1195. static char *pname = NULL;
  1196. static char *ptype = NULL;
  1197. static pcontext_t pcontext = CONTEXT_DEFAULT;
  1198. void
  1199. set_pname(char *p)
  1200. {
  1201. pname = newstralloc(pname, p);
  1202. }
  1203. char *
  1204. get_pname(void)
  1205. {
  1206. if (!pname) pname = stralloc("unknown");
  1207. return pname;
  1208. }
  1209. void
  1210. set_ptype(char *p)
  1211. {
  1212. ptype = newstralloc(ptype, p);
  1213. }
  1214. char *
  1215. get_ptype(void)
  1216. {
  1217. if (!ptype) ptype = stralloc("unknown");
  1218. return ptype;
  1219. }
  1220. void
  1221. set_pcontext(pcontext_t pc)
  1222. {
  1223. pcontext = pc;
  1224. }
  1225. pcontext_t
  1226. get_pcontext(void)
  1227. {
  1228. return pcontext;
  1229. }
  1230. #ifdef __OpenBSD__
  1231. void
  1232. openbsd_fd_inform(void)
  1233. {
  1234. int i;
  1235. for (i = DATA_FD_OFFSET; i < DATA_FD_OFFSET + DATA_FD_COUNT*2; i++) {
  1236. /* a simple fcntl() will cause the library to "look" at this file
  1237. * descriptor, which is good enough */
  1238. (void)fcntl(i, F_GETFL);
  1239. }
  1240. }
  1241. #endif
  1242. void
  1243. debug_executing(
  1244. GPtrArray *argv_ptr)
  1245. {
  1246. guint i;
  1247. char *cmdline = stralloc((char *)g_ptr_array_index(argv_ptr, 0));
  1248. for (i = 1; i < argv_ptr->len-1; i++) {
  1249. char *arg = g_shell_quote((char *)g_ptr_array_index(argv_ptr, i));
  1250. cmdline = vstrextend(&cmdline, " ", arg, NULL);
  1251. amfree(arg);
  1252. }
  1253. g_debug("Executing: %s\n", cmdline);
  1254. amfree(cmdline);
  1255. }