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