PageRenderTime 56ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

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

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