PageRenderTime 91ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

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

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