static void openlog_intern(int option, int facility) { LogStat = option; if (facility && ((facility & ~LOG_FACMASK) == 0)) LogFacility = facility; /* yep, there is a continue inside ;) */ while(1) { if (LogFile == -1) { SyslogAddr.sa_family = AF_UNIX; strncpy(SyslogAddr.sa_data, _PATH_LOG, sizeof(SyslogAddr.sa_data)); if (LogStat & LOG_NDELAY) { if ((LogFile = socket(AF_UNIX, LogType, 0)) == -1) return; __libc_fcntl(LogFile, F_SETFD, 1); } } if ((LogFile != -1) && !connected) { int old_errno=errno; if(connect(LogFile, &SyslogAddr, sizeof(SyslogAddr)) == -1) { int saved_errno=errno; __libc_close(LogFile); LogFile = -1; if((LogType == SOCK_DGRAM) && (saved_errno == EPROTOTYPE)) { /* retry with SOCK_STREAM instead of SOCK_DGRAM */ LogType = SOCK_STREAM; errno=old_errno; continue; } } else connected = 1; } break; } }
/* Duplicate FD to FD2, closing the old FD2 and making FD2 be open the same file as FD is. Return FD2 or -1. */ int __dup2 (int fd, int fd2) { /* For the degenerate case, check if the fd is valid (by trying to get the file status flags) and return it, or else return EBADF. */ if (fd == fd2) return __libc_fcntl (fd, F_GETFL, 0) < 0 ? -1 : fd; return INLINE_SYSCALL (dup3, 3, fd, fd2, 0); }
/* Should other OSes (e.g., Hurd) have different versions which can be written in a better way? */ static void check_one_fd (int fd, int mode) { /* Note that fcntl() with this parameter is not a cancellation point. */ if (__builtin_expect (__libc_fcntl (fd, F_GETFD), 0) == -1 && errno == EBADF) { const char *name; dev_t dev; /* For writable descriptors we use /dev/full. */ if ((mode & O_ACCMODE) == O_WRONLY) { name = _PATH_DEV "full"; dev = makedev (DEV_FULL_MAJOR, DEV_FULL_MINOR); } else { name = _PATH_DEVNULL; dev = makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR); } /* Something is wrong with this descriptor, it's probably not opened. Open /dev/null so that the SUID program we are about to start does not accidently use this descriptor. */ int nullfd = open_not_cancel (name, mode, 0); /* We are very paranoid here. With all means we try to ensure that we are actually opening the /dev/null device and nothing else. Note that the following code assumes that STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO are the three lowest file decsriptor numbers, in this order. */ struct stat64 st; if (__builtin_expect (nullfd != fd, 0) || __builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0) != 0 || __builtin_expect (S_ISCHR (st.st_mode), 1) == 0 || st.st_rdev != dev) /* We cannot even give an error message here since it would run into the same problems. */ while (1) /* Try for ever and ever. */ ABORT_INSTRUCTION; } }
/* Change the ownership and access permission of the slave pseudo terminal associated with the master pseudo terminal specified by FD. */ int grantpt (int fd) { struct statfs fsbuf; #ifdef PATH_MAX char _buf[PATH_MAX]; #else char _buf[512]; #endif char *buf = _buf; if (__builtin_expect (pts_name (fd, &buf, sizeof (_buf)), 0)) { int save_errno = errno; /* Check, if the file descriptor is valid. pts_name returns the wrong errno number, so we cannot use that. */ if (__libc_fcntl (fd, F_GETFD) == -1 && errno == EBADF) return -1; /* If the filedescriptor is no TTY, grantpt has to set errno to EINVAL. */ if (save_errno == ENOTTY) __set_errno (EINVAL); else __set_errno (save_errno); return -1; } if (__statfs (buf, &fsbuf) < 0) return -1; /* If the slave pseudo terminal lives on a `devpts' filesystem, the ownership and access permission are already set. */ if (fsbuf.f_type == DEVPTS_SUPER_MAGIC || fsbuf.f_type == DEVFS_SUPER_MAGIC) return 0; return __unix_grantpt (fd); }
/* Change the ownership and access permission of the slave pseudo terminal associated with the master pseudo terminal specified by FD. */ int grantpt (int fd) { int retval = -1; #ifdef PATH_MAX char _buf[PATH_MAX]; #else char _buf[512]; #endif char *buf = _buf; struct stat64 st; if (__glibc_unlikely (pts_name (fd, &buf, sizeof (_buf), &st))) { int save_errno = errno; /* Check, if the file descriptor is valid. pts_name returns the wrong errno number, so we cannot use that. */ if (__libc_fcntl (fd, F_GETFD) == -1 && errno == EBADF) return -1; /* If the filedescriptor is no TTY, grantpt has to set errno to EINVAL. */ if (save_errno == ENOTTY) __set_errno (EINVAL); else __set_errno (save_errno); return -1; } /* Make sure that we own the device. */ uid_t uid = __getuid (); if (st.st_uid != uid) { if (__chown (buf, uid, st.st_gid) < 0) goto helper; } static int tty_gid = -1; if (__glibc_unlikely (tty_gid == -1)) { char *grtmpbuf; struct group grbuf; size_t grbuflen = __sysconf (_SC_GETGR_R_SIZE_MAX); struct group *p; /* Get the group ID of the special `tty' group. */ if (grbuflen == (size_t) -1L) /* `sysconf' does not support _SC_GETGR_R_SIZE_MAX. Try a moderate value. */ grbuflen = 1024; grtmpbuf = (char *) __alloca (grbuflen); __getgrnam_r (TTY_GROUP, &grbuf, grtmpbuf, grbuflen, &p); if (p != NULL) tty_gid = p->gr_gid; } gid_t gid = tty_gid == -1 ? __getgid () : tty_gid; /* Make sure the group of the device is that special group. */ if (st.st_gid != gid) { if (__chown (buf, uid, gid) < 0) goto helper; } /* Make sure the permission mode is set to readable and writable by the owner, and writable by the group. */ if ((st.st_mode & ACCESSPERMS) != (S_IRUSR|S_IWUSR|S_IWGRP)) { if (__chmod (buf, S_IRUSR|S_IWUSR|S_IWGRP) < 0) goto helper; } retval = 0; goto cleanup; /* We have to use the helper program if it is available. */ helper:; #ifdef HAVE_PT_CHOWN pid_t pid = __fork (); if (pid == -1) goto cleanup; else if (pid == 0) { /* Disable core dumps. */ struct rlimit rl = { 0, 0 }; __setrlimit (RLIMIT_CORE, &rl); /* We pass the master pseudo terminal as file descriptor PTY_FILENO. */ if (fd != PTY_FILENO) if (__dup2 (fd, PTY_FILENO) < 0) _exit (FAIL_EBADF); # ifdef CLOSE_ALL_FDS CLOSE_ALL_FDS (); # endif execle (_PATH_PT_CHOWN, basename (_PATH_PT_CHOWN), NULL, NULL); _exit (FAIL_EXEC); } else { int w; if (__waitpid (pid, &w, 0) == -1) goto cleanup; if (!WIFEXITED (w)) __set_errno (ENOEXEC); else switch (WEXITSTATUS (w)) { case 0: retval = 0; break; case FAIL_EBADF: __set_errno (EBADF); break; case FAIL_EINVAL: __set_errno (EINVAL); break; case FAIL_EACCES: __set_errno (EACCES); break; case FAIL_EXEC: __set_errno (ENOEXEC); break; case FAIL_ENOMEM: __set_errno (ENOMEM); break; default: assert(! "getpt: internal error: invalid exit code from pt_chown"); } } #endif cleanup: if (buf != _buf) free (buf); return retval; }