Print this page
    
NEX-19665 Several door servers don't properly handle exiting threads
Review by: Gordon Ross <gordon.ross@nexenta.com>
Review by: Evan Layton <evan.layton@nexenta.com>
NEX-2225 Unable to join NexentaStor to 2008 AD
NEX-1638 Updated DC Locator
 Includes work by: matt.barden@nexenta.com, kevin.crowe@nexenta.com
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/idmap/idmapd/idmapd.c
          +++ new/usr/src/cmd/idmap/idmapd/idmapd.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  
    | 
      ↓ open down ↓ | 
    12 lines elided | 
    
      ↑ open up ↑ | 
  
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23      - * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
       23 + * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  24   24   */
  25   25  
  26   26  
  27   27  /*
  28   28   * main() of idmapd(1M)
  29   29   */
  30   30  
  31   31  #include "idmapd.h"
  32   32  #include <atomic.h>
  33   33  #include <signal.h>
  34   34  #include <rpc/pmap_clnt.h> /* for pmap_unset */
  35   35  #include <string.h> /* strcmp */
  36   36  #include <unistd.h> /* setsid */
  37   37  #include <sys/types.h>
  38   38  #include <memory.h>
  39   39  #include <stropts.h>
  40   40  #include <netconfig.h>
  41   41  #include <sys/resource.h> /* rlimit */
  42   42  #include <rpcsvc/daemon_utils.h> /* DAEMON_UID and DAEMON_GID */
  43   43  #include <priv_utils.h> /* privileges */
  44   44  #include <locale.h>
  45   45  #include <sys/systeminfo.h>
  46   46  #include <errno.h>
  47   47  #include <sys/wait.h>
  48   48  #include <sys/time.h>
  49   49  #include <zone.h>
  50   50  #include <door.h>
  51   51  #include <port.h>
  52   52  #include <tsol/label.h>
  53   53  #include <sys/resource.h>
  54   54  #include <sys/sid.h>
  55   55  #include <sys/idmap.h>
  56   56  #include <pthread.h>
  57   57  #include <stdarg.h>
  58   58  #include <assert.h>
  59   59  #include <note.h>
  60   60  
  61   61  #define CBUFSIZ 26      /* ctime(3c) */
  62   62  
  63   63  static void     term_handler(int);
  64   64  static void     init_idmapd();
  65   65  static void     fini_idmapd();
  66   66  
  67   67  /* The DC Locator lives inside idmap (for now). */
  68   68  extern void     init_dc_locator(void);
  69   69  extern void     fini_dc_locator(void);
  70   70  
  71   71  idmapd_state_t  _idmapdstate;
  72   72  
  73   73  SVCXPRT *xprt = NULL;
  74   74  
  75   75  static int dfd = -1;            /* our door server fildes, for unregistration */
  76   76  static boolean_t degraded = B_FALSE;
  
    | 
      ↓ open down ↓ | 
    43 lines elided | 
    
      ↑ open up ↑ | 
  
  77   77  
  78   78  
  79   79  static uint32_t         num_threads = 0;
  80   80  static pthread_key_t    create_threads_key;
  81   81  static uint32_t         max_threads = 40;
  82   82  
  83   83  /*
  84   84   * Server door thread start routine.
  85   85   *
  86   86   * Set a TSD value to the door thread. This enables the destructor to
  87      - * be called when this thread exits.
       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.
  88   89   */
  89   90  /*ARGSUSED*/
  90   91  static void *
  91   92  idmapd_door_thread_start(void *arg)
  92   93  {
  93      -        static void *value = 0;
       94 +        static void *value = "NON-NULL TSD";
  94   95  
  95   96          /*
  96   97           * Disable cancellation to avoid memory leaks from not running
  97   98           * the thread cleanup code.
  98   99           */
  99  100          (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
 100  101          (void) pthread_setspecific(create_threads_key, value);
 101  102          (void) door_return(NULL, 0, NULL, 0);
 102  103  
 103  104          /* make lint happy */
 104  105          return (NULL);
 105  106  }
 106  107  
 107  108  /*
 108  109   * Server door threads creation
 109  110   */
 110  111  /*ARGSUSED*/
 111  112  static void
 112  113  idmapd_door_thread_create(door_info_t *dip)
 113  114  {
 114  115          int             num;
 115  116          pthread_t       thread_id;
 116  117  
 117  118          if ((num = atomic_inc_32_nv(&num_threads)) > max_threads) {
 118  119                  atomic_dec_32(&num_threads);
 119  120                  idmapdlog(LOG_DEBUG,
 120  121                      "thread creation refused - %d threads currently active",
 121  122                      num - 1);
 122  123                  return;
 123  124          }
 124  125          (void) pthread_create(&thread_id, NULL, idmapd_door_thread_start, NULL);
 125  126          idmapdlog(LOG_DEBUG,
 126  127              "created thread ID %d - %d threads currently active",
 127  128              thread_id, num);
 128  129  }
  
    | 
      ↓ open down ↓ | 
    25 lines elided | 
    
      ↑ open up ↑ | 
  
 129  130  
 130  131  /*
 131  132   * Server door thread cleanup
 132  133   */
 133  134  /*ARGSUSED*/
 134  135  static void
 135  136  idmapd_door_thread_cleanup(void *arg)
 136  137  {
 137  138          int num;
 138  139  
      140 +        /* set TSD to NULL so we don't loop infinitely */
      141 +        (void) pthread_setspecific(create_threads_key, NULL);
 139  142          num = atomic_dec_32_nv(&num_threads);
 140  143          idmapdlog(LOG_DEBUG,
 141  144              "exiting thread ID %d - %d threads currently active",
 142  145              pthread_self(), num);
 143  146  }
 144  147  
 145  148  /*
 146  149   * This is needed for mech_krb5 -- we run as daemon, yes, but we want
 147  150   * mech_krb5 to think we're root so it can get host/nodename.fqdn
 148  151   * tickets for us so we can authenticate to AD as the machine account
 149  152   * that we are.  For more details look at the entry point in mech_krb5
 150  153   * corresponding to gss_init_sec_context().
 151  154   *
 152  155   * As a side effect of faking our effective UID to mech_krb5 we will use
 153  156   * root's default ccache (/tmp/krb5cc_0).  But if that's created by
 154  157   * another process then we won't have access to it: we run as daemon and
 155  158   * keep PRIV_FILE_DAC_READ, which is insufficient to share the ccache
 156  159   * with others.  We putenv("KRB5CCNAME=/var/run/idmap/ccache") in main()
 157  160   * to avoid this issue; see main().
 158  161   *
 159  162   * Someday we'll have gss/mech_krb5 extensions for acquiring initiator
 160  163   * creds with keytabs/raw keys, and someday we'll have extensions to
 161  164   * libsasl to specify creds/name to use on the initiator side, and
 162  165   * someday we'll have extensions to libldap to pass those through to
 163  166   * libsasl.  Until then this interposer will have to do.
 164  167   *
 165  168   * Also, we have to tell lint to shut up: it thinks app_krb5_user_uid()
 166  169   * is defined but not used.
 167  170   */
 168  171  /*LINTLIBRARY*/
 169  172  uid_t
 170  173  app_krb5_user_uid(void)
 171  174  {
 172  175          return (0);
 173  176  }
 174  177  
 175  178  /*ARGSUSED*/
 176  179  static void
 177  180  term_handler(int sig)
 178  181  {
 179  182          idmapdlog(LOG_INFO, "Terminating.");
 180  183          fini_dc_locator();
 181  184          fini_idmapd();
 182  185          _exit(0);
 183  186  }
 184  187  
 185  188  /*ARGSUSED*/
 186  189  static void
 187  190  usr1_handler(int sig)
 188  191  {
 189  192          NOTE(ARGUNUSED(sig))
 190  193          print_idmapdstate();
 191  194  }
 192  195  
 193  196  static int pipe_fd = -1;
 194  197  
 195  198  static void
 196  199  daemonize_ready(void)
 197  200  {
 198  201          char data = '\0';
 199  202          /*
 200  203           * wake the parent
 201  204           */
 202  205          (void) write(pipe_fd, &data, 1);
 203  206          (void) close(pipe_fd);
 204  207  }
 205  208  
 206  209  static int
 207  210  daemonize_start(void)
 208  211  {
 209  212          char    data;
 210  213          int     status;
 211  214          int     devnull;
 212  215          int     filedes[2];
 213  216          pid_t   pid;
 214  217  
 215  218          (void) sigset(SIGPIPE, SIG_IGN);
 216  219          devnull = open("/dev/null", O_RDONLY);
 217  220          if (devnull < 0)
 218  221                  return (-1);
 219  222          (void) dup2(devnull, 0);
 220  223          (void) dup2(2, 1);      /* stderr only */
 221  224          if (pipe(filedes) < 0)
 222  225                  return (-1);
 223  226          if ((pid = fork1()) < 0)
 224  227                  return (-1);
 225  228          if (pid != 0) {
 226  229                  /*
 227  230                   * parent
 228  231                   */
 229  232                  (void) close(filedes[1]);
 230  233                  if (read(filedes[0], &data, 1) == 1) {
 231  234                          /* presume success */
 232  235                          _exit(0);
 233  236                  }
 234  237                  status = -1;
 235  238                  (void) wait4(pid, &status, 0, NULL);
 236  239                  if (WIFEXITED(status))
 237  240                          _exit(WEXITSTATUS(status));
 238  241                  else
 239  242                          _exit(-1);
 240  243          }
 241  244  
 242  245          /*
 243  246           * child
 244  247           */
 245  248          pipe_fd = filedes[1];
 246  249          (void) close(filedes[0]);
 247  250          (void) setsid();
 248  251          (void) umask(0077);
 249  252          openlog("idmap", LOG_PID, LOG_DAEMON);
 250  253  
 251  254          return (0);
 252  255  }
 253  256  
 254  257  
 255  258  int
 256  259  main(int argc, char **argv)
 257  260  {
 258  261          int c;
 259  262          struct rlimit rl;
 260  263  
 261  264          if (rwlock_init(&_idmapdstate.rwlk_cfg, USYNC_THREAD, NULL) != 0)
 262  265                  return (-1);
 263  266          if (mutex_init(&_idmapdstate.addisc_lk, USYNC_THREAD, NULL) != 0)
 264  267                  return (-1);
 265  268          if (cond_init(&_idmapdstate.addisc_cv, USYNC_THREAD, NULL) != 0)
 266  269                  return (-1);
 267  270  
 268  271          _idmapdstate.daemon_mode = TRUE;
 269  272          while ((c = getopt(argc, argv, "d")) != -1) {
 270  273                  switch (c) {
 271  274                          case 'd':
 272  275                                  _idmapdstate.daemon_mode = FALSE;
 273  276                                  break;
 274  277                          default:
 275  278                                  (void) fprintf(stderr,
 276  279                                      "Usage: /usr/lib/idmapd [-d]\n");
 277  280                                  return (SMF_EXIT_ERR_CONFIG);
 278  281                  }
 279  282          }
 280  283  
 281  284          /* set locale and domain for internationalization */
 282  285          (void) setlocale(LC_ALL, "");
 283  286          (void) textdomain(TEXT_DOMAIN);
 284  287  
 285  288          idmap_set_logger(idmapdlog);
 286  289          adutils_set_logger(idmapdlog);
 287  290  
 288  291          if (is_system_labeled() && getzoneid() != GLOBAL_ZONEID) {
 289  292                  idmapdlog(LOG_ERR,
 290  293                      "with Trusted Extensions idmapd runs only in the "
 291  294                      "global zone");
 292  295                  exit(1);
 293  296          }
 294  297  
 295  298          /*
 296  299           * Raise the fd limit to max
 297  300           */
 298  301          if (getrlimit(RLIMIT_NOFILE, &rl) != 0) {
 299  302                  idmapdlog(LOG_ERR, "getrlimit failed");
 300  303          } else if (rl.rlim_cur < rl.rlim_max) {
 301  304                  rl.rlim_cur = rl.rlim_max;
 302  305                  if (setrlimit(RLIMIT_NOFILE, &rl) != 0)
 303  306                          idmapdlog(LOG_ERR,
 304  307                              "Unable to raise RLIMIT_NOFILE to %d",
 305  308                              rl.rlim_cur);
 306  309          }
 307  310  
 308  311          (void) mutex_init(&_svcstate_lock, USYNC_THREAD, NULL);
 309  312  
 310  313          if (_idmapdstate.daemon_mode == TRUE) {
 311  314                  if (daemonize_start() < 0) {
 312  315                          idmapdlog(LOG_ERR, "unable to daemonize");
 313  316                          exit(-1);
 314  317                  }
 315  318          } else
 316  319                  (void) umask(0077);
 317  320  
 318  321          idmap_init_tsd_key();
 319  322  
 320  323          init_idmapd();
 321  324          init_dc_locator();
 322  325  
 323  326          /* signal handlers that should run only after we're initialized */
 324  327          (void) sigset(SIGTERM, term_handler);
 325  328          (void) sigset(SIGUSR1, usr1_handler);
 326  329          (void) sigset(SIGHUP, idmap_cfg_hup_handler);
 327  330  
 328  331          if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET,
 329  332              DAEMON_UID, DAEMON_GID,
 330  333              PRIV_PROC_AUDIT, PRIV_FILE_DAC_READ,
 331  334              (char *)NULL) == -1) {
 332  335                  idmapdlog(LOG_ERR, "unable to drop privileges");
 333  336                  exit(1);
 334  337          }
 335  338  
 336  339          __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION,
 337  340              PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL);
 338  341  
 339  342          if (_idmapdstate.daemon_mode == TRUE)
 340  343                  daemonize_ready();
 341  344  
 342  345          /* With doors RPC this just wastes this thread, oh well */
 343  346          svc_run();
 344  347          return (0);
 345  348  }
 346  349  
 347  350  static void
 348  351  init_idmapd()
 349  352  {
 350  353          int     error;
 351  354          int     connmaxrec = IDMAP_MAX_DOOR_RPC;
 352  355  
 353  356  
 354  357          /* create directories as root and chown to daemon uid */
 355  358          if (create_directory(IDMAP_DBDIR, DAEMON_UID, DAEMON_GID) < 0)
 356  359                  exit(1);
 357  360          if (create_directory(IDMAP_CACHEDIR, DAEMON_UID, DAEMON_GID) < 0)
 358  361                  exit(1);
 359  362  
 360  363          /*
 361  364           * Set KRB5CCNAME in the environment.  See app_krb5_user_uid()
 362  365           * for more details.  We blow away the existing one, if there is
 363  366           * one.
 364  367           */
 365  368          (void) unlink(IDMAP_CACHEDIR "/ccache");
 366  369          (void) putenv("KRB5CCNAME=" IDMAP_CACHEDIR "/ccache");
 367  370          (void) putenv("MS_INTEROP=1");
 368  371  
 369  372          if (sysinfo(SI_HOSTNAME, _idmapdstate.hostname,
 370  373              sizeof (_idmapdstate.hostname)) == -1) {
 371  374                  error = errno;
  
    | 
      ↓ open down ↓ | 
    223 lines elided | 
    
      ↑ open up ↑ | 
  
 372  375                  idmapdlog(LOG_ERR, "unable to determine hostname, error: %d",
 373  376                      error);
 374  377                  exit(1);
 375  378          }
 376  379  
 377  380          if ((error = init_mapping_system()) < 0) {
 378  381                  idmapdlog(LOG_ERR, "unable to initialize mapping system");
 379  382                  exit(error < -2 ? SMF_EXIT_ERR_CONFIG : 1);
 380  383          }
 381  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 +
 382  392          (void) door_server_create(idmapd_door_thread_create);
 383  393          if ((error = pthread_key_create(&create_threads_key,
 384  394              idmapd_door_thread_cleanup)) != 0) {
 385  395                  idmapdlog(LOG_ERR, "unable to create threads key (%s)",
 386  396                      strerror(error));
 387  397                  goto errout;
 388  398          }
 389  399  
 390  400          xprt = svc_door_create(idmap_prog_1, IDMAP_PROG, IDMAP_V1, connmaxrec);
 391  401          if (xprt == NULL) {
 392  402                  idmapdlog(LOG_ERR, "unable to create door RPC service");
 393  403                  goto errout;
 394  404          }
 395  405  
 396  406          if (!svc_control(xprt, SVCSET_CONNMAXREC, &connmaxrec)) {
 397  407                  idmapdlog(LOG_ERR, "unable to limit RPC request size");
 398  408                  goto errout;
 399  409          }
 400  410  
 401  411          dfd = xprt->xp_fd;
 402  412  
 403  413          if (dfd == -1) {
 404  414                  idmapdlog(LOG_ERR, "unable to register door");
 405  415                  goto errout;
 406  416          }
 407  417          if ((error = __idmap_reg(dfd)) != 0) {
 408  418                  idmapdlog(LOG_ERR, "unable to register door (%s)",
 409  419                      strerror(errno));
 410  420                  goto errout;
 411  421          }
 412  422  
 413  423          if ((error = allocids(_idmapdstate.new_eph_db,
 414  424              8192, &_idmapdstate.next_uid,
 415  425              8192, &_idmapdstate.next_gid)) != 0) {
 416  426                  idmapdlog(LOG_ERR, "unable to allocate ephemeral IDs (%s)",
 417  427                      strerror(errno));
 418  428                  _idmapdstate.next_uid = IDMAP_SENTINEL_PID;
 419  429                  _idmapdstate.limit_uid = IDMAP_SENTINEL_PID;
 420  430                  _idmapdstate.next_gid = IDMAP_SENTINEL_PID;
 421  431                  _idmapdstate.limit_gid = IDMAP_SENTINEL_PID;
 422  432          } else {
 423  433                  _idmapdstate.limit_uid = _idmapdstate.next_uid + 8192;
 424  434                  _idmapdstate.limit_gid = _idmapdstate.next_gid + 8192;
 425  435          }
 426  436  
 427  437          if (DBG(CONFIG, 1))
 428  438                  print_idmapdstate();
 429  439  
 430  440          return;
 431  441  
 432  442  errout:
 433  443          fini_idmapd();
 434  444          exit(1);
 435  445  }
 436  446  
 437  447  static void
 438  448  fini_idmapd()
 439  449  {
 440  450          (void) __idmap_unreg(dfd);
 441  451          fini_mapping_system();
 442  452          if (xprt != NULL)
 443  453                  svc_destroy(xprt);
 444  454  }
 445  455  
 446  456  static
 447  457  const char *
 448  458  get_fmri(void)
 449  459  {
 450  460          static char *fmri = NULL;
 451  461          static char buf[60];
 452  462          char *s;
 453  463  
 454  464          membar_consumer();
 455  465          s = fmri;
 456  466          if (s != NULL && *s == '\0')
 457  467                  return (NULL);
 458  468          else if (s != NULL)
 459  469                  return (s);
 460  470  
 461  471          if ((s = getenv("SMF_FMRI")) == NULL || strlen(s) >= sizeof (buf))
 462  472                  buf[0] = '\0';
 463  473          else
 464  474                  (void) strlcpy(buf, s, sizeof (buf));
 465  475  
 466  476          membar_producer();
 467  477          fmri = buf;
 468  478  
 469  479          return (get_fmri());
 470  480  }
 471  481  
 472  482  /*
 473  483   * Wrappers for smf_degrade/restore_instance()
 474  484   *
 475  485   * smf_restore_instance() is too heavy duty to be calling every time we
 476  486   * have a successful AD name<->SID lookup.
 477  487   */
 478  488  void
 479  489  degrade_svc(int poke_discovery, const char *reason)
 480  490  {
 481  491          const char *fmri;
 482  492  
 483  493          membar_consumer();
 484  494          if (degraded)
 485  495                  return;
 486  496  
 487  497          idmapdlog(LOG_ERR, "Degraded operation (%s).", reason);
 488  498  
 489  499          membar_producer();
 490  500          degraded = B_TRUE;
 491  501  
 492  502          if ((fmri = get_fmri()) != NULL)
 493  503                  (void) smf_degrade_instance(fmri, 0);
 494  504  
 495  505          /*
 496  506           * If the config update thread is in a state where auto-discovery could
 497  507           * be re-tried, then this will make it try it -- a sort of auto-refresh.
 498  508           */
 499  509          if (poke_discovery)
 500  510                  idmap_cfg_poke_updates();
 501  511  }
 502  512  
 503  513  void
 504  514  restore_svc(void)
 505  515  {
 506  516          const char *fmri;
 507  517  
 508  518          membar_consumer();
 509  519          if (!degraded)
 510  520                  return;
 511  521  
 512  522          if ((fmri = get_fmri()) == NULL)
 513  523                  (void) smf_restore_instance(fmri);
 514  524  
 515  525          membar_producer();
 516  526          degraded = B_FALSE;
 517  527  
 518  528          idmapdlog(LOG_NOTICE, "Normal operation restored");
 519  529  }
 520  530  
 521  531  
 522  532  /* printflike */
 523  533  void
 524  534  idmapdlog(int pri, const char *format, ...) {
 525  535          static time_t prev_ts;
 526  536          va_list args;
 527  537          char cbuf[CBUFSIZ];
 528  538          time_t ts;
 529  539  
 530  540          ts = time(NULL);
 531  541          if (prev_ts != ts) {
 532  542                  prev_ts = ts;
 533  543                  /* NB: cbuf has \n */
 534  544                  (void) fprintf(stderr, "@ %s",
 535  545                      ctime_r(&ts, cbuf, sizeof (cbuf)));
 536  546          }
 537  547  
 538  548          va_start(args, format);
 539  549          (void) vfprintf(stderr, format, args);
 540  550          (void) fprintf(stderr, "\n");
 541  551          va_end(args);
 542  552  
 543  553          /*
 544  554           * We don't want to fill up the logs with useless messages when
 545  555           * we're degraded, but we still want to log.
 546  556           */
 547  557          if (degraded)
 548  558                  pri = LOG_DEBUG;
 549  559  
 550  560          va_start(args, format);
 551  561          vsyslog(pri, format, args);
 552  562          va_end(args);
 553  563  }
 554  564  
 555  565  static void
 556  566  trace_str(nvlist_t *entry, char *n1, char *n2, char *str)
 557  567  {
 558  568          char name[IDMAP_TRACE_NAME_MAX+1];      /* Max used is only about 11 */
 559  569  
 560  570          (void) strlcpy(name, n1, sizeof (name));
 561  571          if (n2 != NULL)
 562  572                  (void) strlcat(name, n2, sizeof (name));
 563  573  
 564  574          (void) nvlist_add_string(entry, name, str);
 565  575  }
 566  576  
 567  577  static void
 568  578  trace_int(nvlist_t *entry, char *n1, char *n2, int64_t i)
 569  579  {
 570  580          char name[IDMAP_TRACE_NAME_MAX+1];      /* Max used is only about 11 */
 571  581  
 572  582          (void) strlcpy(name, n1, sizeof (name));
 573  583          if (n2 != NULL)
 574  584                  (void) strlcat(name, n2, sizeof (name));
 575  585  
 576  586          (void) nvlist_add_int64(entry, name, i);
 577  587  }
 578  588  
 579  589  static void
 580  590  trace_sid(nvlist_t *entry, char *n1, char *n2, idmap_sid *sid)
 581  591  {
 582  592          char *str;
 583  593  
 584  594          (void) asprintf(&str, "%s-%u", sid->prefix, sid->rid);
 585  595          if (str == NULL)
 586  596                  return;
 587  597  
 588  598          trace_str(entry, n1, n2, str);
 589  599          free(str);
 590  600  }
 591  601  
 592  602  static void
 593  603  trace_id(nvlist_t *entry, char *fromto, idmap_id *id, char *name, char *domain)
 594  604  {
 595  605          trace_int(entry, fromto, IDMAP_TRACE_TYPE, (int64_t)id->idtype);
 596  606          if (IS_ID_SID(*id)) {
 597  607                  if (name != NULL) {
 598  608                          char *str;
 599  609  
 600  610                          (void) asprintf(&str, "%s%s%s", name,
 601  611                              domain == NULL ? "" : "@",
 602  612                              domain == NULL ? "" : domain);
 603  613                          if (str != NULL) {
 604  614                                  trace_str(entry, fromto, IDMAP_TRACE_NAME, str);
 605  615                                  free(str);
 606  616                          }
 607  617                  }
 608  618                  if (id->idmap_id_u.sid.prefix != NULL) {
 609  619                          trace_sid(entry, fromto, IDMAP_TRACE_SID,
 610  620                              &id->idmap_id_u.sid);
 611  621                  }
 612  622          } else if (IS_ID_POSIX(*id)) {
 613  623                  if (name != NULL)
 614  624                          trace_str(entry, fromto, IDMAP_TRACE_NAME, name);
 615  625                  if (id->idmap_id_u.uid != IDMAP_SENTINEL_PID) {
 616  626                          trace_int(entry, fromto, IDMAP_TRACE_UNIXID,
 617  627                              (int64_t)id->idmap_id_u.uid);
 618  628                  }
 619  629          }
 620  630  }
 621  631  
 622  632  /*
 623  633   * Record a trace event.  TRACE() has already decided whether or not
 624  634   * tracing is required; what we do here is collect the data and send it
 625  635   * to its destination - to the trace log in the response, if
 626  636   * IDMAP_REQ_FLG_TRACE is set, and to the SMF service log, if debug/mapping
 627  637   * is greater than zero.
 628  638   */
 629  639  int
 630  640  trace(idmap_mapping *req, idmap_id_res *res, char *fmt, ...)
 631  641  {
 632  642          va_list va;
 633  643          char *buf;
 634  644          int err;
 635  645          nvlist_t *entry;
 636  646  
 637  647          assert(req != NULL);
 638  648          assert(res != NULL);
 639  649  
 640  650          err = nvlist_alloc(&entry, NV_UNIQUE_NAME, 0);
 641  651          if (err != 0) {
 642  652                  (void) fprintf(stderr, "trace nvlist_alloc(entry):  %s\n",
 643  653                      strerror(err));
 644  654                  return (0);
 645  655          }
 646  656  
 647  657          trace_id(entry, "from", &req->id1, req->id1name, req->id1domain);
 648  658          trace_id(entry, "to", &res->id, req->id2name, req->id2domain);
 649  659  
 650  660          if (IDMAP_ERROR(res->retcode)) {
 651  661                  trace_int(entry, IDMAP_TRACE_ERROR, NULL,
 652  662                      (int64_t)res->retcode);
 653  663          }
 654  664  
 655  665          va_start(va, fmt);
 656  666          (void) vasprintf(&buf, fmt, va);
 657  667          va_end(va);
 658  668          if (buf != NULL) {
 659  669                  trace_str(entry, IDMAP_TRACE_MESSAGE, NULL, buf);
 660  670                  free(buf);
 661  671          }
 662  672  
 663  673          if (DBG(MAPPING, 1))
 664  674                  idmap_trace_print_1(stderr, "", entry);
 665  675  
 666  676          if (req->flag & IDMAP_REQ_FLG_TRACE) {
 667  677                  /* Lazily allocate the trace list */
 668  678                  if (res->info.trace == NULL) {
 669  679                          err = nvlist_alloc(&res->info.trace, 0, 0);
 670  680                          if (err != 0) {
 671  681                                  res->info.trace = NULL; /* just in case */
 672  682                                  (void) fprintf(stderr,
 673  683                                      "trace nvlist_alloc(trace):  %s\n",
 674  684                                      strerror(err));
 675  685                                  nvlist_free(entry);
 676  686                                  return (0);
 677  687                          }
 678  688                  }
 679  689                  (void) nvlist_add_nvlist(res->info.trace, "", entry);
 680  690                  /* Note that entry is copied, so we must still free our copy */
 681  691          }
 682  692  
 683  693          nvlist_free(entry);
 684  694  
 685  695          return (0);
 686  696  }
  
    | 
      ↓ open down ↓ | 
    295 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX