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