Coverage Report

Created: 2026-10-13 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssh/monitor_fdpass.c
Line
Count
Source
1
/* $OpenBSD: monitor_fdpass.c,v 1.23 2026/02/08 19:54:31 dtucker Exp $ */
2
/*
3
 * Copyright 2001 Niels Provos <provos@citi.umich.edu>
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 *
15
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
 */
26
27
#include "includes.h"
28
29
#include <sys/types.h>
30
#include <sys/socket.h>
31
#include <sys/uio.h>
32
#include <sys/un.h>
33
34
#include <errno.h>
35
#include <poll.h>
36
#include <string.h>
37
#include <stdarg.h>
38
39
#include "log.h"
40
#include "monitor_fdpass.h"
41
42
int
43
mm_send_fd(int sock, int fd)
44
0
{
45
0
#if defined(HAVE_SENDMSG) && (defined(HAVE_ACCRIGHTS_IN_MSGHDR) || defined(HAVE_CONTROL_IN_MSGHDR))
46
0
  struct msghdr msg;
47
0
#ifndef HAVE_ACCRIGHTS_IN_MSGHDR
48
0
  union {
49
0
    struct cmsghdr hdr;
50
0
    char buf[CMSG_SPACE(sizeof(int))];
51
0
  } cmsgbuf;
52
0
  struct cmsghdr *cmsg;
53
0
#endif
54
0
  struct iovec vec;
55
0
  char ch = '\0';
56
0
  ssize_t n;
57
0
  struct pollfd pfd;
58
59
0
  memset(&msg, 0, sizeof(msg));
60
#ifdef HAVE_ACCRIGHTS_IN_MSGHDR
61
  msg.msg_accrights = (caddr_t)&fd;
62
  msg.msg_accrightslen = sizeof(fd);
63
#else
64
0
  memset(&cmsgbuf, 0, sizeof(cmsgbuf));
65
0
  msg.msg_control = (caddr_t)&cmsgbuf.buf;
66
0
  msg.msg_controllen = sizeof(cmsgbuf.buf);
67
0
  cmsg = CMSG_FIRSTHDR(&msg);
68
0
  cmsg->cmsg_len = CMSG_LEN(sizeof(int));
69
0
  cmsg->cmsg_level = SOL_SOCKET;
70
0
  cmsg->cmsg_type = SCM_RIGHTS;
71
0
  *(int *)CMSG_DATA(cmsg) = fd;
72
0
#endif
73
74
0
  vec.iov_base = &ch;
75
0
  vec.iov_len = 1;
76
0
  msg.msg_iov = &vec;
77
0
  msg.msg_iovlen = 1;
78
79
0
  pfd.fd = sock;
80
0
  pfd.events = POLLOUT;
81
0
  while ((n = sendmsg(sock, &msg, 0)) == -1 &&
82
0
      (errno == EAGAIN || errno == EINTR)) {
83
0
    debug3_f("sendmsg(%d): %s", fd, strerror(errno));
84
0
    (void)poll(&pfd, 1, -1);
85
0
  }
86
0
  if (n == -1) {
87
0
    error_f("sendmsg(%d): %s", fd, strerror(errno));
88
0
    return -1;
89
0
  }
90
91
0
  if (n != 1) {
92
0
    error_f("sendmsg: expected sent 1 got %zd", n);
93
0
    return -1;
94
0
  }
95
0
  return 0;
96
#else
97
  error_f("file descriptor passing not supported");
98
  return -1;
99
#endif
100
0
}
101
102
int
103
mm_receive_fd(int sock)
104
96
{
105
96
#if defined(HAVE_RECVMSG) && (defined(HAVE_ACCRIGHTS_IN_MSGHDR) || defined(HAVE_CONTROL_IN_MSGHDR))
106
96
  struct msghdr msg;
107
96
#ifndef HAVE_ACCRIGHTS_IN_MSGHDR
108
96
  union {
109
96
    struct cmsghdr hdr;
110
96
    char buf[CMSG_SPACE(sizeof(int))];
111
96
  } cmsgbuf;
112
96
  struct cmsghdr *cmsg;
113
96
#endif
114
96
  struct iovec vec;
115
96
  ssize_t n;
116
96
  char ch;
117
96
  int fd;
118
96
  struct pollfd pfd;
119
120
96
  memset(&msg, 0, sizeof(msg));
121
96
  vec.iov_base = &ch;
122
96
  vec.iov_len = 1;
123
96
  msg.msg_iov = &vec;
124
96
  msg.msg_iovlen = 1;
125
#ifdef HAVE_ACCRIGHTS_IN_MSGHDR
126
  msg.msg_accrights = (caddr_t)&fd;
127
  msg.msg_accrightslen = sizeof(fd);
128
#else
129
96
  memset(&cmsgbuf, 0, sizeof(cmsgbuf));
130
96
  msg.msg_control = &cmsgbuf.buf;
131
96
  msg.msg_controllen = sizeof(cmsgbuf.buf);
132
96
#endif
133
134
96
  pfd.fd = sock;
135
96
  pfd.events = POLLIN;
136
96
  while ((n = recvmsg(sock, &msg, 0)) == -1 &&
137
96
      (errno == EAGAIN || errno == EINTR)) {
138
0
    debug3_f("recvmsg: %s", strerror(errno));
139
0
    (void)poll(&pfd, 1, -1);
140
0
  }
141
96
  if (n == -1) {
142
96
    error_f("recvmsg: %s", strerror(errno));
143
96
    return -1;
144
96
  }
145
146
0
  if (n != 1) {
147
0
    error_f("recvmsg: expected received 1 got %zd", n);
148
0
    return -1;
149
0
  }
150
151
#ifdef HAVE_ACCRIGHTS_IN_MSGHDR
152
  if (msg.msg_accrightslen != sizeof(fd)) {
153
    error_f("no fd");
154
    return -1;
155
  }
156
#else
157
0
  cmsg = CMSG_FIRSTHDR(&msg);
158
0
  if (cmsg == NULL) {
159
0
    error_f("no message header");
160
0
    return -1;
161
0
  }
162
163
0
#ifndef BROKEN_CMSG_TYPE
164
0
  if (cmsg->cmsg_type != SCM_RIGHTS) {
165
0
    error_f("expected %d got %d", SCM_RIGHTS, cmsg->cmsg_type);
166
0
    return -1;
167
0
  }
168
0
#endif
169
0
  fd = (*(int *)CMSG_DATA(cmsg));
170
0
#endif
171
0
  return fd;
172
#else
173
  error_f("file descriptor passing not supported");
174
  return -1;
175
#endif
176
0
}