PageRenderTime 53ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/amanda/tags/amanda261p2/common-src/util.c

#
C | 1112 lines | 877 code | 115 blank | 120 comment | 221 complexity | 0ace0249fc79e94c71e5c73bc91a7e95 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 <regex.h>
  32. #include "arglist.h"
  33. #include "clock.h"
  34. #include "sockaddr-util.h"
  35. #include "conffile.h"
  36. #include "base64.h"
  37. static int make_socket(sa_family_t family);
  38. static int connect_port(sockaddr_union *addrp, in_port_t port, char *proto,
  39. sockaddr_union *svaddr, int nonblock);
  40. static int
  41. make_socket(
  42. sa_family_t family)
  43. {
  44. int s;
  45. int save_errno;
  46. #if defined(SO_KEEPALIVE) || defined(USE_REUSEADDR)
  47. int on=1;
  48. int r;
  49. #endif
  50. g_debug("make_socket opening socket with family %d", family);
  51. s = socket(family, SOCK_STREAM, 0);
  52. if (s == -1) {
  53. save_errno = errno;
  54. dbprintf(_("make_socket: socket() failed: %s\n"), strerror(save_errno));
  55. errno = save_errno;
  56. return -1;
  57. }
  58. if (s < 0 || s >= (int)FD_SETSIZE) {
  59. aclose(s);
  60. errno = EMFILE; /* out of range */
  61. return -1;
  62. }
  63. #ifdef USE_REUSEADDR
  64. r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
  65. if (r < 0) {
  66. save_errno = errno;
  67. dbprintf(_("make_socket: setsockopt(SO_REUSEADDR) failed: %s\n"),
  68. strerror(errno));
  69. errno = save_errno;
  70. }
  71. #endif
  72. #ifdef SO_KEEPALIVE
  73. r = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
  74. (void *)&on, SIZEOF(on));
  75. if (r == -1) {
  76. save_errno = errno;
  77. dbprintf(_("make_socket: setsockopt() failed: %s\n"),
  78. strerror(save_errno));
  79. aclose(s);
  80. errno = save_errno;
  81. return -1;
  82. }
  83. #endif
  84. return s;
  85. }
  86. /* addrp is my address */
  87. /* svaddr is the address of the remote machine */
  88. /* return socket on success */
  89. /* return -1 on failure */
  90. int
  91. connect_portrange(
  92. sockaddr_union *addrp,
  93. in_port_t first_port,
  94. in_port_t last_port,
  95. char * proto,
  96. sockaddr_union *svaddr,
  97. int nonblock)
  98. {
  99. int s;
  100. in_port_t port;
  101. static in_port_t port_in_use[1024];
  102. static int nb_port_in_use = 0;
  103. int i;
  104. int save_errno = EAGAIN;
  105. assert(first_port <= last_port);
  106. /* Try a port already used */
  107. for(i=0; i < nb_port_in_use; i++) {
  108. port = port_in_use[i];
  109. if(port >= first_port && port <= last_port) {
  110. s = connect_port(addrp, port, proto, svaddr, nonblock);
  111. if(s == -2) return -1;
  112. if(s > 0) {
  113. return s;
  114. }
  115. if (errno != EAGAIN && errno != EBUSY)
  116. save_errno = errno;
  117. }
  118. }
  119. /* Try a port in the range */
  120. for (port = first_port; port <= last_port; port++) {
  121. s = connect_port(addrp, port, proto, svaddr, nonblock);
  122. if(s == -2) return -1;
  123. if(s > 0) {
  124. port_in_use[nb_port_in_use++] = port;
  125. return s;
  126. }
  127. if (errno != EAGAIN && errno != EBUSY)
  128. save_errno = errno;
  129. }
  130. dbprintf(_("connect_portrange: All ports between %d and %d are busy.\n"),
  131. first_port,
  132. last_port);
  133. errno = save_errno;
  134. return -1;
  135. }
  136. /* addrp is my address */
  137. /* svaddr is the address of the remote machine */
  138. /* return -2: Don't try again */
  139. /* return -1: Try with another port */
  140. /* return >0: this is the connected socket */
  141. int
  142. connect_port(
  143. sockaddr_union *addrp,
  144. in_port_t port,
  145. char * proto,
  146. sockaddr_union *svaddr,
  147. int nonblock)
  148. {
  149. int save_errno;
  150. struct servent * servPort;
  151. socklen_t_equiv len;
  152. socklen_t_equiv socklen;
  153. int s;
  154. servPort = getservbyport((int)htons(port), proto);
  155. if (servPort != NULL && !strstr(servPort->s_name, "amanda")) {
  156. dbprintf(_("connect_port: Skip port %d: owned by %s.\n"),
  157. port, servPort->s_name);
  158. errno = EBUSY;
  159. return -1;
  160. }
  161. if ((s = make_socket(SU_GET_FAMILY(addrp))) == -1) return -2;
  162. SU_SET_PORT(addrp, port);
  163. socklen = SS_LEN(addrp);
  164. if (bind(s, (struct sockaddr *)addrp, socklen) != 0) {
  165. save_errno = errno;
  166. aclose(s);
  167. if(servPort == NULL) {
  168. dbprintf(_("connect_port: Try port %d: available - %s\n"),
  169. port, strerror(errno));
  170. } else {
  171. dbprintf(_("connect_port: Try port %d: owned by %s - %s\n"),
  172. port, servPort->s_name, strerror(errno));
  173. }
  174. if (save_errno != EADDRINUSE) {
  175. errno = save_errno;
  176. return -2;
  177. }
  178. errno = save_errno;
  179. return -1;
  180. }
  181. if(servPort == NULL) {
  182. dbprintf(_("connect_port: Try port %d: available - Success\n"), port);
  183. } else {
  184. dbprintf(_("connect_port: Try port %d: owned by %s - Success\n"),
  185. port, servPort->s_name);
  186. }
  187. /* find out what port was actually used */
  188. len = sizeof(*addrp);
  189. if (getsockname(s, (struct sockaddr *)addrp, &len) == -1) {
  190. save_errno = errno;
  191. dbprintf(_("connect_port: getsockname() failed: %s\n"),
  192. strerror(save_errno));
  193. aclose(s);
  194. errno = save_errno;
  195. return -1;
  196. }
  197. if (nonblock)
  198. fcntl(s, F_SETFL, fcntl(s, F_GETFL, 0)|O_NONBLOCK);
  199. if (connect(s, (struct sockaddr *)svaddr, SS_LEN(svaddr)) == -1 && !nonblock) {
  200. save_errno = errno;
  201. dbprintf(_("connect_portrange: Connect from %s failed: %s\n"),
  202. str_sockaddr(addrp),
  203. strerror(save_errno));
  204. dbprintf(_("connect_portrange: connect to %s failed: %s\n"),
  205. str_sockaddr(svaddr),
  206. strerror(save_errno));
  207. aclose(s);
  208. errno = save_errno;
  209. if (save_errno == ECONNREFUSED ||
  210. save_errno == EHOSTUNREACH ||
  211. save_errno == ENETUNREACH ||
  212. save_errno == ETIMEDOUT) {
  213. return -2 ;
  214. }
  215. return -1;
  216. }
  217. dbprintf(_("connected to %s\n"),
  218. str_sockaddr(svaddr));
  219. dbprintf(_("our side is %s\n"),
  220. str_sockaddr(addrp));
  221. return s;
  222. }
  223. /*
  224. * Bind to a port in the given range. Takes a begin,end pair of port numbers.
  225. *
  226. * Returns negative on error (EGAIN if all ports are in use). Returns 0
  227. * on success.
  228. */
  229. int
  230. bind_portrange(
  231. int s,
  232. sockaddr_union *addrp,
  233. in_port_t first_port,
  234. in_port_t last_port,
  235. char * proto)
  236. {
  237. in_port_t port;
  238. in_port_t cnt;
  239. socklen_t_equiv socklen;
  240. struct servent *servPort;
  241. const in_port_t num_ports = (in_port_t)(last_port - first_port + 1);
  242. int save_errno = EAGAIN;
  243. assert(first_port <= last_port);
  244. /*
  245. * We pick a different starting port based on our pid and the current
  246. * time to avoid always picking the same reserved port twice.
  247. */
  248. port = (in_port_t)(((getpid() + time(0)) % num_ports) + first_port);
  249. /*
  250. * Scan through the range, trying all available ports that are either
  251. * not taken in /etc/services or registered for *amanda*. Wrap around
  252. * if we don't happen to start at the beginning.
  253. */
  254. for (cnt = 0; cnt < num_ports; cnt++) {
  255. servPort = getservbyport((int)htons(port), proto);
  256. if ((servPort == NULL) || strstr(servPort->s_name, "amanda")) {
  257. SU_SET_PORT(addrp, port);
  258. socklen = SS_LEN(addrp);
  259. if (bind(s, (struct sockaddr *)addrp, socklen) >= 0) {
  260. if (servPort == NULL) {
  261. dbprintf(_("bind_portrange2: Try port %d: Available - Success\n"), port);
  262. } else {
  263. dbprintf(_("bind_portrange2: Try port %d: Owned by %s - Success.\n"), port, servPort->s_name);
  264. }
  265. return 0;
  266. }
  267. if (errno != EAGAIN && errno != EBUSY)
  268. save_errno = errno;
  269. if (servPort == NULL) {
  270. dbprintf(_("bind_portrange2: Try port %d: Available - %s\n"),
  271. port, strerror(errno));
  272. } else {
  273. dbprintf(_("bind_portrange2: Try port %d: Owned by %s - %s\n"),
  274. port, servPort->s_name, strerror(errno));
  275. }
  276. } else {
  277. dbprintf(_("bind_portrange2: Skip port %d: Owned by %s.\n"),
  278. port, servPort->s_name);
  279. }
  280. if (++port > last_port)
  281. port = first_port;
  282. }
  283. dbprintf(_("bind_portrange: all ports between %d and %d busy\n"),
  284. first_port,
  285. last_port);
  286. errno = save_errno;
  287. return -1;
  288. }
  289. /*
  290. * Writes out the entire iovec
  291. */
  292. ssize_t
  293. full_writev(
  294. int fd,
  295. struct iovec * iov,
  296. int iovcnt)
  297. {
  298. ssize_t delta, n, total;
  299. assert(iov != NULL);
  300. total = 0;
  301. while (iovcnt > 0) {
  302. /*
  303. * Write the iovec
  304. */
  305. n = writev(fd, iov, iovcnt);
  306. if (n < 0) {
  307. if (errno != EINTR)
  308. return (-1);
  309. }
  310. else if (n == 0) {
  311. errno = EIO;
  312. return (-1);
  313. } else {
  314. total += n;
  315. /*
  316. * Iterate through each iov. Figure out what we still need
  317. * to write out.
  318. */
  319. for (; n > 0; iovcnt--, iov++) {
  320. /* 'delta' is the bytes written from this iovec */
  321. delta = ((size_t)n < (size_t)iov->iov_len) ? n : (ssize_t)iov->iov_len;
  322. /* subtract from the total num bytes written */
  323. n -= delta;
  324. assert(n >= 0);
  325. /* subtract from this iovec */
  326. iov->iov_len -= delta;
  327. iov->iov_base = (char *)iov->iov_base + delta;
  328. /* if this iovec isn't empty, run the writev again */
  329. if (iov->iov_len > 0)
  330. break;
  331. }
  332. }
  333. }
  334. return (total);
  335. }
  336. int
  337. needs_quotes(
  338. const char * str)
  339. {
  340. return (match("[ \t\f\r\n\"]", str) != 0);
  341. }
  342. /*
  343. * For backward compatibility we are trying for minimal quoting.
  344. * We only quote a string if it contains whitespace or is misquoted...
  345. */
  346. char *
  347. quote_string(
  348. const char *str)
  349. {
  350. char * s;
  351. char * ret;
  352. if ((str == NULL) || (*str == '\0')) {
  353. ret = stralloc("\"\"");
  354. } else if ((match("[:\'\\\"[:space:][:cntrl:]]", str)) == 0) {
  355. /*
  356. * String does not need to be quoted since it contains
  357. * neither whitespace, control or quote characters.
  358. */
  359. ret = stralloc(str);
  360. } else {
  361. /*
  362. * Allocate maximum possible string length.
  363. * (a string of all quotes plus room for leading ", trailing " and NULL)
  364. */
  365. ret = s = alloc((strlen(str) * 2) + 2 + 1);
  366. *(s++) = '"';
  367. while (*str != '\0') {
  368. if (*str == '\t') {
  369. *(s++) = '\\';
  370. *(s++) = 't';
  371. str++;
  372. continue;
  373. } else if (*str == '\n') {
  374. *(s++) = '\\';
  375. *(s++) = 'n';
  376. str++;
  377. continue;
  378. } else if (*str == '\r') {
  379. *(s++) = '\\';
  380. *(s++) = 'r';
  381. str++;
  382. continue;
  383. } else if (*str == '\f') {
  384. *(s++) = '\\';
  385. *(s++) = 'f';
  386. str++;
  387. continue;
  388. } else if (*str == '\\') {
  389. *(s++) = '\\';
  390. *(s++) = '\\';
  391. str++;
  392. continue;
  393. }
  394. if (*str == '"')
  395. *(s++) = '\\';
  396. *(s++) = *(str++);
  397. }
  398. *(s++) = '"';
  399. *s = '\0';
  400. }
  401. return (ret);
  402. }
  403. char *
  404. unquote_string(
  405. const char *str)
  406. {
  407. char * ret;
  408. if ((str == NULL) || (*str == '\0')) {
  409. ret = stralloc("");
  410. } else {
  411. char * in;
  412. char * out;
  413. ret = in = out = stralloc(str);
  414. while (*in != '\0') {
  415. if (*in == '"') {
  416. in++;
  417. continue;
  418. }
  419. if (*in == '\\') {
  420. in++;
  421. if (*in == 'n') {
  422. in++;
  423. *(out++) = '\n';
  424. continue;
  425. } else if (*in == 't') {
  426. in++;
  427. *(out++) = '\t';
  428. continue;
  429. } else if (*in == 'r') {
  430. in++;
  431. *(out++) = '\r';
  432. continue;
  433. } else if (*in == 'f') {
  434. in++;
  435. *(out++) = '\f';
  436. continue;
  437. } else if (*in >= '0' && *in <= '7') {
  438. char c = 0;
  439. int i = 0;
  440. while (i < 3 && *in >= '0' && *in <= '7') {
  441. c = (c << 3) + *(in++) - '0';
  442. i++;
  443. }
  444. if (c)
  445. *(out++) = c;
  446. } else if (*in == '\0') {
  447. /* trailing backslash -- ignore */
  448. break;
  449. }
  450. }
  451. *(out++) = *(in++);
  452. }
  453. *out = '\0';
  454. }
  455. return (ret);
  456. }
  457. gchar **
  458. split_quoted_strings(
  459. const gchar *string)
  460. {
  461. char *local = g_strdup(string);
  462. char *start = local;
  463. char *p = local;
  464. char **result;
  465. GPtrArray *strs = g_ptr_array_new();
  466. int iq = 0;
  467. while (*p) {
  468. if (!iq && *p == ' ') {
  469. *p = '\0';
  470. g_ptr_array_add(strs, unquote_string(start));
  471. start = p+1;
  472. } else if (*p == '\\') {
  473. /* next character is taken literally; if it's a multicharacter
  474. * escape (e.g., \171), that doesn't bother us here */
  475. p++;
  476. if (!*p) break;
  477. } else if (*p == '\"') {
  478. iq = ! iq;
  479. }
  480. p++;
  481. }
  482. if (start != string)
  483. g_ptr_array_add(strs, unquote_string(start));
  484. /* now convert strs into a strv, by stealing its references to the underlying
  485. * strings */
  486. result = g_new0(char *, strs->len + 1);
  487. memmove(result, strs->pdata, sizeof(char *) * strs->len);
  488. g_ptr_array_free(strs, FALSE); /* FALSE => don't free strings */
  489. g_free(local);
  490. return result;
  491. }
  492. char *
  493. strquotedstr(char **saveptr)
  494. {
  495. char * tok = strtok_r(NULL, " ", saveptr);
  496. size_t len;
  497. int in_quote;
  498. int in_backslash;
  499. char *p, *t;
  500. if (!tok)
  501. return tok;
  502. len = strlen(tok);
  503. in_quote = 0;
  504. in_backslash = 0;
  505. p = tok;
  506. while (in_quote || in_backslash || *p != '\0') {
  507. if (*p == '\0') {
  508. /* append a new token */
  509. t = strtok_r(NULL, " ", saveptr);
  510. if (!t)
  511. return NULL;
  512. tok[len] = ' ';
  513. len = strlen(tok);
  514. }
  515. if (!in_backslash) {
  516. if (*p == '"')
  517. in_quote = !in_quote;
  518. else if (*p == '\\') {
  519. in_backslash = 1;
  520. }
  521. } else {
  522. in_backslash = 0;
  523. }
  524. p++;
  525. }
  526. return tok;
  527. }
  528. char *
  529. sanitize_string(
  530. const char *str)
  531. {
  532. char * s;
  533. char * ret;
  534. if ((str == NULL) || (*str == '\0')) {
  535. ret = stralloc("");
  536. } else {
  537. ret = stralloc(str);
  538. for (s = ret; *s != '\0'; s++) {
  539. if (iscntrl((int)*s))
  540. *s = '?';
  541. }
  542. }
  543. return (ret);
  544. }
  545. /*
  546. Return 0 if the following characters are present
  547. * ( ) < > [ ] , ; : ! $ \ / "
  548. else returns 1
  549. */
  550. int
  551. validate_mailto(
  552. const char *mailto)
  553. {
  554. return !match("\\*|<|>|\\(|\\)|\\[|\\]|,|;|:|\\\\|/|\"|\\!|\\$|\\|", mailto);
  555. }
  556. int copy_file(
  557. char *dst,
  558. char *src,
  559. char **errmsg)
  560. {
  561. int infd, outfd;
  562. int save_errno;
  563. size_t nb;
  564. char buf[32768];
  565. char *quoted;
  566. if ((infd = open(src, O_RDONLY)) == -1) {
  567. save_errno = errno;
  568. quoted = quote_string(src);
  569. *errmsg = vstrallocf(_("Can't open file '%s' for reading: %s"),
  570. quoted, strerror(save_errno));
  571. amfree(quoted);
  572. return -1;
  573. }
  574. if ((outfd = open(dst, O_WRONLY|O_CREAT, 0600)) == -1) {
  575. save_errno = errno;
  576. quoted = quote_string(dst);
  577. *errmsg = vstrallocf(_("Can't open file '%s' for writting: %s"),
  578. quoted, strerror(save_errno));
  579. amfree(quoted);
  580. close(infd);
  581. return -1;
  582. }
  583. while((nb=read(infd, &buf, SIZEOF(buf))) > 0) {
  584. if(full_write(outfd,&buf,nb) < nb) {
  585. save_errno = errno;
  586. quoted = quote_string(dst);
  587. *errmsg = vstrallocf(_("Error writing to '%s': %s"),
  588. quoted, strerror(save_errno));
  589. amfree(quoted);
  590. close(infd);
  591. close(outfd);
  592. return -1;
  593. }
  594. }
  595. if (errno != 0) {
  596. save_errno = errno;
  597. quoted = quote_string(src);
  598. *errmsg = vstrallocf(_("Error reading from '%s': %s"),
  599. quoted, strerror(save_errno));
  600. amfree(quoted);
  601. close(infd);
  602. close(outfd);
  603. return -1;
  604. }
  605. close(infd);
  606. close(outfd);
  607. return 0;
  608. }
  609. #ifndef HAVE_READLINE
  610. /*
  611. * simple readline() replacements, used when we don't have readline
  612. * support from the system.
  613. */
  614. char *
  615. readline(
  616. const char *prompt)
  617. {
  618. g_printf("%s", prompt);
  619. fflush(stdout);
  620. fflush(stderr);
  621. return agets(stdin);
  622. }
  623. void
  624. add_history(
  625. const char *line)
  626. {
  627. (void)line; /* Quiet unused parameter warning */
  628. }
  629. #endif
  630. /* Order of preference: readdir64(), readdir(). */
  631. #if HAVE_DECL_READDIR64
  632. # define USE_DIRENT64
  633. # define USE_READDIR64
  634. #elif HAVE_DECL_READDIR
  635. # define USE_READDIR
  636. #else
  637. # error No readdir() or readdir64() available!
  638. #endif
  639. char * portable_readdir(DIR* handle) {
  640. #ifdef USE_DIRENT64
  641. struct dirent64 *entry_p;
  642. #else
  643. struct dirent *entry_p;
  644. #endif
  645. static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
  646. g_static_mutex_lock(&mutex);
  647. #ifdef USE_READDIR
  648. entry_p = readdir(handle);
  649. #endif
  650. #ifdef USE_READDIR64
  651. entry_p = readdir64(handle);
  652. #endif
  653. g_static_mutex_unlock(&mutex);
  654. if (entry_p == NULL)
  655. return NULL;
  656. /* FIXME: According to glibc documentation, d_name may not be
  657. null-terminated in some cases on some very old platforms. Not
  658. sure what to do about that case. */
  659. return strdup(entry_p->d_name);
  660. }
  661. int search_directory(DIR * handle, const char * regex,
  662. SearchDirectoryFunctor functor, gpointer user_data) {
  663. int rval = 0;
  664. regex_t compiled_regex;
  665. gboolean done = FALSE;
  666. if (regcomp(&compiled_regex, regex, REG_EXTENDED | REG_NOSUB) != 0) {
  667. regfree(&compiled_regex);
  668. return -1;
  669. }
  670. rewinddir(handle);
  671. while (!done) {
  672. char * read_name;
  673. int result;
  674. read_name = portable_readdir(handle);
  675. if (read_name == NULL) {
  676. regfree(&compiled_regex);
  677. return rval;
  678. }
  679. result = regexec(&compiled_regex, read_name, 0, NULL, 0);
  680. if (result == 0) {
  681. rval ++;
  682. done = !functor(read_name, user_data);
  683. }
  684. amfree(read_name);
  685. }
  686. regfree(&compiled_regex);
  687. return rval;
  688. }
  689. char* find_regex_substring(const char* base_string, const regmatch_t match) {
  690. char * rval;
  691. int size;
  692. size = match.rm_eo - match.rm_so;
  693. rval = malloc(size+1);
  694. memcpy(rval, base_string + match.rm_so, size);
  695. rval[size] = '\0';
  696. return rval;
  697. }
  698. int compare_possibly_null_strings(const char * a, const char * b) {
  699. if (a == b) {
  700. /* NULL or otherwise, they're the same. */
  701. return 0;
  702. } else if (a == NULL) {
  703. /* b != NULL */
  704. return -1;
  705. } else if (b == NULL) {
  706. /* a != NULL */
  707. return 1;
  708. } else {
  709. /* a != NULL != b */
  710. return strcmp(a, b);
  711. }
  712. }
  713. int
  714. resolve_hostname(const char *hostname,
  715. int socktype,
  716. struct addrinfo **res,
  717. char **canonname)
  718. {
  719. struct addrinfo hints;
  720. struct addrinfo *myres;
  721. int flags = 0;
  722. int result;
  723. if (res) *res = NULL;
  724. if (canonname) {
  725. *canonname = NULL;
  726. flags = AI_CANONNAME;
  727. }
  728. #ifdef AI_ADDRCONFIG
  729. flags |= AI_ADDRCONFIG;
  730. #endif
  731. memset(&hints, 0, sizeof(hints));
  732. #ifdef WORKING_IPV6
  733. /* get any kind of addresss */
  734. hints.ai_family = AF_UNSPEC;
  735. #else
  736. /* even if getaddrinfo supports IPv6, don't let it return
  737. * such an address */
  738. hints.ai_family = AF_INET;
  739. #endif
  740. hints.ai_flags = flags;
  741. hints.ai_socktype = socktype;
  742. result = getaddrinfo(hostname, NULL, &hints, &myres);
  743. if (result != 0) {
  744. return result;
  745. }
  746. if (canonname && myres && myres->ai_canonname) {
  747. *canonname = stralloc(myres->ai_canonname);
  748. }
  749. if (res) {
  750. *res = myres;
  751. } else {
  752. freeaddrinfo(myres);
  753. }
  754. return result;
  755. }
  756. char *
  757. _str_exit_status(
  758. char *subject,
  759. amwait_t status)
  760. {
  761. if (WIFEXITED(status)) {
  762. int exitstatus = WEXITSTATUS(status);
  763. if (exitstatus == 0)
  764. return vstrallocf(_("%s exited normally"), subject);
  765. else
  766. return vstrallocf(_("%s exited with status %d"), subject, exitstatus);
  767. }
  768. if (WIFSIGNALED(status)) {
  769. int signal = WTERMSIG(status);
  770. #ifdef WCOREDUMP
  771. if (WCOREDUMP(status))
  772. return vstrallocf(_("%s exited after receiving signal %d (core dumped)"),
  773. subject, signal);
  774. else
  775. #endif
  776. return vstrallocf(_("%s exited after receiving signal %d"),
  777. subject, signal);
  778. }
  779. if (WIFSTOPPED(status)) {
  780. int signal = WSTOPSIG(status);
  781. return vstrallocf(_("%s stopped temporarily after receiving signal %d"),
  782. subject, signal);
  783. }
  784. #ifdef WIFCONTINUED
  785. if (WIFCONTINUED(status)) {
  786. return vstrallocf(_("%s was resumed"), subject);
  787. }
  788. #endif
  789. return vstrallocf(_("%s exited in unknown circumstances"), subject);
  790. }
  791. void
  792. check_running_as(running_as_flags who)
  793. {
  794. #ifdef CHECK_USERID
  795. struct passwd *pw;
  796. uid_t uid_me;
  797. uid_t uid_target;
  798. char *uname_me = NULL;
  799. char *uname_target = NULL;
  800. char *dumpuser;
  801. uid_me = getuid();
  802. if ((pw = getpwuid(uid_me)) == NULL) {
  803. error(_("current userid %ld not found in password database"), (long)uid_me);
  804. /* NOTREACHED */
  805. }
  806. uname_me = stralloc(pw->pw_name);
  807. #ifndef SINGLE_USERID
  808. if (!(who & RUNNING_AS_UID_ONLY) && uid_me != geteuid()) {
  809. error(_("euid (%lld) does not match uid (%lld); is this program setuid-root when it shouldn't be?"),
  810. (long long int)geteuid(), (long long int)uid_me);
  811. /* NOTREACHED */
  812. }
  813. #endif
  814. switch (who & RUNNING_AS_USER_MASK) {
  815. case RUNNING_AS_ANY:
  816. uid_target = uid_me;
  817. uname_target = uname_me;
  818. return;
  819. case RUNNING_AS_ROOT:
  820. uid_target = 0;
  821. uname_target = "root";
  822. break;
  823. case RUNNING_AS_DUMPUSER_PREFERRED:
  824. dumpuser = getconf_str(CNF_DUMPUSER);
  825. if ((pw = getpwnam(dumpuser)) != NULL &&
  826. uid_me != pw->pw_uid) {
  827. if ((pw = getpwnam(CLIENT_LOGIN)) != NULL &&
  828. uid_me == pw->pw_uid) {
  829. /* uid == CLIENT_LOGIN: not ideal, but OK */
  830. dbprintf(_("NOTE: running as '%s', which is the client"
  831. " user, not the dumpuser ('%s'); forging"
  832. " on anyway\n"),
  833. CLIENT_LOGIN, dumpuser);
  834. uid_target = uid_me; /* force success below */
  835. break;
  836. }
  837. }
  838. /* FALLTHROUGH */
  839. case RUNNING_AS_DUMPUSER:
  840. uname_target = getconf_str(CNF_DUMPUSER);
  841. if ((pw = getpwnam(uname_target)) == NULL) {
  842. error(_("cannot look up dumpuser \"%s\""), uname_target);
  843. /*NOTREACHED*/
  844. }
  845. uid_target = pw->pw_uid;
  846. break;
  847. case RUNNING_AS_CLIENT_LOGIN:
  848. uname_target = CLIENT_LOGIN;
  849. if ((pw = getpwnam(uname_target)) == NULL) {
  850. error(_("cannot look up client user \"%s\""), uname_target);
  851. /*NOTREACHED*/
  852. }
  853. uid_target = pw->pw_uid;
  854. break;
  855. default:
  856. error(_("Unknown check_running_as() call"));
  857. /* NOTREACHED */
  858. }
  859. if (uid_me != uid_target) {
  860. error(_("running as user \"%s\" instead of \"%s\""), uname_me, uname_target);
  861. /*NOTREACHED*/
  862. }
  863. amfree(uname_me);
  864. #else
  865. /* Quiet unused variable warning */
  866. (void)who;
  867. #endif
  868. }
  869. int
  870. set_root_privs(int need_root)
  871. {
  872. #ifndef SINGLE_USERID
  873. if (need_root) {
  874. if (seteuid(0) == -1) return 0;
  875. /* (we don't switch the group back) */
  876. } else {
  877. if (geteuid() != 0) return 0;
  878. if (seteuid(getuid()) == -1) return 0;
  879. if (setegid(getgid()) == -1) return 0;
  880. }
  881. #else
  882. (void)need_root; /* Quiet unused variable warning */
  883. #endif
  884. return 1;
  885. }
  886. int
  887. become_root(void)
  888. {
  889. #ifndef SINGLE_USERID
  890. // if euid !=0, it set only euid
  891. if (setuid(0) == -1) return 0;
  892. // will set ruid because euid == 0.
  893. if (setuid(0) == -1) return 0;
  894. #endif
  895. return 1;
  896. }
  897. char *
  898. base64_decode_alloc_string(
  899. char *in)
  900. {
  901. char *out;
  902. size_t in_len = strlen(in);
  903. size_t out_len = 3 * (in_len / 4) + 3;
  904. out = malloc(out_len);
  905. if (!base64_decode(in, in_len, out, &out_len)) {
  906. amfree(out);
  907. return NULL;
  908. }
  909. out[out_len] = '\0';
  910. return out;
  911. }
  912. /* A GHFunc (callback for g_hash_table_foreach) */
  913. void count_proplist(
  914. gpointer key_p G_GNUC_UNUSED,
  915. gpointer value_p,
  916. gpointer user_data_p)
  917. {
  918. property_t *value_s = value_p;
  919. int *nb = user_data_p;
  920. GSList *value;
  921. for(value=value_s->values; value != NULL; value = value->next) {
  922. (*nb)++;
  923. }
  924. }
  925. /* A GHFunc (callback for g_hash_table_foreach) */
  926. void proplist_add_to_argv(
  927. gpointer key_p,
  928. gpointer value_p,
  929. gpointer user_data_p)
  930. {
  931. char *property_s = key_p;
  932. property_t *value_s = value_p;
  933. char ***argv = user_data_p;
  934. GSList *value;
  935. char *q, *w, *qprop;
  936. q = stralloc(property_s);
  937. /* convert to lower case */
  938. for (w=q; *w != '\0'; w++) {
  939. *w = tolower(*w);
  940. if (*w == '_')
  941. *w = '-';
  942. }
  943. qprop = stralloc2("--", q);
  944. amfree(q);
  945. for(value=value_s->values; value != NULL; value = value->next) {
  946. **argv = stralloc(qprop);
  947. (*argv)++;
  948. **argv = stralloc((char *)value->data);
  949. (*argv)++;
  950. }
  951. amfree(qprop);
  952. }
  953. /*
  954. * Process parameters
  955. */
  956. static char *pname = NULL;
  957. static char *ptype = NULL;
  958. static pcontext_t pcontext = CONTEXT_DEFAULT;
  959. void
  960. set_pname(char *p)
  961. {
  962. pname = newstralloc(pname, p);
  963. }
  964. char *
  965. get_pname(void)
  966. {
  967. if (!pname) pname = stralloc("unknown");
  968. return pname;
  969. }
  970. void
  971. set_ptype(char *p)
  972. {
  973. ptype = newstralloc(ptype, p);
  974. }
  975. char *
  976. get_ptype(void)
  977. {
  978. if (!ptype) ptype = stralloc("unknown");
  979. return ptype;
  980. }
  981. void
  982. set_pcontext(pcontext_t pc)
  983. {
  984. pcontext = pc;
  985. }
  986. pcontext_t
  987. get_pcontext(void)
  988. {
  989. return pcontext;
  990. }