]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/rpc.tlsservd/rpc.tlsservd.c
vmm: fix "set but not used" warnings
[FreeBSD/FreeBSD.git] / usr.sbin / rpc.tlsservd / rpc.tlsservd.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 server 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/linker.h>
41 #include <sys/module.h>
42 #include <sys/queue.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 <pwd.h>
52 #include <signal.h>
53 #include <stdarg.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <stdbool.h>
57 #include <string.h>
58 #include <unistd.h>
59
60 #include <rpc/rpc.h>
61 #include <rpc/rpc_com.h>
62 #include <rpc/rpcsec_tls.h>
63
64 #include <openssl/opensslconf.h>
65 #include <openssl/bio.h>
66 #include <openssl/ssl.h>
67 #include <openssl/err.h>
68 #include <openssl/x509v3.h>
69
70 #include "rpctlssd.h"
71 #include "rpc.tlscommon.h"
72
73 #ifndef _PATH_RPCTLSSDSOCK
74 #define _PATH_RPCTLSSDSOCK      "/var/run/rpc.tlsservd.sock"
75 #endif
76 #ifndef _PATH_CERTANDKEY
77 #define _PATH_CERTANDKEY        "/etc/rpc.tlsservd/"
78 #endif
79 #ifndef _PATH_RPCTLSSDPID
80 #define _PATH_RPCTLSSDPID       "/var/run/rpc.tlsservd.pid"
81 #endif
82 #ifndef _PREFERRED_CIPHERS
83 #define _PREFERRED_CIPHERS      "AES128-GCM-SHA256"
84 #endif
85
86 /* Global variables also used by rpc.tlscommon.c. */
87 int                     rpctls_debug_level;
88 bool                    rpctls_verbose;
89 SSL_CTX                 *rpctls_ctx = NULL;
90 const char              *rpctls_verify_cafile = NULL;
91 const char              *rpctls_verify_capath = NULL;
92 char                    *rpctls_crlfile = NULL;
93 bool                    rpctls_gothup = false;
94 struct ssl_list         rpctls_ssllist;
95
96 static struct pidfh     *rpctls_pfh = NULL;
97 static bool             rpctls_do_mutual = false;
98 static const char       *rpctls_certdir = _PATH_CERTANDKEY;
99 static bool             rpctls_comparehost = false;
100 static unsigned int     rpctls_wildcard = X509_CHECK_FLAG_NO_WILDCARDS;
101 static uint64_t         rpctls_ssl_refno = 0;
102 static uint64_t         rpctls_ssl_sec = 0;
103 static uint64_t         rpctls_ssl_usec = 0;
104 static bool             rpctls_cnuser = false;
105 static char             *rpctls_dnsname;
106 static const char       *rpctls_cnuseroid = "1.3.6.1.4.1.2238.1.1.1";
107 static const char       *rpctls_ciphers = NULL;
108 static int              rpctls_mintls = TLS1_3_VERSION;
109
110 static void             rpctlssd_terminate(int);
111 static SSL_CTX          *rpctls_setup_ssl(const char *certdir);
112 static SSL              *rpctls_server(SSL_CTX *ctx, int s,
113                             uint32_t *flags, uint32_t *uidp,
114                             int *ngrps, uint32_t *gidp, X509 **certp);
115 static int              rpctls_cnname(X509 *cert, uint32_t *uidp,
116                             int *ngrps, uint32_t *gidp);
117 static char             *rpctls_getdnsname(char *dnsname);
118 static void             rpctls_huphandler(int sig __unused);
119
120 extern void             rpctlssd_1(struct svc_req *rqstp, SVCXPRT *transp);
121
122 static struct option longopts[] = {
123         { "allowtls1_2",        no_argument,            NULL,   '2' },
124         { "ciphers",            required_argument,      NULL,   'C' },
125         { "certdir",            required_argument,      NULL,   'D' },
126         { "debuglevel",         no_argument,            NULL,   'd' },
127         { "checkhost",          no_argument,            NULL,   'h' },
128         { "verifylocs",         required_argument,      NULL,   'l' },
129         { "mutualverf",         no_argument,            NULL,   'm' },
130         { "domain",             required_argument,      NULL,   'n' },
131         { "verifydir",          required_argument,      NULL,   'p' },
132         { "crl",                required_argument,      NULL,   'r' },
133         { "certuser",           no_argument,            NULL,   'u' },
134         { "verbose",            no_argument,            NULL,   'v' },
135         { "multiwild",          no_argument,            NULL,   'W' },
136         { "singlewild",         no_argument,            NULL,   'w' },
137         { NULL,                 0,                      NULL,   0  }
138 };
139
140 int
141 main(int argc, char **argv)
142 {
143         /*
144          * We provide an RPC service on a local-domain socket. The
145          * kernel rpctls code will upcall to this daemon to do the initial
146          * TLS handshake.
147          */
148         struct sockaddr_un sun;
149         int ch, fd, oldmask;
150         SVCXPRT *xprt;
151         struct timeval tm;
152         struct timezone tz;
153         char hostname[MAXHOSTNAMELEN + 2];
154         pid_t otherpid;
155         bool tls_enable;
156         size_t tls_enable_len;
157
158         /* Check that another rpctlssd isn't already running. */
159         rpctls_pfh = pidfile_open(_PATH_RPCTLSSDPID, 0600, &otherpid);
160         if (rpctls_pfh == NULL) {
161                 if (errno == EEXIST)
162                         errx(1, "rpctlssd already running, pid: %d.", otherpid);
163                 warn("cannot open or create pidfile");
164         }
165
166         /* Check to see that the ktls is enabled. */
167         tls_enable_len = sizeof(tls_enable);
168         if (sysctlbyname("kern.ipc.tls.enable", &tls_enable, &tls_enable_len,
169             NULL, 0) != 0 || !tls_enable)
170                 errx(1, "Kernel TLS not enabled");
171
172         /* Get the time when this daemon is started. */
173         gettimeofday(&tm, &tz);
174         rpctls_ssl_sec = tm.tv_sec;
175         rpctls_ssl_usec = tm.tv_usec;
176
177         /* Set the dns name for the server. */
178         rpctls_dnsname = rpctls_getdnsname(hostname);
179         if (rpctls_dnsname == NULL) {
180                 strcpy(hostname, "@default.domain");
181                 rpctls_dnsname = hostname;
182         }
183
184         rpctls_verbose = false;
185         while ((ch = getopt_long(argc, argv, "2C:D:dhl:n:mp:r:uvWw", longopts,
186             NULL)) != -1) {
187                 switch (ch) {
188                 case '2':
189                         rpctls_mintls = TLS1_2_VERSION;
190                         break;
191                 case 'C':
192                         rpctls_ciphers = optarg;
193                         break;
194                 case 'D':
195                         rpctls_certdir = optarg;
196                         break;
197                 case 'd':
198                         rpctls_debug_level++;
199                         break;
200                 case 'h':
201                         rpctls_comparehost = true;
202                         break;
203                 case 'l':
204                         rpctls_verify_cafile = optarg;
205                         break;
206                 case 'm':
207                         rpctls_do_mutual = true;
208                         break;
209                 case 'n':
210                         hostname[0] = '@';
211                         strlcpy(&hostname[1], optarg, MAXHOSTNAMELEN + 1);
212                         rpctls_dnsname = hostname;
213                         break;
214                 case 'p':
215                         rpctls_verify_capath = optarg;
216                         break;
217                 case 'r':
218                         rpctls_crlfile = optarg;
219                         break;
220                 case 'u':
221                         rpctls_cnuser = true;
222                         break;
223                 case 'v':
224                         rpctls_verbose = true;
225                         break;
226                 case 'W':
227                         if (rpctls_wildcard != X509_CHECK_FLAG_NO_WILDCARDS)
228                                 errx(1, "options -w and -W are mutually "
229                                     "exclusive");
230                         rpctls_wildcard = X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS;
231                         break;
232                 case 'w':
233                         if (rpctls_wildcard != X509_CHECK_FLAG_NO_WILDCARDS)
234                                 errx(1, "options -w and -W are mutually "
235                                     "exclusive");
236                         rpctls_wildcard = 0;
237                         break;
238                 default:
239                         fprintf(stderr, "usage: %s "
240                             "[-2/--allowtls1_2] "
241                             "[-C/--ciphers available_ciphers] "
242                             "[-D/--certdir certdir] [-d/--debuglevel] "
243                             "[-h/--checkhost] "
244                             "[-l/--verifylocs CAfile] [-m/--mutualverf] "
245                             "[-n/--domain domain_name] "
246                             "[-p/--verifydir CApath] [-r/--crl CRLfile] "
247                             "[-u/--certuser] [-v/--verbose] [-W/--multiwild] "
248                             "[-w/--singlewild]\n", argv[0]);
249                         exit(1);
250                 }
251         }
252         if (rpctls_do_mutual && rpctls_verify_cafile == NULL &&
253             rpctls_verify_capath == NULL)
254                 errx(1, "-m requires the -l <CAfile> and/or "
255                     "-p <CApath> options");
256         if (rpctls_comparehost && (!rpctls_do_mutual ||
257             (rpctls_verify_cafile == NULL && rpctls_verify_capath == NULL)))
258                 errx(1, "-h requires the -m plus the "
259                     "-l <CAfile> and/or -p <CApath> options");
260         if (!rpctls_comparehost && rpctls_wildcard !=
261             X509_CHECK_FLAG_NO_WILDCARDS)
262                 errx(1, "The -w or -W options require the -h option");
263         if (rpctls_cnuser && (!rpctls_do_mutual ||
264             (rpctls_verify_cafile == NULL && rpctls_verify_capath == NULL)))
265                 errx(1, "-u requires the -m plus the "
266                     "-l <CAfile> and/or -p <CApath> options");
267
268         if (modfind("krpc") < 0) {
269                 /* Not present in kernel, try loading it */
270                 if (kldload("krpc") < 0 || modfind("krpc") < 0)
271                         errx(1, "Kernel RPC is not available");
272         }
273
274         if (rpctls_debug_level == 0) {
275                 if (daemon(0, 0) != 0)
276                         err(1, "Can't daemonize");
277                 signal(SIGINT, SIG_IGN);
278                 signal(SIGQUIT, SIG_IGN);
279                 signal(SIGHUP, SIG_IGN);
280         }
281         signal(SIGTERM, rpctlssd_terminate);
282         signal(SIGPIPE, SIG_IGN);
283         signal(SIGHUP, rpctls_huphandler);
284
285         pidfile_write(rpctls_pfh);
286
287         memset(&sun, 0, sizeof sun);
288         sun.sun_family = AF_LOCAL;
289         unlink(_PATH_RPCTLSSDSOCK);
290         strcpy(sun.sun_path, _PATH_RPCTLSSDSOCK);
291         sun.sun_len = SUN_LEN(&sun);
292         fd = socket(AF_LOCAL, SOCK_STREAM, 0);
293         if (fd < 0) {
294                 if (rpctls_debug_level == 0) {
295                         syslog(LOG_ERR, "Can't create local rpctlssd socket");
296                         exit(1);
297                 }
298                 err(1, "Can't create local rpctlssd socket");
299         }
300         oldmask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
301         if (bind(fd, (struct sockaddr *)&sun, sun.sun_len) < 0) {
302                 if (rpctls_debug_level == 0) {
303                         syslog(LOG_ERR, "Can't bind local rpctlssd socket");
304                         exit(1);
305                 }
306                 err(1, "Can't bind local rpctlssd socket");
307         }
308         umask(oldmask);
309         if (listen(fd, SOMAXCONN) < 0) {
310                 if (rpctls_debug_level == 0) {
311                         syslog(LOG_ERR,
312                             "Can't listen on local rpctlssd socket");
313                         exit(1);
314                 }
315                 err(1, "Can't listen on local rpctlssd socket");
316         }
317         xprt = svc_vc_create(fd, RPC_MAXDATASIZE, RPC_MAXDATASIZE);
318         if (!xprt) {
319                 if (rpctls_debug_level == 0) {
320                         syslog(LOG_ERR,
321                             "Can't create transport for local rpctlssd socket");
322                         exit(1);
323                 }
324                 err(1, "Can't create transport for local rpctlssd socket");
325         }
326         if (!svc_reg(xprt, RPCTLSSD, RPCTLSSDVERS, rpctlssd_1, NULL)) {
327                 if (rpctls_debug_level == 0) {
328                         syslog(LOG_ERR,
329                             "Can't register service for local rpctlssd socket");
330                         exit(1);
331                 }
332                 err(1, "Can't register service for local rpctlssd socket");
333         }
334
335         rpctls_ctx = rpctls_setup_ssl(rpctls_certdir);
336         if (rpctls_ctx == NULL) {
337                 if (rpctls_debug_level == 0) {
338                         syslog(LOG_ERR, "Can't create SSL context");
339                         exit(1);
340                 }
341                 err(1, "Can't create SSL context");
342         }
343         rpctls_gothup = false;
344         LIST_INIT(&rpctls_ssllist);
345
346         if (rpctls_syscall(RPCTLS_SYSC_SRVSETPATH, _PATH_RPCTLSSDSOCK) < 0) {
347                 if (rpctls_debug_level == 0) {
348                         syslog(LOG_ERR,
349                             "Can't set upcall socket errno=%d", errno);
350                         exit(1);
351                 }
352                 err(1, "Can't set upcall socket");
353         }
354
355         rpctls_svc_run();
356
357         rpctls_syscall(RPCTLS_SYSC_SRVSHUTDOWN, "");
358
359         SSL_CTX_free(rpctls_ctx);
360         EVP_cleanup();
361         return (0);
362 }
363
364 bool_t
365 rpctlssd_null_1_svc(__unused void *argp, __unused void *result,
366     __unused struct svc_req *rqstp)
367 {
368
369         rpctls_verbose_out("rpctlssd_null_svc: done\n");
370         return (TRUE);
371 }
372
373 bool_t
374 rpctlssd_connect_1_svc(__unused void *argp,
375     struct rpctlssd_connect_res *result, __unused struct svc_req *rqstp)
376 {
377         int ngrps, s;
378         SSL *ssl;
379         uint32_t flags;
380         struct ssl_entry *newslp;
381         uint32_t uid;
382         uint32_t *gidp;
383         X509 *cert;
384
385         rpctls_verbose_out("rpctlsd_connect_svc: started\n");
386         memset(result, 0, sizeof(*result));
387         /* Get the socket fd from the kernel. */
388         s = rpctls_syscall(RPCTLS_SYSC_SRVSOCKET, "");
389         if (s < 0)
390                 return (FALSE);
391
392         /* Do the server side of a TLS handshake. */
393         gidp = calloc(NGROUPS, sizeof(*gidp));
394         ssl = rpctls_server(rpctls_ctx, s, &flags, &uid, &ngrps, gidp, &cert);
395         if (ssl == NULL) {
396                 free(gidp);
397                 rpctls_verbose_out("rpctlssd_connect_svc: ssl "
398                     "accept failed\n");
399                 /*
400                  * For RPC-over-TLS, this upcall is expected
401                  * to close off the socket upon handshake failure.
402                  */
403                 close(s);
404                 return (FALSE);
405         } else {
406                 rpctls_verbose_out("rpctlssd_connect_svc: "
407                     "succeeded flags=0x%x\n", flags);
408                 result->flags = flags;
409                 result->sec = rpctls_ssl_sec;
410                 result->usec = rpctls_ssl_usec;
411                 result->ssl = ++rpctls_ssl_refno;
412                 /* Hard to believe this could ever wrap around.. */
413                 if (rpctls_ssl_refno == 0)
414                         result->ssl = ++rpctls_ssl_refno;
415                 if ((flags & RPCTLS_FLAGS_CERTUSER) != 0) {
416                         result->uid = uid;
417                         result->gid.gid_len = ngrps;
418                         result->gid.gid_val = gidp;
419                 } else {
420                         result->uid = 0;
421                         result->gid.gid_len = 0;
422                         result->gid.gid_val = gidp;
423                 }
424         }
425
426         /* Maintain list of all current SSL *'s */
427         newslp = malloc(sizeof(*newslp));
428         newslp->ssl = ssl;
429         newslp->s = s;
430         newslp->shutoff = false;
431         newslp->refno = rpctls_ssl_refno;
432         newslp->cert = cert;
433         LIST_INSERT_HEAD(&rpctls_ssllist, newslp, next);
434         return (TRUE);
435 }
436
437 bool_t
438 rpctlssd_handlerecord_1_svc(struct rpctlssd_handlerecord_arg *argp,
439     struct rpctlssd_handlerecord_res *result, __unused struct svc_req *rqstp)
440 {
441         struct ssl_entry *slp;
442         int ret;
443         char junk;
444
445         slp = NULL;
446         if (argp->sec == rpctls_ssl_sec && argp->usec ==
447             rpctls_ssl_usec) {
448                 LIST_FOREACH(slp, &rpctls_ssllist, next) {
449                         if (slp->refno == argp->ssl)
450                                 break;
451                 }
452         }
453
454         if (slp != NULL) {
455                 rpctls_verbose_out("rpctlssd_handlerecord fd=%d\n",
456                     slp->s);
457                 /*
458                  * An SSL_read() of 0 bytes should fail, but it should
459                  * handle the non-application data record before doing so.
460                  */
461                 ret = SSL_read(slp->ssl, &junk, 0);
462                 if (ret <= 0) {
463                         /* Check to see if this was a close alert. */
464                         ret = SSL_get_shutdown(slp->ssl);
465                         if ((ret & (SSL_SENT_SHUTDOWN |
466                             SSL_RECEIVED_SHUTDOWN)) == SSL_RECEIVED_SHUTDOWN)
467                                 SSL_shutdown(slp->ssl);
468                 } else {
469                         if (rpctls_debug_level == 0)
470                                 syslog(LOG_ERR, "SSL_read returned %d", ret);
471                         else
472                                 fprintf(stderr, "SSL_read returned %d\n", ret);
473                 }
474                 result->reterr = RPCTLSERR_OK;
475         } else
476                 result->reterr = RPCTLSERR_NOSSL;
477         return (TRUE);
478 }
479
480 bool_t
481 rpctlssd_disconnect_1_svc(struct rpctlssd_disconnect_arg *argp,
482     struct rpctlssd_disconnect_res *result, __unused struct svc_req *rqstp)
483 {
484         struct ssl_entry *slp;
485         int ret;
486
487         slp = NULL;
488         if (argp->sec == rpctls_ssl_sec && argp->usec ==
489             rpctls_ssl_usec) {
490                 LIST_FOREACH(slp, &rpctls_ssllist, next) {
491                         if (slp->refno == argp->ssl)
492                                 break;
493                 }
494         }
495
496         if (slp != NULL) {
497                 rpctls_verbose_out("rpctlssd_disconnect fd=%d closed\n",
498                     slp->s);
499                 LIST_REMOVE(slp, next);
500                 if (!slp->shutoff) {
501                         ret = SSL_get_shutdown(slp->ssl);
502                         /*
503                          * Do an SSL_shutdown() unless a close alert has
504                          * already been sent.
505                          */
506                         if ((ret & SSL_SENT_SHUTDOWN) == 0)
507                                 SSL_shutdown(slp->ssl);
508                 }
509                 SSL_free(slp->ssl);
510                 if (slp->cert != NULL)
511                         X509_free(slp->cert);
512                 /*
513                  * For RPC-over-TLS, this upcall is expected
514                  * to close off the socket.
515                  */
516                 if (!slp->shutoff)
517                         shutdown(slp->s, SHUT_WR);
518                 close(slp->s);
519                 free(slp);
520                 result->reterr = RPCTLSERR_OK;
521         } else
522                 result->reterr = RPCTLSERR_NOCLOSE;
523         return (TRUE);
524 }
525
526 int
527 rpctlssd_1_freeresult(__unused SVCXPRT *transp, xdrproc_t xdr_result,
528     caddr_t result)
529 {
530         rpctlssd_connect_res *res;
531
532         if (xdr_result == (xdrproc_t)xdr_rpctlssd_connect_res) {
533                 res = (rpctlssd_connect_res *)(void *)result;
534                 free(res->gid.gid_val);
535         }
536         return (TRUE);
537 }
538
539 static void
540 rpctlssd_terminate(int sig __unused)
541 {
542         struct ssl_entry *slp;
543
544         rpctls_syscall(RPCTLS_SYSC_SRVSHUTDOWN, "");
545         pidfile_remove(rpctls_pfh);
546
547         LIST_FOREACH(slp, &rpctls_ssllist, next)
548                 shutdown(slp->s, SHUT_RD);
549         exit(0);
550 }
551
552 /* Allow the handshake to proceed. */
553 static int
554 rpctls_verify_callback(__unused int preverify_ok,
555     __unused X509_STORE_CTX *x509_ctx)
556 {
557
558         return (1);
559 }
560
561 static SSL_CTX *
562 rpctls_setup_ssl(const char *certdir)
563 {
564         SSL_CTX *ctx;
565         char path[PATH_MAX];
566         size_t len, rlen;
567         int ret;
568
569         SSL_library_init();
570         SSL_load_error_strings();
571         OpenSSL_add_all_algorithms();
572
573         ctx = SSL_CTX_new(TLS_server_method());
574         if (ctx == NULL) {
575                 rpctls_verbose_out("rpctls_setup_ssl: SSL_CTX_new failed\n");
576                 return (NULL);
577         }
578         SSL_CTX_set_ecdh_auto(ctx, 1);
579
580         if (rpctls_ciphers != NULL) {
581                 /*
582                  * Set available ciphers, since KERN_TLS only supports a
583                  * few of them.  Normally, not doing this should be ok,
584                  * since the library defaults will work.
585                  */
586                 ret = SSL_CTX_set_ciphersuites(ctx, rpctls_ciphers);
587                 if (ret == 0) {
588                         rpctls_verbose_out("rpctls_setup_ssl: "
589                             "SSL_CTX_set_ciphersuites failed: %s\n",
590                             rpctls_ciphers);
591                         SSL_CTX_free(ctx);
592                         return (NULL);
593                 }
594         }
595
596         ret = SSL_CTX_set_min_proto_version(ctx, rpctls_mintls);
597         if (ret == 0) {
598                 rpctls_verbose_out("rpctls_setup_ssl: "
599                     "SSL_CTX_set_min_proto_version failed\n");
600                 SSL_CTX_free(ctx);
601                 return (NULL);
602         }
603         ret = SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION);
604         if (ret == 0) {
605                 rpctls_verbose_out("rpctls_setup_ssl: "
606                     "SSL_CTX_set_max_proto_version failed\n");
607                 SSL_CTX_free(ctx);
608                 return (NULL);
609         }
610
611         /* Get the cert.pem and certkey.pem files from the directory certdir. */
612         len = strlcpy(path, certdir, sizeof(path));
613         rlen = sizeof(path) - len;
614         if (strlcpy(&path[len], "cert.pem", rlen) != 8) {
615                 SSL_CTX_free(ctx);
616                 return (NULL);
617         }
618         ret = SSL_CTX_use_certificate_file(ctx, path, SSL_FILETYPE_PEM);
619         if (ret != 1) {
620                 rpctls_verbose_out("rpctls_setup_ssl: can't use certificate "
621                     "file path=%s ret=%d\n", path, ret);
622                 SSL_CTX_free(ctx);
623                 return (NULL);
624         }
625         if (strlcpy(&path[len], "certkey.pem", rlen) != 11) {
626                 SSL_CTX_free(ctx);
627                 return (NULL);
628         }
629         ret = SSL_CTX_use_PrivateKey_file(ctx, path, SSL_FILETYPE_PEM);
630         if (ret != 1) {
631                 rpctls_verbose_out("rpctls_setup_ssl: Can't use private "
632                     "key path=%s ret=%d\n", path, ret);
633                 SSL_CTX_free(ctx);
634                 return (NULL);
635         }
636
637         /* Set Mutual authentication, as required. */
638         if (rpctls_do_mutual) {
639                 if (rpctls_verify_cafile != NULL ||
640                     rpctls_verify_capath != NULL) {
641                         if (rpctls_crlfile != NULL) {
642                                 ret = rpctls_loadcrlfile(ctx);
643                                 if (ret == 0) {
644                                         rpctls_verbose_out("rpctls_setup_ssl:"
645                                             " Load CRLfile failed\n");
646                                         SSL_CTX_free(ctx);
647                                         return (NULL);
648                                 }
649                         }
650 #if OPENSSL_VERSION_NUMBER >= 0x30000000
651                         ret = 1;
652                         if (rpctls_verify_cafile != NULL)
653                                 ret = SSL_CTX_load_verify_file(ctx,
654                                     rpctls_verify_cafile);
655                         if (ret != 0 && rpctls_verify_capath != NULL)
656                                 ret = SSL_CTX_load_verify_dir(ctx,
657                                     rpctls_verify_capath);
658 #else
659                         ret = SSL_CTX_load_verify_locations(ctx,
660                             rpctls_verify_cafile, rpctls_verify_capath);
661 #endif
662                         if (ret == 0) {
663                                 rpctls_verbose_out("rpctls_setup_ssl: "
664                                     "Can't load verify locations\n");
665                                 SSL_CTX_free(ctx);
666                                 return (NULL);
667                         }
668                         if (rpctls_verify_cafile != NULL)
669                                 SSL_CTX_set_client_CA_list(ctx,
670                                     SSL_load_client_CA_file(
671                             rpctls_verify_cafile));
672                 }
673                 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER,
674                     rpctls_verify_callback);
675         }
676 #ifdef SSL_OP_ENABLE_KTLS
677         SSL_CTX_set_options(ctx, SSL_OP_ENABLE_KTLS);
678 #endif
679 #ifdef SSL_MODE_NO_KTLS_TX
680         SSL_CTX_clear_mode(ctx, SSL_MODE_NO_KTLS_TX | SSL_MODE_NO_KTLS_RX);
681 #endif
682         return (ctx);
683 }
684
685 static SSL *
686 rpctls_server(SSL_CTX *ctx, int s, uint32_t *flags, uint32_t *uidp,
687     int *ngrps, uint32_t *gidp, X509 **certp)
688 {
689         SSL *ssl;
690         X509 *cert;
691         struct sockaddr *sad;
692         struct sockaddr_storage ad;
693         char hostnam[NI_MAXHOST];
694         int gethostret, ret;
695         char *cp, *cp2;
696         long verfret;
697
698         *flags = 0;
699         *certp = NULL;
700         sad = (struct sockaddr *)&ad;
701         ssl = SSL_new(ctx);
702         if (ssl == NULL) {
703                 rpctls_verbose_out("rpctls_server: SSL_new failed\n");
704                 return (NULL);
705         }
706         if (SSL_set_fd(ssl, s) != 1) {
707                 rpctls_verbose_out("rpctls_server: SSL_set_fd failed\n");
708                 SSL_free(ssl);
709                 return (NULL);
710         }
711         ret = SSL_accept(ssl);
712         if (ret != 1) {
713                 rpctls_verbose_out("rpctls_server: SSL_accept "
714                     "failed ret=%d\n", ret);
715                 SSL_free(ssl);
716                 return (NULL);
717         }
718         *flags |= RPCTLS_FLAGS_HANDSHAKE;
719         if (rpctls_verbose) {
720                 gethostret = rpctls_gethost(s, sad, hostnam, sizeof(hostnam));
721                 if (gethostret == 0)
722                         hostnam[0] = '\0';
723                 rpctls_verbose_out("rpctls_server: SSL handshake ok for host %s"
724                     " <%s %s>\n", hostnam, SSL_get_version(ssl),
725                     SSL_get_cipher(ssl));
726         }
727         if (rpctls_do_mutual) {
728                 cert = SSL_get_peer_certificate(ssl);
729                 if (cert != NULL) {
730                         if (!rpctls_verbose) {
731                                 gethostret = rpctls_gethost(s, sad, hostnam,
732                                     sizeof(hostnam));
733                                 if (gethostret == 0)
734                                         hostnam[0] = '\0';
735                         }
736                         cp2 = X509_NAME_oneline(
737                             X509_get_subject_name(cert), NULL, 0);
738                         *flags |= RPCTLS_FLAGS_GOTCERT;
739                         verfret = SSL_get_verify_result(ssl);
740                         if (verfret != X509_V_OK) {
741                                 cp = X509_NAME_oneline(
742                                     X509_get_issuer_name(cert), NULL, 0);
743                                 if (rpctls_debug_level == 0)
744                                         syslog(LOG_INFO | LOG_DAEMON,
745                                             "rpctls_server: client IP %s "
746                                             "issuerName=%s subjectName=%s"
747                                             " verify failed %s\n", hostnam,
748                                             cp, cp2,
749                                             X509_verify_cert_error_string(
750                                             verfret));
751                                 else
752                                         fprintf(stderr,
753                                             "rpctls_server: client IP %s "
754                                             "issuerName=%s subjectName=%s"
755                                             " verify failed %s\n", hostnam,
756                                             cp, cp2,
757                                             X509_verify_cert_error_string(
758                                             verfret));
759                         }
760                         if (verfret ==
761                             X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
762                             verfret == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN)
763                                 *flags |= RPCTLS_FLAGS_SELFSIGNED;
764                         else if (verfret == X509_V_OK) {
765                                 if (rpctls_comparehost) {
766                                         ret = 0;
767                                         if (gethostret != 0)
768                                                 ret = rpctls_checkhost(sad,
769                                                     cert, rpctls_wildcard);
770                                         if (ret != 1) {
771                                                 *flags |=
772                                                     RPCTLS_FLAGS_DISABLED;
773                                                 rpctls_verbose_out(
774                                                     "rpctls_server: "
775                                                     "checkhost "
776                                                     "failed\n");
777                                         }
778                                 }
779                                 if (rpctls_cnuser) {
780                                         ret = rpctls_cnname(cert, uidp,
781                                             ngrps, gidp);
782                                         if (ret != 0)
783                                                 *flags |= RPCTLS_FLAGS_CERTUSER;
784                                 }
785                                 *flags |= RPCTLS_FLAGS_VERIFIED;
786                                 *certp = cert;
787                                 cert = NULL;
788                         }
789                         if (cert != NULL)
790                                 X509_free(cert);
791                 } else
792                         rpctls_verbose_out("rpctls_server: "
793                             "No peer certificate\n");
794         }
795
796         /* Check to see that ktls is working for the connection. */
797         ret = BIO_get_ktls_send(SSL_get_wbio(ssl));
798         rpctls_verbose_out("rpctls_server: BIO_get_ktls_send=%d\n", ret);
799         if (ret != 0) {
800                 ret = BIO_get_ktls_recv(SSL_get_rbio(ssl));
801                 rpctls_verbose_out("rpctls_server: BIO_get_ktls_recv=%d\n",
802                     ret);
803         }
804         if (ret == 0) {
805                 if (rpctls_debug_level == 0)
806                         syslog(LOG_ERR, "ktls not working");
807                 else
808                         fprintf(stderr, "ktls not working\n");
809                 /*
810                  * The handshake has completed, so all that can be
811                  * done is disable the connection.
812                  */
813                 *flags |= RPCTLS_FLAGS_DISABLED;
814         }
815
816         return (ssl);
817 }
818
819 /*
820  * Acquire the dnsname for this server.
821  */
822 static char *
823 rpctls_getdnsname(char *hostname)
824 {
825         char *cp, *dnsname;
826         struct addrinfo *aip, hints;
827         int error;
828
829         dnsname = NULL;
830         if (gethostname(hostname, MAXHOSTNAMELEN) == 0) {
831                 if ((cp = strchr(hostname, '.')) != NULL &&
832                     *(cp + 1) != '\0') {
833                         *cp = '@';
834                         dnsname = cp;
835                 } else {
836                         memset((void *)&hints, 0, sizeof (hints));
837                         hints.ai_flags = AI_CANONNAME;
838                         error = getaddrinfo(hostname, NULL, &hints, &aip);
839                         if (error == 0) {
840                                 if (aip->ai_canonname != NULL &&
841                                     (cp = strchr(aip->ai_canonname, '.')) !=
842                                     NULL && *(cp + 1) != '\0') {
843                                         hostname[0] = '@';
844                                         strlcpy(&hostname[1], cp + 1,
845                                             MAXHOSTNAMELEN + 1);
846                                         dnsname = hostname;
847                                 }
848                                 freeaddrinfo(aip);
849                         }
850                 }
851         }
852         return (dnsname);
853 }
854
855 /*
856  * Check for an otherName component of subjectAltName where the OID
857  * matches and the "domain" matches that of this server.
858  * If found, map "user" to a <uid, gidlist> for it.
859  */
860 static int
861 rpctls_cnname(X509 *cert, uint32_t *uidp, int *ngrps, uint32_t *gidp)
862 {
863         char *cp, usern[1024 + 1];
864         struct passwd *pwd;
865         gid_t gids[NGROUPS];
866         int i, j;
867         GENERAL_NAMES *genlist;
868         GENERAL_NAME *genname;
869         OTHERNAME *val;
870         size_t slen;
871
872         /* First, find the otherName in the subjectAltName. */
873         genlist = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
874         if (genlist == NULL)
875                 return (0);
876         cp = NULL;
877         for (i = 0; i < sk_GENERAL_NAME_num(genlist); i++) {
878                 genname = sk_GENERAL_NAME_value(genlist, i);
879                 if (genname->type != GEN_OTHERNAME)
880                         continue;
881                 val = genname->d.otherName;
882
883                 /* Check to see that it is the correct OID. */
884                 slen = i2t_ASN1_OBJECT(usern, sizeof(usern), val->type_id);
885                 if (slen != strlen(rpctls_cnuseroid) || memcmp(usern,
886                     rpctls_cnuseroid, slen) != 0)
887                         continue;
888
889                 /* Sanity check the otherName. */
890                 if (val->value->type != V_ASN1_UTF8STRING ||
891                     val->value->value.utf8string->length < 3 ||
892                     (size_t)val->value->value.utf8string->length > sizeof(usern)
893                     - 1) {
894                         rpctls_verbose_out("rpctls_cnname: invalid cnuser "
895                             "type=%d\n", val->value->type);
896                         continue;
897                 }
898
899                 /* Look for a "user" in the otherName */
900                 memcpy(usern, val->value->value.utf8string->data,
901                     val->value->value.utf8string->length);
902                 usern[val->value->value.utf8string->length] = '\0';
903
904                 /* Now, look for the @dnsname suffix in the commonName. */
905                 cp = strcasestr(usern, rpctls_dnsname);
906                 if (cp == NULL)
907                         continue;
908                 if (*(cp + strlen(rpctls_dnsname)) != '\0') {
909                         cp = NULL;
910                         continue;
911                 }
912                 *cp = '\0';
913                 break;
914         }
915         if (cp == NULL)
916                 return (0);
917
918         /* See if the "user" is in the passwd database. */
919         pwd = getpwnam(usern);
920         if (pwd == NULL)
921                 return (0);
922         *uidp = pwd->pw_uid;
923         *ngrps = NGROUPS;
924         if (getgrouplist(pwd->pw_name, pwd->pw_gid, gids, ngrps) < 0)
925                 return (0);
926         rpctls_verbose_out("mapped user=%s ngrps=%d uid=%d\n", pwd->pw_name,
927             *ngrps, pwd->pw_uid);
928         for (j = 0; j < *ngrps; j++)
929                 gidp[j] = gids[j];
930         return (1);
931 }
932
933 static void
934 rpctls_huphandler(int sig __unused)
935 {
936
937         rpctls_gothup = true;
938 }