Coverage Report

Created: 2025-11-03 07:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssh/openbsd-compat/bsd-misc.c
Line
Count
Source
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
#include <sys/ioctl.h>
22
#ifdef HAVE_SYS_SELECT_H
23
# include <sys/select.h>
24
#endif
25
#include <sys/time.h>
26
27
#include <fcntl.h>
28
#include <string.h>
29
#include <signal.h>
30
#include <stdlib.h>
31
#include <stdio.h>
32
#include <time.h>
33
#include <unistd.h>
34
35
#ifndef HAVE___PROGNAME
36
char *__progname;
37
#endif
38
39
/*
40
 * NB. duplicate __progname in case it is an alias for argv[0]
41
 * Otherwise it may get clobbered by setproctitle()
42
 */
43
char *ssh_get_progname(char *argv0)
44
0
{
45
0
  char *p, *q;
46
0
#ifdef HAVE___PROGNAME
47
0
  extern char *__progname;
48
49
0
  p = __progname;
50
#else
51
  if (argv0 == NULL)
52
    return ("unknown"); /* XXX */
53
  p = strrchr(argv0, '/');
54
  if (p == NULL)
55
    p = argv0;
56
  else
57
    p++;
58
#endif
59
0
  if ((q = strdup(p)) == NULL) {
60
0
    perror("strdup");
61
0
    exit(1);
62
0
  }
63
0
  return q;
64
0
}
65
66
#ifndef HAVE_SETLOGIN
67
int setlogin(const char *name)
68
0
{
69
0
  return (0);
70
0
}
71
#endif /* !HAVE_SETLOGIN */
72
73
#ifndef HAVE_INNETGR
74
int innetgr(const char *netgroup, const char *host,
75
      const char *user, const char *domain)
76
{
77
  return (0);
78
}
79
#endif /* HAVE_INNETGR */
80
81
#if !defined(HAVE_SETEUID) && defined(HAVE_SETREUID)
82
int seteuid(uid_t euid)
83
{
84
  return (setreuid(-1, euid));
85
}
86
#endif /* !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) */
87
88
#if !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID)
89
int setegid(uid_t egid)
90
{
91
  return(setresgid(-1, egid, -1));
92
}
93
#endif /* !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) */
94
95
#if !defined(HAVE_STRERROR) && defined(HAVE_SYS_ERRLIST) && defined(HAVE_SYS_NERR)
96
const char *strerror(int e)
97
{
98
  extern int sys_nerr;
99
  extern char *sys_errlist[];
100
101
  if ((e >= 0) && (e < sys_nerr))
102
    return (sys_errlist[e]);
103
104
  return ("unlisted error");
105
}
106
#endif
107
108
#ifndef HAVE_UTIMES
109
int utimes(const char *filename, struct timeval *tvp)
110
{
111
  struct utimbuf ub;
112
113
  ub.actime = tvp[0].tv_sec;
114
  ub.modtime = tvp[1].tv_sec;
115
116
  return (utime(filename, &ub));
117
}
118
#endif
119
120
#ifndef HAVE_UTIMENSAT
121
/*
122
 * A limited implementation of utimensat() that only implements the
123
 * functionality used by OpenSSH, currently only AT_FDCWD and
124
 * AT_SYMLINK_NOFOLLOW.
125
 */
126
int
127
utimensat(int fd, const char *path, const struct timespec times[2],
128
    int flag)
129
{
130
  struct timeval tv[2];
131
# ifdef HAVE_FUTIMES
132
  int ret, oflags = O_WRONLY;
133
# endif
134
135
  tv[0].tv_sec = times[0].tv_sec;
136
  tv[0].tv_usec = times[0].tv_nsec / 1000;
137
  tv[1].tv_sec = times[1].tv_sec;
138
  tv[1].tv_usec = times[1].tv_nsec / 1000;
139
140
  if (fd != AT_FDCWD) {
141
    errno = ENOSYS;
142
    return -1;
143
  }
144
# ifndef HAVE_FUTIMES
145
  return utimes(path, tv);
146
# else
147
#  ifdef O_NOFOLLOW
148
  if (flag & AT_SYMLINK_NOFOLLOW)
149
    oflags |= O_NOFOLLOW;
150
#  endif /* O_NOFOLLOW */
151
  if ((fd = open(path, oflags)) == -1)
152
    return -1;
153
  ret = futimes(fd, tv);
154
  close(fd);
155
  return ret;
156
# endif
157
}
158
#endif
159
160
#ifndef HAVE_DIRFD
161
int
162
dirfd(void *dir)
163
{
164
  errno = ENOSYS;
165
  return -1;
166
}
167
#endif
168
169
#ifndef HAVE_FCHOWNAT
170
/*
171
 * A limited implementation of fchownat() that only implements the
172
 * functionality used by OpenSSH, currently only AT_FDCWD and
173
 * AT_SYMLINK_NOFOLLOW.
174
 */
175
int
176
fchownat(int fd, const char *path, uid_t owner, gid_t group, int flag)
177
{
178
  int ret, oflags = O_WRONLY;
179
180
  if (fd != AT_FDCWD) {
181
    errno = ENOSYS;
182
    return -1;
183
  }
184
# ifndef HAVE_FCHOWN
185
  return chown(path, owner, group);
186
# else
187
#  ifdef O_NOFOLLOW
188
  if (flag & AT_SYMLINK_NOFOLLOW)
189
    oflags |= O_NOFOLLOW;
190
#  endif /* O_NOFOLLOW */
191
  if ((fd = open(path, oflags)) == -1)
192
    return -1;
193
  ret = fchown(fd, owner, group);
194
  close(fd);
195
  return ret;
196
# endif
197
}
198
#endif
199
200
#ifndef HAVE_FCHMODAT
201
/*
202
 * A limited implementation of fchmodat() that only implements the
203
 * functionality used by OpenSSH, currently only AT_FDCWD and
204
 * AT_SYMLINK_NOFOLLOW.
205
 */
206
int
207
fchmodat(int fd, const char *path, mode_t mode, int flag)
208
{
209
  int ret, oflags = O_WRONLY;
210
211
  if (fd != AT_FDCWD) {
212
    errno = ENOSYS;
213
    return -1;
214
  }
215
# ifndef HAVE_FCHMOD
216
  return chmod(path, mode);
217
# else
218
#  ifdef O_NOFOLLOW
219
  if (flag & AT_SYMLINK_NOFOLLOW)
220
    oflags |= O_NOFOLLOW;
221
#  endif /* O_NOFOLLOW */
222
  if ((fd = open(path, oflags)) == -1)
223
    return -1;
224
  ret = fchmod(fd, mode);
225
  close(fd);
226
  return ret;
227
# endif
228
}
229
#endif
230
231
#ifndef HAVE_FSTATAT
232
/*
233
 * A limited implementation of fstatat that just has what OpenSSH uses:
234
 * cwd-relative and absolute paths, with or without following symlinks.
235
 */
236
int
237
fstatat(int dirfd, const char *path, struct stat *sb, int flag)
238
{
239
  if (dirfd != AT_FDCWD && path && path[0] != '/') {
240
    errno = ENOSYS;
241
    return -1;
242
  }
243
  if (flag == 0)
244
    return stat(path, sb);
245
  else if (flag == AT_SYMLINK_NOFOLLOW)
246
    return lstat(path, sb);
247
  errno = ENOSYS;
248
  return -1;
249
}
250
#endif
251
252
#ifndef HAVE_UNLINKAT
253
/*
254
 * A limited implementation of unlinkat that just has what OpenSSH uses:
255
 * cwd-relative and absolute paths.
256
 */
257
int
258
unlinkat(int dirfd, const char *path, int flag)
259
{
260
  if (dirfd != AT_FDCWD && path && path[0] != '/') {
261
    errno = ENOSYS;
262
    return -1;
263
  }
264
  if (flag == 0)
265
    return unlink(path);
266
  errno = ENOSYS;
267
  return -1;
268
}
269
#endif
270
271
#ifndef HAVE_TRUNCATE
272
int truncate(const char *path, off_t length)
273
{
274
  int fd, ret, saverrno;
275
276
  fd = open(path, O_WRONLY);
277
  if (fd < 0)
278
    return (-1);
279
280
  ret = ftruncate(fd, length);
281
  saverrno = errno;
282
  close(fd);
283
  if (ret == -1)
284
    errno = saverrno;
285
286
  return(ret);
287
}
288
#endif /* HAVE_TRUNCATE */
289
290
#if !defined(HAVE_NANOSLEEP) && !defined(HAVE_NSLEEP)
291
int nanosleep(const struct timespec *req, struct timespec *rem)
292
{
293
  int rc, saverrno;
294
  extern int errno;
295
  struct timeval tstart, tstop, tremain, time2wait;
296
297
  TIMESPEC_TO_TIMEVAL(&time2wait, req)
298
  (void) gettimeofday(&tstart, NULL);
299
  rc = select(0, NULL, NULL, NULL, &time2wait);
300
  if (rc == -1) {
301
    saverrno = errno;
302
    (void) gettimeofday (&tstop, NULL);
303
    errno = saverrno;
304
    tremain.tv_sec = time2wait.tv_sec -
305
      (tstop.tv_sec - tstart.tv_sec);
306
    tremain.tv_usec = time2wait.tv_usec -
307
      (tstop.tv_usec - tstart.tv_usec);
308
    tremain.tv_sec += tremain.tv_usec / 1000000L;
309
    tremain.tv_usec %= 1000000L;
310
  } else {
311
    tremain.tv_sec = 0;
312
    tremain.tv_usec = 0;
313
  }
314
  if (rem != NULL)
315
    TIMEVAL_TO_TIMESPEC(&tremain, rem)
316
317
  return(rc);
318
}
319
#endif
320
321
#if !defined(HAVE_USLEEP)
322
int usleep(unsigned int useconds)
323
{
324
  struct timespec ts;
325
326
  ts.tv_sec = useconds / 1000000;
327
  ts.tv_nsec = (useconds % 1000000) * 1000;
328
  return nanosleep(&ts, NULL);
329
}
330
#endif
331
332
#ifndef HAVE_TCGETPGRP
333
pid_t
334
tcgetpgrp(int fd)
335
{
336
  int ctty_pgrp;
337
338
  if (ioctl(fd, TIOCGPGRP, &ctty_pgrp) == -1)
339
    return(-1);
340
  else
341
    return(ctty_pgrp);
342
}
343
#endif /* HAVE_TCGETPGRP */
344
345
#ifndef HAVE_TCSENDBREAK
346
int
347
tcsendbreak(int fd, int duration)
348
{
349
# if defined(TIOCSBRK) && defined(TIOCCBRK)
350
  struct timeval sleepytime;
351
352
  sleepytime.tv_sec = 0;
353
  sleepytime.tv_usec = 400000;
354
  if (ioctl(fd, TIOCSBRK, 0) == -1)
355
    return (-1);
356
  (void)select(0, 0, 0, 0, &sleepytime);
357
  if (ioctl(fd, TIOCCBRK, 0) == -1)
358
    return (-1);
359
  return (0);
360
# else
361
  return -1;
362
# endif
363
}
364
#endif /* HAVE_TCSENDBREAK */
365
366
#ifndef HAVE_STRDUP
367
char *
368
strdup(const char *str)
369
{
370
  size_t len;
371
  char *cp;
372
373
  len = strlen(str) + 1;
374
  cp = malloc(len);
375
  if (cp != NULL)
376
    return(memcpy(cp, str, len));
377
  return NULL;
378
}
379
#endif
380
381
#ifndef HAVE_ISBLANK
382
int
383
isblank(int c)
384
{
385
  return (c == ' ' || c == '\t');
386
}
387
#endif
388
389
#ifndef HAVE_GETPGID
390
pid_t
391
getpgid(pid_t pid)
392
{
393
#if defined(HAVE_GETPGRP) && !defined(GETPGRP_VOID) && GETPGRP_VOID == 0
394
  return getpgrp(pid);
395
#elif defined(HAVE_GETPGRP)
396
  if (pid == 0)
397
    return getpgrp();
398
#endif
399
400
  errno = ESRCH;
401
  return -1;
402
}
403
#endif
404
405
#ifndef HAVE_PLEDGE
406
int
407
pledge(const char *promises, const char *execpromises)
408
0
{
409
0
  return 0;
410
0
}
411
#endif
412
413
#ifndef HAVE_MBTOWC
414
/* a mbtowc that only supports ASCII */
415
int
416
mbtowc(wchar_t *pwc, const char *s, size_t n)
417
{
418
  if (s == NULL || *s == '\0')
419
    return 0; /* ASCII is not state-dependent */
420
  if (*s < 0 || *s > 0x7f || n < 1) {
421
    errno = EOPNOTSUPP;
422
    return -1;
423
  }
424
  if (pwc != NULL)
425
    *pwc = *s;
426
  return 1;
427
}
428
#endif
429
430
#ifndef HAVE_LLABS
431
long long
432
llabs(long long j)
433
{
434
  return (j < 0 ? -j : j);
435
}
436
#endif
437
438
#ifndef HAVE_BZERO
439
void
440
bzero(void *b, size_t n)
441
{
442
  (void)memset(b, 0, n);
443
}
444
#endif
445
446
#ifndef HAVE_RAISE
447
int
448
raise(int sig)
449
{
450
  kill(getpid(), sig);
451
}
452
#endif
453
454
#ifndef HAVE_GETSID
455
pid_t
456
getsid(pid_t pid)
457
{
458
  errno = ENOSYS;
459
  return -1;
460
}
461
#endif
462
463
#ifndef HAVE_KILLPG
464
int
465
killpg(pid_t pgrp, int sig)
466
{
467
  return kill(pgrp, sig);
468
}
469
#endif
470
471
#ifdef FFLUSH_NULL_BUG
472
#undef fflush
473
int _ssh_compat_fflush(FILE *f)
474
{
475
  int r1, r2;
476
477
  if (f == NULL) {
478
    r1 = fflush(stdout);
479
    r2 = fflush(stderr);
480
    if (r1 == -1 || r2 == -1)
481
      return -1;
482
    return 0;
483
  }
484
  return fflush(f);
485
}
486
#endif
487
488
#ifndef HAVE_LOCALTIME_R
489
struct tm *
490
localtime_r(const time_t *timep, struct tm *result)
491
{
492
  struct tm *tm = localtime(timep);
493
  *result = *tm;
494
  return result;
495
}
496
#endif
497
498
#ifndef HAVE_CLOCK_GETTIME
499
int
500
clock_gettime(clockid_t clockid, struct timespec *ts)
501
{
502
  struct timeval tv;
503
504
  if (clockid != CLOCK_REALTIME) {
505
    errno = ENOSYS;
506
    return -1;
507
  }
508
  if (ts == NULL) {
509
    errno = EFAULT;
510
    return -1;
511
  }
512
513
  if (gettimeofday(&tv, NULL) == -1)
514
    return -1;
515
516
  ts->tv_sec = tv.tv_sec;
517
  ts->tv_nsec = (long)tv.tv_usec * 1000;
518
  return 0;
519
}
520
#endif
521
522
#ifdef ASAN_OPTIONS
523
const char *__asan_default_options(void) {
524
  return ASAN_OPTIONS;
525
}
526
#endif
527
528
#ifdef MSAN_OPTIONS
529
const char *__msan_default_options(void) {
530
  return MSAN_OPTIONS;
531
}
532
#endif