-static int open_file_and_lock(const char *fn) {
- int fd;
-
- assert(fn);
-
- if ((fd = open(fn, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW|O_CREAT, 0600)) < 0)
- return -errno;
-
- /* The BSD socket semantics are a lot nicer than those of
- * POSIX locks. Which is why we use flock() here. BSD locking
- * does not work across NFS which however is not needed here
- * as the filesystems in question should be local, and only
- * locally accessible, and most likely even tmpfs. */
-
- if (flock(fd, LOCK_EX) < 0) {
- close_nointr_nofail(fd);
- return -errno;
- }
-
- return fd;
-}
-
-enum {
- SESSION_ID_AUDIT = 'a',
- SESSION_ID_COUNTER = 'c',
- SESSION_ID_RANDOM = 'r'
-};
-
-static uint64_t get_session_id(int *mode) {
- char *s;
- int fd;
-
- assert(mode);
-
- /* First attempt: let's use the session ID of the audit
- * system, if it is available. */
- if (have_effective_cap(CAP_AUDIT_CONTROL) > 0)
- if (read_one_line_file("/proc/self/sessionid", &s) >= 0) {
- uint32_t u;
- int r;
-
- r = safe_atou32(s, &u);
- free(s);
-
- if (r >= 0 && u != (uint32_t) -1 && u > 0) {
- *mode = SESSION_ID_AUDIT;
- return (uint64_t) u;
- }
- }
-
- /* Second attempt, use our own counter. */
- if ((fd = open_file_and_lock(RUNTIME_DIR "/user/.pam-systemd-session")) >= 0) {
- uint64_t counter;
- ssize_t r;
-
- /* We do a bit of endianess swapping here, just to be
- * sure. /run should be machine specific anyway, and
- * even mounted from tmpfs, so this byteswapping
- * should really not be necessary. But then again, you
- * never know, so let's avoid any risk. */
-
- if (loop_read(fd, &counter, sizeof(counter), false) != sizeof(counter))
- counter = 1;
- else
- counter = le64toh(counter) + 1;
-
- if (lseek(fd, 0, SEEK_SET) == 0) {
- uint64_t swapped = htole64(counter);
-
- r = loop_write(fd, &swapped, sizeof(swapped), false);
-
- if (r != sizeof(swapped))
- r = -EIO;
- } else
- r = -errno;
-
- close_nointr_nofail(fd);
-
- if (r >= 0) {
- *mode = SESSION_ID_COUNTER;
- return counter;
- }
- }
-
- *mode = SESSION_ID_RANDOM;
-
- /* Last attempt, pick a random value */
- return (uint64_t) random_ull();
-}
-