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