Coverage Report

Created: 2025-11-11 06:44

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