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(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 int ret, oflags = O_WRONLY; 133 134 tv[0].tv_sec = times[0].tv_sec; 135 tv[0].tv_usec = times[0].tv_nsec / 1000; 136 tv[1].tv_sec = times[1].tv_sec; 137 tv[1].tv_usec = times[1].tv_nsec / 1000; 138 139 if (fd != AT_FDCWD) { 140 errno = ENOSYS; 141 return -1; 142 } 143 # ifndef HAVE_FUTIMES 144 return utimes(path, tv); 145 # else 146 # ifdef O_NOFOLLOW 147 if (flag & AT_SYMLINK_NOFOLLOW) 148 oflags |= O_NOFOLLOW; 149 # endif /* O_NOFOLLOW */ 150 if ((fd = open(path, oflags)) == -1) 151 return -1; 152 ret = futimes(fd, tv); 153 close(fd); 154 return ret; 155 # endif 156 } 157 #endif 158 159 #ifndef HAVE_FCHOWNAT 160 /* 161 * A limited implementation of fchownat() that only implements the 162 * functionality used by OpenSSH, currently only AT_FDCWD and 163 * AT_SYMLINK_NOFOLLOW. 164 */ 165 int 166 fchownat(int fd, const char *path, uid_t owner, gid_t group, int flag) 167 { 168 int ret, oflags = O_WRONLY; 169 170 if (fd != AT_FDCWD) { 171 errno = ENOSYS; 172 return -1; 173 } 174 # ifndef HAVE_FCHOWN 175 return chown(pathname, owner, group); 176 # else 177 # ifdef O_NOFOLLOW 178 if (flag & AT_SYMLINK_NOFOLLOW) 179 oflags |= O_NOFOLLOW; 180 # endif /* O_NOFOLLOW */ 181 if ((fd = open(path, oflags)) == -1) 182 return -1; 183 ret = fchown(fd, owner, group); 184 close(fd); 185 return ret; 186 # endif 187 } 188 #endif 189 190 #ifndef HAVE_FCHMODAT 191 /* 192 * A limited implementation of fchmodat() that only implements the 193 * functionality used by OpenSSH, currently only AT_FDCWD and 194 * AT_SYMLINK_NOFOLLOW. 195 */ 196 int 197 fchmodat(int fd, const char *path, mode_t mode, int flag) 198 { 199 int ret, oflags = O_WRONLY; 200 201 if (fd != AT_FDCWD) { 202 errno = ENOSYS; 203 return -1; 204 } 205 # ifndef HAVE_FCHMOD 206 return chown(pathname, owner, group); 207 # else 208 # ifdef O_NOFOLLOW 209 if (flag & AT_SYMLINK_NOFOLLOW) 210 oflags |= O_NOFOLLOW; 211 # endif /* O_NOFOLLOW */ 212 if ((fd = open(path, oflags)) == -1) 213 return -1; 214 ret = fchmod(fd, mode); 215 close(fd); 216 return ret; 217 # endif 218 } 219 #endif 220 221 #ifndef HAVE_TRUNCATE 222 int truncate(const char *path, off_t length) 223 { 224 int fd, ret, saverrno; 225 226 fd = open(path, O_WRONLY); 227 if (fd < 0) 228 return (-1); 229 230 ret = ftruncate(fd, length); 231 saverrno = errno; 232 close(fd); 233 if (ret == -1) 234 errno = saverrno; 235 236 return(ret); 237 } 238 #endif /* HAVE_TRUNCATE */ 239 240 #if !defined(HAVE_NANOSLEEP) && !defined(HAVE_NSLEEP) 241 int nanosleep(const struct timespec *req, struct timespec *rem) 242 { 243 int rc, saverrno; 244 extern int errno; 245 struct timeval tstart, tstop, tremain, time2wait; 246 247 TIMESPEC_TO_TIMEVAL(&time2wait, req) 248 (void) gettimeofday(&tstart, NULL); 249 rc = select(0, NULL, NULL, NULL, &time2wait); 250 if (rc == -1) { 251 saverrno = errno; 252 (void) gettimeofday (&tstop, NULL); 253 errno = saverrno; 254 tremain.tv_sec = time2wait.tv_sec - 255 (tstop.tv_sec - tstart.tv_sec); 256 tremain.tv_usec = time2wait.tv_usec - 257 (tstop.tv_usec - tstart.tv_usec); 258 tremain.tv_sec += tremain.tv_usec / 1000000L; 259 tremain.tv_usec %= 1000000L; 260 } else { 261 tremain.tv_sec = 0; 262 tremain.tv_usec = 0; 263 } 264 if (rem != NULL) 265 TIMEVAL_TO_TIMESPEC(&tremain, rem) 266 267 return(rc); 268 } 269 #endif 270 271 #if !defined(HAVE_USLEEP) 272 int usleep(unsigned int useconds) 273 { 274 struct timespec ts; 275 276 ts.tv_sec = useconds / 1000000; 277 ts.tv_nsec = (useconds % 1000000) * 1000; 278 return nanosleep(&ts, NULL); 279 } 280 #endif 281 282 #ifndef HAVE_TCGETPGRP 283 pid_t 284 tcgetpgrp(int fd) 285 { 286 int ctty_pgrp; 287 288 if (ioctl(fd, TIOCGPGRP, &ctty_pgrp) == -1) 289 return(-1); 290 else 291 return(ctty_pgrp); 292 } 293 #endif /* HAVE_TCGETPGRP */ 294 295 #ifndef HAVE_TCSENDBREAK 296 int 297 tcsendbreak(int fd, int duration) 298 { 299 # if defined(TIOCSBRK) && defined(TIOCCBRK) 300 struct timeval sleepytime; 301 302 sleepytime.tv_sec = 0; 303 sleepytime.tv_usec = 400000; 304 if (ioctl(fd, TIOCSBRK, 0) == -1) 305 return (-1); 306 (void)select(0, 0, 0, 0, &sleepytime); 307 if (ioctl(fd, TIOCCBRK, 0) == -1) 308 return (-1); 309 return (0); 310 # else 311 return -1; 312 # endif 313 } 314 #endif /* HAVE_TCSENDBREAK */ 315 316 #ifndef HAVE_STRDUP 317 char * 318 strdup(const char *str) 319 { 320 size_t len; 321 char *cp; 322 323 len = strlen(str) + 1; 324 cp = malloc(len); 325 if (cp != NULL) 326 return(memcpy(cp, str, len)); 327 return NULL; 328 } 329 #endif 330 331 #ifndef HAVE_ISBLANK 332 int 333 isblank(int c) 334 { 335 return (c == ' ' || c == '\t'); 336 } 337 #endif 338 339 #ifndef HAVE_GETPGID 340 pid_t 341 getpgid(pid_t pid) 342 { 343 #if defined(HAVE_GETPGRP) && !defined(GETPGRP_VOID) && GETPGRP_VOID == 0 344 return getpgrp(pid); 345 #elif defined(HAVE_GETPGRP) 346 if (pid == 0) 347 return getpgrp(); 348 #endif 349 350 errno = ESRCH; 351 return -1; 352 } 353 #endif 354 355 #ifndef HAVE_PLEDGE 356 int 357 pledge(const char *promises, const char *paths[]) 358 { 359 return 0; 360 } 361 #endif 362 363 #ifndef HAVE_MBTOWC 364 /* a mbtowc that only supports ASCII */ 365 int 366 mbtowc(wchar_t *pwc, const char *s, size_t n) 367 { 368 if (s == NULL || *s == '\0') 369 return 0; /* ASCII is not state-dependent */ 370 if (*s < 0 || *s > 0x7f || n < 1) { 371 errno = EOPNOTSUPP; 372 return -1; 373 } 374 if (pwc != NULL) 375 *pwc = *s; 376 return 1; 377 } 378 #endif 379 380 #ifndef HAVE_LLABS 381 long long 382 llabs(long long j) 383 { 384 return (j < 0 ? -j : j); 385 } 386 #endif 387 388 #ifndef HAVE_BZERO 389 void 390 bzero(void *b, size_t n) 391 { 392 (void)memset(b, 0, n); 393 } 394 #endif 395 396 #ifndef HAVE_RAISE 397 int 398 raise(int sig) 399 { 400 kill(getpid(), sig); 401 } 402 #endif 403 404 #ifndef HAVE_GETSID 405 pid_t 406 getsid(pid_t pid) 407 { 408 errno = ENOSYS; 409 return -1; 410 } 411 #endif 412 413 #ifdef FFLUSH_NULL_BUG 414 #undef fflush 415 int _ssh_compat_fflush(FILE *f) 416 { 417 int r1, r2; 418 419 if (f == NULL) { 420 r1 = fflush(stdout); 421 r2 = fflush(stderr); 422 if (r1 == -1 || r2 == -1) 423 return -1; 424 return 0; 425 } 426 return fflush(f); 427 } 428 #endif 429