Coverage Report

Created: 2025-06-20 06:25

/src/openssh/openbsd-compat/bsd-misc.c
Line
Count
Source (jump to first uncovered line)
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
0
{
46
0
  char *p, *q;
47
0
#ifdef HAVE___PROGNAME
48
0
  extern char *__progname;
49
50
0
  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
0
  if ((q = strdup(p)) == NULL) {
61
0
    perror("strdup");
62
0
    exit(1);
63
0
  }
64
0
  return q;
65
0
}
66
67
#ifndef HAVE_SETLOGIN
68
int setlogin(const char *name)
69
0
{
70
0
  return (0);
71
0
}
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(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
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_DIRFD
162
int
163
dirfd(void *dir)
164
{
165
  errno = ENOSYS;
166
  return -1;
167
}
168
#endif
169
170
#ifndef HAVE_FCHOWNAT
171
/*
172
 * A limited implementation of fchownat() that only implements the
173
 * functionality used by OpenSSH, currently only AT_FDCWD and
174
 * AT_SYMLINK_NOFOLLOW.
175
 */
176
int
177
fchownat(int fd, const char *path, uid_t owner, gid_t group, int flag)
178
{
179
  int ret, oflags = O_WRONLY;
180
181
  if (fd != AT_FDCWD) {
182
    errno = ENOSYS;
183
    return -1;
184
  }
185
# ifndef HAVE_FCHOWN
186
  return chown(path, owner, group);
187
# else
188
#  ifdef O_NOFOLLOW
189
  if (flag & AT_SYMLINK_NOFOLLOW)
190
    oflags |= O_NOFOLLOW;
191
#  endif /* O_NOFOLLOW */
192
  if ((fd = open(path, oflags)) == -1)
193
    return -1;
194
  ret = fchown(fd, owner, group);
195
  close(fd);
196
  return ret;
197
# endif
198
}
199
#endif
200
201
#ifndef HAVE_FCHMODAT
202
/*
203
 * A limited implementation of fchmodat() that only implements the
204
 * functionality used by OpenSSH, currently only AT_FDCWD and
205
 * AT_SYMLINK_NOFOLLOW.
206
 */
207
int
208
fchmodat(int fd, const char *path, mode_t mode, int flag)
209
{
210
  int ret, oflags = O_WRONLY;
211
212
  if (fd != AT_FDCWD) {
213
    errno = ENOSYS;
214
    return -1;
215
  }
216
# ifndef HAVE_FCHMOD
217
  return chmod(path, mode);
218
# else
219
#  ifdef O_NOFOLLOW
220
  if (flag & AT_SYMLINK_NOFOLLOW)
221
    oflags |= O_NOFOLLOW;
222
#  endif /* O_NOFOLLOW */
223
  if ((fd = open(path, oflags)) == -1)
224
    return -1;
225
  ret = fchmod(fd, mode);
226
  close(fd);
227
  return ret;
228
# endif
229
}
230
#endif
231
232
#ifndef HAVE_FSTATAT
233
/*
234
 * A limited implementation of fstatat that just has what OpenSSH uses:
235
 * cwd-relative and absolute paths, with or without following symlinks.
236
 */
237
int
238
fstatat(int dirfd, const char *path, struct stat *sb, int flag)
239
{
240
  if (dirfd != AT_FDCWD && path && path[0] != '/') {
241
    errno = ENOSYS;
242
    return -1;
243
  }
244
  if (flag == 0)
245
    return stat(path, sb);
246
  else if (flag == AT_SYMLINK_NOFOLLOW)
247
    return lstat(path, sb);
248
  errno = ENOSYS;
249
  return -1;
250
}
251
#endif
252
253
#ifndef HAVE_UNLINKAT
254
/*
255
 * A limited implementation of unlinkat that just has what OpenSSH uses:
256
 * cwd-relative and absolute paths.
257
 */
258
int
259
unlinkat(int dirfd, const char *path, int flag)
260
{
261
  if (dirfd != AT_FDCWD && path && path[0] != '/') {
262
    errno = ENOSYS;
263
    return -1;
264
  }
265
  if (flag == 0)
266
    return unlink(path);
267
  errno = ENOSYS;
268
  return -1;
269
}
270
#endif
271
272
#ifndef HAVE_TRUNCATE
273
int truncate(const char *path, off_t length)
274
{
275
  int fd, ret, saverrno;
276
277
  fd = open(path, O_WRONLY);
278
  if (fd < 0)
279
    return (-1);
280
281
  ret = ftruncate(fd, length);
282
  saverrno = errno;
283
  close(fd);
284
  if (ret == -1)
285
    errno = saverrno;
286
287
  return(ret);
288
}
289
#endif /* HAVE_TRUNCATE */
290
291
#if !defined(HAVE_NANOSLEEP) && !defined(HAVE_NSLEEP)
292
int nanosleep(const struct timespec *req, struct timespec *rem)
293
{
294
  int rc, saverrno;
295
  extern int errno;
296
  struct timeval tstart, tstop, tremain, time2wait;
297
298
  TIMESPEC_TO_TIMEVAL(&time2wait, req)
299
  (void) gettimeofday(&tstart, NULL);
300
  rc = select(0, NULL, NULL, NULL, &time2wait);
301
  if (rc == -1) {
302
    saverrno = errno;
303
    (void) gettimeofday (&tstop, NULL);
304
    errno = saverrno;
305
    tremain.tv_sec = time2wait.tv_sec -
306
      (tstop.tv_sec - tstart.tv_sec);
307
    tremain.tv_usec = time2wait.tv_usec -
308
      (tstop.tv_usec - tstart.tv_usec);
309
    tremain.tv_sec += tremain.tv_usec / 1000000L;
310
    tremain.tv_usec %= 1000000L;
311
  } else {
312
    tremain.tv_sec = 0;
313
    tremain.tv_usec = 0;
314
  }
315
  if (rem != NULL)
316
    TIMEVAL_TO_TIMESPEC(&tremain, rem)
317
318
  return(rc);
319
}
320
#endif
321
322
#if !defined(HAVE_USLEEP)
323
int usleep(unsigned int useconds)
324
{
325
  struct timespec ts;
326
327
  ts.tv_sec = useconds / 1000000;
328
  ts.tv_nsec = (useconds % 1000000) * 1000;
329
  return nanosleep(&ts, NULL);
330
}
331
#endif
332
333
#ifndef HAVE_TCGETPGRP
334
pid_t
335
tcgetpgrp(int fd)
336
{
337
  int ctty_pgrp;
338
339
  if (ioctl(fd, TIOCGPGRP, &ctty_pgrp) == -1)
340
    return(-1);
341
  else
342
    return(ctty_pgrp);
343
}
344
#endif /* HAVE_TCGETPGRP */
345
346
#ifndef HAVE_TCSENDBREAK
347
int
348
tcsendbreak(int fd, int duration)
349
{
350
# if defined(TIOCSBRK) && defined(TIOCCBRK)
351
  struct timeval sleepytime;
352
353
  sleepytime.tv_sec = 0;
354
  sleepytime.tv_usec = 400000;
355
  if (ioctl(fd, TIOCSBRK, 0) == -1)
356
    return (-1);
357
  (void)select(0, 0, 0, 0, &sleepytime);
358
  if (ioctl(fd, TIOCCBRK, 0) == -1)
359
    return (-1);
360
  return (0);
361
# else
362
  return -1;
363
# endif
364
}
365
#endif /* HAVE_TCSENDBREAK */
366
367
#ifndef HAVE_STRDUP
368
char *
369
strdup(const char *str)
370
{
371
  size_t len;
372
  char *cp;
373
374
  len = strlen(str) + 1;
375
  cp = malloc(len);
376
  if (cp != NULL)
377
    return(memcpy(cp, str, len));
378
  return NULL;
379
}
380
#endif
381
382
#ifndef HAVE_ISBLANK
383
int
384
isblank(int c)
385
{
386
  return (c == ' ' || c == '\t');
387
}
388
#endif
389
390
#ifndef HAVE_GETPGID
391
pid_t
392
getpgid(pid_t pid)
393
{
394
#if defined(HAVE_GETPGRP) && !defined(GETPGRP_VOID) && GETPGRP_VOID == 0
395
  return getpgrp(pid);
396
#elif defined(HAVE_GETPGRP)
397
  if (pid == 0)
398
    return getpgrp();
399
#endif
400
401
  errno = ESRCH;
402
  return -1;
403
}
404
#endif
405
406
#ifndef HAVE_PLEDGE
407
int
408
pledge(const char *promises, const char *paths[])
409
0
{
410
0
  return 0;
411
0
}
412
#endif
413
414
#ifndef HAVE_MBTOWC
415
/* a mbtowc that only supports ASCII */
416
int
417
mbtowc(wchar_t *pwc, const char *s, size_t n)
418
{
419
  if (s == NULL || *s == '\0')
420
    return 0; /* ASCII is not state-dependent */
421
  if (*s < 0 || *s > 0x7f || n < 1) {
422
    errno = EOPNOTSUPP;
423
    return -1;
424
  }
425
  if (pwc != NULL)
426
    *pwc = *s;
427
  return 1;
428
}
429
#endif
430
431
#ifndef HAVE_LLABS
432
long long
433
llabs(long long j)
434
{
435
  return (j < 0 ? -j : j);
436
}
437
#endif
438
439
#ifndef HAVE_BZERO
440
void
441
bzero(void *b, size_t n)
442
{
443
  (void)memset(b, 0, n);
444
}
445
#endif
446
447
#ifndef HAVE_RAISE
448
int
449
raise(int sig)
450
{
451
  kill(getpid(), sig);
452
}
453
#endif
454
455
#ifndef HAVE_GETSID
456
pid_t
457
getsid(pid_t pid)
458
{
459
  errno = ENOSYS;
460
  return -1;
461
}
462
#endif
463
464
#ifndef HAVE_KILLPG
465
int
466
killpg(pid_t pgrp, int sig)
467
{
468
  return kill(pgrp, sig);
469
}
470
#endif
471
472
#ifdef FFLUSH_NULL_BUG
473
#undef fflush
474
int _ssh_compat_fflush(FILE *f)
475
{
476
  int r1, r2;
477
478
  if (f == NULL) {
479
    r1 = fflush(stdout);
480
    r2 = fflush(stderr);
481
    if (r1 == -1 || r2 == -1)
482
      return -1;
483
    return 0;
484
  }
485
  return fflush(f);
486
}
487
#endif
488
489
#ifndef HAVE_LOCALTIME_R
490
struct tm *
491
localtime_r(const time_t *timep, struct tm *result)
492
{
493
  struct tm *tm = localtime(timep);
494
  *result = *tm;
495
  return result;
496
}
497
#endif
498
499
#ifdef ASAN_OPTIONS
500
const char *__asan_default_options(void) {
501
  return ASAN_OPTIONS;
502
}
503
#endif
504
505
#ifdef MSAN_OPTIONS
506
const char *__msan_default_options(void) {
507
  return MSAN_OPTIONS;
508
}
509
#endif