pcsc-lite
1.7.4
|
00001 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ 00002 00003 /*** 00004 Copyright 2010 Lennart Poettering 00005 00006 Permission is hereby granted, free of charge, to any person 00007 obtaining a copy of this software and associated documentation files 00008 (the "Software"), to deal in the Software without restriction, 00009 including without limitation the rights to use, copy, modify, merge, 00010 publish, distribute, sublicense, and/or sell copies of the Software, 00011 and to permit persons to whom the Software is furnished to do so, 00012 subject to the following conditions: 00013 00014 The above copyright notice and this permission notice shall be 00015 included in all copies or substantial portions of the Software. 00016 00017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 00018 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00019 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00020 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 00021 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 00022 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 00023 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 00024 SOFTWARE. 00025 ***/ 00026 00027 #ifndef _GNU_SOURCE 00028 #define _GNU_SOURCE 00029 #endif 00030 00031 #include <sys/types.h> 00032 #include <sys/stat.h> 00033 #include <sys/socket.h> 00034 #include <sys/un.h> 00035 #include <sys/fcntl.h> 00036 #include <netinet/in.h> 00037 #include <stdlib.h> 00038 #include <errno.h> 00039 #include <unistd.h> 00040 #include <string.h> 00041 #include <stdarg.h> 00042 #include <stdio.h> 00043 #include <stddef.h> 00044 #include <limits.h> 00045 00046 #if defined(__linux__) 00047 #include <mqueue.h> 00048 #endif 00049 00050 #include "sd-daemon.h" 00051 00052 #if (__GNUC__ >= 4) && !defined(SD_EXPORT_SYMBOLS) 00053 #define _sd_hidden_ __attribute__ ((visibility("hidden"))) 00054 #else 00055 #define _sd_hidden_ 00056 #endif 00057 00058 _sd_hidden_ int sd_listen_fds(int unset_environment) { 00059 00060 #if defined(DISABLE_SYSTEMD) || !defined(__linux__) 00061 return 0; 00062 #else 00063 int r, fd; 00064 const char *e; 00065 char *p = NULL; 00066 unsigned long l; 00067 00068 if (!(e = getenv("LISTEN_PID"))) { 00069 r = 0; 00070 goto finish; 00071 } 00072 00073 errno = 0; 00074 l = strtoul(e, &p, 10); 00075 00076 if (errno != 0) { 00077 r = -errno; 00078 goto finish; 00079 } 00080 00081 if (!p || *p || l <= 0) { 00082 r = -EINVAL; 00083 goto finish; 00084 } 00085 00086 /* Is this for us? */ 00087 if (getpid() != (pid_t) l) { 00088 r = 0; 00089 goto finish; 00090 } 00091 00092 if (!(e = getenv("LISTEN_FDS"))) { 00093 r = 0; 00094 goto finish; 00095 } 00096 00097 errno = 0; 00098 l = strtoul(e, &p, 10); 00099 00100 if (errno != 0) { 00101 r = -errno; 00102 goto finish; 00103 } 00104 00105 if (!p || *p) { 00106 r = -EINVAL; 00107 goto finish; 00108 } 00109 00110 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) { 00111 int flags; 00112 00113 if ((flags = fcntl(fd, F_GETFD)) < 0) { 00114 r = -errno; 00115 goto finish; 00116 } 00117 00118 if (flags & FD_CLOEXEC) 00119 continue; 00120 00121 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) { 00122 r = -errno; 00123 goto finish; 00124 } 00125 } 00126 00127 r = (int) l; 00128 00129 finish: 00130 if (unset_environment) { 00131 unsetenv("LISTEN_PID"); 00132 unsetenv("LISTEN_FDS"); 00133 } 00134 00135 return r; 00136 #endif 00137 } 00138 00139 _sd_hidden_ int sd_is_fifo(int fd, const char *path) { 00140 struct stat st_fd; 00141 00142 if (fd < 0) 00143 return -EINVAL; 00144 00145 memset(&st_fd, 0, sizeof(st_fd)); 00146 if (fstat(fd, &st_fd) < 0) 00147 return -errno; 00148 00149 if (!S_ISFIFO(st_fd.st_mode)) 00150 return 0; 00151 00152 if (path) { 00153 struct stat st_path; 00154 00155 memset(&st_path, 0, sizeof(st_path)); 00156 if (stat(path, &st_path) < 0) { 00157 00158 if (errno == ENOENT || errno == ENOTDIR) 00159 return 0; 00160 00161 return -errno; 00162 } 00163 00164 return 00165 st_path.st_dev == st_fd.st_dev && 00166 st_path.st_ino == st_fd.st_ino; 00167 } 00168 00169 return 1; 00170 } 00171 00172 _sd_hidden_ int sd_is_special(int fd, const char *path) { 00173 struct stat st_fd; 00174 00175 if (fd < 0) 00176 return -EINVAL; 00177 00178 if (fstat(fd, &st_fd) < 0) 00179 return -errno; 00180 00181 if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode)) 00182 return 0; 00183 00184 if (path) { 00185 struct stat st_path; 00186 00187 if (stat(path, &st_path) < 0) { 00188 00189 if (errno == ENOENT || errno == ENOTDIR) 00190 return 0; 00191 00192 return -errno; 00193 } 00194 00195 if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode)) 00196 return 00197 st_path.st_dev == st_fd.st_dev && 00198 st_path.st_ino == st_fd.st_ino; 00199 else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode)) 00200 return st_path.st_rdev == st_fd.st_rdev; 00201 else 00202 return 0; 00203 } 00204 00205 return 1; 00206 } 00207 00208 static int sd_is_socket_internal(int fd, int type, int listening) { 00209 struct stat st_fd; 00210 00211 if (fd < 0 || type < 0) 00212 return -EINVAL; 00213 00214 if (fstat(fd, &st_fd) < 0) 00215 return -errno; 00216 00217 if (!S_ISSOCK(st_fd.st_mode)) 00218 return 0; 00219 00220 if (type != 0) { 00221 int other_type = 0; 00222 socklen_t l = sizeof(other_type); 00223 00224 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0) 00225 return -errno; 00226 00227 if (l != sizeof(other_type)) 00228 return -EINVAL; 00229 00230 if (other_type != type) 00231 return 0; 00232 } 00233 00234 if (listening >= 0) { 00235 int accepting = 0; 00236 socklen_t l = sizeof(accepting); 00237 00238 if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0) 00239 return -errno; 00240 00241 if (l != sizeof(accepting)) 00242 return -EINVAL; 00243 00244 if (!accepting != !listening) 00245 return 0; 00246 } 00247 00248 return 1; 00249 } 00250 00251 union sockaddr_union { 00252 struct sockaddr sa; 00253 struct sockaddr_in in4; 00254 struct sockaddr_in6 in6; 00255 struct sockaddr_un un; 00256 struct sockaddr_storage storage; 00257 }; 00258 00259 _sd_hidden_ int sd_is_socket(int fd, int family, int type, int listening) { 00260 int r; 00261 00262 if (family < 0) 00263 return -EINVAL; 00264 00265 if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) 00266 return r; 00267 00268 if (family > 0) { 00269 union sockaddr_union sockaddr; 00270 socklen_t l; 00271 00272 memset(&sockaddr, 0, sizeof(sockaddr)); 00273 l = sizeof(sockaddr); 00274 00275 if (getsockname(fd, &sockaddr.sa, &l) < 0) 00276 return -errno; 00277 00278 if (l < sizeof(sa_family_t)) 00279 return -EINVAL; 00280 00281 return sockaddr.sa.sa_family == family; 00282 } 00283 00284 return 1; 00285 } 00286 00287 _sd_hidden_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) { 00288 union sockaddr_union sockaddr; 00289 socklen_t l; 00290 int r; 00291 00292 if (family != 0 && family != AF_INET && family != AF_INET6) 00293 return -EINVAL; 00294 00295 if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) 00296 return r; 00297 00298 memset(&sockaddr, 0, sizeof(sockaddr)); 00299 l = sizeof(sockaddr); 00300 00301 if (getsockname(fd, &sockaddr.sa, &l) < 0) 00302 return -errno; 00303 00304 if (l < sizeof(sa_family_t)) 00305 return -EINVAL; 00306 00307 if (sockaddr.sa.sa_family != AF_INET && 00308 sockaddr.sa.sa_family != AF_INET6) 00309 return 0; 00310 00311 if (family > 0) 00312 if (sockaddr.sa.sa_family != family) 00313 return 0; 00314 00315 if (port > 0) { 00316 if (sockaddr.sa.sa_family == AF_INET) { 00317 if (l < sizeof(struct sockaddr_in)) 00318 return -EINVAL; 00319 00320 return htons(port) == sockaddr.in4.sin_port; 00321 } else { 00322 if (l < sizeof(struct sockaddr_in6)) 00323 return -EINVAL; 00324 00325 return htons(port) == sockaddr.in6.sin6_port; 00326 } 00327 } 00328 00329 return 1; 00330 } 00331 00332 _sd_hidden_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) { 00333 union sockaddr_union sockaddr; 00334 socklen_t l; 00335 int r; 00336 00337 if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) 00338 return r; 00339 00340 memset(&sockaddr, 0, sizeof(sockaddr)); 00341 l = sizeof(sockaddr); 00342 00343 if (getsockname(fd, &sockaddr.sa, &l) < 0) 00344 return -errno; 00345 00346 if (l < sizeof(sa_family_t)) 00347 return -EINVAL; 00348 00349 if (sockaddr.sa.sa_family != AF_UNIX) 00350 return 0; 00351 00352 if (path) { 00353 if (length <= 0) 00354 length = strlen(path); 00355 00356 if (length <= 0) 00357 /* Unnamed socket */ 00358 return l == offsetof(struct sockaddr_un, sun_path); 00359 00360 if (path[0]) 00361 /* Normal path socket */ 00362 return 00363 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) && 00364 memcmp(path, sockaddr.un.sun_path, length+1) == 0; 00365 else 00366 /* Abstract namespace socket */ 00367 return 00368 (l == offsetof(struct sockaddr_un, sun_path) + length) && 00369 memcmp(path, sockaddr.un.sun_path, length) == 0; 00370 } 00371 00372 return 1; 00373 } 00374 00375 _sd_hidden_ int sd_is_mq(int fd, const char *path) { 00376 #if !defined(__linux__) 00377 return 0; 00378 #else 00379 struct mq_attr attr; 00380 00381 if (fd < 0) 00382 return -EINVAL; 00383 00384 if (mq_getattr(fd, &attr) < 0) 00385 return -errno; 00386 00387 if (path) { 00388 char fpath[PATH_MAX]; 00389 struct stat a, b; 00390 00391 if (path[0] != '/') 00392 return -EINVAL; 00393 00394 if (fstat(fd, &a) < 0) 00395 return -errno; 00396 00397 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12); 00398 fpath[sizeof(fpath)-1] = 0; 00399 00400 if (stat(fpath, &b) < 0) 00401 return -errno; 00402 00403 if (a.st_dev != b.st_dev || 00404 a.st_ino != b.st_ino) 00405 return 0; 00406 } 00407 00408 return 1; 00409 #endif 00410 } 00411 00412 _sd_hidden_ int sd_notify(int unset_environment, const char *state) { 00413 #if defined(DISABLE_SYSTEMD) || !defined(__linux__) || !defined(SOCK_CLOEXEC) 00414 return 0; 00415 #else 00416 int fd = -1, r; 00417 struct msghdr msghdr; 00418 struct iovec iovec; 00419 union sockaddr_union sockaddr; 00420 const char *e; 00421 00422 if (!state) { 00423 r = -EINVAL; 00424 goto finish; 00425 } 00426 00427 if (!(e = getenv("NOTIFY_SOCKET"))) 00428 return 0; 00429 00430 /* Must be an abstract socket, or an absolute path */ 00431 if ((e[0] != '@' && e[0] != '/') || e[1] == 0) { 00432 r = -EINVAL; 00433 goto finish; 00434 } 00435 00436 if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) { 00437 r = -errno; 00438 goto finish; 00439 } 00440 00441 memset(&sockaddr, 0, sizeof(sockaddr)); 00442 sockaddr.sa.sa_family = AF_UNIX; 00443 strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path)); 00444 00445 if (sockaddr.un.sun_path[0] == '@') 00446 sockaddr.un.sun_path[0] = 0; 00447 00448 memset(&iovec, 0, sizeof(iovec)); 00449 iovec.iov_base = (char*) state; 00450 iovec.iov_len = strlen(state); 00451 00452 memset(&msghdr, 0, sizeof(msghdr)); 00453 msghdr.msg_name = &sockaddr; 00454 msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e); 00455 00456 if (msghdr.msg_namelen > sizeof(struct sockaddr_un)) 00457 msghdr.msg_namelen = sizeof(struct sockaddr_un); 00458 00459 msghdr.msg_iov = &iovec; 00460 msghdr.msg_iovlen = 1; 00461 00462 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) { 00463 r = -errno; 00464 goto finish; 00465 } 00466 00467 r = 1; 00468 00469 finish: 00470 if (unset_environment) 00471 unsetenv("NOTIFY_SOCKET"); 00472 00473 if (fd >= 0) 00474 close(fd); 00475 00476 return r; 00477 #endif 00478 } 00479 00480 _sd_hidden_ int sd_notifyf(int unset_environment, const char *format, ...) { 00481 #if defined(DISABLE_SYSTEMD) || !defined(__linux__) 00482 return 0; 00483 #else 00484 va_list ap; 00485 char *p = NULL; 00486 int r; 00487 00488 va_start(ap, format); 00489 r = vasprintf(&p, format, ap); 00490 va_end(ap); 00491 00492 if (r < 0 || !p) 00493 return -ENOMEM; 00494 00495 r = sd_notify(unset_environment, p); 00496 free(p); 00497 00498 return r; 00499 #endif 00500 } 00501 00502 _sd_hidden_ int sd_booted(void) { 00503 #if defined(DISABLE_SYSTEMD) || !defined(__linux__) 00504 return 0; 00505 #else 00506 00507 struct stat a, b; 00508 00509 /* We simply test whether the systemd cgroup hierarchy is 00510 * mounted */ 00511 00512 if (lstat("/sys/fs/cgroup", &a) < 0) 00513 return 0; 00514 00515 if (lstat("/sys/fs/cgroup/systemd", &b) < 0) 00516 return 0; 00517 00518 return a.st_dev != b.st_dev; 00519 #endif 00520 }