]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/rpc.tlsservd/rpc.tlscommon.c
fib_dxr: log malloc() failures.
[FreeBSD/FreeBSD.git] / usr.sbin / rpc.tlsservd / rpc.tlscommon.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2021 Rick Macklem
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 AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  */
28
29 #include <sys/cdefs.h>
30 #include <sys/queue.h>
31 #include <sys/syslog.h>
32 #include <sys/select.h>
33 #include <sys/time.h>
34
35 #include <netdb.h>
36 #include <signal.h>
37 #include <stdarg.h>
38 #include <stdbool.h>
39 #include <string.h>
40
41 #include <rpc/rpc.h>
42
43 #include <openssl/opensslconf.h>
44 #include <openssl/bio.h>
45 #include <openssl/ssl.h>
46 #include <openssl/err.h>
47 #include <openssl/x509v3.h>
48
49 #include "rpc.tlscommon.h"
50
51 /*
52  * How long to delay a reload of the CRL when there are RPC request(s)
53  * to process, in usec.  Must be less than 1second.
54  */
55 #define RELOADDELAY     250000
56
57 void
58 rpctls_svc_run(void)
59 {
60         int ret;
61         struct timeval tv;
62         fd_set readfds;
63         uint64_t curtime, nexttime;
64         struct timespec tp;
65         sigset_t sighup_mask;
66
67         /* Expand svc_run() here so that we can call rpctls_loadcrlfile(). */
68         curtime = nexttime = 0;
69         sigemptyset(&sighup_mask);
70         sigaddset(&sighup_mask, SIGHUP);
71         for (;;) {
72                 clock_gettime(CLOCK_MONOTONIC, &tp);
73                 curtime = tp.tv_sec;
74                 curtime = curtime * 1000000 + tp.tv_nsec / 1000;
75                 sigprocmask(SIG_BLOCK, &sighup_mask, NULL);
76                 if (rpctls_gothup && curtime >= nexttime) {
77                         rpctls_gothup = false;
78                         sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
79                         ret = rpctls_loadcrlfile(rpctls_ctx);
80                         if (ret != 0)
81                                 rpctls_checkcrl();
82                         else
83                                 rpctls_verbose_out("rpc.tlsservd: Can't "
84                                     "reload CRLfile\n");
85                         clock_gettime(CLOCK_MONOTONIC, &tp);
86                         nexttime = tp.tv_sec;
87                         nexttime = nexttime * 1000000 + tp.tv_nsec / 1000 +
88                             RELOADDELAY;
89                 } else
90                         sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
91
92                 /*
93                  * If a reload is pending, poll for received request(s),
94                  * otherwise set a RELOADDELAY timeout, since a SIGHUP
95                  * could be processed between the got_sighup test and
96                  * the select() system call.
97                  */
98                 tv.tv_sec = 0;
99                 if (rpctls_gothup)
100                         tv.tv_usec = 0;
101                 else
102                         tv.tv_usec = RELOADDELAY;
103                 readfds = svc_fdset;
104                 switch (select(svc_maxfd + 1, &readfds, NULL, NULL, &tv)) {
105                 case -1:
106                         if (errno == EINTR) {
107                                 /* Allow a reload now. */
108                                 nexttime = 0;
109                                 continue;
110                         }
111                         syslog(LOG_ERR, "rpc.tls daemon died: select: %m");
112                         exit(1);
113                 case 0:
114                         /* Allow a reload now. */
115                         nexttime = 0;
116                         continue;
117                 default:
118                         svc_getreqset(&readfds);
119                 }
120         }
121 }
122
123 /*
124  * (re)load the CRLfile into the certificate verification store.
125  */
126 int
127 rpctls_loadcrlfile(SSL_CTX *ctx)
128 {
129         X509_STORE *certstore;
130         X509_LOOKUP *certlookup;
131         int ret;
132
133         if ((rpctls_verify_cafile != NULL ||
134             rpctls_verify_capath != NULL) &&
135             rpctls_crlfile != NULL) {
136                 certstore = SSL_CTX_get_cert_store(ctx);
137                 certlookup = X509_STORE_add_lookup(
138                     certstore, X509_LOOKUP_file());
139                 ret = 0;
140                 if (certlookup != NULL)
141                         ret = X509_load_crl_file(certlookup,
142                             rpctls_crlfile, X509_FILETYPE_PEM);
143                 if (ret != 0)
144                         ret = X509_STORE_set_flags(certstore,
145                             X509_V_FLAG_CRL_CHECK |
146                             X509_V_FLAG_CRL_CHECK_ALL);
147                 if (ret == 0) {
148                         rpctls_verbose_out(
149                             "rpctls_loadcrlfile: Can't"
150                             " load CRLfile=%s\n",
151                             rpctls_crlfile);
152                         return (ret);
153                 }
154         }
155         return (1);
156 }
157
158 /*
159  * Read the CRL file and check for any extant connections
160  * that might now be revoked.
161  */
162 void
163 rpctls_checkcrl(void)
164 {
165         struct ssl_entry *slp;
166         BIO *infile;
167         X509_CRL *crl;
168         X509_REVOKED *revoked;
169         char *cp, *cp2, nullstr[1];
170         int ret;
171
172         if (rpctls_crlfile == NULL || (rpctls_verify_cafile == NULL &&
173             rpctls_verify_capath == NULL))
174                 return;
175         infile = BIO_new(BIO_s_file());
176         if (infile == NULL) {
177                 rpctls_verbose_out("rpctls_checkcrl: Cannot BIO_new\n");
178                 return;
179         }
180         ret = BIO_read_filename(infile, rpctls_crlfile);
181         if (ret != 1) {
182                 rpctls_verbose_out("rpctls_checkcrl: Cannot read CRL file\n");
183                 BIO_free(infile);
184                 return;
185         }
186
187         nullstr[0] = '\0';
188         for (crl = PEM_read_bio_X509_CRL(infile, NULL, NULL, nullstr);
189             crl != NULL; crl = PEM_read_bio_X509_CRL(infile, NULL, NULL,
190             nullstr)) {
191                 LIST_FOREACH(slp, &rpctls_ssllist, next) {
192                         if (slp->cert != NULL) {
193                                 ret = X509_CRL_get0_by_cert(crl, &revoked,
194                                     slp->cert);
195                                 /*
196                                  * Do a shutdown on the socket, so that it
197                                  * can no longer be used.  The kernel RPC
198                                  * code will notice the socket is disabled
199                                  * and will do a disconnect upcall, which will
200                                  * close the socket.
201                                  */
202                                 if (ret == 1) {
203                                         cp2 = X509_NAME_oneline(
204                                             X509_get_subject_name(slp->cert),
205                                             NULL, 0);
206                                         cp = X509_NAME_oneline(
207                                             X509_get_issuer_name(slp->cert),
208                                             NULL, 0);
209                                         if (rpctls_debug_level == 0)
210                                                 syslog(LOG_INFO | LOG_DAEMON,
211                                                     "rpctls_daemon: Certificate"
212                                                     " Revoked "
213                                                     "issuerName=%s "
214                                                     "subjectName=%s: "
215                                                     "TCP connection closed",
216                                                     cp, cp2);
217                                         else
218                                                 fprintf(stderr,
219                                                     "rpctls_daemon: Certificate"
220                                                     " Revoked "
221                                                     "issuerName=%s "
222                                                     "subjectName=%s: "
223                                                     "TCP connection closed",
224                                                     cp, cp2);
225                                         shutdown(slp->s, SHUT_WR);
226                                         slp->shutoff = true;
227                                 }
228                         }
229                 }
230                 X509_CRL_free(crl);
231         }
232         BIO_free(infile);
233 }
234
235 void
236 rpctls_verbose_out(const char *fmt, ...)
237 {
238         va_list ap;
239
240         if (rpctls_verbose) {
241                 va_start(ap, fmt);
242                 if (rpctls_debug_level == 0)
243                         vsyslog(LOG_INFO | LOG_DAEMON, fmt, ap);
244                 else
245                         vfprintf(stderr, fmt, ap);
246                 va_end(ap);
247         }
248 }
249
250 /*
251  * Check a IP address against any host address in the
252  * certificate.  Basically getnameinfo(3) and
253  * X509_check_host().
254  */
255 int
256 rpctls_checkhost(struct sockaddr *sad, X509 *cert, unsigned int wildcard)
257 {
258         char hostnam[NI_MAXHOST];
259         int ret;
260
261         if (getnameinfo((const struct sockaddr *)sad,
262             sad->sa_len, hostnam, sizeof(hostnam),
263             NULL, 0, NI_NAMEREQD) != 0)
264                 return (0);
265         rpctls_verbose_out("rpctls_checkhost: DNS %s\n",
266             hostnam);
267         ret = X509_check_host(cert, hostnam, strlen(hostnam),
268             wildcard, NULL);
269         return (ret);
270 }
271
272 /*
273  * Get the peer's IP address.
274  */
275 int
276 rpctls_gethost(int s, struct sockaddr *sad, char *hostip, size_t hostlen)
277 {
278         socklen_t slen;
279         int ret;
280
281         slen = sizeof(struct sockaddr_storage);
282         if (getpeername(s, sad, &slen) < 0)
283                 return (0);
284         ret = 0;
285         if (getnameinfo((const struct sockaddr *)sad,
286             sad->sa_len, hostip, hostlen,
287             NULL, 0, NI_NUMERICHOST) == 0) {
288                 rpctls_verbose_out("rpctls_gethost: %s\n",
289                     hostip);
290                 ret = 1;
291         }
292         return (ret);
293 }