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