]> git.ipfire.org Git - thirdparty/dhcp.git/blobdiff - omapip/isclib.c
[#182] Corrected CVE: CVE-2021-25217
[thirdparty/dhcp.git] / omapip / isclib.c
index 59332ed9b241255bd060e02108edc26888acb3cc..2293cbe417544220a17d5478d46c95b0a9c87700 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * Copyright(c) 2009-2010,2013-2014 by Internet Systems Consortium, Inc.("ISC")
+ * Copyright(C) 2009-2022 Internet Systems Consortium, Inc.("ISC")
  *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *
  *   Internet Systems Consortium, Inc.
- *   950 Charter Street
- *   Redwood City, CA 94063
+ *   PO Box 360
+ *   Newmarket, NH 03857 USA
  *   <info@isc.org>
  *   http://www.isc.org/
  *
  */
 
 /*Trying to figure out what we need to define to get things to work.
-  It looks like we want/need the export library but need the fdwatchcommand
+  It looks like we want/need the library but need the fdwatchcommand
   which may be a problem */
 
 #include "dhcpd.h"
@@ -40,7 +40,7 @@ int shutdown_signal = 0;
  * It may be moved to be part of the dns client code instead
  * of being in the DHCP code
  */
-isc_result_t 
+isc_result_t
 dhcp_dns_client_setservers(void)
 {
        isc_result_t result;
@@ -82,7 +82,7 @@ dhcp_dns_client_setservers(void)
        }
        return (result);
 }
-#endif
+#endif /* defined NSUPDATE */
 
 void
 isclib_cleanup(void)
@@ -90,7 +90,7 @@ isclib_cleanup(void)
 #if defined (NSUPDATE)
        if (dhcp_gbl_ctx.dnsclient != NULL)
                dns_client_destroy((dns_client_t **)&dhcp_gbl_ctx.dnsclient);
-#endif
+#endif /* defined NSUPDATE */
 
        if (dhcp_gbl_ctx.task != NULL) {
                isc_task_shutdown(dhcp_gbl_ctx.task);
@@ -120,6 +120,49 @@ isclib_cleanup(void)
        return;
 }
 
+/* Installs a handler for a signal using sigaction */
+static void
+handle_signal(int sig, void (*handler)(int)) {
+       struct sigaction sa;
+
+       memset(&sa, 0, sizeof(sa));
+       sa.sa_handler = handler;
+       sigfillset(&sa.sa_mask);
+       if (sigaction(sig, &sa, NULL) != 0) {
+               log_debug("handle_signal() failed for signal %d error: %s",
+                          sig, strerror(errno));
+       }
+}
+
+/* Callback passed to isc_app_ctxonrun
+ *
+ * BIND9 context code will invoke this handler once the context has
+ * entered the running state.  We use it to set a global marker so that
+ * we can tell if the context is running.  Several of the isc_app_
+ * calls REQUIRE that the context is running and we need a way to
+ * know that.
+ *
+ * We also check to see if we received a shutdown signal prior to
+ * the context entering the run state.  If we did, then we can just
+ * simply shut the context down now.  This closes the relatively
+ * small window between start up and entering run via the call
+ * to dispatch().
+ *
+ */
+static void
+set_ctx_running(isc_task_t *task, isc_event_t *event) {
+    IGNORE_UNUSED(task);
+       dhcp_gbl_ctx.actx_running = ISC_TRUE;
+
+       if (shutdown_signal) {
+               // We got signaled shutdown before we entered running state.
+               // Now that we've reached running state, shut'er down.
+               isc_app_ctxsuspend(dhcp_gbl_ctx.actx);
+       }
+
+        isc_event_free(&event);
+}
+
 isc_result_t
 dhcp_context_create(int flags,
                    struct in_addr  *local4,
@@ -127,6 +170,9 @@ dhcp_context_create(int flags,
        isc_result_t result;
 
        if ((flags & DHCP_CONTEXT_PRE_DB) != 0) {
+               dhcp_gbl_ctx.actx_started = ISC_FALSE;
+               dhcp_gbl_ctx.actx_running = ISC_FALSE;
+
                /*
                 * Set up the error messages, this isn't the right place
                 * for this call but it is convienent for now.
@@ -137,7 +183,7 @@ dhcp_context_create(int flags,
                }
 
                memset(&dhcp_gbl_ctx, 0, sizeof (dhcp_gbl_ctx));
-       
+
                isc_lib_register();
 
                /* get the current time for use as the random seed */
@@ -157,25 +203,20 @@ dhcp_context_create(int flags,
                result = dns_lib_init();
                if (result != ISC_R_SUCCESS)
                        goto cleanup;
-#else
+#else /* defined NSUPDATE */
                /* The dst library is inited as part of dns_lib_init, we don't
                 * need it if NSUPDATE is enabled */
                result = dst_lib_init(dhcp_gbl_ctx.mctx, NULL, 0);
                if (result != ISC_R_SUCCESS)
                        goto cleanup;
 
-#endif
+#endif /* defined NSUPDATE */
 
                result = isc_appctx_create(dhcp_gbl_ctx.mctx,
                                           &dhcp_gbl_ctx.actx);
                if (result != ISC_R_SUCCESS)
                        goto cleanup;
 
-               result = isc_app_ctxstart(dhcp_gbl_ctx.actx);
-               if (result != ISC_R_SUCCESS)
-                       return (result);
-               dhcp_gbl_ctx.actx_started = ISC_TRUE;
-
                result = isc_taskmgr_createinctx(dhcp_gbl_ctx.mctx,
                                                 dhcp_gbl_ctx.actx,
                                                 1, 0,
@@ -195,41 +236,58 @@ dhcp_context_create(int flags,
                if (result != ISC_R_SUCCESS)
                        goto cleanup;
 
-               result = isc_task_create(dhcp_gbl_ctx.taskmgr, 0, &dhcp_gbl_ctx.task);
+               result = isc_task_create(dhcp_gbl_ctx.taskmgr, 0,
+                                        &dhcp_gbl_ctx.task);
                if (result != ISC_R_SUCCESS)
                        goto cleanup;
+
+               result = isc_app_ctxstart(dhcp_gbl_ctx.actx);
+               if (result != ISC_R_SUCCESS)
+                       goto cleanup;
+
+               dhcp_gbl_ctx.actx_started = ISC_TRUE;
+
+               // Install the onrun callback.
+               result = isc_app_ctxonrun(dhcp_gbl_ctx.actx, dhcp_gbl_ctx.mctx,
+                                         dhcp_gbl_ctx.task, set_ctx_running,
+                                         dhcp_gbl_ctx.actx);
+               if (result != ISC_R_SUCCESS)
+                       goto cleanup;
+
+               /* Not all OSs support suppressing SIGPIPE through socket
+                * options, so set the sigal action to be ignore.  This allows
+                * broken connections to fail gracefully with EPIPE on writes */
+               handle_signal(SIGPIPE, SIG_IGN);
+
+               /* Reset handlers installed by isc_app_ctxstart()
+                * to default for control-c and kill */
+               handle_signal(SIGINT, SIG_DFL);
+               handle_signal(SIGTERM, SIG_DFL);
        }
 
 #if defined (NSUPDATE)
        if ((flags & DHCP_CONTEXT_POST_DB) != 0) {
-               isc_sockaddr_t localaddr4, *localaddr4_ptr = NULL;
-               isc_sockaddr_t localaddr6, *localaddr6_ptr = NULL;
+               /* Setting addresses only.
+                * All real work will be done later on if needed to avoid
+                * listening on ddns port if client/server was compiled with
+                * ddns support but not using it. */
                if (local4 != NULL) {
-                       isc_sockaddr_fromin(&localaddr4, local4, 0);
-                       localaddr4_ptr = &localaddr4;
+                       dhcp_gbl_ctx.use_local4 = 1;
+                       isc_sockaddr_fromin(&dhcp_gbl_ctx.local4_sockaddr,
+                                           local4, 0);
                }
+
                if (local6 != NULL) {
-                       isc_sockaddr_fromin6(&localaddr6, local6, 0);
-                       localaddr6_ptr = &localaddr6;
+                       dhcp_gbl_ctx.use_local6 = 1;
+                       isc_sockaddr_fromin6(&dhcp_gbl_ctx.local6_sockaddr,
+                                            local6, 0);
                }
 
-               result = dns_client_createx2(dhcp_gbl_ctx.mctx,
-                                            dhcp_gbl_ctx.actx,
-                                            dhcp_gbl_ctx.taskmgr,
-                                            dhcp_gbl_ctx.socketmgr,
-                                            dhcp_gbl_ctx.timermgr,
-                                            0,
-                                            &dhcp_gbl_ctx.dnsclient,
-                                            localaddr4_ptr,
-                                            localaddr6_ptr);
-               if (result != ISC_R_SUCCESS)
-                       goto cleanup;
-
-               result = dhcp_dns_client_setservers();
-               if (result != ISC_R_SUCCESS)
-                       goto cleanup;
+               if (!(flags & DHCP_DNS_CLIENT_LAZY_INIT)) {
+                       result = dns_client_init();
+               }
        }
-#endif
+#endif /* defined NSUPDATE */
 
        return(ISC_R_SUCCESS);
 
@@ -260,7 +318,7 @@ dhcp_isc_name(unsigned char   *namestr,
        isc_buffer_t b;
        isc_result_t result;
 
-       namelen = strlen((char *)namestr); 
+       namelen = strlen((char *)namestr);
        isc_buffer_init(&b, namestr, namelen);
        isc_buffer_add(&b, namelen);
        dns_fixedname_init(namefix);
@@ -281,12 +339,24 @@ isclib_make_dst_key(char          *inname,
        dns_name_t *name;
        dns_fixedname_t name0;
        isc_buffer_t b;
+       unsigned int algorithm_code;
 
        isc_buffer_init(&b, secret, length);
        isc_buffer_add(&b, length);
 
-       /* We only support HMAC_MD5 currently */
-       if (strcasecmp(algorithm, DHCP_HMAC_MD5_NAME) != 0) {
+       if (strcasecmp(algorithm, DHCP_HMAC_MD5_NAME) == 0) {
+               algorithm_code =  DST_ALG_HMACMD5;
+       } else if (strcasecmp(algorithm, DHCP_HMAC_SHA1_NAME) == 0) {
+               algorithm_code =  DST_ALG_HMACSHA1;
+       } else if (strcasecmp(algorithm, DHCP_HMAC_SHA224_NAME) == 0) {
+               algorithm_code =  DST_ALG_HMACSHA224;
+       } else if (strcasecmp(algorithm, DHCP_HMAC_SHA256_NAME) == 0) {
+               algorithm_code =  DST_ALG_HMACSHA256;
+       } else if (strcasecmp(algorithm, DHCP_HMAC_SHA384_NAME) == 0) {
+               algorithm_code =  DST_ALG_HMACSHA384;
+       } else if (strcasecmp(algorithm, DHCP_HMAC_SHA512_NAME) == 0) {
+               algorithm_code =  DST_ALG_HMACSHA512;
+       } else {
                return(DHCP_R_INVALIDARG);
        }
 
@@ -295,7 +365,7 @@ isclib_make_dst_key(char          *inname,
                return(result);
        }
 
-       return(dst_key_frombuffer(name, DST_ALG_HMACMD5, DNS_KEYOWNER_ENTITY,
+       return(dst_key_frombuffer(name, algorithm_code, DNS_KEYOWNER_ENTITY,
                                  DNS_KEYPROTO_DNSSEC, dns_rdataclass_in,
                                  &b, dhcp_gbl_ctx.mctx, dstkey));
 }
@@ -306,18 +376,55 @@ isclib_make_dst_key(char          *inname,
  * @param signal signal code that we received
  */
 void dhcp_signal_handler(int signal) {
-       isc_appctx_t *ctx = dhcp_gbl_ctx.actx;
-       int prev = shutdown_signal;
-
-       if (prev != 0) {
+       if (shutdown_signal != 0) {
                /* Already in shutdown. */
                return;
        }
+
        /* Possible race but does it matter? */
        shutdown_signal = signal;
 
-       /* Use reload (aka suspend) for easier dispatch() reenter. */
-       if (ctx && ctx->methods && ctx->methods->ctxsuspend) {
-               (void) isc_app_ctxsuspend(ctx);
+       /* If the application context is running tell it to shut down */
+       if (dhcp_gbl_ctx.actx_running == ISC_TRUE) {
+               (void) isc_app_ctxsuspend(dhcp_gbl_ctx.actx);
        }
 }
+
+#if defined (NSUPDATE)
+isc_result_t dns_client_init() {
+       isc_result_t result;
+       if (dhcp_gbl_ctx.dnsclient == NULL) {
+               result = dns_client_createx2(dhcp_gbl_ctx.mctx,
+                                            dhcp_gbl_ctx.actx,
+                                            dhcp_gbl_ctx.taskmgr,
+                                            dhcp_gbl_ctx.socketmgr,
+                                            dhcp_gbl_ctx.timermgr,
+                                            0,
+                                            &dhcp_gbl_ctx.dnsclient,
+                                            (dhcp_gbl_ctx.use_local4 ?
+                                             &dhcp_gbl_ctx.local4_sockaddr
+                                             : NULL),
+                                            (dhcp_gbl_ctx.use_local6 ?
+                                             &dhcp_gbl_ctx.local6_sockaddr
+                                             : NULL));
+
+               if (result != ISC_R_SUCCESS) {
+                       log_error("Unable to create DNS client context:"
+                                 " result: %d", result);
+                       return result;
+               }
+
+               /* If we can't set up the servers we may not be able to
+                * do DDNS but we should continue to try and perform
+                * our basic functions and let the user sort it out. */
+               result = dhcp_dns_client_setservers();
+               if (result != ISC_R_SUCCESS) {
+                       log_error("Unable to set resolver from resolv.conf; "
+                                 "startup continuing but DDNS support "
+                                 "may be affected: result %d", result);
+               }
+       }
+
+       return ISC_R_SUCCESS;
+}
+#endif /* defined (NSUPDATE) */