2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1999 University of Maryland at College Park
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.
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.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
27 * $Id: util.c,v 1.42 2006/08/24 01:57:15 paddy_s Exp $
36 #include "sockaddr-util.h"
40 #include "pipespawn.h"
44 static int make_socket(sa_family_t family);
45 static int connect_port(sockaddr_union *addrp, in_port_t port, char *proto,
46 sockaddr_union *svaddr, int nonblock);
54 #if defined(SO_KEEPALIVE) || defined(USE_REUSEADDR)
59 g_debug("make_socket opening socket with family %d", family);
60 s = socket(family, SOCK_STREAM, 0);
63 dbprintf(_("make_socket: socket() failed: %s\n"), strerror(save_errno));
67 if (s < 0 || s >= (int)FD_SETSIZE) {
69 errno = EMFILE; /* out of range */
74 r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
77 dbprintf(_("make_socket: setsockopt(SO_REUSEADDR) failed: %s\n"),
84 r = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
85 (void *)&on, SIZEOF(on));
88 dbprintf(_("make_socket: setsockopt() failed: %s\n"),
89 strerror(save_errno));
99 GQuark am_util_error_quark(void)
101 return g_quark_from_static_string("am-util-error-quark");
104 /* addrp is my address */
105 /* svaddr is the address of the remote machine */
106 /* return socket on success */
107 /* return -1 on failure */
110 sockaddr_union *addrp,
111 in_port_t first_port,
114 sockaddr_union *svaddr,
119 static in_port_t port_in_use[1024];
120 static int nb_port_in_use = 0;
122 int save_errno = EAGAIN;
124 assert(first_port <= last_port);
125 /* Try a port already used */
126 for(i=0; i < nb_port_in_use; i++) {
127 port = port_in_use[i];
128 if(port >= first_port && port <= last_port) {
129 s = connect_port(addrp, port, proto, svaddr, nonblock);
130 if(s == -2) return -1;
134 if (errno != EAGAIN && errno != EBUSY)
139 /* Try a port in the range */
140 for (port = first_port; port <= last_port; port++) {
141 s = connect_port(addrp, port, proto, svaddr, nonblock);
142 if(s == -2) return -1;
144 port_in_use[nb_port_in_use++] = port;
147 if (errno != EAGAIN && errno != EBUSY)
151 dbprintf(_("connect_portrange: All ports between %d and %d are busy.\n"),
158 /* addrp is my address */
159 /* svaddr is the address of the remote machine */
160 /* return -2: Don't try again */
161 /* return -1: Try with another port */
162 /* return >0: this is the connected socket */
165 sockaddr_union *addrp,
168 sockaddr_union *svaddr,
172 struct servent * servPort;
174 socklen_t_equiv socklen;
177 servPort = getservbyport((int)htons(port), proto);
178 if (servPort != NULL && !strstr(servPort->s_name, "amanda")) {
179 dbprintf(_("connect_port: Skip port %d: owned by %s.\n"),
180 port, servPort->s_name);
185 if ((s = make_socket(SU_GET_FAMILY(addrp))) == -1) return -2;
187 SU_SET_PORT(addrp, port);
188 socklen = SS_LEN(addrp);
189 if (bind(s, (struct sockaddr *)addrp, socklen) != 0) {
192 if(servPort == NULL) {
193 dbprintf(_("connect_port: Try port %d: available - %s\n"),
194 port, strerror(errno));
196 dbprintf(_("connect_port: Try port %d: owned by %s - %s\n"),
197 port, servPort->s_name, strerror(errno));
199 if (save_errno != EADDRINUSE) {
207 if(servPort == NULL) {
208 dbprintf(_("connect_port: Try port %d: available - Success\n"), port);
210 dbprintf(_("connect_port: Try port %d: owned by %s - Success\n"),
211 port, servPort->s_name);
214 /* find out what port was actually used */
216 len = sizeof(*addrp);
217 if (getsockname(s, (struct sockaddr *)addrp, &len) == -1) {
219 dbprintf(_("connect_port: getsockname() failed: %s\n"),
220 strerror(save_errno));
227 fcntl(s, F_SETFL, fcntl(s, F_GETFL, 0)|O_NONBLOCK);
228 if (connect(s, (struct sockaddr *)svaddr, SS_LEN(svaddr)) == -1 && !nonblock) {
230 dbprintf(_("connect_portrange: Connect from %s failed: %s\n"),
232 strerror(save_errno));
233 dbprintf(_("connect_portrange: connect to %s failed: %s\n"),
234 str_sockaddr(svaddr),
235 strerror(save_errno));
238 if (save_errno == ECONNREFUSED ||
239 save_errno == EHOSTUNREACH ||
240 save_errno == ENETUNREACH ||
241 save_errno == ETIMEDOUT) {
247 dbprintf(_("connected to %s\n"),
248 str_sockaddr(svaddr));
249 dbprintf(_("our side is %s\n"),
250 str_sockaddr(addrp));
256 * Bind to a port in the given range. Takes a begin,end pair of port numbers.
258 * Returns negative on error (EGAIN if all ports are in use). Returns 0
264 sockaddr_union *addrp,
265 in_port_t first_port,
271 socklen_t_equiv socklen;
272 struct servent *servPort;
273 const in_port_t num_ports = (in_port_t)(last_port - first_port + 1);
274 int save_errno = EAGAIN;
276 assert(first_port <= last_port);
279 * We pick a different starting port based on our pid and the current
280 * time to avoid always picking the same reserved port twice.
282 port = (in_port_t)(((getpid() + time(0)) % num_ports) + first_port);
285 * Scan through the range, trying all available ports that are either
286 * not taken in /etc/services or registered for *amanda*. Wrap around
287 * if we don't happen to start at the beginning.
289 for (cnt = 0; cnt < num_ports; cnt++) {
290 servPort = getservbyport((int)htons(port), proto);
291 if ((servPort == NULL) || strstr(servPort->s_name, "amanda")) {
292 SU_SET_PORT(addrp, port);
293 socklen = SS_LEN(addrp);
294 if (bind(s, (struct sockaddr *)addrp, socklen) >= 0) {
295 if (servPort == NULL) {
296 g_debug(_("bind_portrange2: Try port %d: Available - Success"), port);
298 g_debug(_("bind_portrange2: Try port %d: Owned by %s - Success."), port, servPort->s_name);
302 if (errno != EAGAIN && errno != EBUSY)
304 if (servPort == NULL) {
305 g_debug(_("bind_portrange2: Try port %d: Available - %s"),
306 port, strerror(errno));
308 g_debug(_("bind_portrange2: Try port %d: Owned by %s - %s"),
309 port, servPort->s_name, strerror(errno));
312 g_debug(_("bind_portrange2: Skip port %d: Owned by %s."),
313 port, servPort->s_name);
315 if (++port > last_port)
318 g_debug(_("bind_portrange: all ports between %d and %d busy"),
326 * Writes out the entire iovec
334 ssize_t delta, n, total;
343 n = writev(fd, iov, iovcnt);
354 * Iterate through each iov. Figure out what we still need
357 for (; n > 0; iovcnt--, iov++) {
358 /* 'delta' is the bytes written from this iovec */
359 delta = ((size_t)n < (size_t)iov->iov_len) ? n : (ssize_t)iov->iov_len;
360 /* subtract from the total num bytes written */
363 /* subtract from this iovec */
364 iov->iov_len -= delta;
365 iov->iov_base = (char *)iov->iov_base + delta;
366 /* if this iovec isn't empty, run the writev again */
367 if (iov->iov_len > 0)
377 * For backward compatibility we are trying for minimal quoting. Unless ALWAYS
378 * is true, we only quote a string if it contains whitespace or is misquoted...
389 if ((str == NULL) || (*str == '\0')) {
390 ret = stralloc("\"\"");
391 } else if (!always && (match("[:\'\\\"[:space:][:cntrl:]]", str)) == 0) {
393 * String does not need to be quoted since it contains
394 * neither whitespace, control or quote characters.
399 * Allocate maximum possible string length.
400 * (a string of all quotes plus room for leading ", trailing " and NULL)
402 ret = s = alloc((strlen(str) * 2) + 2 + 1);
404 while (*str != '\0') {
410 } else if (*str == '\n') {
415 } else if (*str == '\r') {
420 } else if (*str == '\f') {
425 } else if (*str == '\\') {
448 if ((str == NULL) || (*str == '\0')) {
454 ret = in = out = stralloc(str);
455 while (*in != '\0') {
467 } else if (*in == 't') {
471 } else if (*in == 'r') {
475 } else if (*in == 'f') {
479 } else if (*in >= '0' && *in <= '7') {
483 while (i < 3 && *in >= '0' && *in <= '7') {
484 c = (c << 3) + *(in++) - '0';
489 } else if (*in == '\0') {
490 /* trailing backslash -- ignore */
502 split_quoted_strings(
515 p = start = local = g_strdup(string);
516 strs = g_ptr_array_new();
519 if (!iq && *p == ' ') {
521 g_ptr_array_add(strs, unquote_string(start));
523 } else if (*p == '\\') {
524 /* next character is taken literally; if it's a multicharacter
525 * escape (e.g., \171), that doesn't bother us here */
528 } else if (*p == '\"') {
535 g_ptr_array_add(strs, unquote_string(start));
537 /* now convert strs into a strv, by stealing its references to the underlying
539 result = g_new0(char *, strs->len + 1);
540 memmove(result, strs->pdata, sizeof(char *) * strs->len);
542 g_ptr_array_free(strs, FALSE); /* FALSE => don't free strings */
549 strquotedstr(char **saveptr)
551 char * tok = strtok_r(NULL, " ", saveptr);
563 while (in_quote || in_backslash || *p != '\0') {
565 /* append a new token */
566 t = strtok_r(NULL, " ", saveptr);
574 in_quote = !in_quote;
575 else if (*p == '\\') {
593 if ((str == NULL) || (*str == '\0')) {
597 for (s = ret; *s != '\0'; s++) {
598 if (iscntrl((int)*s))
605 char *hexencode_string(const char *str)
607 size_t orig_len, new_len, i;
611 s = g_string_sized_new(0);
614 new_len = orig_len = strlen(str);
615 for (i = 0; i < orig_len; i++) {
616 if (!g_ascii_isalnum(str[i])) {
620 s = g_string_sized_new(new_len);
622 for (i = 0; i < orig_len; i++) {
623 if (g_ascii_isalnum(str[i])) {
624 g_string_append_c(s, str[i]);
626 g_string_append_printf(s, "%%%02hhx", str[i]);
632 g_string_free(s, FALSE);
636 char *hexdecode_string(const char *str, GError **err)
638 size_t orig_len, new_len, i;
642 s = g_string_sized_new(0);
645 new_len = orig_len = strlen(str);
646 for (i = 0; i < orig_len; i++) {
651 s = g_string_sized_new(new_len);
653 for (i = 0; (orig_len > 2) && (i < orig_len-2); i++) {
657 for (j = 1; j < 3; j++) {
659 if (str[i+j] >= '0' && str[i+j] <= '9') {
660 tmp += str[i+j] - '0';
661 } else if (str[i+j] >= 'a' && str[i+j] <= 'f') {
662 tmp += str[i+j] - 'a' + 10;
663 } else if (str[i+j] >= 'A' && str[i+j] <= 'F') {
664 tmp += str[i+j] - 'A' + 10;
667 g_set_error(err, am_util_error_quark(), AM_UTIL_ERROR_HEXDECODEINVAL,
668 "Illegal character (non-hex) 0x%02hhx at offset %zd", str[i+j], i+j);
669 g_string_truncate(s, 0);
674 g_set_error(err, am_util_error_quark(), AM_UTIL_ERROR_HEXDECODEINVAL,
675 "Encoded NULL at starting offset %zd", i);
676 g_string_truncate(s, 0);
679 g_string_append_c(s, tmp);
682 g_string_append_c(s, str[i]);
685 for ( /*nothing*/; i < orig_len; i++) {
687 g_set_error(err, am_util_error_quark(), AM_UTIL_ERROR_HEXDECODEINVAL,
688 "'%%' found at offset %zd, but fewer than two characters follow it (%zd)", i, orig_len-i-1);
689 g_string_truncate(s, 0);
692 g_string_append_c(s, str[i]);
698 g_string_free(s, FALSE);
702 /* Helper for expand_braced_alternates; returns a list of un-escaped strings
703 * for the first "component" of str, where a component is a plain string or a
704 * brace-enclosed set of alternatives. str is pointing to the first character
705 * of the next component on return. */
707 parse_braced_component(char **str)
709 GPtrArray *result = g_ptr_array_new();
713 char *local = g_malloc(strlen(*str)+1);
714 char *current = local;
718 if (*p == '\0' || *p == '{') {
719 /* unterminated { .. } or extra '{' */
721 g_ptr_array_free(result, TRUE);
725 if (*p == '}' || *p == ',') {
727 g_ptr_array_add(result, g_strdup(current));
737 if (*(p+1) == '{' || *(p+1) == '}' || *(p+1) == '\\' || *(p+1) == ',')
750 /* no braces -- just un-escape a plain string */
751 char *local = g_malloc(strlen(*str)+1);
755 while (*p && *p != '{') {
757 if (*(p+1) == '{' || *(p+1) == '}' || *(p+1) == '\\' || *(p+1) == ',')
763 g_ptr_array_add(result, local);
771 expand_braced_alternates(
774 GPtrArray *rval = g_ptr_array_new();
776 g_ptr_array_add(rval, g_strdup(""));
779 GPtrArray *new_components;
783 new_components = parse_braced_component(&source);
784 if (!new_components) {
786 g_ptr_array_free(rval, TRUE);
790 new_rval = g_ptr_array_new();
792 /* do a cartesian join of rval and new_components */
793 for (i = 0; i < rval->len; i++) {
794 for (j = 0; j < new_components->len; j++) {
795 g_ptr_array_add(new_rval, g_strconcat(
796 g_ptr_array_index(rval, i),
797 g_ptr_array_index(new_components, j),
802 g_ptr_array_free(rval, TRUE);
803 g_ptr_array_free(new_components, TRUE);
811 collapse_braced_alternates(
814 GString *result = NULL;
817 result = g_string_new("{");
819 for (i = 0; i < source->len; i ++) {
820 const char *str = g_ptr_array_index(source, i);
823 if (strchr(str, ',') || strchr(str, '\\') ||
824 strchr(str, '{') || strchr(str, '}')) {
829 qstr = d = g_malloc(strlen(str)*2+1);
831 if (*s == ',' || *s == '\\' || *s == '{' || *s == '}')
837 g_string_append_printf(result, "%s%s", qstr? qstr : str,
838 (i < source->len-1)? "," : "");
843 g_string_append(result, "}");
844 return g_string_free(result, FALSE);
848 Return 0 if the following characters are present
849 * ( ) < > [ ] , ; : ! $ \ / "
857 return !match("\\*|<|>|\\(|\\)|\\[|\\]|,|;|:|\\\\|/|\"|\\!|\\$|\\|", mailto);
871 if ((infd = open(src, O_RDONLY)) == -1) {
873 quoted = quote_string(src);
874 *errmsg = vstrallocf(_("Can't open file '%s' for reading: %s"),
875 quoted, strerror(save_errno));
880 if ((outfd = open(dst, O_WRONLY|O_CREAT, 0600)) == -1) {
882 quoted = quote_string(dst);
883 *errmsg = vstrallocf(_("Can't open file '%s' for writting: %s"),
884 quoted, strerror(save_errno));
890 while((nb=read(infd, &buf, SIZEOF(buf))) > 0) {
891 if(full_write(outfd,&buf,nb) < nb) {
893 quoted = quote_string(dst);
894 *errmsg = vstrallocf(_("Error writing to '%s': %s"),
895 quoted, strerror(save_errno));
905 quoted = quote_string(src);
906 *errmsg = vstrallocf(_("Error reading from '%s': %s"),
907 quoted, strerror(save_errno));
919 #ifndef HAVE_READLINE
921 * simple readline() replacements, used when we don't have readline
922 * support from the system.
929 g_printf("%s", prompt);
939 (void)line; /* Quiet unused parameter warning */
944 /* Order of preference: readdir64(), readdir(). */
945 #if HAVE_DECL_READDIR64
946 # define USE_DIRENT64
947 # define USE_READDIR64
948 #elif HAVE_DECL_READDIR
951 # error No readdir() or readdir64() available!
954 char * portable_readdir(DIR* handle) {
957 struct dirent64 *entry_p;
959 struct dirent *entry_p;
962 static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
964 g_static_mutex_lock(&mutex);
967 entry_p = readdir(handle);
970 entry_p = readdir64(handle);
973 g_static_mutex_unlock(&mutex);
978 /* FIXME: According to glibc documentation, d_name may not be
979 null-terminated in some cases on some very old platforms. Not
980 sure what to do about that case. */
981 return strdup(entry_p->d_name);
984 int search_directory(DIR * handle, const char * regex,
985 SearchDirectoryFunctor functor, gpointer user_data) {
987 regex_t compiled_regex;
988 gboolean done = FALSE;
990 if (regcomp(&compiled_regex, regex, REG_EXTENDED | REG_NOSUB) != 0) {
991 regfree(&compiled_regex);
1000 read_name = portable_readdir(handle);
1001 if (read_name == NULL) {
1002 regfree(&compiled_regex);
1005 result = regexec(&compiled_regex, read_name, 0, NULL, 0);
1008 done = !functor(read_name, user_data);
1012 regfree(&compiled_regex);
1016 char* find_regex_substring(const char* base_string, const regmatch_t match) {
1020 size = match.rm_eo - match.rm_so;
1021 rval = malloc(size+1);
1022 memcpy(rval, base_string + match.rm_so, size);
1028 int compare_possibly_null_strings(const char * a, const char * b) {
1030 /* NULL or otherwise, they're the same. */
1032 } else if (a == NULL) {
1035 } else if (b == NULL) {
1039 /* a != NULL != b */
1040 return strcmp(a, b);
1045 resolve_hostname(const char *hostname,
1047 struct addrinfo **res,
1050 struct addrinfo hints;
1051 struct addrinfo *myres;
1055 if (res) *res = NULL;
1058 flags = AI_CANONNAME;
1061 #ifdef AI_ADDRCONFIG
1062 flags |= AI_ADDRCONFIG;
1065 memset(&hints, 0, sizeof(hints));
1067 /* get any kind of addresss */
1068 hints.ai_family = AF_UNSPEC;
1070 /* even if getaddrinfo supports IPv6, don't let it return
1071 * such an address */
1072 hints.ai_family = AF_INET;
1074 hints.ai_flags = flags;
1075 hints.ai_socktype = socktype;
1076 result = getaddrinfo(hostname, NULL, &hints, &myres);
1081 if (canonname && myres && myres->ai_canonname) {
1082 *canonname = stralloc(myres->ai_canonname);
1088 freeaddrinfo(myres);
1099 if (WIFEXITED(status)) {
1100 int exitstatus = WEXITSTATUS(status);
1101 if (exitstatus == 0)
1102 return vstrallocf(_("%s exited normally"), subject);
1104 return vstrallocf(_("%s exited with status %d"), subject, exitstatus);
1107 if (WIFSIGNALED(status)) {
1108 int signal = WTERMSIG(status);
1110 if (WCOREDUMP(status))
1111 return vstrallocf(_("%s exited after receiving signal %d (core dumped)"),
1115 return vstrallocf(_("%s exited after receiving signal %d"),
1119 if (WIFSTOPPED(status)) {
1120 int signal = WSTOPSIG(status);
1121 return vstrallocf(_("%s stopped temporarily after receiving signal %d"),
1126 if (WIFCONTINUED(status)) {
1127 return vstrallocf(_("%s was resumed"), subject);
1131 return vstrallocf(_("%s exited in unknown circumstances"), subject);
1135 check_running_as(running_as_flags who)
1141 char *uname_me = NULL;
1142 char *uname_target = NULL;
1146 if ((pw = getpwuid(uid_me)) == NULL) {
1147 error(_("current userid %ld not found in password database"), (long)uid_me);
1150 uname_me = stralloc(pw->pw_name);
1152 #ifndef SINGLE_USERID
1153 if (!(who & RUNNING_AS_UID_ONLY) && uid_me != geteuid()) {
1154 error(_("euid (%lld) does not match uid (%lld); is this program setuid-root when it shouldn't be?"),
1155 (long long int)geteuid(), (long long int)uid_me);
1160 switch (who & RUNNING_AS_USER_MASK) {
1161 case RUNNING_AS_ANY:
1162 uid_target = uid_me;
1163 uname_target = uname_me;
1167 case RUNNING_AS_ROOT:
1169 uname_target = "root";
1172 case RUNNING_AS_DUMPUSER_PREFERRED:
1173 dumpuser = getconf_str(CNF_DUMPUSER);
1174 if ((pw = getpwnam(dumpuser)) != NULL &&
1175 uid_me != pw->pw_uid) {
1176 if ((pw = getpwnam(CLIENT_LOGIN)) != NULL &&
1177 uid_me == pw->pw_uid) {
1178 /* uid == CLIENT_LOGIN: not ideal, but OK */
1179 dbprintf(_("NOTE: running as '%s', which is the client"
1180 " user, not the dumpuser ('%s'); forging"
1182 CLIENT_LOGIN, dumpuser);
1183 uid_target = uid_me; /* force success below */
1189 case RUNNING_AS_DUMPUSER:
1190 uname_target = getconf_str(CNF_DUMPUSER);
1191 if ((pw = getpwnam(uname_target)) == NULL) {
1192 error(_("cannot look up dumpuser \"%s\""), uname_target);
1195 uid_target = pw->pw_uid;
1198 case RUNNING_AS_CLIENT_LOGIN:
1199 uname_target = CLIENT_LOGIN;
1200 if ((pw = getpwnam(uname_target)) == NULL) {
1201 error(_("cannot look up client user \"%s\""), uname_target);
1204 uid_target = pw->pw_uid;
1208 error(_("Unknown check_running_as() call"));
1212 if (uid_me != uid_target) {
1213 error(_("running as user \"%s\" instead of \"%s\""), uname_me, uname_target);
1219 /* Quiet unused variable warning */
1225 set_root_privs(int need_root)
1227 #ifndef SINGLE_USERID
1228 static gboolean first_call = TRUE;
1229 static uid_t unpriv = 1;
1232 /* save the original real userid (that of our invoker) */
1235 /* and set all of our userids (including, importantly, the saved
1239 /* don't need to do this next time */
1243 if (need_root == 1) {
1244 if (geteuid() == 0) return 1; /* already done */
1246 if (seteuid(0) == -1) return 0;
1247 /* (we don't switch the group back) */
1248 } else if (need_root == -1) {
1249 /* make sure the euid is 0 so that we can set the uid */
1250 if (geteuid() != 0) {
1251 if (seteuid(0) == -1) return 0;
1254 /* now set the uid to the unprivileged userid */
1255 if (setuid(unpriv) == -1) return 0;
1257 if (geteuid() != 0) return 1; /* already done */
1259 /* set the *effective* userid only */
1260 if (seteuid(unpriv) == -1) return 0;
1261 if (setegid(getgid()) == -1) return 0;
1264 (void)need_root; /* Quiet unused variable warning */
1272 #ifndef SINGLE_USERID
1273 /* first, set the effective userid to 0 */
1274 if (seteuid(0) == -1) return 0;
1276 /* then, set all of the userids to 0 */
1277 if (setuid(0) == -1) return 0;
1283 base64_decode_alloc_string(
1287 size_t in_len = strlen(in);
1288 size_t out_len = 3 * (in_len / 4) + 3;
1290 out = malloc(out_len);
1291 if (!base64_decode(in, in_len, out, &out_len)) {
1295 out[out_len] = '\0';
1301 /* A GHFunc (callback for g_hash_table_foreach) */
1302 void count_proplist(
1303 gpointer key_p G_GNUC_UNUSED,
1305 gpointer user_data_p)
1307 property_t *value_s = value_p;
1308 int *nb = user_data_p;
1311 for(value=value_s->values; value != NULL; value = value->next) {
1316 /* A GHFunc (callback for g_hash_table_foreach) */
1317 void proplist_add_to_argv(
1320 gpointer user_data_p)
1322 char *property_s = key_p;
1323 property_t *value_s = value_p;
1324 GPtrArray *argv_ptr = user_data_p;
1326 char *q, *w, *qprop;
1328 q = stralloc(property_s);
1329 /* convert to lower case */
1330 for (w=q; *w != '\0'; w++) {
1335 qprop = stralloc2("--", q);
1337 for(value=value_s->values; value != NULL; value = value->next) {
1338 g_ptr_array_add(argv_ptr, stralloc(qprop));
1339 g_ptr_array_add(argv_ptr, stralloc((char *)value->data));
1346 * Process parameters
1349 static char *pname = NULL;
1350 static char *ptype = NULL;
1351 static pcontext_t pcontext = CONTEXT_DEFAULT;
1356 pname = newstralloc(pname, p);
1362 if (!pname) pname = stralloc("unknown");
1369 ptype = newstralloc(ptype, p);
1375 if (!ptype) ptype = stralloc("unknown");
1380 set_pcontext(pcontext_t pc)
1393 openbsd_fd_inform(void)
1396 for (i = DATA_FD_OFFSET; i < DATA_FD_OFFSET + DATA_FD_COUNT*2; i++) {
1397 /* a simple fcntl() will cause the library to "look" at this file
1398 * descriptor, which is good enough */
1399 (void)fcntl(i, F_GETFL);
1406 GPtrArray *argv_ptr)
1409 char *cmdline = stralloc((char *)g_ptr_array_index(argv_ptr, 0));
1411 for (i = 1; i < argv_ptr->len-1; i++) {
1412 char *arg = g_shell_quote((char *)g_ptr_array_index(argv_ptr, i));
1413 cmdline = vstrextend(&cmdline, " ", arg, NULL);
1416 g_debug("Executing: %s\n", cmdline);