pcsc-lite
1.8.2
|
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) 00053 #ifdef SD_EXPORT_SYMBOLS 00054 /* Export symbols */ 00055 #define _sd_export_ __attribute__ ((visibility("default"))) 00056 #else 00057 /* Don't export the symbols */ 00058 #define _sd_export_ __attribute__ ((visibility("hidden"))) 00059 #endif 00060 #else 00061 #define _sd_export_ 00062 #endif 00063 00064 _sd_export_ int sd_listen_fds(int unset_environment) { 00065 00066 #if defined(DISABLE_SYSTEMD) || !defined(__linux__) 00067 return 0; 00068 #else 00069 int r, fd; 00070 const char *e; 00071 char *p = NULL; 00072 unsigned long l; 00073 00074 if (!(e = getenv("LISTEN_PID"))) { 00075 r = 0; 00076 goto finish; 00077 } 00078 00079 errno = 0; 00080 l = strtoul(e, &p, 10); 00081 00082 if (errno != 0) { 00083 r = -errno; 00084 goto finish; 00085 } 00086 00087 if (!p || *p || l <= 0) { 00088 r = -EINVAL; 00089 goto finish; 00090 } 00091 00092 /* Is this for us? */ 00093 if (getpid() != (pid_t) l) { 00094 r = 0; 00095 goto finish; 00096 } 00097 00098 if (!(e = getenv("LISTEN_FDS"))) { 00099 r = 0; 00100 goto finish; 00101 } 00102 00103 errno = 0; 00104 l = strtoul(e, &p, 10); 00105 00106 if (errno != 0) { 00107 r = -errno; 00108 goto finish; 00109 } 00110 00111 if (!p || *p) { 00112 r = -EINVAL; 00113 goto finish; 00114 } 00115 00116 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) { 00117 int flags; 00118 00119 if ((flags = fcntl(fd, F_GETFD)) < 0) { 00120 r = -errno; 00121 goto finish; 00122 } 00123 00124 if (flags & FD_CLOEXEC) 00125 continue; 00126 00127 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) { 00128 r = -errno; 00129 goto finish; 00130 } 00131 } 00132 00133 r = (int) l; 00134 00135 finish: 00136 if (unset_environment) { 00137 unsetenv("LISTEN_PID"); 00138 unsetenv("LISTEN_FDS"); 00139 } 00140 00141 return r; 00142 #endif 00143 } 00144 00145 _sd_export_ int sd_is_fifo(int fd, const char *path) { 00146 struct stat st_fd; 00147 00148 if (fd < 0) 00149 return -EINVAL; 00150 00151 memset(&st_fd, 0, sizeof(st_fd)); 00152 if (fstat(fd, &st_fd) < 0) 00153 return -errno; 00154 00155 if (!S_ISFIFO(st_fd.st_mode)) 00156 return 0; 00157 00158 if (path) { 00159 struct stat st_path; 00160 00161 memset(&st_path, 0, sizeof(st_path)); 00162 if (stat(path, &st_path) < 0) { 00163 00164 if (errno == ENOENT || errno == ENOTDIR) 00165 return 0; 00166 00167 return -errno; 00168 } 00169 00170 return 00171 st_path.st_dev == st_fd.st_dev && 00172 st_path.st_ino == st_fd.st_ino; 00173 } 00174 00175 return 1; 00176 } 00177 00178 _sd_export_ int sd_is_special(int fd, const char *path) { 00179 struct stat st_fd; 00180 00181 if (fd < 0) 00182 return -EINVAL; 00183 00184 if (fstat(fd, &st_fd) < 0) 00185 return -errno; 00186 00187 if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode)) 00188 return 0; 00189 00190 if (path) { 00191 struct stat st_path; 00192 00193 if (stat(path, &st_path) < 0) { 00194 00195 if (errno == ENOENT || errno == ENOTDIR) 00196 return 0; 00197 00198 return -errno; 00199 } 00200 00201 if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode)) 00202 return 00203 st_path.st_dev == st_fd.st_dev && 00204 st_path.st_ino == st_fd.st_ino; 00205 else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode)) 00206 return st_path.st_rdev == st_fd.st_rdev; 00207 else 00208 return 0; 00209 } 00210 00211 return 1; 00212 } 00213 00214 static int sd_is_socket_internal(int fd, int type, int listening) { 00215 struct stat st_fd; 00216 00217 if (fd < 0 || type < 0) 00218 return -EINVAL; 00219 00220 if (fstat(fd, &st_fd) < 0) 00221 return -errno; 00222 00223 if (!S_ISSOCK(st_fd.st_mode)) 00224 return 0; 00225 00226 if (type != 0) { 00227 int other_type = 0; 00228 socklen_t l = sizeof(other_type); 00229 00230 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0) 00231 return -errno; 00232 00233 if (l != sizeof(other_type)) 00234 return -EINVAL; 00235 00236 if (other_type != type) 00237 return 0; 00238 } 00239 00240 if (listening >= 0) { 00241 int accepting = 0; 00242 socklen_t l = sizeof(accepting); 00243 00244 if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0) 00245 return -errno; 00246 00247 if (l != sizeof(accepting)) 00248 return -EINVAL; 00249 00250 if (!accepting != !listening) 00251 return 0; 00252 } 00253 00254 return 1; 00255 } 00256 00257 union sockaddr_union { 00258 struct sockaddr sa; 00259 struct sockaddr_in in4; 00260 struct sockaddr_in6 in6; 00261 struct sockaddr_un un; 00262 struct sockaddr_storage storage; 00263 }; 00264 00265 _sd_export_ int sd_is_socket(int fd, int family, int type, int listening) { 00266 int r; 00267 00268 if (family < 0) 00269 return -EINVAL; 00270 00271 if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) 00272 return r; 00273 00274 if (family > 0) { 00275 union sockaddr_union sockaddr; 00276 socklen_t l; 00277 00278 memset(&sockaddr, 0, sizeof(sockaddr)); 00279 l = sizeof(sockaddr); 00280 00281 if (getsockname(fd, &sockaddr.sa, &l) < 0) 00282 return -errno; 00283 00284 if (l < sizeof(sa_family_t)) 00285 return -EINVAL; 00286 00287 return sockaddr.sa.sa_family == family; 00288 } 00289 00290 return 1; 00291 } 00292 00293 _sd_export_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) { 00294 union sockaddr_union sockaddr; 00295 socklen_t l; 00296 int r; 00297 00298 if (family != 0 && family != AF_INET && family != AF_INET6) 00299 return -EINVAL; 00300 00301 if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) 00302 return r; 00303 00304 memset(&sockaddr, 0, sizeof(sockaddr)); 00305 l = sizeof(sockaddr); 00306 00307 if (getsockname(fd, &sockaddr.sa, &l) < 0) 00308 return -errno; 00309 00310 if (l < sizeof(sa_family_t)) 00311 return -EINVAL; 00312 00313 if (sockaddr.sa.sa_family != AF_INET && 00314 sockaddr.sa.sa_family != AF_INET6) 00315 return 0; 00316 00317 if (family > 0) 00318 if (sockaddr.sa.sa_family != family) 00319 return 0; 00320 00321 if (port > 0) { 00322 if (sockaddr.sa.sa_family == AF_INET) { 00323 if (l < sizeof(struct sockaddr_in)) 00324 return -EINVAL; 00325 00326 return htons(port) == sockaddr.in4.sin_port; 00327 } else { 00328 if (l < sizeof(struct sockaddr_in6)) 00329 return -EINVAL; 00330 00331 return htons(port) == sockaddr.in6.sin6_port; 00332 } 00333 } 00334 00335 return 1; 00336 } 00337 00338 _sd_export_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) { 00339 union sockaddr_union sockaddr; 00340 socklen_t l; 00341 int r; 00342 00343 if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) 00344 return r; 00345 00346 memset(&sockaddr, 0, sizeof(sockaddr)); 00347 l = sizeof(sockaddr); 00348 00349 if (getsockname(fd, &sockaddr.sa, &l) < 0) 00350 return -errno; 00351 00352 if (l < sizeof(sa_family_t)) 00353 return -EINVAL; 00354 00355 if (sockaddr.sa.sa_family != AF_UNIX) 00356 return 0; 00357 00358 if (path) { 00359 if (length <= 0) 00360 length = strlen(path); 00361 00362 if (length <= 0) 00363 /* Unnamed socket */ 00364 return l == offsetof(struct sockaddr_un, sun_path); 00365 00366 if (path[0]) 00367 /* Normal path socket */ 00368 return 00369 (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) && 00370 memcmp(path, sockaddr.un.sun_path, length+1) == 0; 00371 else 00372 /* Abstract namespace socket */ 00373 return 00374 (l == offsetof(struct sockaddr_un, sun_path) + length) && 00375 memcmp(path, sockaddr.un.sun_path, length) == 0; 00376 } 00377 00378 return 1; 00379 } 00380 00381 _sd_export_ int sd_is_mq(int fd, const char *path) { 00382 #if !defined(__linux__) 00383 return 0; 00384 #else 00385 struct mq_attr attr; 00386 00387 if (fd < 0) 00388 return -EINVAL; 00389 00390 if (mq_getattr(fd, &attr) < 0) 00391 return -errno; 00392 00393 if (path) { 00394 char fpath[PATH_MAX]; 00395 struct stat a, b; 00396 00397 if (path[0] != '/') 00398 return -EINVAL; 00399 00400 if (fstat(fd, &a) < 0) 00401 return -errno; 00402 00403 strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12); 00404 fpath[sizeof(fpath)-1] = 0; 00405 00406 if (stat(fpath, &b) < 0) 00407 return -errno; 00408 00409 if (a.st_dev != b.st_dev || 00410 a.st_ino != b.st_ino) 00411 return 0; 00412 } 00413 00414 return 1; 00415 #endif 00416 } 00417 00418 _sd_export_ int sd_notify(int unset_environment, const char *state) { 00419 #if defined(DISABLE_SYSTEMD) || !defined(__linux__) || !defined(SOCK_CLOEXEC) 00420 return 0; 00421 #else 00422 int fd = -1, r; 00423 struct msghdr msghdr; 00424 struct iovec iovec; 00425 union sockaddr_union sockaddr; 00426 const char *e; 00427 00428 if (!state) { 00429 r = -EINVAL; 00430 goto finish; 00431 } 00432 00433 if (!(e = getenv("NOTIFY_SOCKET"))) 00434 return 0; 00435 00436 /* Must be an abstract socket, or an absolute path */ 00437 if ((e[0] != '@' && e[0] != '/') || e[1] == 0) { 00438 r = -EINVAL; 00439 goto finish; 00440 } 00441 00442 if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) { 00443 r = -errno; 00444 goto finish; 00445 } 00446 00447 memset(&sockaddr, 0, sizeof(sockaddr)); 00448 sockaddr.sa.sa_family = AF_UNIX; 00449 strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path)); 00450 00451 if (sockaddr.un.sun_path[0] == '@') 00452 sockaddr.un.sun_path[0] = 0; 00453 00454 memset(&iovec, 0, sizeof(iovec)); 00455 iovec.iov_base = (char*) state; 00456 iovec.iov_len = strlen(state); 00457 00458 memset(&msghdr, 0, sizeof(msghdr)); 00459 msghdr.msg_name = &sockaddr; 00460 msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e); 00461 00462 if (msghdr.msg_namelen > sizeof(struct sockaddr_un)) 00463 msghdr.msg_namelen = sizeof(struct sockaddr_un); 00464 00465 msghdr.msg_iov = &iovec; 00466 msghdr.msg_iovlen = 1; 00467 00468 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) { 00469 r = -errno; 00470 goto finish; 00471 } 00472 00473 r = 1; 00474 00475 finish: 00476 if (unset_environment) 00477 unsetenv("NOTIFY_SOCKET"); 00478 00479 if (fd >= 0) 00480 close(fd); 00481 00482 return r; 00483 #endif 00484 } 00485 00486 _sd_export_ int sd_notifyf(int unset_environment, const char *format, ...) { 00487 #if defined(DISABLE_SYSTEMD) || !defined(__linux__) 00488 return 0; 00489 #else 00490 va_list ap; 00491 char *p = NULL; 00492 int r; 00493 00494 va_start(ap, format); 00495 r = vasprintf(&p, format, ap); 00496 va_end(ap); 00497 00498 if (r < 0 || !p) 00499 return -ENOMEM; 00500 00501 r = sd_notify(unset_environment, p); 00502 free(p); 00503 00504 return r; 00505 #endif 00506 } 00507 00508 _sd_export_ int sd_booted(void) { 00509 #if defined(DISABLE_SYSTEMD) || !defined(__linux__) 00510 return 0; 00511 #else 00512 00513 struct stat a, b; 00514 00515 /* We simply test whether the systemd cgroup hierarchy is 00516 * mounted */ 00517 00518 if (lstat("/sys/fs/cgroup", &a) < 0) 00519 return 0; 00520 00521 if (lstat("/sys/fs/cgroup/systemd", &b) < 0) 00522 return 0; 00523 00524 return a.st_dev != b.st_dev; 00525 #endif 00526 }