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  */
ssh_get_progname(char * argv0)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
setlogin(const char * name)68 int setlogin(const char *name)
69 {
70 	return (0);
71 }
72 #endif /* !HAVE_SETLOGIN */
73 
74 #ifndef HAVE_INNETGR
innetgr(const char * netgroup,const char * host,const char * user,const char * domain)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)
seteuid(uid_t euid)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)
setegid(uid_t egid)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)
strerror(int e)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
utimes(const char * filename,struct timeval * tvp)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
utimensat(int fd,const char * path,const struct timespec times[2],int flag)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
fchownat(int fd,const char * path,uid_t owner,gid_t group,int flag)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
fchmodat(int fd,const char * path,mode_t mode,int flag)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
truncate(const char * path,off_t length)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)
nanosleep(const struct timespec * req,struct timespec * rem)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)
usleep(unsigned int useconds)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
tcgetpgrp(int fd)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
tcsendbreak(int fd,int duration)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 *
strdup(const char * str)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
isblank(int c)335 isblank(int c)
336 {
337 	return (c == ' ' || c == '\t');
338 }
339 #endif
340 
341 #ifndef HAVE_GETPGID
342 pid_t
getpgid(pid_t pid)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
pledge(const char * promises,const char * paths[])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
mbtowc(wchar_t * pwc,const char * s,size_t n)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
llabs(long long j)384 llabs(long long j)
385 {
386 	return (j < 0 ? -j : j);
387 }
388 #endif
389 
390 #ifndef HAVE_BZERO
391 void
bzero(void * b,size_t n)392 bzero(void *b, size_t n)
393 {
394 	(void)memset(b, 0, n);
395 }
396 #endif
397 
398 #ifndef HAVE_RAISE
399 int
raise(int sig)400 raise(int sig)
401 {
402 	kill(getpid(), sig);
403 }
404 #endif
405 
406 #ifndef HAVE_GETSID
407 pid_t
getsid(pid_t pid)408 getsid(pid_t pid)
409 {
410 	errno = ENOSYS;
411 	return -1;
412 }
413 #endif
414 
415 #ifndef HAVE_KILLPG
416 int
killpg(pid_t pgrp,int sig)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
_ssh_compat_fflush(FILE * f)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 *
localtime_r(const time_t * timep,struct tm * result)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
__asan_default_options(void)451 const char *__asan_default_options(void) {
452 	return ASAN_OPTIONS;
453 }
454 #endif
455 
456 #ifdef MSAN_OPTIONS
__msan_default_options(void)457 const char *__msan_default_options(void) {
458 	return MSAN_OPTIONS;
459 }
460 #endif
461