1 2/* 3 * Copyright (c) 1999-2004 Damien Miller <djm@mindrot.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18#include "includes.h" 19 20#include <sys/types.h> 21#ifdef HAVE_SYS_SELECT_H 22# include <sys/select.h> 23#endif 24#ifdef HAVE_SYS_TIME_H 25# include <sys/time.h> 26#endif 27 28#include <fcntl.h> 29#include <string.h> 30#include <signal.h> 31#include <stdlib.h> 32#include <stdio.h> 33#include <time.h> 34#include <unistd.h> 35 36#ifndef HAVE___PROGNAME 37char *__progname; 38#endif 39 40/* 41 * NB. duplicate __progname in case it is an alias for argv[0] 42 * Otherwise it may get clobbered by setproctitle() 43 */ 44char *ssh_get_progname(char *argv0) 45{ 46 char *p, *q; 47#ifdef HAVE___PROGNAME 48 extern char *__progname; 49 50 p = __progname; 51#else 52 if (argv0 == NULL) 53 return ("unknown"); /* XXX */ 54 p = strrchr(argv0, '/'); 55 if (p == NULL) 56 p = argv0; 57 else 58 p++; 59#endif 60 if ((q = strdup(p)) == NULL) { 61 perror("strdup"); 62 exit(1); 63 } 64 return q; 65} 66 67#ifndef HAVE_SETLOGIN 68int setlogin(const char *name) 69{ 70 return (0); 71} 72#endif /* !HAVE_SETLOGIN */ 73 74#ifndef HAVE_INNETGR 75int innetgr(const char *netgroup, const char *host, 76 const char *user, const char *domain) 77{ 78 return (0); 79} 80#endif /* HAVE_INNETGR */ 81 82#if !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) 83int seteuid(uid_t euid) 84{ 85 return (setreuid(-1, euid)); 86} 87#endif /* !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) */ 88 89#if !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) 90int setegid(uid_t egid) 91{ 92 return(setresgid(-1, egid, -1)); 93} 94#endif /* !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) */ 95 96#if !defined(HAVE_STRERROR) && defined(HAVE_SYS_ERRLIST) && defined(HAVE_SYS_NERR) 97const char *strerror(int e) 98{ 99 extern int sys_nerr; 100 extern char *sys_errlist[]; 101 102 if ((e >= 0) && (e < sys_nerr)) 103 return (sys_errlist[e]); 104 105 return ("unlisted error"); 106} 107#endif 108 109#ifndef HAVE_UTIMES 110int utimes(const char *filename, struct timeval *tvp) 111{ 112 struct utimbuf ub; 113 114 ub.actime = tvp[0].tv_sec; 115 ub.modtime = tvp[1].tv_sec; 116 117 return (utime(filename, &ub)); 118} 119#endif 120 121#ifndef HAVE_UTIMENSAT 122/* 123 * A limited implementation of utimensat() that only implements the 124 * functionality used by OpenSSH, currently only AT_FDCWD and 125 * AT_SYMLINK_NOFOLLOW. 126 */ 127int 128utimensat(int fd, const char *path, const struct timespec times[2], 129 int flag) 130{ 131 struct timeval tv[2]; 132# ifdef HAVE_FUTIMES 133 int ret, oflags = O_WRONLY; 134# endif 135 136 tv[0].tv_sec = times[0].tv_sec; 137 tv[0].tv_usec = times[0].tv_nsec / 1000; 138 tv[1].tv_sec = times[1].tv_sec; 139 tv[1].tv_usec = times[1].tv_nsec / 1000; 140 141 if (fd != AT_FDCWD) { 142 errno = ENOSYS; 143 return -1; 144 } 145# ifndef HAVE_FUTIMES 146 return utimes(path, tv); 147# else 148# ifdef O_NOFOLLOW 149 if (flag & AT_SYMLINK_NOFOLLOW) 150 oflags |= O_NOFOLLOW; 151# endif /* O_NOFOLLOW */ 152 if ((fd = open(path, oflags)) == -1) 153 return -1; 154 ret = futimes(fd, tv); 155 close(fd); 156 return ret; 157# endif 158} 159#endif 160 161#ifndef HAVE_FCHOWNAT 162/* 163 * A limited implementation of fchownat() that only implements the 164 * functionality used by OpenSSH, currently only AT_FDCWD and 165 * AT_SYMLINK_NOFOLLOW. 166 */ 167int 168fchownat(int fd, const char *path, uid_t owner, gid_t group, int flag) 169{ 170 int ret, oflags = O_WRONLY; 171 172 if (fd != AT_FDCWD) { 173 errno = ENOSYS; 174 return -1; 175 } 176# ifndef HAVE_FCHOWN 177 return chown(path, owner, group); 178# else 179# ifdef O_NOFOLLOW 180 if (flag & AT_SYMLINK_NOFOLLOW) 181 oflags |= O_NOFOLLOW; 182# endif /* O_NOFOLLOW */ 183 if ((fd = open(path, oflags)) == -1) 184 return -1; 185 ret = fchown(fd, owner, group); 186 close(fd); 187 return ret; 188# endif 189} 190#endif 191 192#ifndef HAVE_FCHMODAT 193/* 194 * A limited implementation of fchmodat() that only implements the 195 * functionality used by OpenSSH, currently only AT_FDCWD and 196 * AT_SYMLINK_NOFOLLOW. 197 */ 198int 199fchmodat(int fd, const char *path, mode_t mode, int flag) 200{ 201 int ret, oflags = O_WRONLY; 202 203 if (fd != AT_FDCWD) { 204 errno = ENOSYS; 205 return -1; 206 } 207# ifndef HAVE_FCHMOD 208 return chmod(path, mode); 209# else 210# ifdef O_NOFOLLOW 211 if (flag & AT_SYMLINK_NOFOLLOW) 212 oflags |= O_NOFOLLOW; 213# endif /* O_NOFOLLOW */ 214 if ((fd = open(path, oflags)) == -1) 215 return -1; 216 ret = fchmod(fd, mode); 217 close(fd); 218 return ret; 219# endif 220} 221#endif 222 223#ifndef HAVE_TRUNCATE 224int truncate(const char *path, off_t length) 225{ 226 int fd, ret, saverrno; 227 228 fd = open(path, O_WRONLY); 229 if (fd < 0) 230 return (-1); 231 232 ret = ftruncate(fd, length); 233 saverrno = errno; 234 close(fd); 235 if (ret == -1) 236 errno = saverrno; 237 238 return(ret); 239} 240#endif /* HAVE_TRUNCATE */ 241 242#if !defined(HAVE_NANOSLEEP) && !defined(HAVE_NSLEEP) 243int nanosleep(const struct timespec *req, struct timespec *rem) 244{ 245 int rc, saverrno; 246 extern int errno; 247 struct timeval tstart, tstop, tremain, time2wait; 248 249 TIMESPEC_TO_TIMEVAL(&time2wait, req) 250 (void) gettimeofday(&tstart, NULL); 251 rc = select(0, NULL, NULL, NULL, &time2wait); 252 if (rc == -1) { 253 saverrno = errno; 254 (void) gettimeofday (&tstop, NULL); 255 errno = saverrno; 256 tremain.tv_sec = time2wait.tv_sec - 257 (tstop.tv_sec - tstart.tv_sec); 258 tremain.tv_usec = time2wait.tv_usec - 259 (tstop.tv_usec - tstart.tv_usec); 260 tremain.tv_sec += tremain.tv_usec / 1000000L; 261 tremain.tv_usec %= 1000000L; 262 } else { 263 tremain.tv_sec = 0; 264 tremain.tv_usec = 0; 265 } 266 if (rem != NULL) 267 TIMEVAL_TO_TIMESPEC(&tremain, rem) 268 269 return(rc); 270} 271#endif 272 273#if !defined(HAVE_USLEEP) 274int usleep(unsigned int useconds) 275{ 276 struct timespec ts; 277 278 ts.tv_sec = useconds / 1000000; 279 ts.tv_nsec = (useconds % 1000000) * 1000; 280 return nanosleep(&ts, NULL); 281} 282#endif 283 284#ifndef HAVE_TCGETPGRP 285pid_t 286tcgetpgrp(int fd) 287{ 288 int ctty_pgrp; 289 290 if (ioctl(fd, TIOCGPGRP, &ctty_pgrp) == -1) 291 return(-1); 292 else 293 return(ctty_pgrp); 294} 295#endif /* HAVE_TCGETPGRP */ 296 297#ifndef HAVE_TCSENDBREAK 298int 299tcsendbreak(int fd, int duration) 300{ 301# if defined(TIOCSBRK) && defined(TIOCCBRK) 302 struct timeval sleepytime; 303 304 sleepytime.tv_sec = 0; 305 sleepytime.tv_usec = 400000; 306 if (ioctl(fd, TIOCSBRK, 0) == -1) 307 return (-1); 308 (void)select(0, 0, 0, 0, &sleepytime); 309 if (ioctl(fd, TIOCCBRK, 0) == -1) 310 return (-1); 311 return (0); 312# else 313 return -1; 314# endif 315} 316#endif /* HAVE_TCSENDBREAK */ 317 318#ifndef HAVE_STRDUP 319char * 320strdup(const char *str) 321{ 322 size_t len; 323 char *cp; 324 325 len = strlen(str) + 1; 326 cp = malloc(len); 327 if (cp != NULL) 328 return(memcpy(cp, str, len)); 329 return NULL; 330} 331#endif 332 333#ifndef HAVE_ISBLANK 334int 335isblank(int c) 336{ 337 return (c == ' ' || c == '\t'); 338} 339#endif 340 341#ifndef HAVE_GETPGID 342pid_t 343getpgid(pid_t pid) 344{ 345#if defined(HAVE_GETPGRP) && !defined(GETPGRP_VOID) && GETPGRP_VOID == 0 346 return getpgrp(pid); 347#elif defined(HAVE_GETPGRP) 348 if (pid == 0) 349 return getpgrp(); 350#endif 351 352 errno = ESRCH; 353 return -1; 354} 355#endif 356 357#ifndef HAVE_PLEDGE 358int 359pledge(const char *promises, const char *paths[]) 360{ 361 return 0; 362} 363#endif 364 365#ifndef HAVE_MBTOWC 366/* a mbtowc that only supports ASCII */ 367int 368mbtowc(wchar_t *pwc, const char *s, size_t n) 369{ 370 if (s == NULL || *s == '\0') 371 return 0; /* ASCII is not state-dependent */ 372 if (*s < 0 || *s > 0x7f || n < 1) { 373 errno = EOPNOTSUPP; 374 return -1; 375 } 376 if (pwc != NULL) 377 *pwc = *s; 378 return 1; 379} 380#endif 381 382#ifndef HAVE_LLABS 383long long 384llabs(long long j) 385{ 386 return (j < 0 ? -j : j); 387} 388#endif 389 390#ifndef HAVE_BZERO 391void 392bzero(void *b, size_t n) 393{ 394 (void)memset(b, 0, n); 395} 396#endif 397 398#ifndef HAVE_RAISE 399int 400raise(int sig) 401{ 402 kill(getpid(), sig); 403} 404#endif 405 406#ifndef HAVE_GETSID 407pid_t 408getsid(pid_t pid) 409{ 410 errno = ENOSYS; 411 return -1; 412} 413#endif 414 415#ifndef HAVE_KILLPG 416int 417killpg(pid_t pgrp, int sig) 418{ 419 return kill(pgrp, sig); 420} 421#endif 422 423#ifdef FFLUSH_NULL_BUG 424#undef fflush 425int _ssh_compat_fflush(FILE *f) 426{ 427 int r1, r2; 428 429 if (f == NULL) { 430 r1 = fflush(stdout); 431 r2 = fflush(stderr); 432 if (r1 == -1 || r2 == -1) 433 return -1; 434 return 0; 435 } 436 return fflush(f); 437} 438#endif 439 440#ifndef HAVE_LOCALTIME_R 441struct tm * 442localtime_r(const time_t *timep, struct tm *result) 443{ 444 struct tm *tm = localtime(timep); 445 *result = *tm; 446 return result; 447} 448#endif 449 450#ifdef ASAN_OPTIONS 451const char *__asan_default_options(void) { 452 return ASAN_OPTIONS; 453} 454#endif 455 456#ifdef MSAN_OPTIONS 457const char *__msan_default_options(void) { 458 return MSAN_OPTIONS; 459} 460#endif 461