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