]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/rpc.tlsclntd/rpc.tlsclntd.c
zfs: merge openzfs/zfs@2163cde45
[FreeBSD/FreeBSD.git] / usr.sbin / rpc.tlsclntd / rpc.tlsclntd.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
5  * Authors: Doug Rabson <dfr@rabson.org>
6  * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 /*
31  * Extensively modified from /usr/src/usr.sbin/gssd.c r344402 for
32  * the client side of kernel RPC-over-TLS by Rick Macklem.
33  */
34
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38 #include <sys/param.h>
39 #include <sys/types.h>
40 #include <sys/queue.h>
41 #include <sys/linker.h>
42 #include <sys/module.h>
43 #include <sys/stat.h>
44 #include <sys/sysctl.h>
45 #include <sys/syslog.h>
46 #include <sys/time.h>
47 #include <err.h>
48 #include <getopt.h>
49 #include <libutil.h>
50 #include <netdb.h>
51 #include <signal.h>
52 #include <stdarg.h>
53 #include <stdbool.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <unistd.h>
58
59 #include <rpc/rpc.h>
60 #include <rpc/rpc_com.h>
61 #include <rpc/rpcsec_tls.h>
62
63 #include <openssl/opensslconf.h>
64 #include <openssl/bio.h>
65 #include <openssl/ssl.h>
66 #include <openssl/err.h>
67 #include <openssl/x509v3.h>
68
69 #include "rpctlscd.h"
70 #include "rpc.tlscommon.h"
71
72 #ifndef _PATH_RPCTLSCDSOCK
73 #define _PATH_RPCTLSCDSOCK      "/var/run/rpc.tlsclntd.sock"
74 #endif
75 #ifndef _PATH_CERTANDKEY
76 #define _PATH_CERTANDKEY        "/etc/rpc.tlsclntd/"
77 #endif
78 #ifndef _PATH_RPCTLSCDPID
79 #define _PATH_RPCTLSCDPID       "/var/run/rpc.tlsclntd.pid"
80 #endif
81
82 /* Global variables also used by rpc.tlscommon.c. */
83 int                     rpctls_debug_level;
84 bool                    rpctls_verbose;
85 SSL_CTX                 *rpctls_ctx = NULL;
86 const char              *rpctls_verify_cafile = NULL;
87 const char              *rpctls_verify_capath = NULL;
88 char                    *rpctls_crlfile = NULL;
89 bool                    rpctls_cert = false;
90 bool                    rpctls_gothup = false;
91 struct ssl_list         rpctls_ssllist;
92
93 static struct pidfh     *rpctls_pfh = NULL;
94 static const char       *rpctls_certdir = _PATH_CERTANDKEY;
95 static const char       *rpctls_ciphers = NULL;
96 static uint64_t         rpctls_ssl_refno = 0;
97 static uint64_t         rpctls_ssl_sec = 0;
98 static uint64_t         rpctls_ssl_usec = 0;
99 static int              rpctls_tlsvers = TLS1_3_VERSION;
100
101 static void             rpctlscd_terminate(int);
102 static SSL_CTX          *rpctls_setupcl_ssl(void);
103 static SSL              *rpctls_connect(SSL_CTX *ctx, int s, char *certname,
104                             u_int certlen, X509 **certp);
105 static void             rpctls_huphandler(int sig __unused);
106
107 extern void rpctlscd_1(struct svc_req *rqstp, SVCXPRT *transp);
108
109 static struct option longopts[] = {
110         { "usetls1_2",          no_argument,            NULL,   '2' },
111         { "certdir",            required_argument,      NULL,   'D' },
112         { "ciphers",            required_argument,      NULL,   'C' },
113         { "debuglevel",         no_argument,            NULL,   'd' },
114         { "verifylocs",         required_argument,      NULL,   'l' },
115         { "mutualverf",         no_argument,            NULL,   'm' },
116         { "verifydir",          required_argument,      NULL,   'p' },
117         { "crl",                required_argument,      NULL,   'r' },
118         { "verbose",            no_argument,            NULL,   'v' },
119         { NULL,                 0,                      NULL,   0  }
120 };
121
122 int
123 main(int argc, char **argv)
124 {
125         /*
126          * We provide an RPC service on a local-domain socket. The
127          * kernel rpctls code will upcall to this daemon to do the initial
128          * TLS handshake.
129          */
130         struct sockaddr_un sun;
131         int ch, fd, oldmask;
132         SVCXPRT *xprt;
133         bool tls_enable;
134         struct timeval tm;
135         struct timezone tz;
136         pid_t otherpid;
137         size_t tls_enable_len;
138
139         /* Check that another rpctlscd isn't already running. */
140         rpctls_pfh = pidfile_open(_PATH_RPCTLSCDPID, 0600, &otherpid);
141         if (rpctls_pfh == NULL) {
142                 if (errno == EEXIST)
143                         errx(1, "rpctlscd already running, pid: %d.", otherpid);
144                 warn("cannot open or create pidfile");
145         }
146
147         /* Check to see that the ktls is enabled. */
148         tls_enable_len = sizeof(tls_enable);
149         if (sysctlbyname("kern.ipc.tls.enable", &tls_enable, &tls_enable_len,
150             NULL, 0) != 0 || !tls_enable)
151                 errx(1, "Kernel TLS not enabled");
152
153         /* Get the time when this daemon is started. */
154         gettimeofday(&tm, &tz);
155         rpctls_ssl_sec = tm.tv_sec;
156         rpctls_ssl_usec = tm.tv_usec;
157
158         rpctls_verbose = false;
159         while ((ch = getopt_long(argc, argv, "2C:D:dl:mp:r:v", longopts,
160             NULL)) != -1) {
161                 switch (ch) {
162                 case '2':
163                         rpctls_tlsvers = TLS1_2_VERSION;
164                         break;
165                 case 'C':
166                         rpctls_ciphers = optarg;
167                         break;
168                 case 'D':
169                         rpctls_certdir = optarg;
170                         break;
171                 case 'd':
172                         rpctls_debug_level++;
173                         break;
174                 case 'l':
175                         rpctls_verify_cafile = optarg;
176                         break;
177                 case 'm':
178                         rpctls_cert = true;
179                         break;
180                 case 'p':
181                         rpctls_verify_capath = optarg;
182                         break;
183                 case 'r':
184                         rpctls_crlfile = optarg;
185                         break;
186                 case 'v':
187                         rpctls_verbose = true;
188                         break;
189                 default:
190                         fprintf(stderr, "usage: %s "
191                             "[-2/--usetls1_2] "
192                             "[-C/--ciphers available_ciphers] "
193                             "[-D/--certdir certdir] [-d/--debuglevel] "
194                             "[-l/--verifylocs CAfile] [-m/--mutualverf] "
195                             "[-p/--verifydir CApath] [-r/--crl CRLfile] "
196                             "[-v/--verbose]\n", argv[0]);
197                         exit(1);
198                         break;
199                 }
200         }
201         if (rpctls_crlfile != NULL && rpctls_verify_cafile == NULL &&
202             rpctls_verify_capath == NULL)
203                 errx(1, "-r requires the -l <CAfile> and/or "
204                     "-p <CApath> options");
205
206         if (modfind("krpc") < 0) {
207                 /* Not present in kernel, try loading it */
208                 if (kldload("krpc") < 0 || modfind("krpc") < 0)
209                         errx(1, "Kernel RPC is not available");
210         }
211
212         /*
213          * Set up the SSL_CTX *.
214          * Do it now, before daemonizing, in case the private key
215          * is encrypted and requires a passphrase to be entered.
216          */
217         rpctls_ctx = rpctls_setupcl_ssl();
218         if (rpctls_ctx == NULL) {
219                 if (rpctls_debug_level == 0) {
220                         syslog(LOG_ERR, "Can't set up TLS context");
221                         exit(1);
222                 }
223                 err(1, "Can't set up TLS context");
224         }
225         LIST_INIT(&rpctls_ssllist);
226
227         if (!rpctls_debug_level) {
228                 if (daemon(0, 0) != 0)
229                         err(1, "Can't daemonize");
230                 signal(SIGINT, SIG_IGN);
231                 signal(SIGQUIT, SIG_IGN);
232                 signal(SIGHUP, SIG_IGN);
233         }
234         signal(SIGTERM, rpctlscd_terminate);
235         signal(SIGPIPE, SIG_IGN);
236         signal(SIGHUP, rpctls_huphandler);
237
238         pidfile_write(rpctls_pfh);
239
240         memset(&sun, 0, sizeof sun);
241         sun.sun_family = AF_LOCAL;
242         unlink(_PATH_RPCTLSCDSOCK);
243         strcpy(sun.sun_path, _PATH_RPCTLSCDSOCK);
244         sun.sun_len = SUN_LEN(&sun);
245         fd = socket(AF_LOCAL, SOCK_STREAM, 0);
246         if (fd < 0) {
247                 if (rpctls_debug_level == 0) {
248                         syslog(LOG_ERR, "Can't create local rpctlscd socket");
249                         exit(1);
250                 }
251                 err(1, "Can't create local rpctlscd socket");
252         }
253         oldmask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
254         if (bind(fd, (struct sockaddr *)&sun, sun.sun_len) < 0) {
255                 if (rpctls_debug_level == 0) {
256                         syslog(LOG_ERR, "Can't bind local rpctlscd socket");
257                         exit(1);
258                 }
259                 err(1, "Can't bind local rpctlscd socket");
260         }
261         umask(oldmask);
262         if (listen(fd, SOMAXCONN) < 0) {
263                 if (rpctls_debug_level == 0) {
264                         syslog(LOG_ERR,
265                             "Can't listen on local rpctlscd socket");
266                         exit(1);
267                 }
268                 err(1, "Can't listen on local rpctlscd socket");
269         }
270         xprt = svc_vc_create(fd, RPC_MAXDATASIZE, RPC_MAXDATASIZE);
271         if (!xprt) {
272                 if (rpctls_debug_level == 0) {
273                         syslog(LOG_ERR,
274                             "Can't create transport for local rpctlscd socket");
275                         exit(1);
276                 }
277                 err(1, "Can't create transport for local rpctlscd socket");
278         }
279         if (!svc_reg(xprt, RPCTLSCD, RPCTLSCDVERS, rpctlscd_1, NULL)) {
280                 if (rpctls_debug_level == 0) {
281                         syslog(LOG_ERR,
282                             "Can't register service for local rpctlscd socket");
283                         exit(1);
284                 }
285                 err(1, "Can't register service for local rpctlscd socket");
286         }
287
288         rpctls_syscall(RPCTLS_SYSC_CLSETPATH, _PATH_RPCTLSCDSOCK);
289
290         rpctls_svc_run();
291
292         rpctls_syscall(RPCTLS_SYSC_CLSHUTDOWN, "");
293
294         SSL_CTX_free(rpctls_ctx);
295         EVP_cleanup();
296         return (0);
297 }
298
299 bool_t
300 rpctlscd_null_1_svc(__unused void *argp, __unused void *result,
301     __unused struct svc_req *rqstp)
302 {
303
304         rpctls_verbose_out("rpctlscd_null: done\n");
305         return (TRUE);
306 }
307
308 bool_t
309 rpctlscd_connect_1_svc(struct rpctlscd_connect_arg *argp,
310     struct rpctlscd_connect_res *result, __unused struct svc_req *rqstp)
311 {
312         int s;
313         SSL *ssl;
314         struct ssl_entry *newslp;
315         X509 *cert;
316
317         rpctls_verbose_out("rpctlsd_connect: started\n");
318         /* Get the socket fd from the kernel. */
319         s = rpctls_syscall(RPCTLS_SYSC_CLSOCKET, "");
320         if (s < 0) {
321                 result->reterr = RPCTLSERR_NOSOCKET;
322                 return (TRUE);
323         }
324
325         /* Do a TLS connect handshake. */
326         ssl = rpctls_connect(rpctls_ctx, s, argp->certname.certname_val,
327             argp->certname.certname_len, &cert);
328         if (ssl == NULL) {
329                 rpctls_verbose_out("rpctlsd_connect: can't do TLS "
330                     "handshake\n");
331                 result->reterr = RPCTLSERR_NOSSL;
332         } else {
333                 result->reterr = RPCTLSERR_OK;
334                 result->sec = rpctls_ssl_sec;
335                 result->usec = rpctls_ssl_usec;
336                 result->ssl = ++rpctls_ssl_refno;
337                 /* Hard to believe this will ever wrap around.. */
338                 if (rpctls_ssl_refno == 0)
339                         result->ssl = ++rpctls_ssl_refno;
340         }
341
342         if (ssl == NULL) {
343                 /*
344                  * For RPC-over-TLS, this upcall is expected
345                  * to close off the socket.
346                  */
347                 close(s);
348                 return (TRUE);
349         }
350
351         /* Maintain list of all current SSL *'s */
352         newslp = malloc(sizeof(*newslp));
353         newslp->refno = rpctls_ssl_refno;
354         newslp->s = s;
355         newslp->shutoff = false;
356         newslp->ssl = ssl;
357         newslp->cert = cert;
358         LIST_INSERT_HEAD(&rpctls_ssllist, newslp, next);
359         return (TRUE);
360 }
361
362 bool_t
363 rpctlscd_handlerecord_1_svc(struct rpctlscd_handlerecord_arg *argp,
364     struct rpctlscd_handlerecord_res *result, __unused struct svc_req *rqstp)
365 {
366         struct ssl_entry *slp;
367         int ret;
368         char junk;
369
370         slp = NULL;
371         if (argp->sec == rpctls_ssl_sec && argp->usec ==
372             rpctls_ssl_usec) {
373                 LIST_FOREACH(slp, &rpctls_ssllist, next) {
374                         if (slp->refno == argp->ssl)
375                                 break;
376                 }
377         }
378
379         if (slp != NULL) {
380                 rpctls_verbose_out("rpctlscd_handlerecord fd=%d\n",
381                     slp->s);
382                 /*
383                  * An SSL_read() of 0 bytes should fail, but it should
384                  * handle the non-application data record before doing so.
385                  */
386                 ret = SSL_read(slp->ssl, &junk, 0);
387                 if (ret <= 0) {
388                         /* Check to see if this was a close alert. */
389                         ret = SSL_get_shutdown(slp->ssl);
390                         if ((ret & (SSL_SENT_SHUTDOWN |
391                             SSL_RECEIVED_SHUTDOWN)) == SSL_RECEIVED_SHUTDOWN)
392                                 SSL_shutdown(slp->ssl);
393                 } else {
394                         if (rpctls_debug_level == 0)
395                                 syslog(LOG_ERR, "SSL_read returned %d", ret);
396                         else
397                                 fprintf(stderr, "SSL_read returned %d\n", ret);
398                 }
399                 result->reterr = RPCTLSERR_OK;
400         } else
401                 result->reterr = RPCTLSERR_NOSSL;
402         return (TRUE);
403 }
404
405 bool_t
406 rpctlscd_disconnect_1_svc(struct rpctlscd_disconnect_arg *argp,
407     struct rpctlscd_disconnect_res *result, __unused struct svc_req *rqstp)
408 {
409         struct ssl_entry *slp;
410         int ret;
411
412         slp = NULL;
413         if (argp->sec == rpctls_ssl_sec && argp->usec ==
414             rpctls_ssl_usec) {
415                 LIST_FOREACH(slp, &rpctls_ssllist, next) {
416                         if (slp->refno == argp->ssl)
417                                 break;
418                 }
419         }
420
421         if (slp != NULL) {
422                 rpctls_verbose_out("rpctlscd_disconnect: fd=%d closed\n",
423                     slp->s);
424                 LIST_REMOVE(slp, next);
425                 if (!slp->shutoff) {
426                         ret = SSL_get_shutdown(slp->ssl);
427                         /*
428                          * Do an SSL_shutdown() unless a close alert has
429                          * already been sent.
430                          */
431                         if ((ret & SSL_SENT_SHUTDOWN) == 0)
432                                 SSL_shutdown(slp->ssl);
433                 }
434                 SSL_free(slp->ssl);
435                 if (slp->cert != NULL)
436                         X509_free(slp->cert);
437                 /*
438                  * For RPC-over-TLS, this upcall is expected
439                  * to close off the socket.
440                  */
441                 if (!slp->shutoff)
442                         shutdown(slp->s, SHUT_WR);
443                 close(slp->s);
444                 free(slp);
445                 result->reterr = RPCTLSERR_OK;
446         } else
447                 result->reterr = RPCTLSERR_NOCLOSE;
448         return (TRUE);
449 }
450
451 int
452 rpctlscd_1_freeresult(__unused SVCXPRT *transp, __unused xdrproc_t xdr_result,
453     __unused caddr_t result)
454 {
455
456         return (TRUE);
457 }
458
459 static void
460 rpctlscd_terminate(int sig __unused)
461 {
462
463         rpctls_syscall(RPCTLS_SYSC_CLSHUTDOWN, "");
464         pidfile_remove(rpctls_pfh);
465         exit(0);
466 }
467
468 static SSL_CTX *
469 rpctls_setupcl_ssl(void)
470 {
471         SSL_CTX *ctx;
472         char path[PATH_MAX];
473         size_t len, rlen;
474         int ret;
475
476         SSL_library_init();
477         SSL_load_error_strings();
478         OpenSSL_add_all_algorithms();
479
480         ctx = SSL_CTX_new(TLS_client_method());
481         if (ctx == NULL) {
482                 rpctls_verbose_out("rpctls_setupcl_ssl: SSL_CTX_new "
483                     "failed\n");
484                 return (NULL);
485         }
486         SSL_CTX_set_ecdh_auto(ctx, 1);
487
488         if (rpctls_ciphers != NULL) {
489                 /*
490                  * Set available ciphers, since KERN_TLS only supports a
491                  * few of them.
492                  */
493                 ret = SSL_CTX_set_ciphersuites(ctx, rpctls_ciphers);
494                 if (ret == 0) {
495                         rpctls_verbose_out("rpctls_setupcl_ssl: "
496                             "SSL_CTX_set_ciphersuites failed: %s\n",
497                             rpctls_ciphers);
498                         SSL_CTX_free(ctx);
499                         return (NULL);
500                 }
501         }
502
503         /*
504          * If rpctls_cert is true, a certificate and key exists in
505          * rpctls_certdir, so that it can do mutual authentication.
506          */
507         if (rpctls_cert) {
508                 /* Get the cert.pem and certkey.pem files. */
509                 len = strlcpy(path, rpctls_certdir, sizeof(path));
510                 rlen = sizeof(path) - len;
511                 if (strlcpy(&path[len], "cert.pem", rlen) != 8) {
512                         SSL_CTX_free(ctx);
513                         return (NULL);
514                 }
515                 ret = SSL_CTX_use_certificate_file(ctx, path,
516                     SSL_FILETYPE_PEM);
517                 if (ret != 1) {
518                         rpctls_verbose_out("rpctls_setupcl_ssl: can't use "
519                             "certificate file path=%s ret=%d\n", path, ret);
520                         SSL_CTX_free(ctx);
521                         return (NULL);
522                 }
523                 if (strlcpy(&path[len], "certkey.pem", rlen) != 11) {
524                         SSL_CTX_free(ctx);
525                         return (NULL);
526                 }
527                 ret = SSL_CTX_use_PrivateKey_file(ctx, path,
528                     SSL_FILETYPE_PEM);
529                 if (ret != 1) {
530                         rpctls_verbose_out("rpctls_setupcl_ssl: Can't use "
531                             "private key path=%s ret=%d\n", path, ret);
532                         SSL_CTX_free(ctx);
533                         return (NULL);
534                 }
535         }
536
537         if (rpctls_verify_cafile != NULL || rpctls_verify_capath != NULL) {
538                 if (rpctls_crlfile != NULL) {
539                         ret = rpctls_loadcrlfile(ctx);
540                         if (ret == 0) {
541                                 rpctls_verbose_out("rpctls_setupcl_ssl: "
542                                     "Load CRLfile failed\n");
543                                 SSL_CTX_free(ctx);
544                                 return (NULL);
545                         }
546                 }
547 #if OPENSSL_VERSION_NUMBER >= 0x30000000
548                 ret = 1;
549                 if (rpctls_verify_cafile != NULL)
550                         ret = SSL_CTX_load_verify_file(ctx,
551                             rpctls_verify_cafile);
552                 if (ret != 0 && rpctls_verify_capath != NULL)
553                         ret = SSL_CTX_load_verify_dir(ctx,
554                             rpctls_verify_capath);
555 #else
556                 ret = SSL_CTX_load_verify_locations(ctx,
557                     rpctls_verify_cafile, rpctls_verify_capath);
558 #endif
559                 if (ret == 0) {
560                         rpctls_verbose_out("rpctls_setupcl_ssl: "
561                             "Can't load verify locations\n");
562                         SSL_CTX_free(ctx);
563                         return (NULL);
564                 }
565                 /*
566                  * The man page says that the
567                  * SSL_CTX_set0_CA_list() call is not normally
568                  * needed, but I believe it is harmless.
569                  */
570                 if (rpctls_verify_cafile != NULL)
571                         SSL_CTX_set0_CA_list(ctx,
572                             SSL_load_client_CA_file(rpctls_verify_cafile));
573         }
574
575         /*
576          * The RFC specifies that RPC-over-TLS must use TLS1.3.
577          * However, early FreeBSD versions (13.0, 13.1) did not
578          * support RX for KTLS1.3, so TLS1.2 needs to be used for
579          * these servers.
580          */
581         ret = SSL_CTX_set_min_proto_version(ctx, rpctls_tlsvers);
582         if (ret == 0) {
583                 rpctls_verbose_out("rpctls_setupcl_ssl: "
584                     "SSL_CTX_set_min_proto_version failed\n");
585                 SSL_CTX_free(ctx);
586                 return (NULL);
587         }
588         ret = SSL_CTX_set_max_proto_version(ctx, rpctls_tlsvers);
589         if (ret == 0) {
590                 rpctls_verbose_out("rpctls_setupcl_ssl: "
591                     "SSL_CTX_set_max_proto_version failed\n");
592                 SSL_CTX_free(ctx);
593                 return (NULL);
594         }
595
596 #ifdef SSL_OP_ENABLE_KTLS
597         SSL_CTX_set_options(ctx, SSL_OP_ENABLE_KTLS);
598 #endif
599 #ifdef SSL_MODE_NO_KTLS_TX
600         SSL_CTX_clear_mode(ctx, SSL_MODE_NO_KTLS_TX | SSL_MODE_NO_KTLS_RX);
601 #endif
602         return (ctx);
603 }
604
605 static SSL *
606 rpctls_connect(SSL_CTX *ctx, int s, char *certname, u_int certlen, X509 **certp)
607 {
608         SSL *ssl;
609         X509 *cert;
610         struct sockaddr_storage ad;
611         struct sockaddr *sad;
612         char hostnam[NI_MAXHOST], path[PATH_MAX];
613         int gethostret, ret;
614         char *cp, *cp2;
615         size_t len, rlen;
616         long verfret;
617
618         *certp = NULL;
619         sad = (struct sockaddr *)&ad;
620         ssl = SSL_new(ctx);
621         if (ssl == NULL) {
622                 rpctls_verbose_out("rpctls_connect: "
623                     "SSL_new failed\n");
624                 return (NULL);
625         }
626         if (SSL_set_fd(ssl, s) != 1) {
627                 rpctls_verbose_out("rpctls_connect: "
628                     "SSL_set_fd failed\n");
629                 SSL_free(ssl);
630                 return (NULL);
631         }
632
633         /*
634          * If rpctls_cert is true and certname is set, a alternate certificate
635          * and key exists in files named <certname>.pem and <certname>key.pem
636          * in rpctls_certdir that is to be used for mutual authentication.
637          */
638         if (rpctls_cert && certlen > 0) {
639                 len = strlcpy(path, rpctls_certdir, sizeof(path));
640                 rlen = sizeof(path) - len;
641                 if (rlen <= certlen) {
642                         SSL_free(ssl);
643                         return (NULL);
644                 }
645                 memcpy(&path[len], certname, certlen);
646                 rlen -= certlen;
647                 len += certlen;
648                 path[len] = '\0';
649                 if (strlcpy(&path[len], ".pem", rlen) != 4) {
650                         SSL_free(ssl);
651                         return (NULL);
652                 }
653                 ret = SSL_use_certificate_file(ssl, path, SSL_FILETYPE_PEM);
654                 if (ret != 1) {
655                         rpctls_verbose_out("rpctls_connect: can't use "
656                             "certificate file path=%s ret=%d\n", path, ret);
657                         SSL_free(ssl);
658                         return (NULL);
659                 }
660                 if (strlcpy(&path[len], "key.pem", rlen) != 7) {
661                         SSL_free(ssl);
662                         return (NULL);
663                 }
664                 ret = SSL_use_PrivateKey_file(ssl, path, SSL_FILETYPE_PEM);
665                 if (ret != 1) {
666                         rpctls_verbose_out("rpctls_connect: Can't use "
667                             "private key path=%s ret=%d\n", path, ret);
668                         SSL_free(ssl);
669                         return (NULL);
670                 }
671         }
672
673         ret = SSL_connect(ssl);
674         if (ret != 1) {
675                 rpctls_verbose_out("rpctls_connect: "
676                     "SSL_connect failed %d\n",
677                     ret);
678                 SSL_free(ssl);
679                 return (NULL);
680         }
681
682         cert = SSL_get_peer_certificate(ssl);
683         if (cert == NULL) {
684                 rpctls_verbose_out("rpctls_connect: get peer"
685                     " certificate failed\n");
686                 SSL_free(ssl);
687                 return (NULL);
688         }
689         gethostret = rpctls_gethost(s, sad, hostnam, sizeof(hostnam));
690         if (gethostret == 0)
691                 hostnam[0] = '\0';
692         verfret = SSL_get_verify_result(ssl);
693         if (verfret == X509_V_OK && (rpctls_verify_cafile != NULL ||
694             rpctls_verify_capath != NULL) && (gethostret == 0 ||
695             rpctls_checkhost(sad, cert, X509_CHECK_FLAG_NO_WILDCARDS) != 1))
696                 verfret = X509_V_ERR_HOSTNAME_MISMATCH;
697         if (verfret != X509_V_OK && (rpctls_verify_cafile != NULL ||
698             rpctls_verify_capath != NULL)) {
699                 if (verfret != X509_V_OK) {
700                         cp = X509_NAME_oneline(X509_get_issuer_name(cert),
701                             NULL, 0);
702                         cp2 = X509_NAME_oneline(X509_get_subject_name(cert),
703                             NULL, 0);
704                         if (rpctls_debug_level == 0)
705                                 syslog(LOG_INFO | LOG_DAEMON,
706                                     "rpctls_connect: client IP %s "
707                                     "issuerName=%s subjectName=%s verify "
708                                     "failed %s\n", hostnam, cp, cp2,
709                                     X509_verify_cert_error_string(verfret));
710                         else
711                                 fprintf(stderr,
712                                     "rpctls_connect: client IP %s "
713                                     "issuerName=%s subjectName=%s verify "
714                                     "failed %s\n", hostnam, cp, cp2,
715                                     X509_verify_cert_error_string(verfret));
716                 }
717                 X509_free(cert);
718                 SSL_free(ssl);
719                 return (NULL);
720         }
721
722         /* Check to see if ktls is enabled on the connection. */
723         ret = BIO_get_ktls_send(SSL_get_wbio(ssl));
724         rpctls_verbose_out("rpctls_connect: BIO_get_ktls_send=%d\n", ret);
725         if (ret != 0) {
726                 ret = BIO_get_ktls_recv(SSL_get_rbio(ssl));
727                 rpctls_verbose_out("rpctls_connect: BIO_get_ktls_recv=%d\n",
728                     ret);
729         }
730         if (ret == 0) {
731                 if (rpctls_debug_level == 0)
732                         syslog(LOG_ERR, "ktls not working\n");
733                 else
734                         fprintf(stderr, "ktls not working\n");
735                 X509_free(cert);
736                 SSL_free(ssl);
737                 return (NULL);
738         }
739         if (ret == X509_V_OK && (rpctls_verify_cafile != NULL ||
740             rpctls_verify_capath != NULL) && rpctls_crlfile != NULL)
741                 *certp = cert;
742         else
743                 X509_free(cert);
744
745         return (ssl);
746 }
747
748 static void
749 rpctls_huphandler(int sig __unused)
750 {
751
752         rpctls_gothup = true;
753 }