/* To test for Windows (64 bit or 32 bit) use _WIN32 and _WIN64 in addition for64bitwindows._WIN32isdefinedforboth. TotestforLinuxuse__linux__.
To test for BSD use BSD */
/* this is so we can use #ifdef BSD later */ /* This is the recommended way of detecting BSD in the
FreeBSD Porter's Handbook. */ #if (defined(__unix__) || defined(unix)) && !defined(USG) #include <sys/param.h> #endif
/* sys/ucred.h needs to be included to use struct xucred
* in FreeBSD and OS X. No need for other BSDs except GNU/kFreeBSD */ #ifdefined(__FreeBSD__) || defined(__APPLE__) || defined(__FreeBSD_kernel__) #include <sys/ucred.h> #endif
/* for solaris */ #if !defined(PF_LOCAL) #define PF_LOCAL AF_UNIX #endif #if !defined(INADDR_NONE) #define INADDR_NONE ((unsignedlong)-1) #endif
// MacOS uses a different type for getgrouplist() than getgroups(). This // appears to be the only platform which does this. #ifdef __APPLE__ # define GETGROUPLIST_T int #else # define GETGROUPLIST_T GETGROUPS_T #endif
/*****************************************************************************/ /* output text to stdout, try to use g_write / g_writeln instead to avoid
linux / windows EOL problems */ void
g_printf(constchar *format, ...)
{
va_list ap;
va_start(ap, format);
vfprintf(stdout, format, ap);
va_end(ap);
}
va_start(ap, format);
vsprintf(dest, format, ap);
va_end(ap);
}
/*****************************************************************************/ int
g_snprintf(char *dest, int len, constchar *format, ...)
{ int err;
va_list ap;
va_start(ap, format);
err = vsnprintf(dest, len, format, ap);
va_end(ap);
va_start(ap, format);
vfprintf(stdout, format, ap);
va_end(ap);
}
/*****************************************************************************/ /* print a hex dump to stdout*/ void
g_hexdump(constchar *p, int len)
{ unsignedchar *line; int i; int thisline; int offset;
line = (unsignedchar *)p;
offset = 0;
while (offset < len)
{
g_printf("%04x ", offset);
thisline = len - offset;
if (thisline > 16)
{
thisline = 16;
}
for (i = 0; i < thisline; i++)
{
g_printf("%02x ", line[i]);
}
for (; i < 16; i++)
{
g_printf(" ");
}
for (i = 0; i < thisline; i++)
{
g_printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.');
}
g_writeln("%s", "");
offset += thisline;
line += thisline;
}
}
/*****************************************************************************/ int
g_getchar(void)
{ return getchar();
}
/*****************************************************************************/ /*Returns 0 on success*/ int
g_tcp_set_no_delay(int sck)
{ int ret = 1; /* error */ int option_value;
socklen_t option_len;
/*****************************************************************************/ /*Returns 0 on success*/ int
g_tcp_set_keepalive(int sck)
{ int ret = 1; /* error */ int option_value;
socklen_t option_len;
/*****************************************************************************/ /* returns a newly created socket or -1 on error */ /* in win32 a socket is an unsigned int, in linux, it's an int */ int
g_tcp_socket(void)
{ int rv;
#ifdefined(XRDP_ENABLE_IPV6)
rv = (int)socket(AF_INET6, SOCK_STREAM, 0); if (rv < 0)
{ switch (errno)
{ case EPROTONOSUPPORT: /* if IPv6 is supported, but don't have an IPv6 address */ case EAFNOSUPPORT: /* if IPv6 not supported, retry IPv4 */
LOG(LOG_LEVEL_INFO, "IPv6 not supported, falling back to IPv4");
rv = (int)socket(AF_INET, SOCK_STREAM, 0); break;
/*****************************************************************************/ /* returns error */ int
g_sck_set_send_buffer_bytes(int sck, int bytes)
{ int option_value;
socklen_t option_len;
/*****************************************************************************/ /* returns error */ int
g_sck_get_send_buffer_bytes(int sck, int *bytes)
{ int option_value;
socklen_t option_len;
/*****************************************************************************/ /* returns error */ int
g_sck_set_recv_buffer_bytes(int sck, int bytes)
{ int option_value;
socklen_t option_len;
/*****************************************************************************/ /* returns error */ int
g_sck_get_recv_buffer_bytes(int sck, int *bytes)
{ int option_value;
socklen_t option_len;
/*****************************************************************************/ int
g_sck_set_reuseaddr(int sck)
{ int rv; int option_value = 1;
socklen_t option_len = sizeof(option_value);
/*****************************************************************************/ /* returns error, zero is good */ /* The connection might get to be in progress, if so -1 is returned. */ /* The caller needs to call again to check if succeed. */ #ifdefined(XRDP_ENABLE_IPV6) int
g_tcp_connect(int sck, constchar *address, constchar *port)
{ int res = 0; struct addrinfo p; struct addrinfo *h = (struct addrinfo *)NULL; struct addrinfo *rp = (struct addrinfo *)NULL;
g_memset(&p, 0, sizeof(struct addrinfo));
p.ai_socktype = SOCK_STREAM;
p.ai_protocol = IPPROTO_TCP;
p.ai_flags = AI_ADDRCONFIG | AI_V4MAPPED;
p.ai_family = AF_INET6; if (g_strcmp(address, "127.0.0.1") == 0)
{ return connect_loopback(sck, port);
} else
{
res = getaddrinfo(address, port, &p, &h);
} if (res != 0)
{
LOG(LOG_LEVEL_ERROR, "g_tcp_connect(%d, %s, %s): getaddrinfo() failed: %s",
sck, address, port, gai_strerror(res));
} if (res > -1)
{ if (h != NULL)
{ for (rp = h; rp != NULL; rp = rp->ai_next)
{
res = connect(sck, (struct sockaddr *)(rp->ai_addr),
rp->ai_addrlen); if (res == -1 && errno == EINPROGRESS)
{ break; /* Return -1 */
} if (res == 0 || (res == -1 && errno == EISCONN))
{
res = 0; break; /* Success */
}
}
freeaddrinfo(h);
}
}
return res;
} #else int
g_tcp_connect(int sck, constchar *address, constchar *port)
{ struct sockaddr_in s; struct hostent *h; int res;
g_memset(&s, 0, sizeof(struct sockaddr_in));
s.sin_family = AF_INET;
s.sin_port = htons((tui16)atoi(port));
s.sin_addr.s_addr = inet_addr(address); if (s.sin_addr.s_addr == INADDR_NONE)
{
h = gethostbyname(address); if (h != 0)
{ if (h->h_name != 0)
{ if (h->h_addr_list != 0)
{ if ((*(h->h_addr_list)) != 0)
{
s.sin_addr.s_addr = *((int *)(*(h->h_addr_list)));
}
}
}
}
}
res = connect(sck, (struct sockaddr *)&s, sizeof(struct sockaddr_in));
/* Mac OSX connect() returns -1 for already established connections */ if (res == -1 && errno == EISCONN)
{
res = 0;
}
return res;
} #endif
/*****************************************************************************/ /* returns error, zero is good */ int
g_sck_local_connect(int sck, constchar *port)
{ #ifdefined(_WIN32) return -1; #else struct sockaddr_un s;
/*****************************************************************************/ int
g_sck_set_non_blocking(int sck)
{ unsignedlong i;
#ifdefined(_WIN32)
i = 1;
ioctlsocket(sck, FIONBIO, &i); #else
i = fcntl(sck, F_GETFL);
i = i | O_NONBLOCK; if (fcntl(sck, F_SETFL, i) < 0)
{
LOG(LOG_LEVEL_ERROR, "g_sck_set_non_blocking: fcntl() failed");
} #endif return0;
}
#ifdefined(XRDP_ENABLE_IPV6) /*****************************************************************************/ /* returns error, zero is good */ int
g_tcp_bind(int sck, constchar *port)
{ struct sockaddr_in6 sa; struct sockaddr_in s; int errno6;
/*****************************************************************************/ /* Binds a socket to a port. If no specified address the port will be bind */ /* to 'any', i.e. available on all network. */ /* For bind to local host, see valid address strings below. */ /* Returns error, zero is good. */ int
g_tcp_bind_address(int sck, constchar *port, constchar *address)
{ int res;
// Let getaddrinfo translate the address string... // IPv4: ddd.ddd.ddd.ddd // IPv6: x:x:x:x:x:x:x:x%<interface>, or x::x:x:x:x%<interface>
res = getaddrinfo_bind(sck, port, address); if (res != 0)
{ // If fail and it is an IPv4 address, try with the mapped address struct in_addr a; if ((inet_aton(address, &a) == 1) && (strlen(address) <= 15))
{ char sz[7 + 15 + 1];
sprintf(sz, "::FFFF:%s", address);
res = getaddrinfo_bind(sck, port, sz); if (res == 0)
{ return0;
}
}
/*****************************************************************************/ /* returns error, zero is good */ int
g_sck_listen(int sck)
{ return listen(sck, 2);
}
/*****************************************************************************/ int
g_sck_accept(int sck)
{ int ret; union sock_info sock_info;
socklen_t sock_len = sizeof(sock_info);
memset(&sock_info, 0, sock_len);
ret = accept(sck, (struct sockaddr *)&sock_info, &sock_len);
if (ret > 0)
{ char description[MAX_PEER_DESCSTRLEN];
get_peer_description(&sock_info, description, sizeof(description));
LOG(LOG_LEVEL_INFO, "Socket %d: connection accepted from %s",
ret, description);
/*****************************************************************************/ int
g_sck_recv_fd_set(int sck, void *ptr, unsignedint len, int fds[], unsignedint maxfd, unsignedint *fdcount)
{ int rv = -1; #if !defined(_WIN32) // The POSIX API gives us no way to see how much ancillary data is // present for recvmsg() - just use a big buffer. // // Use a union, so control_un.control is properly aligned. union
{ struct cmsghdr cm; unsignedchar control[8192];
} control_un; struct msghdr msg = {0};
*fdcount = 0;
/* Set up descriptor for vanilla data */ struct iovec iov[1] = { {ptr, len} };
msg.msg_iov = &iov[0];
msg.msg_iovlen = 1;
/* Add in the ancillary data buffer */
msg.msg_control = control_un.control;
msg.msg_controllen = sizeof(control_un.control);
// Coverity: msg is 'tainted', so check msg.control and // msg.msg_controllen are sane (i.e. recvmsg() hasn't done // something odd)
msg.msg_control = control_un.control; if (msg.msg_controllen > sizeof(control_un.control))
{
msg.msg_controllen = sizeof(control_un.control);
}
if ((msg.msg_flags & MSG_CTRUNC) != 0)
{
LOG(LOG_LEVEL_WARNING, "Ancillary data on recvmsg() was truncated");
}
// Iterate over the cmsghdr structures in the ancillary data for (cmsg = CMSG_FIRSTHDR(&msg);
cmsg != NULL;
cmsg = CMSG_NXTHDR(&msg, cmsg))
{ if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_RIGHTS)
{ constunsignedchar *data = CMSG_DATA(cmsg); unsignedint data_len = cmsg->cmsg_len - CMSG_LEN(0);
// Check the data length doesn't point past the end of // control_un.control (see below). This shouldn't happen, // but is conceivable if the ancillary data is truncated // and the OS doesn't handle that properly. // // <-- (sizeof(control_un.control) --> // +------------------------------------+ // | | // +------------------------------------+ // ^ ^ // | | <- data_len -> // | | // control_un.control data unsignedint max_data_len = sizeof(control_un.control) - (data - control_un.control); if (len > max_data_len)
{
len = max_data_len;
}
// Process all the file descriptors in the structure while (data_len >= sizeof(int))
{ int fd;
memcpy(&fd, data, sizeof(int));
data += sizeof(int);
data_len -= sizeof(int);
if (*fdcount < maxfd)
{
fds[(*fdcount)++] = fd;
} else
{ // No room in the user's buffer for this fd
close(fd);
}
}
}
}
} #endif/* !WIN32 */
return rv;
}
/*****************************************************************************/ int
g_sck_send_fd_set(int sck, constvoid *ptr, unsignedint len, int fds[], unsignedint fdcount)
{ int rv = -1; #if !defined(_WIN32) struct msghdr msg = {0};
/* Set up descriptor for vanilla data */ struct iovec iov[1] = { {(void *)ptr, len} };
msg.msg_iov = &iov[0];
msg.msg_iovlen = 1;
/*****************************************************************************/ /* returns boolean */ int
g_sck_socket_ok(int sck)
{ int opt;
socklen_t opt_len;
opt_len = sizeof(opt);
if (getsockopt(sck, SOL_SOCKET, SO_ERROR, (char *)(&opt), &opt_len) == 0)
{ if (opt == 0)
{ return1;
}
}
return0;
}
/*****************************************************************************/ /* wait 'millis' milliseconds for the socket to be able to write */ /* returns boolean */ int
g_sck_can_send(int sck, int millis)
{ int rv = 0; if (sck > 0)
{ struct pollfd pollfd;
/*****************************************************************************/ /* wait 'millis' milliseconds for the socket to be able to receive */ /* returns boolean */ int
g_sck_can_recv(int sck, int millis)
{ int rv = 0;
/*****************************************************************************/ int
g_sck_select(int sck1, int sck2)
{ struct pollfd pollfd[2] = {0}; int rvmask[2] = {0}; /* Output masks corresponding to fds in pollfd */
/*****************************************************************************/ /* returns error */ int
g_set_wait_obj(tintptr obj)
{ #ifdef _WIN32 #error"Win32 is no longer supported." #else int error; int fd; int written; int to_write; char buf[4] = "sig";
/*****************************************************************************/ /* returns -1 on error, else return handle or file descriptor */ int
g_file_open_ex(constchar *file_name, int aread, int awrite, int acreate, int atrunc)
{ #ifdefined(_WIN32) return -1; #else int rv; int flags;
/*****************************************************************************/ /* read from file, returns the number of bytes read or -1 on error */ int
g_file_read(int fd, char *ptr, int len)
{ #ifdefined(_WIN32)
/*****************************************************************************/ /* write to file, returns the number of bytes written or -1 on error */ int
g_file_write(int fd, constchar *ptr, int len)
{ #ifdefined(_WIN32)
/*****************************************************************************/ /* move file pointer, returns offset on success, -1 on failure */ int
g_file_seek(int fd, int offset)
{ #ifdefined(_WIN32) int rv;
/*****************************************************************************/ /* move file pointer to end of file, plus an offset */ int
g_file_seek_end(int fd, int offset)
{ #ifdefined(_WIN32) int rv;
/*****************************************************************************/ /* do a write lock on a file */ /* return boolean */ int
g_file_lock(int fd, int start, int len)
{ #ifdefined(_WIN32) return LockFile((HANDLE)fd, start, 0, len, 0); #else struct flock lock;
/*****************************************************************************/ /* Gets the close-on-exec flag for a file descriptor */ int
g_file_get_cloexec(int fd)
{ int rv = 0; int flags = fcntl(fd, F_GETFD); if (flags >= 0 && (flags & FD_CLOEXEC) != 0)
{
rv = 1;
}
return rv;
}
/*****************************************************************************/ /* Sets/clears the close-on-exec flag for a file descriptor */ /* return boolean */ int
g_file_set_cloexec(int fd, int status)
{ int rv = 0; int current_flags = fcntl(fd, F_GETFD); if (current_flags >= 0)
{ int new_flags; if (status)
{
new_flags = current_flags | FD_CLOEXEC;
} else
{
new_flags = current_flags & ~FD_CLOEXEC;
} if (new_flags != current_flags)
{
rv = (fcntl(fd, F_SETFD, new_flags) >= 0);
}
}
return rv;
}
/*****************************************************************************/ struct list *
g_get_open_fds(int min, int max)
{ if (min < 0)
{
min = 0;
}
struct list *result = list_create();
if (result != NULL)
{ if (max < 0)
{ // sysconf() returns a long. Limit it to a sane value #define SANE_MAX 100000 long sc_max = sysconf(_SC_OPEN_MAX);
max = (sc_max < 0) ? 0 :
(sc_max > (long)SANE_MAX) ? SANE_MAX :
sc_max; #undef SANE_MAX
}
// max and min are now both guaranteed to be >= 0 if (max > min)
{ struct pollfd *fds = g_new0(struct pollfd, max - min); int i;
if (fds == NULL)
{ goto nomem;
}
for (i = min ; i < max ; ++i)
{
fds[i - min].fd = i;
}
if (poll(fds, max - min, 0) >= 0)
{ for (i = min ; i < max ; ++i)
{ if (fds[i - min].revents != POLLNVAL)
{ // Descriptor is open if (!list_add_item(result, i))
{
g_free(fds); goto nomem;
}
}
}
}
g_free(fds);
}
}
return result;
nomem:
list_delete(result); return NULL;
}
/*****************************************************************************/ int
g_file_map(int fd, int aread, int awrite, size_t length, void **addr)
{ int prot = 0; void *laddr;
/*****************************************************************************/ /* Converts a mode_t value to a hex mask */ #if !defined(_WIN32) staticint
mode_t_to_hex(mode_t mode)
{ int hex = 0;
/*****************************************************************************/ /* Duplicates a file descriptor onto another one using the semantics
* of dup2() */ /* return boolean */ int
g_file_duplicate_on(int fd, int target_fd)
{ int rv = (dup2(fd, target_fd) >= 0);
if (rv < 0)
{
LOG(LOG_LEVEL_ERROR, "Can't clone file %d as file %d [%s]",
fd, target_fd, g_get_strerror());
}
return rv;
}
/*****************************************************************************/ /* returns error */ int
g_chmod_hex(constchar *filename, int flags)
{ #ifdefined(_WIN32) return0; #else
mode_t m = hex_to_mode_t(flags); return chmod(filename, m); #endif
}
/*****************************************************************************/ /* returns error */ int
g_umask_hex(int flags)
{ #ifdefined(_WIN32) return flags; #else
mode_t m = hex_to_mode_t(flags);
m = umask(m); return mode_t_to_hex(m); #endif
}
/*****************************************************************************/ /* returns error, zero is ok */ int
g_chown(constchar *name, int uid, int gid)
{ return chown(name, uid, gid);
}
/*****************************************************************************/ /* returns error, always zero */ int
g_mkdir(constchar *dirname)
{ #ifdefined(_WIN32) return0; #else return mkdir(dirname, S_IRWXU); #endif
}
/*****************************************************************************/ /* gets the current working directory and puts up to maxlen chars in dirname
always returns 0 */ char *
g_get_current_dir(char *dirname, int maxlen)
{ #ifdefined(_WIN32)
GetCurrentDirectoryA(maxlen, dirname); return0; #else
if (getcwd(dirname, maxlen) == 0)
{
}
return0; #endif
}
/*****************************************************************************/ /* returns error, zero on success and -1 on failure */ int
g_set_current_dir(constchar *dirname)
{ #ifdefined(_WIN32)
if (SetCurrentDirectoryA(dirname))
{ return0;
} else
{ return -1;
}
#else return chdir(dirname); #endif
}
/*****************************************************************************/ /* returns boolean, non zero if the file exists */ int
g_file_exist(constchar *filename)
{ #ifdefined(_WIN32) return0; // use FileAge(filename) <> -1 #else return access(filename, F_OK) == 0; #endif
}
/*****************************************************************************/ /* returns boolean, non zero if the file is readable */ int
g_file_readable(constchar *filename)
{ #ifdefined(_WIN32) return _waccess(filename, 04) == 0; #else return access(filename, R_OK) == 0; #endif
}
/*****************************************************************************/ /* returns boolean, non zero if the directory exists */ int
g_directory_exist(constchar *dirname)
{ #ifdefined(_WIN32) return0; // use GetFileAttributes and check return value // is not -1 and FILE_ATTRIBUTE_DIRECTORY bit is set #else struct stat st;
/*****************************************************************************/ /* returns boolean, non zero if the file exists and is a readable executable */ int
g_executable_exist(constchar *exename)
{ return access(exename, R_OK | X_OK) == 0;
}
/*****************************************************************************/ /* returns boolean */ int
g_create_dir(constchar *dirname)
{ #ifdefined(_WIN32) return CreateDirectoryA(dirname, 0); // test this #else return mkdir(dirname, 0777) == 0; #endif
}
/*****************************************************************************/ /* will try to create directories up to last / in name example/tmp/a/b/c/readme.txtwilltrytocreate/tmp/a/b/c
returns boolean */ int
g_create_path(constchar *path)
{ char *pp; char *sp; char *copypath; int status;
if (!g_directory_exist(copypath))
{ if (!g_create_dir(copypath))
{
status = 0; break;
}
}
*sp = '/';
}
pp = sp + 1;
sp = strchr(pp, '/');
}
g_free(copypath); return status;
}
/*****************************************************************************/ /* returns boolean */ int
g_remove_dir(constchar *dirname)
{ #ifdefined(_WIN32) return RemoveDirectoryA(dirname); // test this #else return rmdir(dirname) == 0; #endif
}
/*****************************************************************************/ /* returns non zero if the file was deleted */ int
g_file_delete(constchar *filename)
{ #ifdefined(_WIN32) return DeleteFileA(filename); #else return unlink(filename) != -1; #endif
}
/*****************************************************************************/ /* returns file size, -1 on error */ int
g_file_get_size(constchar *filename)
{ #ifdefined(_WIN32) return -1; #else struct stat st;
/*****************************************************************************/ /* does not work in win32 */ int
g_system(constchar *aexec)
{ #ifdefined(_WIN32) return0; #else return system(aexec); #endif
}
/*****************************************************************************/ /* does not work in win32 */ char *
g_get_strerror(void)
{ #ifdefined(_WIN32) return0; #else return strerror(errno); #endif
}
/*****************************************************************************/ int
g_execvp_list(constchar *file, struct list *argv)
{ int rv = -1;
/* Push a terminating NULL onto the list for the system call */ if (!list_add_item(argv, (tintptr)NULL))
{
LOG(LOG_LEVEL_ERROR, "No memory for exec to terminate list");
errno = ENOMEM;
} else
{ /* Read the argv argument straight from the list */
rv = g_execvp(file, (char **)argv->items);
/* should not get here */
list_remove_item(argv, argv->count - 1); // Lose terminating NULL
} return rv;
}
/*****************************************************************************/ /* does not work in win32 */ int
g_execlp3(constchar *a1, constchar *a2, constchar *a3)
{ #ifdefined(_WIN32) return0; #else int rv; constchar *args[] = {a2, a3, NULL}; char args_str[ARGS_STR_LEN];
/* should not get here */
LOG(LOG_LEVEL_ERROR, "Error calling exec (executable: %s, arguments: %s) " "returned errno: %d, description: %s",
a1, args_str, g_get_errno(), g_get_strerror());
return rv; #endif
}
/*****************************************************************************/ /* does not work in win32 */ unsignedint
g_set_alarm(void (*func)(int), unsignedint secs)
{ #ifdefined(_WIN32) return0; #else struct sigaction action;
/* Cancel any previous alarm to prevent a race */ unsignedint rv = alarm(0);
/*****************************************************************************/ /* does not work in win32 */ void
g_signal_child_stop(void (*func)(int))
{ #ifdefined(_WIN32) #else struct sigaction action;
if (func == NULL)
{
action.sa_handler = SIG_DFL;
action.sa_flags = 0;
} else
{
action.sa_handler = func; // Don't need to know when children are stopped or started
action.sa_flags = (SA_RESTART | SA_NOCLDSTOP);
}
sigemptyset (&action.sa_mask);
if (func == NULL)
{
action.sa_handler = SIG_DFL;
action.sa_flags = 0;
} else
{
action.sa_handler = func;
action.sa_flags = SA_RESETHAND; // This is a one-shot
}
sigemptyset (&action.sa_mask);
sigaction(SIGSEGV, &action, NULL); #endif
}
/*****************************************************************************/ /* does not work in win32 */ void
g_signal_hang_up(void (*func)(int))
{ #ifdefined(_WIN32) #else struct sigaction action;
/*****************************************************************************/ /* does not work in win32 */ void
g_signal_user_interrupt(void (*func)(int))
{ #ifdefined(_WIN32) #else struct sigaction action;
/*****************************************************************************/ /* does not work in win32 */ void
g_signal_terminate(void (*func)(int))
{ #ifdefined(_WIN32) #else struct sigaction action;
/*****************************************************************************/ /* does not work in win32 */ void
g_signal_pipe(void (*func)(int))
{ #ifdefined(_WIN32) #else struct sigaction action;
/*****************************************************************************/ /* does not work in win32 */ void
g_signal_usr1(void (*func)(int))
{ #ifdefined(_WIN32) #else struct sigaction action;
/*****************************************************************************/ /* does not work in win32 */ int
g_fork(void)
{ #ifdefined(_WIN32) return0; #else int rv;
rv = fork();
if (rv == -1) /* error */
{
LOG(LOG_LEVEL_ERROR, "Process fork failed with errno: %d, description: %s",
g_get_errno(), g_get_strerror());
}
return rv; #endif
}
/*****************************************************************************/ /* does not work in win32 */ int
g_setgid(int pid)
{ #ifdefined(_WIN32) return0; #else return setgid(pid); #endif
}
/*****************************************************************************/ /* Used by daemonizing code */ /* returns error, zero is success, non zero is error */ int
g_drop_privileges(constchar *user, constchar *group)
{ int rv = 1; int uid; int gid; if (g_getuser_info_by_name(user, &uid, NULL, NULL, NULL, NULL) != 0)
{
LOG(LOG_LEVEL_ERROR, "Unable to get UID for user '%s' [%s]", user,
g_get_strerror());
} elseif (g_getgroup_info(group, &gid) != 0)
{
LOG(LOG_LEVEL_ERROR, "Unable to get GID for group '%s' [%s]", group,
g_get_strerror());
} elseif (initgroups(user, gid) != 0)
{
LOG(LOG_LEVEL_ERROR, "Unable to init groups for '%s' [%s]", user,
g_get_strerror());
} elseif (g_setgid(gid) != 0)
{
LOG(LOG_LEVEL_ERROR, "Unable to set group to '%s' [%s]", group,
g_get_strerror());
} elseif (g_setuid(uid) != 0)
{
LOG(LOG_LEVEL_ERROR, "Unable to set user to '%s' [%s]", user,
g_get_strerror());
} else
{
rv = 0;
}
return rv;
}
/*****************************************************************************/ /* returns error, zero is success, non zero is error */ /* does not work in win32 */ int
g_initgroups(constchar *username)
{ #ifdefined(_WIN32) return0; #else int gid; int error = g_getuser_info_by_name(username, NULL, &gid, NULL, NULL, NULL); if (error == 0)
{
error = initgroups(username, gid);
} return error; #endif
}
/*****************************************************************************/ /* does not work in win32 */ /* returns user id */ int
g_getuid(void)
{ #ifdefined(_WIN32) return0; #else return getuid(); #endif
}
/*****************************************************************************/ /* does not work in win32 */ /* returns user id */ int
g_getgid(void)
{ #ifdefined(_WIN32) return0; #else return getgid(); #endif
}
/*****************************************************************************/ /* does not work in win32 */ /* On success, zero is returned. On error, -1 is returned */ int
g_setuid(int pid)
{ #ifdefined(_WIN32) return0; #else return setuid(pid); #endif
}
/*****************************************************************************/ #ifdef HAVE_SETUSERCONTEXT int
g_set_allusercontext(int uid)
{ int rv; struct passwd *pwd = getpwuid(uid); if (pwd == NULL)
{
LOG(LOG_LEVEL_ERROR, "No password entry for UID %d", uid);
rv = 1;
} else
{
rv = setusercontext(NULL, pwd, uid, LOGIN_SETALL); if (rv != 0)
{
LOG(LOG_LEVEL_ERROR, "setusercontext(%d) failed [%s]",
uid, g_get_strerror());
}
}
return (rv != 0); /* Return 0 or 1 */
} #endif /*****************************************************************************/ /* does not work in win32 returnspidofprocessthatexitsorzeroifsignaloccurred aproc_exit_statusstructcanoptionallybepassedintogetthe
exit status of the child */ int
g_waitchild(struct proc_exit_status *e)
{ #ifdefined(_WIN32) return0; #else int wstat; int rv;
struct proc_exit_status dummy;
if (e == NULL)
{
e = &dummy; // Set this, then throw it away
}
e->reason = E_PXR_UNEXPECTED;
e->val = 0;
rv = waitpid(-1, &wstat, WNOHANG);
if (rv == -1)
{ if (errno == EINTR)
{ /* This shouldn't happen as signal handlers use SA_RESTART */
rv = 0;
}
} elseif (WIFEXITED(wstat))
{
e->reason = E_PXR_STATUS_CODE;
e->val = WEXITSTATUS(wstat);
} elseif (WIFSIGNALED(wstat))
{
e->reason = E_PXR_SIGNAL;
e->val = WTERMSIG(wstat);
}
return rv; #endif
}
/*****************************************************************************/ /* does not work in win32 returnspidofprocessthatexitsor<=0ifnoprocesswasfound
NotethatsignalhandlersareestablishedwithBSD-stylesemantics,
so this call is NOT interrupted by a signal */ int
g_waitpid(int pid)
{ #ifdefined(_WIN32) return0; #else int rv = 0;
/*****************************************************************************/ /* does not work in win32 returnsexitstatuscodeofchildprocesswithpid
NotethatsignalhandlersareestablishedwithBSD-stylesemantics,
so this call is NOT interrupted by a signal */ struct proc_exit_status
g_waitpid_status(int pid)
{ struct proc_exit_status exit_status =
{
.reason = E_PXR_UNEXPECTED,
.val = 0
};
#if !defined(_WIN32) if (pid > 0)
{ int rv; int status;
LOG(LOG_LEVEL_DEBUG, "waiting for pid %d to exit", pid);
rv = waitpid(pid, &status, 0);
if (rv != -1)
{ if (WIFEXITED(status))
{
exit_status.reason = E_PXR_STATUS_CODE;
exit_status.val = WEXITSTATUS(status);
} if (WIFSIGNALED(status))
{
exit_status.reason = E_PXR_SIGNAL;
exit_status.val = WTERMSIG(status);
}
} else
{
LOG(LOG_LEVEL_WARNING, "wait for pid %d returned unknown result", pid);
}
}
#endif return exit_status;
}
/*****************************************************************************/ int
g_setpgid(int pid, int pgid)
{ int rv = setpgid(pid, pgid); if (rv < 0)
{ if (pid == 0)
{
pid = getpid();
}
LOG(LOG_LEVEL_ERROR, "Can't set process group ID of %d to %d [%s]",
pid, pgid, g_get_strerror());
}
return rv;
}
/*****************************************************************************/ /* does not work in win32 */ void
g_clearenv(void)
{ #ifdefined(HAVE_CLEARENV)
clearenv(); #elifdefined(_WIN32) #elifdefined(BSD) externchar **environ;
environ[0] = 0; #else externchar **environ;
environ = 0; #endif
}
/*****************************************************************************/ /* does not work in win32 */ int
g_setenv(constchar *name, constchar *value, int rewrite)
{ #ifdefined(_WIN32) return0; #else return setenv(name, value, rewrite); #endif
}
/*****************************************************************************/ /* does not work in win32 */ void
g_setenv_log(constchar *name, constchar *value, int rewrite)
{ #ifdefined(_WIN32) return0; #else if (setenv(name, value, rewrite) != 0)
{
LOG(LOG_LEVEL_WARNING, "Unable to set environment variable '%s' [%s]",
name, g_get_strerror());
} #endif
}
/*****************************************************************************/ /* does not work in win32 */ char *
g_getenv(constchar *name)
{ #ifdefined(_WIN32) return0; #else return getenv(name); #endif
}
/*****************************************************************************/ int
g_exit(int exit_code)
{ exit(exit_code); return0;
}
/*****************************************************************************/ /* does not work in win32 */ int
g_sigterm(int pid)
{ #ifdefined(_WIN32) return0; #else return kill(pid, SIGTERM); #endif
}
/*****************************************************************************/ /* does not work in win32 */ int
g_sighup(int pid)
{ #ifdefined(_WIN32) return0; #else return kill(pid, SIGHUP); #endif
}
/*****************************************************************************/ /* returns 0 if ok */ /* the caller is responsible to free the buffs */ /* does not work in win32 */ int
g_getuser_info_by_name(constchar *username, int *uid, int *gid, char **shell, char **dir, char **gecos)
{ int rv = 1; #if !defined(_WIN32)
if (username == NULL)
{
LOG(LOG_LEVEL_ERROR, "g_getuser_info_by_name() called for NULL user");
} else
{ struct passwd *pwd_1 = getpwnam(username);
if (pwd_1 != 0)
{
rv = 0;
if (uid != 0)
{
*uid = pwd_1->pw_uid;
}
if (gid != 0)
{
*gid = pwd_1->pw_gid;
}
if (shell != 0)
{
*shell = g_strdup(pwd_1->pw_shell);
}
/*****************************************************************************/ /* returns 0 if ok */ /* the caller is responsible to free the buffs */ /* does not work in win32 */ int
g_getuser_info_by_uid(int uid, char **username, int *gid, char **shell, char **dir, char **gecos)
{ #ifdefined(_WIN32) return1; #else struct passwd *pwd_1;
pwd_1 = getpwuid(uid);
if (pwd_1 != 0)
{ if (username != NULL)
{
*username = g_strdup(pwd_1->pw_name);
}
if (gid != 0)
{
*gid = pwd_1->pw_gid;
}
if (shell != 0)
{
*shell = g_strdup(pwd_1->pw_shell);
}
if (dir != 0)
{
*dir = g_strdup(pwd_1->pw_dir);
}
if (gecos != 0)
{
*gecos = g_strdup(pwd_1->pw_gecos);
}
return0;
}
return1; #endif
}
/*****************************************************************************/ /* returns 0 if ok */ /* does not work in win32 */ int
g_getgroup_info(constchar *groupname, int *gid)
{ #ifdefined(_WIN32) return1; #else struct group *g;
g = getgrnam(groupname);
if (g != 0)
{ if (gid != 0)
{
*gid = g->gr_gid;
}
return0;
}
return1; #endif
}
/*****************************************************************************/ #ifdef HAVE_GETGROUPLIST int
g_check_user_in_group(constchar *username, int gid, int *ok)
{ int rv = 1; struct passwd *pwd_1 = getpwnam(username); if (pwd_1 != NULL)
{ // Get number of groups for user // // Some implementations of getgrouplist() (i.e. muslc) don't // allow ngroups to be <1 on entry int ngroups = 1;
GETGROUPLIST_T dummy;
getgrouplist(username, pwd_1->pw_gid, &dummy, &ngroups);
if (ngroups > 0) // Should always be true
{
GETGROUPLIST_T *grouplist;
grouplist = (GETGROUPLIST_T *)malloc(ngroups * sizeof(grouplist[0])); if (grouplist != NULL)
{ // Now get the actual groups. The number of groups returned // by this call is not necessarily the same as the number // returned by the first call. int allocgroups = ngroups;
getgrouplist(username, pwd_1->pw_gid, grouplist, &ngroups);
ngroups = MIN(ngroups, allocgroups);
rv = 0;
*ok = 0;
int i; for (i = 0 ; i < ngroups; ++i)
{ if (grouplist[i] == (GETGROUPLIST_T)gid)
{
*ok = 1; break;
}
}
free(grouplist);
}
}
} return rv;
} /*****************************************************************************/ #else// HAVE_GETGROUPLIST int
g_check_user_in_group(constchar *username, int gid, int *ok)
{ #ifdefined(_WIN32) return1; #else int i;
struct passwd *pwd_1 = getpwnam(username); struct group *groups = getgrgid(gid); if (pwd_1 == NULL || groups == NULL)
{ return1;
}
if (pwd_1->pw_gid == gid)
{
*ok = 1;
} else
{
*ok = 0;
i = 0;
while (0 != groups->gr_mem[i])
{ if (0 == g_strcmp(groups->gr_mem[i], username))
{
*ok = 1; break;
}
i++;
}
}
return0; #endif
} #endif// HAVE_GETGROUPLIST
/*****************************************************************************/ /* returns the time since the Epoch (00:00:00 UTC, January 1, 1970), measuredinseconds. forwindows,returnsthenumberofsecondssincethemachinewas
started. */ int
g_time1(void)
{ #ifdefined(_WIN32) return GetTickCount() / 1000; #else return time(0); #endif
}
/*****************************************************************************/ /* returns the number of milliseconds since the machine was
started. */ int
g_time2(void)
{ #ifdefined(_WIN32) return (int)GetTickCount(); #else struct tms tm;
clock_t num_ticks = 0;
g_memset(&tm, 0, sizeof(struct tms));
num_ticks = times(&tm); return (int)(num_ticks * 10); #endif
}
/*****************************************************************************/ /* returns time in milliseconds, uses gettimeofday
does not work in win32 */ int
g_time3(void)
{ #ifdefined(_WIN32) return0; #else struct timeval tp;
struct bmp_hdr
{ unsignedint size; /* file size in bytes */ unsignedshort reserved1; unsignedshort reserved2; unsignedint offset; /* offset to image data, in bytes */
};
struct dib_hdr
{ unsignedint hdr_size; int width; int height; unsignedshort nplanes; unsignedshort bpp; unsignedint compress_type; unsignedint image_size; int hres; int vres; unsignedint ncolors; unsignedint nimpcolors;
};
/******************************************************************************/ int
g_save_to_bmp(constchar *filename, char *data, int stride_bytes, int width, int height, int depth, int bits_per_pixel)
{ struct bmp_magic bm; struct bmp_hdr bh; struct dib_hdr dh; int bytes; int fd; int index; int i1; int pixel; int extra; int file_stride_bytes; char *line; char *line_ptr;
/* scan lines are 32 bit aligned, bottom 2 bits must be zero */
file_stride_bytes = width * ((depth + 7) / 8);
extra = file_stride_bytes;
extra = extra & 3;
extra = (4 - extra) & 3;
file_stride_bytes += extra;
/*****************************************************************************/ /* returns -1 on error 0 on success */ int
g_shmdt(constvoid *shmaddr)
{ #ifdefined(_WIN32) return -1; #else return shmdt(shmaddr); #endif
}
/*****************************************************************************/ /* returns -1 on error 0 on success */ int
g_gethostname(char *name, int len)
{ return gethostname(name, len);
}
/*****************************************************************************/ int
g_tcp6_socket(void)
{ #ifdefined(XRDP_ENABLE_IPV6) int rv; int option_value;
socklen_t option_len;
/*****************************************************************************/ /* returns error, zero is success, non zero is error */ /* only works in linux */ int
g_no_new_privs(void)
{ #ifdefined(HAVE_SYS_PRCTL_H) && defined(PR_SET_NO_NEW_PRIVS) /* *PR_SET_NO_NEW_PRIVSrequiresLinuxkernel3.5andnewer.
*/ return prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); #else return0; #endif
}
/*****************************************************************************/ int
g_fips_mode_enabled(void)
{ int rv = 0; #ifdefined (__linux) char buff[16]; int fd = open("/proc/sys/crypto/fips_enabled", O_RDONLY);
if (fd >= 0)
{
ssize_t res = read(fd, buff, sizeof(buff)); if (res > 0 && (size_t)res < sizeof(buff))
{
rv = (buff[0] != '0');
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.128Bemerkung:
(vorverarbeitet am 2026-07-10)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.