1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
/*
* $Id: ud_socket.c,v 1.6 2009/04/22 18:22:28 thockin Exp $
* A few routines for handling UNIX domain sockets
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <fcntl.h>
#include "acpid.h"
#include "log.h"
#include "ud_socket.h"
#include "libc_compat.h"
int
ud_create_socket(const char *name, mode_t socketmode)
{
int fd;
int r;
struct sockaddr_un uds_addr;
if (strnlen(name, sizeof(uds_addr.sun_path)) >
sizeof(uds_addr.sun_path) - 1) {
acpid_log(LOG_ERR, "ud_create_socket(): "
"socket filename longer than %zu characters: %s",
sizeof(uds_addr.sun_path) - 1, name);
errno = EINVAL;
return -1;
}
/* JIC */
unlink(name);
fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
if (fd < 0) {
return fd;
}
/* Clear the umask to guarantee predictable results from fchmod(). */
umask(0);
if (fchmod(fd, socketmode) < 0) {
close(fd);
acpid_log(LOG_ERR, "fchmod() on socket %s: %s",
name, strerror(errno));
return -1;
}
/* setup address struct */
memset(&uds_addr, 0, sizeof(uds_addr));
uds_addr.sun_family = AF_UNIX;
strncpy(uds_addr.sun_path, name, sizeof(uds_addr.sun_path) - 1);
/* bind it to the socket */
r = bind(fd, (struct sockaddr *)&uds_addr, sizeof(uds_addr));
if (r < 0) {
close (fd);
return r;
}
/* listen - allow 10 to queue */
r = listen(fd, 10);
if (r < 0) {
close(fd);
return r;
}
return fd;
}
int
ud_accept(int listenfd, struct ucred *cred)
{
while (1) {
int newsock = 0;
struct sockaddr_un cliaddr;
socklen_t len = sizeof(struct sockaddr_un);
newsock = TEMP_FAILURE_RETRY (accept4(listenfd, (struct sockaddr *)&cliaddr, &len, SOCK_CLOEXEC|SOCK_NONBLOCK));
if (newsock < 0) {
return newsock;
}
if (cred) {
len = sizeof(struct ucred);
getsockopt(newsock,SOL_SOCKET,SO_PEERCRED,cred,&len);
}
return newsock;
}
}
int
ud_connect(const char *name)
{
int fd;
int r;
struct sockaddr_un addr;
if (strnlen(name, sizeof(addr.sun_path)) > sizeof(addr.sun_path) - 1) {
acpid_log(LOG_ERR, "ud_connect(): "
"socket filename longer than %zu characters: %s",
sizeof(addr.sun_path) - 1, name);
errno = EINVAL;
return -1;
}
fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (fd < 0) {
return fd;
}
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
sprintf(addr.sun_path, "%s", name);
/* safer: */
/*strncpy(addr.sun_path, name, sizeof(addr.sun_path) - 1);*/
r = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
if (r < 0) {
close(fd);
return r;
}
return fd;
}
int
ud_get_peercred(int fd, struct ucred *cred)
{
socklen_t len = sizeof(struct ucred);
getsockopt(fd, SOL_SOCKET, SO_PEERCRED, cred, &len);
return 0;
}
|