1 /** 2 * Copyright (c) 2013 Larisa Grigore. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/param.h> 28 #include <sys/un.h> 29 #include <sys/uio.h> 30 #include <sys/types.h> 31 #include <sys/stat.h> 32 #include <err.h> 33 #include <errno.h> 34 #include <fcntl.h> 35 #include <signal.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <unistd.h> 40 41 #include "sysvipc_utils.h" 42 #include "sysvipc_sockets.h" 43 44 #define MAX_CONN 10 45 46 int 47 init_socket(const char *sockfile) 48 { 49 struct sockaddr_un un_addr; 50 int sock; 51 52 /* create server socket */ 53 if ( (sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { 54 sysv_print_err("init socket"); 55 return (-1); 56 } 57 58 /* bind it */ 59 memset(&un_addr, 0, sizeof(un_addr)); 60 un_addr.sun_len = sizeof(un_addr); 61 un_addr.sun_family = AF_UNIX; 62 strcpy(un_addr.sun_path, sockfile); 63 64 unlink(un_addr.sun_path); 65 66 if (bind(sock, (struct sockaddr *)&un_addr, sizeof(un_addr)) < 0) { 67 close(sock); 68 sysv_print_err("bind"); 69 return (-1); 70 } 71 72 if (listen(sock, MAX_CONN) < 0) { 73 close(sock); 74 sysv_print_err("listen"); 75 return (-1); 76 } 77 78 /* turn on credentials passing */ 79 return (sock); 80 } 81 82 int 83 handle_new_connection(int sock) 84 { 85 int fd, flags; 86 87 do { 88 fd = accept(sock, NULL, NULL); 89 } while (fd < 0 && errno == EINTR); 90 91 if (fd < 0) { 92 sysv_print_err("accept"); 93 return (-1); 94 } 95 96 flags = fcntl(fd, F_GETFL, 0); 97 fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); 98 99 return (fd); 100 } 101 102 int 103 connect_to_daemon(const char *sockfile) 104 { 105 int sock, flags; 106 struct sockaddr_un serv_addr; 107 108 if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { 109 sysv_print_err("socket(%d)\n", sock); 110 return (-1); 111 } 112 113 flags = fcntl(sock, F_GETFL, 0); 114 fcntl(sock, F_SETFL, flags & ~O_NONBLOCK); 115 116 memset(&serv_addr, 0, sizeof(serv_addr)); 117 serv_addr.sun_family = AF_UNIX; 118 strcpy(serv_addr.sun_path, sockfile); 119 120 if (connect(sock, (struct sockaddr *)&serv_addr, 121 sizeof(serv_addr)) < 0) { 122 close(sock); 123 sysv_print_err("connect(%d)\n", sock); 124 return (-1); 125 } 126 127 return (sock); 128 } 129 130 int 131 send_fd(int sock, int fd) 132 { 133 struct msghdr msg; 134 struct iovec vec; 135 #ifndef HAVE_ACCRIGHTS_IN_MSGHDR 136 union { 137 struct cmsghdr hdr; 138 char buf[CMSG_SPACE(sizeof(int))]; 139 } cmsgbuf; 140 struct cmsghdr *cmsg; 141 #endif 142 int result = 0; 143 ssize_t n; 144 145 memset(&msg, 0, sizeof(msg)); 146 147 if (fd < 0) 148 result = errno; 149 else { 150 #ifdef HAVE_ACCRIGHTS_IN_MSGHDR 151 msg.msg_accrights = (caddr_t)&fd; 152 msg.msg_accrightslen = sizeof(fd); 153 #else 154 msg.msg_control = (caddr_t)cmsgbuf.buf; 155 msg.msg_controllen = sizeof(cmsgbuf.buf); 156 cmsg = CMSG_FIRSTHDR(&msg); 157 cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 158 cmsg->cmsg_level = SOL_SOCKET; 159 cmsg->cmsg_type = SCM_RIGHTS; 160 *(int *)CMSG_DATA(cmsg) = fd; 161 #endif 162 } 163 164 vec.iov_base = (caddr_t)&result; 165 vec.iov_len = sizeof(int); 166 msg.msg_iov = &vec; 167 msg.msg_iovlen = 1; 168 169 if ((n = sendmsg(sock, &msg, 0)) == -1) { 170 sysv_print_err("sendmsg(%d)\n", sock); 171 return (-1); 172 } 173 if (n != sizeof(int)) { 174 sysv_print_err("sendmsg: expected sent 1 got %ld\n", 175 (long)n); 176 return (-1); 177 } 178 179 return (0); 180 } 181 182 /**/ 183 int 184 receive_fd(int sock) 185 { 186 struct msghdr msg; 187 struct iovec vec; 188 #ifndef HAVE_ACCRIGHTS_IN_MSGHDR 189 union { 190 struct cmsghdr hdr; 191 char buf[CMSG_SPACE(sizeof(int))]; 192 } cmsgbuf; 193 struct cmsghdr *cmsg; 194 #endif 195 ssize_t n; 196 int result; 197 int fd; 198 199 memset(&msg, 0, sizeof(msg)); 200 vec.iov_base = (caddr_t)&result; 201 vec.iov_len = sizeof(int); 202 msg.msg_iov = &vec; 203 msg.msg_iovlen = 1; 204 205 #ifdef HAVE_ACCRIGHTS_IN_MSGHDR 206 msg.msg_accrights = (caddr_t)&fd; 207 msg.msg_accrightslen = sizeof(fd); 208 #else 209 msg.msg_control = &cmsgbuf.buf; 210 msg.msg_controllen = sizeof(cmsgbuf.buf); 211 #endif 212 213 if ((n = recvmsg(sock, &msg, 0)) == -1) 214 sysv_print_err("recvmsg\n"); 215 if (n != sizeof(int)) { 216 sysv_print_err("recvmsg: expected received 1 got %ld\n", 217 (long)n); 218 } 219 if (result == 0) { 220 cmsg = CMSG_FIRSTHDR(&msg); 221 if (cmsg == NULL) { 222 sysv_print_err("no message header\n"); 223 return (-1); 224 } 225 if (cmsg->cmsg_type != SCM_RIGHTS) 226 sysv_print_err("expected type %d got %d\n", 227 SCM_RIGHTS, cmsg->cmsg_type); 228 229 fd = (*(int *)CMSG_DATA(cmsg)); 230 return (fd); 231 } else { 232 errno = result; 233 return (-1); 234 } 235 } 236 237 static void 238 close_fds(int *fds, int num_fds) 239 { 240 int i; 241 242 for (i=0; i < num_fds; i++) 243 close(fds[i]); 244 } 245 246 /* Send with the message, credentials too. */ 247 int 248 send_msg_with_cred(int sock, char *buffer, size_t size) 249 { 250 struct msghdr msg; 251 struct iovec vec; 252 ssize_t n; 253 254 struct { 255 struct cmsghdr hdr; 256 char cred[CMSG_SPACE(sizeof(struct cmsgcred))]; 257 } cmsg; 258 259 memset(&cmsg, 0, sizeof(cmsg)); 260 cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(struct cmsgcred)); 261 cmsg.hdr.cmsg_level = SOL_SOCKET; 262 cmsg.hdr.cmsg_type = SCM_CREDS; 263 264 memset(&msg, 0, sizeof(struct msghdr)); 265 msg.msg_iov = &vec; 266 msg.msg_iovlen = 1; 267 msg.msg_control = (caddr_t)&cmsg; 268 msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred)); 269 270 vec.iov_base = buffer; 271 vec.iov_len = size; 272 273 if ((n = sendmsg(sock, &msg, 0)) == -1) { 274 sysv_print_err("sendmsg on fd %d\n", sock); 275 return (-1); 276 } 277 278 return (0); 279 } 280 281 /* Receive a message and the credentials of the sender. */ 282 int 283 receive_msg_with_cred(int sock, char *buffer, size_t size, 284 struct cmsgcred *cred) 285 { 286 struct msghdr msg = { .msg_name = NULL }; 287 struct iovec vec; 288 ssize_t n; 289 int result; 290 struct cmsghdr *cmp; 291 struct { 292 struct cmsghdr hdr; 293 char cred[CMSG_SPACE(sizeof(struct cmsgcred))]; 294 } cmsg; 295 296 memset(&msg, 0, sizeof(msg)); 297 vec.iov_base = buffer; 298 vec.iov_len = size; 299 msg.msg_iov = &vec; 300 msg.msg_iovlen = 1; 301 302 msg.msg_control = &cmsg; 303 msg.msg_controllen = sizeof(cmsg); 304 305 do { 306 n = recvmsg(sock, &msg, 0); 307 } while (n < 0 && errno == EINTR); 308 309 if (n < 0) { 310 sysv_print_err("recvmsg on fd %d\n", sock); 311 return (-1); 312 } 313 314 if (n == 0) { 315 return (-1); 316 } 317 318 result = -1; 319 cmp = CMSG_FIRSTHDR(&msg); 320 321 while(cmp != NULL) { 322 if (cmp->cmsg_level == SOL_SOCKET 323 && cmp->cmsg_type == SCM_CREDS) { 324 if (cred) 325 memcpy(cred, CMSG_DATA(cmp), sizeof(*cred)); 326 result = n; 327 } else if (cmp->cmsg_level == SOL_SOCKET 328 && cmp->cmsg_type == SCM_RIGHTS) { 329 close_fds((int *) CMSG_DATA(cmp), 330 (cmp->cmsg_len - CMSG_LEN(0)) 331 / sizeof(int)); 332 } 333 cmp = CMSG_NXTHDR(&msg, cmp); 334 } 335 336 return (result); 337 } 338