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 37 char *__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 */ 44 char *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 68 int setlogin(const char *name) 69 { 70 return (0); 71 } 72 #endif /* !HAVE_SETLOGIN */ 73 74 #ifndef HAVE_INNETGR 75 int 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) 83 int 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) 90 int 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) 97 const 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 110 int 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 */ 127 int 128 utimensat(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 */ 167 int 168 fchownat(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 */ 198 int 199 fchmodat(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 224 int 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) 243 int 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) 274 int 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 285 pid_t 286 tcgetpgrp(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 298 int 299 tcsendbreak(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 319 char * 320 strdup(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 334 int 335 isblank(int c) 336 { 337 return (c == ' ' || c == '\t'); 338 } 339 #endif 340 341 #ifndef HAVE_GETPGID 342 pid_t 343 getpgid(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 358 int 359 pledge(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 */ 367 int 368 mbtowc(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 383 long long 384 llabs(long long j) 385 { 386 return (j < 0 ? -j : j); 387 } 388 #endif 389 390 #ifndef HAVE_BZERO 391 void 392 bzero(void *b, size_t n) 393 { 394 (void)memset(b, 0, n); 395 } 396 #endif 397 398 #ifndef HAVE_RAISE 399 int 400 raise(int sig) 401 { 402 kill(getpid(), sig); 403 } 404 #endif 405 406 #ifndef HAVE_GETSID 407 pid_t 408 getsid(pid_t pid) 409 { 410 errno = ENOSYS; 411 return -1; 412 } 413 #endif 414 415 #ifndef HAVE_KILLPG 416 int 417 killpg(pid_t pgrp, int sig) 418 { 419 return kill(pgrp, sig); 420 } 421 #endif 422 423 #ifdef FFLUSH_NULL_BUG 424 #undef fflush 425 int _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 441 struct tm * 442 localtime_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 451 const char *__asan_default_options(void) { 452 return ASAN_OPTIONS; 453 } 454 #endif 455 456 #ifdef MSAN_OPTIONS 457 const char *__msan_default_options(void) { 458 return MSAN_OPTIONS; 459 } 460 #endif 461