/* * Copyright (c) 1999-2004 Damien Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "includes.h" #include #ifdef HAVE_SYS_SELECT_H # include #endif #ifdef HAVE_SYS_TIME_H # include #endif #include #include #include #include #include #include #include #ifndef HAVE___PROGNAME char *__progname; #endif /* * NB. duplicate __progname in case it is an alias for argv[0] * Otherwise it may get clobbered by setproctitle() */ char *ssh_get_progname(char *argv0) { char *p, *q; #ifdef HAVE___PROGNAME extern char *__progname; p = __progname; #else if (argv0 == NULL) return ("unknown"); /* XXX */ p = strrchr(argv0, '/'); if (p == NULL) p = argv0; else p++; #endif if ((q = strdup(p)) == NULL) { perror("strdup"); exit(1); } return q; } #ifndef HAVE_SETLOGIN int setlogin(const char *name) { return (0); } #endif /* !HAVE_SETLOGIN */ #ifndef HAVE_INNETGR int innetgr(const char *netgroup, const char *host, const char *user, const char *domain) { return (0); } #endif /* HAVE_INNETGR */ #if !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) int seteuid(uid_t euid) { return (setreuid(-1, euid)); } #endif /* !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) */ #if !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) int setegid(uid_t egid) { return(setresgid(-1, egid, -1)); } #endif /* !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) */ #if !defined(HAVE_STRERROR) && defined(HAVE_SYS_ERRLIST) && defined(HAVE_SYS_NERR) const char *strerror(int e) { extern int sys_nerr; extern char *sys_errlist[]; if ((e >= 0) && (e < sys_nerr)) return (sys_errlist[e]); return ("unlisted error"); } #endif #ifndef HAVE_UTIMES int utimes(const char *filename, struct timeval *tvp) { struct utimbuf ub; ub.actime = tvp[0].tv_sec; ub.modtime = tvp[1].tv_sec; return (utime(filename, &ub)); } #endif #ifndef HAVE_UTIMENSAT /* * A limited implementation of utimensat() that only implements the * functionality used by OpenSSH, currently only AT_FDCWD and * AT_SYMLINK_NOFOLLOW. */ int utimensat(int fd, const char *path, const struct timespec times[2], int flag) { struct timeval tv[2]; # ifdef HAVE_FUTIMES int ret, oflags = O_WRONLY; # endif tv[0].tv_sec = times[0].tv_sec; tv[0].tv_usec = times[0].tv_nsec / 1000; tv[1].tv_sec = times[1].tv_sec; tv[1].tv_usec = times[1].tv_nsec / 1000; if (fd != AT_FDCWD) { errno = ENOSYS; return -1; } # ifndef HAVE_FUTIMES return utimes(path, tv); # else # ifdef O_NOFOLLOW if (flag & AT_SYMLINK_NOFOLLOW) oflags |= O_NOFOLLOW; # endif /* O_NOFOLLOW */ if ((fd = open(path, oflags)) == -1) return -1; ret = futimes(fd, tv); close(fd); return ret; # endif } #endif #ifndef HAVE_FCHOWNAT /* * A limited implementation of fchownat() that only implements the * functionality used by OpenSSH, currently only AT_FDCWD and * AT_SYMLINK_NOFOLLOW. */ int fchownat(int fd, const char *path, uid_t owner, gid_t group, int flag) { int ret, oflags = O_WRONLY; if (fd != AT_FDCWD) { errno = ENOSYS; return -1; } # ifndef HAVE_FCHOWN return chown(path, owner, group); # else # ifdef O_NOFOLLOW if (flag & AT_SYMLINK_NOFOLLOW) oflags |= O_NOFOLLOW; # endif /* O_NOFOLLOW */ if ((fd = open(path, oflags)) == -1) return -1; ret = fchown(fd, owner, group); close(fd); return ret; # endif } #endif #ifndef HAVE_FCHMODAT /* * A limited implementation of fchmodat() that only implements the * functionality used by OpenSSH, currently only AT_FDCWD and * AT_SYMLINK_NOFOLLOW. */ int fchmodat(int fd, const char *path, mode_t mode, int flag) { int ret, oflags = O_WRONLY; if (fd != AT_FDCWD) { errno = ENOSYS; return -1; } # ifndef HAVE_FCHMOD return chmod(path, mode); # else # ifdef O_NOFOLLOW if (flag & AT_SYMLINK_NOFOLLOW) oflags |= O_NOFOLLOW; # endif /* O_NOFOLLOW */ if ((fd = open(path, oflags)) == -1) return -1; ret = fchmod(fd, mode); close(fd); return ret; # endif } #endif #ifndef HAVE_TRUNCATE int truncate(const char *path, off_t length) { int fd, ret, saverrno; fd = open(path, O_WRONLY); if (fd < 0) return (-1); ret = ftruncate(fd, length); saverrno = errno; close(fd); if (ret == -1) errno = saverrno; return(ret); } #endif /* HAVE_TRUNCATE */ #if !defined(HAVE_NANOSLEEP) && !defined(HAVE_NSLEEP) int nanosleep(const struct timespec *req, struct timespec *rem) { int rc, saverrno; extern int errno; struct timeval tstart, tstop, tremain, time2wait; TIMESPEC_TO_TIMEVAL(&time2wait, req) (void) gettimeofday(&tstart, NULL); rc = select(0, NULL, NULL, NULL, &time2wait); if (rc == -1) { saverrno = errno; (void) gettimeofday (&tstop, NULL); errno = saverrno; tremain.tv_sec = time2wait.tv_sec - (tstop.tv_sec - tstart.tv_sec); tremain.tv_usec = time2wait.tv_usec - (tstop.tv_usec - tstart.tv_usec); tremain.tv_sec += tremain.tv_usec / 1000000L; tremain.tv_usec %= 1000000L; } else { tremain.tv_sec = 0; tremain.tv_usec = 0; } if (rem != NULL) TIMEVAL_TO_TIMESPEC(&tremain, rem) return(rc); } #endif #if !defined(HAVE_USLEEP) int usleep(unsigned int useconds) { struct timespec ts; ts.tv_sec = useconds / 1000000; ts.tv_nsec = (useconds % 1000000) * 1000; return nanosleep(&ts, NULL); } #endif #ifndef HAVE_TCGETPGRP pid_t tcgetpgrp(int fd) { int ctty_pgrp; if (ioctl(fd, TIOCGPGRP, &ctty_pgrp) == -1) return(-1); else return(ctty_pgrp); } #endif /* HAVE_TCGETPGRP */ #ifndef HAVE_TCSENDBREAK int tcsendbreak(int fd, int duration) { # if defined(TIOCSBRK) && defined(TIOCCBRK) struct timeval sleepytime; sleepytime.tv_sec = 0; sleepytime.tv_usec = 400000; if (ioctl(fd, TIOCSBRK, 0) == -1) return (-1); (void)select(0, 0, 0, 0, &sleepytime); if (ioctl(fd, TIOCCBRK, 0) == -1) return (-1); return (0); # else return -1; # endif } #endif /* HAVE_TCSENDBREAK */ #ifndef HAVE_STRDUP char * strdup(const char *str) { size_t len; char *cp; len = strlen(str) + 1; cp = malloc(len); if (cp != NULL) return(memcpy(cp, str, len)); return NULL; } #endif #ifndef HAVE_ISBLANK int isblank(int c) { return (c == ' ' || c == '\t'); } #endif #ifndef HAVE_GETPGID pid_t getpgid(pid_t pid) { #if defined(HAVE_GETPGRP) && !defined(GETPGRP_VOID) && GETPGRP_VOID == 0 return getpgrp(pid); #elif defined(HAVE_GETPGRP) if (pid == 0) return getpgrp(); #endif errno = ESRCH; return -1; } #endif #ifndef HAVE_PLEDGE int pledge(const char *promises, const char *paths[]) { return 0; } #endif #ifndef HAVE_MBTOWC /* a mbtowc that only supports ASCII */ int mbtowc(wchar_t *pwc, const char *s, size_t n) { if (s == NULL || *s == '\0') return 0; /* ASCII is not state-dependent */ if (*s < 0 || *s > 0x7f || n < 1) { errno = EOPNOTSUPP; return -1; } if (pwc != NULL) *pwc = *s; return 1; } #endif #ifndef HAVE_LLABS long long llabs(long long j) { return (j < 0 ? -j : j); } #endif #ifndef HAVE_BZERO void bzero(void *b, size_t n) { (void)memset(b, 0, n); } #endif #ifndef HAVE_RAISE int raise(int sig) { kill(getpid(), sig); } #endif #ifndef HAVE_GETSID pid_t getsid(pid_t pid) { errno = ENOSYS; return -1; } #endif #ifndef HAVE_KILLPG int killpg(pid_t pgrp, int sig) { return kill(pgrp, sig); } #endif #ifdef FFLUSH_NULL_BUG #undef fflush int _ssh_compat_fflush(FILE *f) { int r1, r2; if (f == NULL) { r1 = fflush(stdout); r2 = fflush(stderr); if (r1 == -1 || r2 == -1) return -1; return 0; } return fflush(f); } #endif #ifndef HAVE_LOCALTIME_R struct tm * localtime_r(const time_t *timep, struct tm *result) { struct tm *tm = localtime(timep); *result = *tm; return result; } #endif #ifdef ASAN_OPTIONS const char *__asan_default_options(void) { return ASAN_OPTIONS; } #endif #ifdef MSAN_OPTIONS const char *__msan_default_options(void) { return MSAN_OPTIONS; } #endif