PageRenderTime 47ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

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

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