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