3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  24  */
  25 
  26 
  27 /*
  28  * main() of idmapd(1M)
  29  */
  30 
  31 #include "idmapd.h"
  32 #include <atomic.h>
  33 #include <signal.h>
  34 #include <rpc/pmap_clnt.h> /* for pmap_unset */
  35 #include <string.h> /* strcmp */
  36 #include <unistd.h> /* setsid */
  37 #include <sys/types.h>
  38 #include <memory.h>
  39 #include <stropts.h>
  40 #include <netconfig.h>
  41 #include <sys/resource.h> /* rlimit */
  42 #include <rpcsvc/daemon_utils.h> /* DAEMON_UID and DAEMON_GID */
  43 #include <priv_utils.h> /* privileges */
 
 
  67 /* The DC Locator lives inside idmap (for now). */
  68 extern void     init_dc_locator(void);
  69 extern void     fini_dc_locator(void);
  70 
  71 idmapd_state_t  _idmapdstate;
  72 
  73 SVCXPRT *xprt = NULL;
  74 
  75 static int dfd = -1;            /* our door server fildes, for unregistration */
  76 static boolean_t degraded = B_FALSE;
  77 
  78 
  79 static uint32_t         num_threads = 0;
  80 static pthread_key_t    create_threads_key;
  81 static uint32_t         max_threads = 40;
  82 
  83 /*
  84  * Server door thread start routine.
  85  *
  86  * Set a TSD value to the door thread. This enables the destructor to
  87  * be called when this thread exits.
  88  */
  89 /*ARGSUSED*/
  90 static void *
  91 idmapd_door_thread_start(void *arg)
  92 {
  93         static void *value = 0;
  94 
  95         /*
  96          * Disable cancellation to avoid memory leaks from not running
  97          * the thread cleanup code.
  98          */
  99         (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
 100         (void) pthread_setspecific(create_threads_key, value);
 101         (void) door_return(NULL, 0, NULL, 0);
 102 
 103         /* make lint happy */
 104         return (NULL);
 105 }
 106 
 107 /*
 108  * Server door threads creation
 109  */
 110 /*ARGSUSED*/
 111 static void
 112 idmapd_door_thread_create(door_info_t *dip)
 113 {
 
 119                 idmapdlog(LOG_DEBUG,
 120                     "thread creation refused - %d threads currently active",
 121                     num - 1);
 122                 return;
 123         }
 124         (void) pthread_create(&thread_id, NULL, idmapd_door_thread_start, NULL);
 125         idmapdlog(LOG_DEBUG,
 126             "created thread ID %d - %d threads currently active",
 127             thread_id, num);
 128 }
 129 
 130 /*
 131  * Server door thread cleanup
 132  */
 133 /*ARGSUSED*/
 134 static void
 135 idmapd_door_thread_cleanup(void *arg)
 136 {
 137         int num;
 138 
 139         num = atomic_dec_32_nv(&num_threads);
 140         idmapdlog(LOG_DEBUG,
 141             "exiting thread ID %d - %d threads currently active",
 142             pthread_self(), num);
 143 }
 144 
 145 /*
 146  * This is needed for mech_krb5 -- we run as daemon, yes, but we want
 147  * mech_krb5 to think we're root so it can get host/nodename.fqdn
 148  * tickets for us so we can authenticate to AD as the machine account
 149  * that we are.  For more details look at the entry point in mech_krb5
 150  * corresponding to gss_init_sec_context().
 151  *
 152  * As a side effect of faking our effective UID to mech_krb5 we will use
 153  * root's default ccache (/tmp/krb5cc_0).  But if that's created by
 154  * another process then we won't have access to it: we run as daemon and
 155  * keep PRIV_FILE_DAC_READ, which is insufficient to share the ccache
 156  * with others.  We putenv("KRB5CCNAME=/var/run/idmap/ccache") in main()
 157  * to avoid this issue; see main().
 158  *
 
 362          * for more details.  We blow away the existing one, if there is
 363          * one.
 364          */
 365         (void) unlink(IDMAP_CACHEDIR "/ccache");
 366         (void) putenv("KRB5CCNAME=" IDMAP_CACHEDIR "/ccache");
 367         (void) putenv("MS_INTEROP=1");
 368 
 369         if (sysinfo(SI_HOSTNAME, _idmapdstate.hostname,
 370             sizeof (_idmapdstate.hostname)) == -1) {
 371                 error = errno;
 372                 idmapdlog(LOG_ERR, "unable to determine hostname, error: %d",
 373                     error);
 374                 exit(1);
 375         }
 376 
 377         if ((error = init_mapping_system()) < 0) {
 378                 idmapdlog(LOG_ERR, "unable to initialize mapping system");
 379                 exit(error < -2 ? SMF_EXIT_ERR_CONFIG : 1);
 380         }
 381 
 382         (void) door_server_create(idmapd_door_thread_create);
 383         if ((error = pthread_key_create(&create_threads_key,
 384             idmapd_door_thread_cleanup)) != 0) {
 385                 idmapdlog(LOG_ERR, "unable to create threads key (%s)",
 386                     strerror(error));
 387                 goto errout;
 388         }
 389 
 390         xprt = svc_door_create(idmap_prog_1, IDMAP_PROG, IDMAP_V1, connmaxrec);
 391         if (xprt == NULL) {
 392                 idmapdlog(LOG_ERR, "unable to create door RPC service");
 393                 goto errout;
 394         }
 395 
 396         if (!svc_control(xprt, SVCSET_CONNMAXREC, &connmaxrec)) {
 397                 idmapdlog(LOG_ERR, "unable to limit RPC request size");
 398                 goto errout;
 399         }
 400 
 401         dfd = xprt->xp_fd;
 
 | 
 
 
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  24  */
  25 
  26 
  27 /*
  28  * main() of idmapd(1M)
  29  */
  30 
  31 #include "idmapd.h"
  32 #include <atomic.h>
  33 #include <signal.h>
  34 #include <rpc/pmap_clnt.h> /* for pmap_unset */
  35 #include <string.h> /* strcmp */
  36 #include <unistd.h> /* setsid */
  37 #include <sys/types.h>
  38 #include <memory.h>
  39 #include <stropts.h>
  40 #include <netconfig.h>
  41 #include <sys/resource.h> /* rlimit */
  42 #include <rpcsvc/daemon_utils.h> /* DAEMON_UID and DAEMON_GID */
  43 #include <priv_utils.h> /* privileges */
 
 
  67 /* The DC Locator lives inside idmap (for now). */
  68 extern void     init_dc_locator(void);
  69 extern void     fini_dc_locator(void);
  70 
  71 idmapd_state_t  _idmapdstate;
  72 
  73 SVCXPRT *xprt = NULL;
  74 
  75 static int dfd = -1;            /* our door server fildes, for unregistration */
  76 static boolean_t degraded = B_FALSE;
  77 
  78 
  79 static uint32_t         num_threads = 0;
  80 static pthread_key_t    create_threads_key;
  81 static uint32_t         max_threads = 40;
  82 
  83 /*
  84  * Server door thread start routine.
  85  *
  86  * Set a TSD value to the door thread. This enables the destructor to
  87  * be called when this thread exits. Note that we need a non-NULL
  88  * value for this or the TSD destructor is not called.
  89  */
  90 /*ARGSUSED*/
  91 static void *
  92 idmapd_door_thread_start(void *arg)
  93 {
  94         static void *value = "NON-NULL TSD";
  95 
  96         /*
  97          * Disable cancellation to avoid memory leaks from not running
  98          * the thread cleanup code.
  99          */
 100         (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
 101         (void) pthread_setspecific(create_threads_key, value);
 102         (void) door_return(NULL, 0, NULL, 0);
 103 
 104         /* make lint happy */
 105         return (NULL);
 106 }
 107 
 108 /*
 109  * Server door threads creation
 110  */
 111 /*ARGSUSED*/
 112 static void
 113 idmapd_door_thread_create(door_info_t *dip)
 114 {
 
 120                 idmapdlog(LOG_DEBUG,
 121                     "thread creation refused - %d threads currently active",
 122                     num - 1);
 123                 return;
 124         }
 125         (void) pthread_create(&thread_id, NULL, idmapd_door_thread_start, NULL);
 126         idmapdlog(LOG_DEBUG,
 127             "created thread ID %d - %d threads currently active",
 128             thread_id, num);
 129 }
 130 
 131 /*
 132  * Server door thread cleanup
 133  */
 134 /*ARGSUSED*/
 135 static void
 136 idmapd_door_thread_cleanup(void *arg)
 137 {
 138         int num;
 139 
 140         /* set TSD to NULL so we don't loop infinitely */
 141         (void) pthread_setspecific(create_threads_key, NULL);
 142         num = atomic_dec_32_nv(&num_threads);
 143         idmapdlog(LOG_DEBUG,
 144             "exiting thread ID %d - %d threads currently active",
 145             pthread_self(), num);
 146 }
 147 
 148 /*
 149  * This is needed for mech_krb5 -- we run as daemon, yes, but we want
 150  * mech_krb5 to think we're root so it can get host/nodename.fqdn
 151  * tickets for us so we can authenticate to AD as the machine account
 152  * that we are.  For more details look at the entry point in mech_krb5
 153  * corresponding to gss_init_sec_context().
 154  *
 155  * As a side effect of faking our effective UID to mech_krb5 we will use
 156  * root's default ccache (/tmp/krb5cc_0).  But if that's created by
 157  * another process then we won't have access to it: we run as daemon and
 158  * keep PRIV_FILE_DAC_READ, which is insufficient to share the ccache
 159  * with others.  We putenv("KRB5CCNAME=/var/run/idmap/ccache") in main()
 160  * to avoid this issue; see main().
 161  *
 
 365          * for more details.  We blow away the existing one, if there is
 366          * one.
 367          */
 368         (void) unlink(IDMAP_CACHEDIR "/ccache");
 369         (void) putenv("KRB5CCNAME=" IDMAP_CACHEDIR "/ccache");
 370         (void) putenv("MS_INTEROP=1");
 371 
 372         if (sysinfo(SI_HOSTNAME, _idmapdstate.hostname,
 373             sizeof (_idmapdstate.hostname)) == -1) {
 374                 error = errno;
 375                 idmapdlog(LOG_ERR, "unable to determine hostname, error: %d",
 376                     error);
 377                 exit(1);
 378         }
 379 
 380         if ((error = init_mapping_system()) < 0) {
 381                 idmapdlog(LOG_ERR, "unable to initialize mapping system");
 382                 exit(error < -2 ? SMF_EXIT_ERR_CONFIG : 1);
 383         }
 384 
 385         /*
 386          * This means max_threads can't be updated without restarting idmap.
 387          */
 388         RDLOCK_CONFIG();
 389         max_threads = _idmapdstate.cfg->pgcfg.max_threads;
 390         UNLOCK_CONFIG();
 391 
 392         (void) door_server_create(idmapd_door_thread_create);
 393         if ((error = pthread_key_create(&create_threads_key,
 394             idmapd_door_thread_cleanup)) != 0) {
 395                 idmapdlog(LOG_ERR, "unable to create threads key (%s)",
 396                     strerror(error));
 397                 goto errout;
 398         }
 399 
 400         xprt = svc_door_create(idmap_prog_1, IDMAP_PROG, IDMAP_V1, connmaxrec);
 401         if (xprt == NULL) {
 402                 idmapdlog(LOG_ERR, "unable to create door RPC service");
 403                 goto errout;
 404         }
 405 
 406         if (!svc_control(xprt, SVCSET_CONNMAXREC, &connmaxrec)) {
 407                 idmapdlog(LOG_ERR, "unable to limit RPC request size");
 408                 goto errout;
 409         }
 410 
 411         dfd = xprt->xp_fd;
 
 |