Print this page
    
NEX-20549 smb AD join broken if no site name
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
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>
Merge with illumos-gate 8dcafc606a22eddb15cded4783cf27221c4404b3 (htable whitespace)
NEX-2750 idmapd spams console with "ignoring preferred_dc value"
NEX-2225 Unable to join NexentaStor to 2008 AD
NEX-2302 Need a way to control the idmap rediscovery interval
NEX-1810 extended security Kerberos (inbound)
NEX-1852 re-enable Kerberos-style AD join
NEX-1638 Updated DC Locator
 Includes work by: matt.barden@nexenta.com, kevin.crowe@nexenta.com
SMB-56 extended security NTLMSSP, inbound (lint)
SMB-56 extended security NTLMSSP, inbound
OS-7 Add cache timeout settings to idmapd manifest, increase defaults
re #13190 rb4312 idmapd error -9961 (No AD servers)
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/idmap/idmapd/idmap_config.c
          +++ new/usr/src/cmd/idmap/idmapd/idmap_config.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 2019 Nexenta Systems, Inc.  All rights reserved.
  24   24   */
  25   25  
  26   26  
  27   27  /*
  28   28   * Config routines common to idmap(1M) and idmapd(1M)
  29   29   */
  30   30  
  31   31  #include <stdlib.h>
  32   32  #include <strings.h>
  33   33  #include <libintl.h>
  34   34  #include <ctype.h>
  35   35  #include <errno.h>
  36   36  #include <stdio.h>
  37   37  #include <stdarg.h>
  
    | 
      ↓ open down ↓ | 
    4 lines elided | 
    
      ↑ open up ↑ | 
  
  38   38  #include <uuid/uuid.h>
  39   39  #include <pthread.h>
  40   40  #include <port.h>
  41   41  #include <sys/socket.h>
  42   42  #include <net/route.h>
  43   43  #include <sys/u8_textprep.h>
  44   44  #include <netinet/in.h>
  45   45  #include <arpa/inet.h>
  46   46  #include <netdb.h>
  47   47  #include <note.h>
       48 +#include <limits.h>
  48   49  #include "idmapd.h"
  49   50  #include "addisc.h"
  50   51  
  51   52  #define MACHINE_SID_LEN         (9 + 3 * 11)
  52   53  #define FMRI_BASE               "svc:/system/idmap"
  53   54  #define CONFIG_PG               "config"
  54   55  #define DEBUG_PG                "debug"
  55   56  #define RECONFIGURE             1
  56   57  #define POKE_AUTO_DISCOVERY     2
  57   58  #define KICK_AUTO_DISCOVERY     3
  58   59  
  59   60  /*
  60   61   * Default cache timeouts.  Can override via svccfg
  61   62   * config/id_cache_timeout = count: seconds
  62   63   * config/name_cache_timeout = count: seconds
  63   64   */
  64   65  #define ID_CACHE_TMO_DEFAULT    86400
  65   66  #define NAME_CACHE_TMO_DEFAULT  604800
  66   67  
  67   68  /*
  68   69   * Default maximum time between rediscovery runs.
  69   70   * config/rediscovery_interval = count: seconds
  
    | 
      ↓ open down ↓ | 
    12 lines elided | 
    
      ↑ open up ↑ | 
  
  70   71   */
  71   72  #define REDISCOVERY_INTERVAL_DEFAULT    3600
  72   73  
  73   74  /*
  74   75   * Mininum time between rediscovery runs, in case adutils gives us a
  75   76   * really short TTL (which it never should, but be defensive)
  76   77   * (not configurable) seconds.
  77   78   */
  78   79  #define MIN_REDISCOVERY_INTERVAL        60
  79   80  
       81 +/*
       82 + * Max number of concurrent door calls
       83 + */
       84 +#define MAX_THREADS_DEFAULT     40
       85 +
  80   86  enum event_type {
  81   87          EVENT_NOTHING,  /* Woke up for no good reason */
  82   88          EVENT_TIMEOUT,  /* Timeout expired */
  83   89          EVENT_ROUTING,  /* An interesting routing event happened */
  84   90          EVENT_POKED,    /* Requested from degrade_svc() */
  85   91          EVENT_KICKED,   /* Force rediscovery, i.e. DC failed. */
  86   92          EVENT_REFRESH,  /* SMF refresh */
  87   93  };
  88   94  
  89   95  
  90   96  static void idmapd_set_krb5_realm(char *);
  91   97  
  92   98  static pthread_t update_thread_handle = 0;
  93   99  
  94  100  static int idmapd_ev_port = -1;
  95  101  static int rt_sock = -1;
  96  102  
  97  103  struct enum_lookup_map directory_mapping_map[] = {
  98  104          { DIRECTORY_MAPPING_NONE, "none" },
  99  105          { DIRECTORY_MAPPING_NAME, "name" },
 100  106          { DIRECTORY_MAPPING_IDMU, "idmu" },
 101  107          { 0, NULL },
 102  108  };
 103  109  
 104  110  struct enum_lookup_map trust_dir_map[] = {
 105  111          { 1, "they trust us" },
 106  112          { 2, "we trust them" },
 107  113          { 3, "we trust each other" },
 108  114          { 0, NULL },
 109  115  };
 110  116  
 111  117  static int
 112  118  generate_machine_uuid(char **machine_uuid)
 113  119  {
 114  120          uuid_t uu;
 115  121  
 116  122          *machine_uuid = calloc(1, UUID_PRINTABLE_STRING_LENGTH + 1);
 117  123          if (*machine_uuid == NULL) {
 118  124                  idmapdlog(LOG_ERR, "Out of memory");
 119  125                  return (-1);
 120  126          }
 121  127  
 122  128          uuid_clear(uu);
 123  129          uuid_generate_time(uu);
 124  130          uuid_unparse(uu, *machine_uuid);
 125  131  
 126  132          return (0);
 127  133  }
 128  134  
 129  135  static int
 130  136  generate_machine_sid(char **machine_sid, char *machine_uuid)
 131  137  {
 132  138          union {
 133  139                  uuid_t uu;
 134  140                  uint32_t v[4];
 135  141          } uv;
 136  142          int len;
 137  143  
 138  144          /*
 139  145           * Split the 128-bit machine UUID into three 32-bit values
 140  146           * we'll use as the "sub-authorities" of the machine SID.
 141  147           * The machine_sid will have the form S-1-5-21-J-K-L
 142  148           * (that's four sub-authorities altogether) where:
 143  149           *      J = last 4 bytes of node_addr,
 144  150           *      K = time_mid, time_hi_and_version
 145  151           *      L = time_low
 146  152           * (see struct uuid)
 147  153           */
 148  154  
 149  155          (void) memset(&uv, 0, sizeof (uv));
 150  156          (void) uuid_parse(machine_uuid, uv.uu);
 151  157  
 152  158          len = asprintf(machine_sid, "S-1-5-21-%u-%u-%u",
 153  159              uv.v[3], uv.v[0], uv.v[1]);
 154  160  
 155  161          if (len == -1 || *machine_sid == NULL) {
 156  162                  idmapdlog(LOG_ERR, "Out of memory");
 157  163                  return (-1);
 158  164          }
 159  165  
 160  166          return (0);
 161  167  }
 162  168  
 163  169  
 164  170  /* In the case of error, exists is set to FALSE anyway */
 165  171  static int
 166  172  prop_exists(idmap_cfg_handles_t *handles, const char *name, boolean_t *exists)
 167  173  {
 168  174  
 169  175          scf_property_t *scf_prop;
 170  176  
 171  177          *exists = B_FALSE;
 172  178  
 173  179          scf_prop = scf_property_create(handles->main);
 174  180          if (scf_prop == NULL) {
 175  181                  idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
 176  182                      scf_strerror(scf_error()));
 177  183                  return (-1);
 178  184          }
 179  185  
 180  186          if (scf_pg_get_property(handles->config_pg, name, scf_prop) == 0)
 181  187                  *exists = B_TRUE;
 182  188  
 183  189          scf_property_destroy(scf_prop);
 184  190  
 185  191          return (0);
 186  192  }
 187  193  
 188  194  static int
 189  195  get_debug(idmap_cfg_handles_t *handles, const char *name)
 190  196  {
 191  197          int64_t i64 = 0;
 192  198  
 193  199          scf_property_t *scf_prop;
 194  200          scf_value_t *value;
 195  201  
 196  202          scf_prop = scf_property_create(handles->main);
 197  203          if (scf_prop == NULL) {
 198  204                  idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
 199  205                      scf_strerror(scf_error()));
 200  206                  abort();
 201  207          }
 202  208          value = scf_value_create(handles->main);
 203  209          if (value == NULL) {
 204  210                  idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
 205  211                      scf_strerror(scf_error()));
 206  212                  abort();
 207  213          }
 208  214  
 209  215          if (scf_pg_get_property(handles->debug_pg, name, scf_prop) < 0) {
 210  216                  /* this is OK: the property is just undefined */
 211  217                  goto destruction;
 212  218          }
 213  219  
 214  220  
 215  221          if (scf_property_get_value(scf_prop, value) < 0) {
 216  222                  /* It is still OK when a property doesn't have any value */
 217  223                  goto destruction;
 218  224          }
 219  225  
 220  226          if (scf_value_get_integer(value, &i64) != 0) {
 221  227                  idmapdlog(LOG_ERR, "Can not retrieve %s/%s:  %s",
 222  228                      DEBUG_PG, name, scf_strerror(scf_error()));
 223  229                  abort();
 224  230          }
 225  231  
 226  232  destruction:
 227  233          scf_value_destroy(value);
 228  234          scf_property_destroy(scf_prop);
 229  235  
 230  236          return ((int)i64);
 231  237  }
 232  238  
 233  239  static int
 234  240  get_val_bool(idmap_cfg_handles_t *handles, const char *name,
 235  241          boolean_t *val, boolean_t default_val)
 236  242  {
 237  243          int rc = 0;
 238  244  
 239  245          scf_property_t *scf_prop;
 240  246          scf_value_t *value;
 241  247  
 242  248          *val = default_val;
 243  249  
 244  250          scf_prop = scf_property_create(handles->main);
 245  251          if (scf_prop == NULL) {
 246  252                  idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
 247  253                      scf_strerror(scf_error()));
 248  254                  return (-1);
 249  255          }
 250  256          value = scf_value_create(handles->main);
 251  257          if (value == NULL) {
 252  258                  idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
 253  259                      scf_strerror(scf_error()));
 254  260                  scf_property_destroy(scf_prop);
 255  261                  return (-1);
 256  262          }
 257  263  
 258  264          /* It is OK if the property is undefined */
 259  265          if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0)
 260  266                  goto destruction;
 261  267  
 262  268  
 263  269          /* It is still OK when a property doesn't have any value */
 264  270          if (scf_property_get_value(scf_prop, value) < 0)
 265  271                  goto destruction;
 266  272  
 267  273          uint8_t b;
 268  274          rc = scf_value_get_boolean(value, &b);
 269  275  
 270  276          if (rc == 0)
 271  277                  *val = (boolean_t)b;
 272  278  
 273  279  destruction:
 274  280          scf_value_destroy(value);
 275  281          scf_property_destroy(scf_prop);
 276  282  
 277  283          return (rc);
 278  284  }
 279  285  
 280  286  static int
 281  287  get_val_int(idmap_cfg_handles_t *handles, const char *name,
 282  288          void *val, scf_type_t type)
 283  289  {
 284  290          int rc = 0;
 285  291  
 286  292          scf_property_t *scf_prop;
 287  293          scf_value_t *value;
 288  294  
 289  295          switch (type) {
 290  296          case SCF_TYPE_COUNT:
 291  297                  *(uint64_t *)val = 0;
 292  298                  break;
 293  299          case SCF_TYPE_INTEGER:
 294  300                  *(int64_t *)val = 0;
 295  301                  break;
 296  302          default:
 297  303                  idmapdlog(LOG_ERR, "Invalid scf integer type (%d)",
 298  304                      type);
 299  305                  abort();
 300  306          }
 301  307  
 302  308          scf_prop = scf_property_create(handles->main);
 303  309          if (scf_prop == NULL) {
 304  310                  idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
 305  311                      scf_strerror(scf_error()));
 306  312                  return (-1);
 307  313          }
 308  314          value = scf_value_create(handles->main);
 309  315          if (value == NULL) {
 310  316                  idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
 311  317                      scf_strerror(scf_error()));
 312  318                  scf_property_destroy(scf_prop);
 313  319                  return (-1);
 314  320          }
 315  321  
 316  322          if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0)
 317  323          /* this is OK: the property is just undefined */
 318  324                  goto destruction;
 319  325  
 320  326  
 321  327          if (scf_property_get_value(scf_prop, value) < 0)
 322  328          /* It is still OK when a property doesn't have any value */
 323  329                  goto destruction;
 324  330  
 325  331          switch (type) {
 326  332          case SCF_TYPE_COUNT:
 327  333                  rc = scf_value_get_count(value, val);
 328  334                  break;
 329  335          case SCF_TYPE_INTEGER:
 330  336                  rc = scf_value_get_integer(value, val);
 331  337                  break;
 332  338          default:
 333  339                  abort();        /* tested above */
 334  340                  /* NOTREACHED */
 335  341          }
 336  342  
 337  343          if (rc != 0) {
 338  344                  idmapdlog(LOG_ERR, "Can not retrieve config/%s:  %s",
 339  345                      name, scf_strerror(scf_error()));
 340  346          }
 341  347  
 342  348  destruction:
 343  349          scf_value_destroy(value);
 344  350          scf_property_destroy(scf_prop);
 345  351  
 346  352          return (rc);
 347  353  }
 348  354  
 349  355  static char *
 350  356  scf_value2string(const char *name, scf_value_t *value)
 351  357  {
 352  358          static size_t max_val = 0;
 353  359  
 354  360          if (max_val == 0)
 355  361                  max_val = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
 356  362  
 357  363          char buf[max_val + 1];
 358  364          if (scf_value_get_astring(value, buf, max_val + 1) < 0) {
 359  365                  idmapdlog(LOG_ERR, "Can not retrieve config/%s:  %s",
 360  366                      name, scf_strerror(scf_error()));
 361  367                  return (NULL);
 362  368          }
 363  369  
 364  370          char *s = strdup(buf);
 365  371          if (s == NULL)
 366  372                  idmapdlog(LOG_ERR, "Out of memory");
 367  373  
 368  374          return (s);
 369  375  }
 370  376  
 371  377  static int
 372  378  get_val_ds(idmap_cfg_handles_t *handles, const char *name, int defport,
 373  379                  ad_disc_ds_t **val)
 374  380  {
 375  381          char port_str[8];
 376  382          struct addrinfo hints;
 377  383          struct addrinfo *ai;
 378  384          ad_disc_ds_t *servers = NULL;
 379  385          scf_property_t *scf_prop;
 380  386          scf_value_t *value;
 381  387          scf_iter_t *iter;
 382  388          char *host, *portstr;
 383  389          int err, len, i;
 384  390          int count = 0;
 385  391          int rc = -1;
 386  392  
 387  393          *val = NULL;
 388  394  
 389  395  restart:
 390  396          scf_prop = scf_property_create(handles->main);
 391  397          if (scf_prop == NULL) {
 392  398                  idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
 393  399                      scf_strerror(scf_error()));
 394  400                  return (-1);
 395  401          }
 396  402  
 397  403          value = scf_value_create(handles->main);
 398  404          if (value == NULL) {
 399  405                  idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
 400  406                      scf_strerror(scf_error()));
 401  407                  scf_property_destroy(scf_prop);
 402  408                  return (-1);
 403  409          }
 404  410  
 405  411          iter = scf_iter_create(handles->main);
 406  412          if (iter == NULL) {
 407  413                  idmapdlog(LOG_ERR, "scf_iter_create() failed: %s",
 408  414                      scf_strerror(scf_error()));
 409  415                  scf_value_destroy(value);
 410  416                  scf_property_destroy(scf_prop);
 411  417                  return (-1);
 412  418          }
 413  419  
 414  420          if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0) {
 415  421                  /* this is OK: the property is just undefined */
 416  422                  rc = 0;
 417  423                  goto destruction;
 418  424          }
 419  425  
 420  426          if (scf_iter_property_values(iter, scf_prop) < 0) {
 421  427                  idmapdlog(LOG_ERR,
 422  428                      "scf_iter_property_values(%s) failed: %s",
 423  429                      name, scf_strerror(scf_error()));
 424  430                  goto destruction;
 425  431          }
 426  432  
 427  433          /* Workaround scf bugs -- can't reset an iteration */
 428  434          if (count == 0) {
 429  435                  while (scf_iter_next_value(iter, value) > 0)
 430  436                          count++;
 431  437  
 432  438                  if (count == 0) {
 433  439                          /* no values */
 434  440                          rc = 0;
 435  441                          goto destruction;
 436  442                  }
 437  443  
 438  444                  scf_value_destroy(value);
 439  445                  scf_iter_destroy(iter);
 440  446                  scf_property_destroy(scf_prop);
 441  447                  goto restart;
 442  448          }
 443  449  
 444  450          if ((servers = calloc(count + 1, sizeof (*servers))) == NULL) {
 445  451                  idmapdlog(LOG_ERR, "Out of memory");
 446  452                  goto destruction;
 447  453          }
 448  454  
 449  455          (void) memset(&hints, 0, sizeof (hints));
 450  456          hints.ai_protocol = IPPROTO_TCP;
 451  457          hints.ai_socktype = SOCK_STREAM;
 452  458          host = NULL;
 453  459  
 454  460          i = 0;
 455  461          while (i < count && scf_iter_next_value(iter, value) > 0) {
 456  462                  if (host) {
 457  463                          free(host);
 458  464                          host = NULL;
 459  465                  }
 460  466                  servers[i].priority = 0;
 461  467                  servers[i].weight = 100;
 462  468                  servers[i].port = defport;
 463  469                  if ((host = scf_value2string(name, value)) == NULL)
 464  470                          continue;
 465  471                  if ((portstr = strchr(host, ':')) != NULL) {
 466  472                          *portstr++ = '\0';
 467  473                          servers[i].port = strtol(portstr,
 468  474                              (char **)NULL, 10);
 469  475                          if (servers[i].port == 0)
 470  476                                  servers[i].port = defport;
 471  477                  }
 472  478  
 473  479                  /*
 474  480                   * Ignore this server if the hostname is too long
 475  481                   * or empty (continue without i++)
 476  482                   */
 477  483                  len = strlen(host);
 478  484                  if (len == 0) {
 479  485                          if (DBG(CONFIG, 1)) {
 480  486                                  idmapdlog(LOG_INFO, "%s host=\"\"", name);
 481  487                          }
 482  488                          continue;
 483  489                  }
 484  490                  if (len >= sizeof (servers->host)) {
 485  491                          idmapdlog(LOG_ERR, "Host name too long: %s", host);
 486  492                          idmapdlog(LOG_ERR, "ignoring %s value", name);
 487  493                          continue;
 488  494                  }
 489  495  
 490  496                  /*
 491  497                   * Get the host address too.  If we can't, then
 492  498                   * log an error and skip this host.
 493  499                   */
 494  500                  (void) snprintf(port_str, sizeof (port_str),
 495  501                      "%d", servers[i].port);
 496  502                  ai = NULL;
 497  503                  err = getaddrinfo(host, port_str, &hints, &ai);
 498  504                  if (err != 0) {
 499  505                          idmapdlog(LOG_ERR, "No address for host: %s (%s)",
 500  506                              host, gai_strerror(err));
 501  507                          idmapdlog(LOG_ERR, "ignoring %s value", name);
 502  508                          continue;
 503  509                  }
 504  510  
 505  511                  (void) strlcpy(servers[i].host, host,
 506  512                      sizeof (servers->host));
 507  513                  (void) memcpy(&servers[i].addr, ai->ai_addr, ai->ai_addrlen);
 508  514                  freeaddrinfo(ai);
 509  515  
 510  516                  /* Added a DS to the array. */
 511  517                  i++;
 512  518          }
 513  519          free(host);
 514  520  
 515  521          if (i == 0) {
 516  522                  if (DBG(CONFIG, 1)) {
 517  523                          idmapdlog(LOG_INFO, "%s is empty", name);
 518  524                  }
 519  525                  free(servers);
 520  526                  servers = NULL;
 521  527          }
 522  528          *val = servers;
 523  529  
 524  530          rc = 0;
 525  531  
 526  532  destruction:
 527  533          scf_value_destroy(value);
 528  534          scf_iter_destroy(iter);
 529  535          scf_property_destroy(scf_prop);
 530  536  
 531  537          if (rc < 0) {
 532  538                  if (servers)
 533  539                          free(servers);
 534  540                  *val = NULL;
 535  541          }
 536  542  
 537  543          return (rc);
 538  544  }
 539  545  
 540  546  static int
 541  547  get_val_astring(idmap_cfg_handles_t *handles, const char *name, char **val)
 542  548  {
 543  549          int rc = 0;
 544  550  
 545  551          scf_property_t *scf_prop;
 546  552          scf_value_t *value;
 547  553  
 548  554          scf_prop = scf_property_create(handles->main);
 549  555          if (scf_prop == NULL) {
 550  556                  idmapdlog(LOG_ERR, "scf_property_create() failed: %s",
 551  557                      scf_strerror(scf_error()));
 552  558                  return (-1);
 553  559          }
 554  560          value = scf_value_create(handles->main);
 555  561          if (value == NULL) {
 556  562                  idmapdlog(LOG_ERR, "scf_value_create() failed: %s",
 557  563                      scf_strerror(scf_error()));
 558  564                  scf_property_destroy(scf_prop);
 559  565                  return (-1);
 560  566          }
 561  567  
 562  568          *val = NULL;
 563  569  
 564  570          if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0)
 565  571          /* this is OK: the property is just undefined */
 566  572                  goto destruction;
 567  573  
 568  574          if (scf_property_get_value(scf_prop, value) < 0) {
 569  575                  idmapdlog(LOG_ERR,
 570  576                      "scf_property_get_value(%s) failed: %s",
 571  577                      name, scf_strerror(scf_error()));
 572  578                  rc = -1;
 573  579                  goto destruction;
 574  580          }
 575  581  
 576  582          *val = scf_value2string(name, value);
 577  583          if (*val == NULL)
 578  584                  rc = -1;
 579  585  
 580  586  destruction:
 581  587          scf_value_destroy(value);
 582  588          scf_property_destroy(scf_prop);
 583  589  
 584  590          if (rc < 0) {
 585  591                  if (*val)
 586  592                          free(*val);
 587  593                  *val = NULL;
 588  594          }
 589  595  
 590  596          return (rc);
 591  597  }
 592  598  
 593  599  
 594  600  static int
 595  601  del_val(
 596  602      idmap_cfg_handles_t *handles,
 597  603      scf_propertygroup_t *pg,
 598  604      const char *name)
 599  605  {
 600  606          int                     rc = -1;
 601  607          int                     ret;
 602  608          scf_transaction_t       *tx = NULL;
 603  609          scf_transaction_entry_t *ent = NULL;
 604  610  
 605  611          if ((tx = scf_transaction_create(handles->main)) == NULL) {
 606  612                  idmapdlog(LOG_ERR,
 607  613                      "scf_transaction_create() failed: %s",
 608  614                      scf_strerror(scf_error()));
 609  615                  goto destruction;
 610  616          }
 611  617          if ((ent = scf_entry_create(handles->main)) == NULL) {
 612  618                  idmapdlog(LOG_ERR,
 613  619                      "scf_entry_create() failed: %s",
 614  620                      scf_strerror(scf_error()));
 615  621                  goto destruction;
 616  622          }
 617  623  
 618  624          do {
 619  625                  if (scf_pg_update(pg) == -1) {
 620  626                          idmapdlog(LOG_ERR,
 621  627                              "scf_pg_update(%s) failed: %s",
 622  628                              name, scf_strerror(scf_error()));
 623  629                          goto destruction;
 624  630                  }
 625  631                  if (scf_transaction_start(tx, pg) != 0) {
 626  632                          idmapdlog(LOG_ERR,
 627  633                              "scf_transaction_start(%s) failed: %s",
 628  634                              name, scf_strerror(scf_error()));
 629  635                          goto destruction;
 630  636                  }
 631  637  
 632  638                  if (scf_transaction_property_delete(tx, ent, name) != 0) {
 633  639                          /* Don't complain if it already doesn't exist. */
 634  640                          if (scf_error() != SCF_ERROR_NOT_FOUND) {
 635  641                                  idmapdlog(LOG_ERR,
 636  642                                      "scf_transaction_property_delete() failed:"
 637  643                                      " %s",
 638  644                                      scf_strerror(scf_error()));
 639  645                          }
 640  646                          goto destruction;
 641  647                  }
 642  648  
 643  649                  ret = scf_transaction_commit(tx);
 644  650  
 645  651                  if (ret == 0)
 646  652                          scf_transaction_reset(tx);
 647  653          } while (ret == 0);
 648  654  
 649  655          if (ret == -1) {
 650  656                  idmapdlog(LOG_ERR,
 651  657                      "scf_transaction_commit(%s) failed: %s",
 652  658                      name, scf_strerror(scf_error()));
 653  659                  goto destruction;
 654  660          }
 655  661  
 656  662          rc = 0;
 657  663  
 658  664  destruction:
 659  665          if (ent != NULL)
 660  666                  scf_entry_destroy(ent);
 661  667          if (tx != NULL)
 662  668                  scf_transaction_destroy(tx);
 663  669          return (rc);
 664  670  }
 665  671  
 666  672  
 667  673  static int
 668  674  set_val(
 669  675      idmap_cfg_handles_t *handles,
 670  676      scf_propertygroup_t *pg,
 671  677      const char *name,
 672  678      scf_value_t *value)
 673  679  {
 674  680          int                     rc = -1;
 675  681          int                     i;
 676  682          scf_property_t          *prop = NULL;
 677  683          scf_transaction_t       *tx = NULL;
 678  684          scf_transaction_entry_t *ent = NULL;
 679  685  
 680  686          if ((prop = scf_property_create(handles->main)) == NULL ||
 681  687              (tx = scf_transaction_create(handles->main)) == NULL ||
 682  688              (ent = scf_entry_create(handles->main)) == NULL) {
 683  689                  idmapdlog(LOG_ERR, "Unable to set property %s",
 684  690                      name, scf_strerror(scf_error()));
 685  691                  goto destruction;
 686  692          }
 687  693  
 688  694          for (i = 0; i < MAX_TRIES; i++) {
 689  695                  int ret;
 690  696  
 691  697                  if (scf_pg_update(pg) == -1) {
 692  698                          idmapdlog(LOG_ERR,
 693  699                              "scf_pg_update() failed: %s",
 694  700                              scf_strerror(scf_error()));
 695  701                          goto destruction;
 696  702                  }
 697  703  
 698  704                  if (scf_transaction_start(tx, pg) == -1) {
 699  705                          idmapdlog(LOG_ERR,
 700  706                              "scf_transaction_start(%s) failed: %s",
 701  707                              name, scf_strerror(scf_error()));
 702  708                          goto destruction;
 703  709                  }
 704  710  
 705  711                  ret = scf_pg_get_property(pg, name, prop);
 706  712                  if (ret == SCF_SUCCESS) {
 707  713                          if (scf_transaction_property_change_type(tx, ent, name,
 708  714                              scf_value_type(value)) < 0) {
 709  715                                  idmapdlog(LOG_ERR,
 710  716                                      "scf_transaction_property_change_type(%s)"
 711  717                                      " failed: %s",
 712  718                                      name, scf_strerror(scf_error()));
 713  719                                  goto destruction;
 714  720                          }
 715  721                  } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
 716  722                          if (scf_transaction_property_new(tx, ent, name,
 717  723                              scf_value_type(value)) < 0) {
 718  724                                  idmapdlog(LOG_ERR,
 719  725                                      "scf_transaction_property_new() failed: %s",
 720  726                                      scf_strerror(scf_error()));
 721  727                                  goto destruction;
 722  728                          }
 723  729                  } else {
 724  730                          idmapdlog(LOG_ERR,
 725  731                              "scf_pg_get_property(%s) failed: %s",
 726  732                              name, scf_strerror(scf_error()));
 727  733                          goto destruction;
 728  734                  }
 729  735  
 730  736                  if (scf_entry_add_value(ent, value) == -1) {
 731  737                          idmapdlog(LOG_ERR,
 732  738                              "scf_entry_add_value() failed: %s",
 733  739                              scf_strerror(scf_error()));
 734  740                          goto destruction;
 735  741                  }
 736  742  
 737  743                  ret = scf_transaction_commit(tx);
 738  744                  if (ret == 0) {
 739  745                          /*
 740  746                           * Property group set in scf_transaction_start()
 741  747                           * is not the most recent. Update pg, reset tx and
 742  748                           * retry tx.
 743  749                           */
 744  750                          idmapdlog(LOG_WARNING,
 745  751                              "scf_transaction_commit(%s) failed: %s",
 746  752                              name, scf_strerror(scf_error()));
 747  753                          scf_transaction_reset(tx);
 748  754                          continue;
 749  755                  }
 750  756                  if (ret != 1) {
 751  757                          idmapdlog(LOG_ERR,
 752  758                              "scf_transaction_commit(%s) failed: %s",
 753  759                              name, scf_strerror(scf_error()));
 754  760                          goto destruction;
 755  761                  }
 756  762                  /* Success! */
 757  763                  rc = 0;
 758  764                  break;
 759  765          }
 760  766  
 761  767  destruction:
 762  768          scf_entry_destroy(ent);
 763  769          scf_transaction_destroy(tx);
 764  770          scf_property_destroy(prop);
 765  771          return (rc);
 766  772  }
 767  773  
 768  774  static int
 769  775  set_val_integer(
 770  776      idmap_cfg_handles_t *handles,
 771  777      scf_propertygroup_t *pg,
 772  778      const char *name,
 773  779      int64_t val)
 774  780  {
 775  781          scf_value_t             *value = NULL;
 776  782          int                     rc;
 777  783  
 778  784          if ((value = scf_value_create(handles->main)) == NULL) {
 779  785                  idmapdlog(LOG_ERR, "Unable to set property %s",
 780  786                      name, scf_strerror(scf_error()));
 781  787                  return (-1);
 782  788          }
 783  789  
 784  790          scf_value_set_integer(value, val);
 785  791  
 786  792          rc = set_val(handles, pg, name, value);
 787  793  
 788  794          scf_value_destroy(value);
 789  795  
 790  796          return (rc);
 791  797  }
 792  798  
 793  799  
 794  800  static int
 795  801  set_val_astring(
 796  802      idmap_cfg_handles_t *handles,
 797  803      scf_propertygroup_t *pg,
 798  804      const char *name,
 799  805      const char *val)
 800  806  {
 801  807          scf_value_t             *value = NULL;
 802  808          int                     rc = -1;
 803  809  
 804  810          if ((value = scf_value_create(handles->main)) == NULL) {
 805  811                  idmapdlog(LOG_ERR, "Unable to set property %s",
 806  812                      name, scf_strerror(scf_error()));
 807  813                  goto out;
 808  814          }
 809  815  
 810  816          if (scf_value_set_astring(value, val) == -1) {
 811  817                  idmapdlog(LOG_ERR,
 812  818                      "scf_value_set_astring() failed: %s",
 813  819                      scf_strerror(scf_error()));
 814  820                  goto out;
 815  821          }
 816  822  
 817  823          rc = set_val(handles, pg, name, value);
 818  824  
 819  825  out:
 820  826          scf_value_destroy(value);
 821  827          return (rc);
 822  828  }
 823  829  
 824  830  
 825  831  
 826  832  /*
 827  833   * This function updates a boolean value.
 828  834   * If nothing has changed it returns 0 else 1
 829  835   */
 830  836  static int
 831  837  update_bool(boolean_t *value, boolean_t *new, char *name)
 832  838  {
 833  839          if (*value == *new)
 834  840                  return (0);
 835  841  
 836  842          if (DBG(CONFIG, 1)) {
 837  843                  idmapdlog(LOG_INFO, "change %s=%s", name,
 838  844                      *new ? "true" : "false");
 839  845          }
 840  846  
 841  847          *value = *new;
 842  848          return (1);
 843  849  }
 844  850  
 845  851  /*
 846  852   * This function updates a uint64_t value.
 847  853   * If nothing has changed it returns 0 else 1
 848  854   */
 849  855  static int
 850  856  update_uint64(uint64_t *value, uint64_t *new, char *name)
 851  857  {
 852  858          if (*value == *new)
 853  859                  return (0);
 854  860  
 855  861          if (DBG(CONFIG, 1))
 856  862                  idmapdlog(LOG_INFO, "change %s=%llu", name, *new);
 857  863  
 858  864          *value = *new;
 859  865          return (1);
 860  866  }
 861  867  
 862  868  /*
 863  869   * This function updates a string value.
 864  870   * If nothing has changed it returns 0 else 1
 865  871   */
 866  872  static int
 867  873  update_string(char **value, char **new, char *name)
 868  874  {
 869  875          int changed;
 870  876  
 871  877          if (*new == NULL && *value != NULL)
 872  878                  changed = 1;
 873  879          else if (*new != NULL && *value == NULL)
 874  880                  changed = 1;
 875  881          else if (*new != NULL && *value != NULL && strcmp(*new, *value) != 0)
 876  882                  changed = 1;
 877  883          else
 878  884                  changed = 0;
 879  885  
 880  886          /*
 881  887           * Note that even if unchanged we can't just return; we must free one
 882  888           * of the values.
 883  889           */
 884  890  
 885  891          if (DBG(CONFIG, 1) && changed)
 886  892                  idmapdlog(LOG_INFO, "change %s=%s", name, CHECK_NULL(*new));
 887  893  
 888  894          free(*value);
 889  895          *value = *new;
 890  896          *new = NULL;
 891  897          return (changed);
 892  898  }
 893  899  
 894  900  static int
 895  901  update_enum(int *value, int *new, char *name, struct enum_lookup_map *map)
 896  902  {
 897  903          if (*value == *new)
 898  904                  return (0);
 899  905  
 900  906          if (DBG(CONFIG, 1)) {
 901  907                  idmapdlog(LOG_INFO, "change %s=%s", name,
 902  908                      enum_lookup(*new, map));
 903  909          }
 904  910  
 905  911          *value = *new;
 906  912  
 907  913          return (1);
 908  914  }
 909  915  
 910  916  /*
 911  917   * This function updates a directory service structure.
 912  918   * If nothing has changed it returns 0 else 1
 913  919   */
 914  920  static int
 915  921  update_dirs(ad_disc_ds_t **value, ad_disc_ds_t **new, char *name)
 916  922  {
 917  923  
 918  924          if (*value == *new)
 919  925                  /* Nothing to do */
 920  926                  return (0);
 921  927  
 922  928          if (*value != NULL && *new != NULL &&
 923  929              ad_disc_compare_ds(*value, *new) == 0) {
 924  930                  free(*new);
 925  931                  *new = NULL;
 926  932                  return (0);
 927  933          }
 928  934  
 929  935          if (*value != NULL)
 930  936                  free(*value);
 931  937  
 932  938          *value = *new;
 933  939          *new = NULL;
 934  940  
 935  941          if (*value == NULL) {
 936  942                  /* We're unsetting this DS property */
 937  943                  if (DBG(CONFIG, 1))
 938  944                          idmapdlog(LOG_INFO, "change %s=<none>", name);
 939  945                  return (1);
 940  946          }
 941  947  
 942  948          if (DBG(CONFIG, 1)) {
 943  949                  /* List all the new DSs */
 944  950                  char buf[64];
 945  951                  ad_disc_ds_t *ds;
 946  952                  for (ds = *value; ds->host[0] != '\0'; ds++) {
 947  953                          if (ad_disc_getnameinfo(buf, sizeof (buf), &ds->addr))
 948  954                                  (void) strlcpy(buf, "?", sizeof (buf));
 949  955                          idmapdlog(LOG_INFO, "change %s=%s addr=%s port=%d",
 950  956                              name, ds->host, buf, ds->port);
 951  957                  }
 952  958          }
 953  959          return (1);
 954  960  }
 955  961  
 956  962  /*
 957  963   * This function updates a trusted domains structure.
 958  964   * If nothing has changed it returns 0 else 1
 959  965   */
 960  966  static int
 961  967  update_trusted_domains(ad_disc_trusteddomains_t **value,
 962  968                          ad_disc_trusteddomains_t **new, char *name)
 963  969  {
 964  970          int i;
 965  971  
 966  972          if (*value == *new)
 967  973                  /* Nothing to do */
 968  974                  return (0);
 969  975  
 970  976          if (*value != NULL && *new != NULL &&
 971  977              ad_disc_compare_trusteddomains(*value, *new) == 0) {
 972  978                  free(*new);
 973  979                  *new = NULL;
 974  980                  return (0);
 975  981          }
 976  982  
 977  983          if (*value != NULL)
 978  984                  free(*value);
 979  985  
 980  986          *value = *new;
 981  987          *new = NULL;
 982  988  
 983  989          if (*value == NULL) {
 984  990                  /* We're unsetting this DS property */
 985  991                  if (DBG(CONFIG, 1))
 986  992                          idmapdlog(LOG_INFO, "change %s=<none>", name);
 987  993                  return (1);
 988  994          }
 989  995  
 990  996          if (DBG(CONFIG, 1)) {
 991  997                  /* List all the new domains */
 992  998                  for (i = 0; (*value)[i].domain[0] != '\0'; i++) {
 993  999                          idmapdlog(LOG_INFO, "change %s=%s direction=%s", name,
 994 1000                              (*value)[i].domain,
 995 1001                              enum_lookup((*value)[i].direction, trust_dir_map));
 996 1002                  }
 997 1003          }
 998 1004          return (1);
 999 1005  }
1000 1006  
1001 1007  
1002 1008  /*
1003 1009   * This function updates a domains in a forest structure.
1004 1010   * If nothing has changed it returns 0 else 1
1005 1011   */
1006 1012  static int
1007 1013  update_domains_in_forest(ad_disc_domainsinforest_t **value,
1008 1014                          ad_disc_domainsinforest_t **new, char *name)
1009 1015  {
1010 1016          int i;
1011 1017  
1012 1018          if (*value == *new)
1013 1019                  /* Nothing to do */
1014 1020                  return (0);
1015 1021  
1016 1022          if (*value != NULL && *new != NULL &&
1017 1023              ad_disc_compare_domainsinforest(*value, *new) == 0) {
1018 1024                  free(*new);
1019 1025                  *new = NULL;
1020 1026                  return (0);
1021 1027          }
1022 1028  
1023 1029          if (*value != NULL)
1024 1030                  free(*value);
1025 1031  
1026 1032          *value = *new;
1027 1033          *new = NULL;
1028 1034  
1029 1035          if (*value == NULL) {
1030 1036                  /* We're unsetting this DS property */
1031 1037                  if (DBG(CONFIG, 1))
1032 1038                          idmapdlog(LOG_INFO, "change %s=<none>", name);
1033 1039                  return (1);
1034 1040          }
1035 1041  
1036 1042          if (DBG(CONFIG, 1)) {
1037 1043                  /* List all the new domains */
1038 1044                  for (i = 0; (*value)[i].domain[0] != '\0'; i++) {
1039 1045                          idmapdlog(LOG_INFO, "change %s=%s", name,
1040 1046                              (*value)[i].domain);
1041 1047                  }
1042 1048          }
1043 1049          return (1);
1044 1050  }
1045 1051  
1046 1052  
1047 1053  static void
1048 1054  free_trusted_forests(idmap_trustedforest_t **value, int *num_values)
1049 1055  {
1050 1056          int i;
1051 1057  
1052 1058          for (i = 0; i < *num_values; i++) {
1053 1059                  free((*value)[i].forest_name);
1054 1060                  free((*value)[i].global_catalog);
1055 1061                  free((*value)[i].domains_in_forest);
1056 1062          }
1057 1063          free(*value);
1058 1064          *value = NULL;
1059 1065          *num_values = 0;
1060 1066  }
1061 1067  
1062 1068  
1063 1069  static int
1064 1070  compare_trusteddomainsinforest(ad_disc_domainsinforest_t *df1,
1065 1071                          ad_disc_domainsinforest_t *df2)
1066 1072  {
1067 1073          int             i, j;
1068 1074          int             num_df1 = 0;
1069 1075          int             num_df2 = 0;
1070 1076          boolean_t       match;
1071 1077  
1072 1078          for (i = 0; df1[i].domain[0] != '\0'; i++)
1073 1079                  if (df1[i].trusted)
1074 1080                          num_df1++;
1075 1081  
1076 1082          for (j = 0; df2[j].domain[0] != '\0'; j++)
1077 1083                  if (df2[j].trusted)
1078 1084                          num_df2++;
1079 1085  
1080 1086          if (num_df1 != num_df2)
1081 1087                  return (1);
1082 1088  
1083 1089          for (i = 0; df1[i].domain[0] != '\0'; i++) {
1084 1090                  if (df1[i].trusted) {
1085 1091                          match = B_FALSE;
1086 1092                          for (j = 0; df2[j].domain[0] != '\0'; j++) {
1087 1093                                  if (df2[j].trusted &&
1088 1094                                      domain_eq(df1[i].domain, df2[j].domain) &&
1089 1095                                      strcmp(df1[i].sid, df2[j].sid) == 0) {
1090 1096                                          match = B_TRUE;
1091 1097                                          break;
1092 1098                                  }
1093 1099                          }
1094 1100                          if (!match)
1095 1101                                  return (1);
1096 1102                  }
1097 1103          }
1098 1104          return (0);
1099 1105  }
1100 1106  
1101 1107  
1102 1108  
1103 1109  /*
1104 1110   * This function updates trusted forest structure.
1105 1111   * If nothing has changed it returns 0 else 1
1106 1112   */
1107 1113  static int
1108 1114  update_trusted_forest(idmap_trustedforest_t **value, int *num_value,
1109 1115                          idmap_trustedforest_t **new, int *num_new, char *name)
1110 1116  {
1111 1117          int i, j;
1112 1118          boolean_t match;
1113 1119  
1114 1120          if (*value == *new)
1115 1121                  /* Nothing to do */
1116 1122                  return (0);
1117 1123  
1118 1124          if (*value != NULL && *new != NULL) {
1119 1125                  if (*num_value != *num_new)
1120 1126                          goto not_equal;
1121 1127                  for (i = 0; i < *num_value; i++) {
1122 1128                          match = B_FALSE;
1123 1129                          for (j = 0; j < *num_new; j++) {
1124 1130                                  if (strcmp((*value)[i].forest_name,
1125 1131                                      (*new)[j].forest_name) == 0 &&
1126 1132                                      ad_disc_compare_ds(
1127 1133                                      (*value)[i].global_catalog,
1128 1134                                      (*new)[j].global_catalog) == 0 &&
1129 1135                                      compare_trusteddomainsinforest(
1130 1136                                      (*value)[i].domains_in_forest,
1131 1137                                      (*new)[j].domains_in_forest) == 0) {
1132 1138                                          match = B_TRUE;
1133 1139                                          break;
1134 1140                                  }
1135 1141                          }
1136 1142                          if (!match)
1137 1143                                  goto not_equal;
1138 1144                  }
1139 1145                  free_trusted_forests(new, num_new);
1140 1146                  return (0);
1141 1147          }
1142 1148  not_equal:
1143 1149          if (*value != NULL)
1144 1150                  free_trusted_forests(value, num_value);
1145 1151          *value = *new;
1146 1152          *num_value = *num_new;
1147 1153          *new = NULL;
1148 1154          *num_new = 0;
1149 1155  
1150 1156          if (*value == NULL) {
1151 1157                  /* We're unsetting this DS property */
1152 1158                  if (DBG(CONFIG, 1))
1153 1159                          idmapdlog(LOG_INFO, "change %s=<none>", name);
1154 1160                  return (1);
1155 1161          }
1156 1162  
1157 1163          if (DBG(CONFIG, 1)) {
1158 1164                  /* List all the trusted forests */
1159 1165                  for (i = 0; i < *num_value; i++) {
1160 1166                          idmap_trustedforest_t *f = &(*value)[i];
1161 1167                          for (j = 0;
1162 1168                              f->domains_in_forest[j].domain[0] != '\0';
1163 1169                              j++) {
1164 1170                                  /* List trusted Domains in the forest. */
1165 1171                                  if (f->domains_in_forest[j].trusted)
1166 1172                                          idmapdlog(LOG_INFO,
1167 1173                                              "change %s=%s domain=%s",
1168 1174                                              name, f->forest_name,
1169 1175                                              f->domains_in_forest[j].domain);
1170 1176                          }
1171 1177                          /* List the hosts */
1172 1178                          for (j = 0;
1173 1179                              f->global_catalog[j].host[0] != '\0';
1174 1180                              j++) {
1175 1181                                  idmapdlog(LOG_INFO,
1176 1182                                      "change %s=%s host=%s port=%d",
1177 1183                                      name, f->forest_name,
1178 1184                                      f->global_catalog[j].host,
1179 1185                                      f->global_catalog[j].port);
1180 1186                          }
1181 1187                  }
1182 1188          }
1183 1189          return (1);
1184 1190  }
1185 1191  
1186 1192  const char *
1187 1193  enum_lookup(int value, struct enum_lookup_map *map)
1188 1194  {
1189 1195          for (; map->string != NULL; map++) {
1190 1196                  if (value == map->value) {
1191 1197                          return (map->string);
1192 1198                  }
1193 1199          }
1194 1200          return ("(invalid)");
1195 1201  }
1196 1202  
1197 1203  /*
1198 1204   * Returns 1 if the PF_ROUTE socket event indicates that we should rescan the
1199 1205   * interfaces.
1200 1206   *
1201 1207   * Shamelessly based on smb_nics_changed() and other PF_ROUTE uses in ON.
1202 1208   */
1203 1209  static
1204 1210  boolean_t
1205 1211  pfroute_event_is_interesting(int rt_sock)
1206 1212  {
1207 1213          int nbytes;
1208 1214          int64_t msg[2048 / 8];
1209 1215          struct rt_msghdr *rtm;
1210 1216          boolean_t is_interesting = B_FALSE;
1211 1217  
1212 1218          for (;;) {
1213 1219                  if ((nbytes = read(rt_sock, msg, sizeof (msg))) <= 0)
1214 1220                          break;
1215 1221                  rtm = (struct rt_msghdr *)msg;
1216 1222                  if (rtm->rtm_version != RTM_VERSION)
1217 1223                          continue;
1218 1224                  if (nbytes < rtm->rtm_msglen)
1219 1225                          continue;
1220 1226                  switch (rtm->rtm_type) {
1221 1227                  case RTM_NEWADDR:
1222 1228                  case RTM_DELADDR:
1223 1229                  case RTM_IFINFO:
1224 1230                          is_interesting = B_TRUE;
1225 1231                          break;
1226 1232                  default:
1227 1233                          break;
1228 1234                  }
1229 1235          }
1230 1236          return (is_interesting);
1231 1237  }
1232 1238  
1233 1239  /*
1234 1240   * Wait for an event, and report what kind of event occurred.
1235 1241   *
1236 1242   * Note that there are cases where we are awoken but don't care about
1237 1243   * the lower-level event.  We can't just loop here because we can't
1238 1244   * readily calculate how long to sleep the next time.  We return
1239 1245   * EVENT_NOTHING and let the caller loop.
1240 1246   */
1241 1247  static
1242 1248  enum event_type
1243 1249  wait_for_event(struct timespec *timeoutp)
1244 1250  {
1245 1251          port_event_t pe;
1246 1252  
1247 1253          (void) memset(&pe, 0, sizeof (pe));
1248 1254          if (port_get(idmapd_ev_port, &pe, timeoutp) != 0) {
1249 1255                  switch (errno) {
1250 1256                  case EINTR:
1251 1257                          return (EVENT_NOTHING);
1252 1258                  case ETIME:
1253 1259                          /* Timeout */
1254 1260                          return (EVENT_TIMEOUT);
1255 1261                  default:
1256 1262                          /* EBADF, EBADFD, EFAULT, EINVAL (end of time?)? */
1257 1263                          idmapdlog(LOG_ERR, "Event port failed: %s",
1258 1264                              strerror(errno));
1259 1265                          exit(1);
1260 1266                          /* NOTREACHED */
1261 1267                  }
1262 1268          }
1263 1269  
1264 1270  
1265 1271          switch (pe.portev_source) {
1266 1272          case 0:
1267 1273                  /*
1268 1274                   * This isn't documented, but seems to be what you get if
1269 1275                   * the timeout is zero seconds and there are no events
1270 1276                   * pending.
1271 1277                   */
1272 1278                  return (EVENT_TIMEOUT);
1273 1279  
1274 1280          case PORT_SOURCE_USER:
1275 1281                  switch (pe.portev_events) {
1276 1282                  case RECONFIGURE:
1277 1283                          return (EVENT_REFRESH);
1278 1284                  case POKE_AUTO_DISCOVERY:
1279 1285                          return (EVENT_POKED);
1280 1286                  case KICK_AUTO_DISCOVERY:
1281 1287                          return (EVENT_KICKED);
1282 1288                  }
1283 1289                  return (EVENT_NOTHING);
1284 1290  
1285 1291          case PORT_SOURCE_FD:
1286 1292                  if (pe.portev_object == rt_sock) {
1287 1293                          /*
1288 1294                           * PF_ROUTE socket read event:
1289 1295                           *    re-associate fd
1290 1296                           *    handle event
1291 1297                           */
1292 1298                          if (port_associate(idmapd_ev_port, PORT_SOURCE_FD,
1293 1299                              rt_sock, POLLIN, NULL) != 0) {
1294 1300                                  idmapdlog(LOG_ERR, "Failed to re-associate the "
1295 1301                                      "routing socket with the event port: %s",
1296 1302                                      strerror(errno));
1297 1303                                  abort();
1298 1304                          }
1299 1305                          /*
1300 1306                           * The network configuration may still be in flux.
1301 1307                           * No matter, the resolver will re-transmit and
1302 1308                           * timeout if need be.
1303 1309                           */
1304 1310                          if (pfroute_event_is_interesting(rt_sock)) {
1305 1311                                  if (DBG(CONFIG, 1)) {
1306 1312                                          idmapdlog(LOG_DEBUG,
1307 1313                                              "Interesting routing event");
1308 1314                                  }
1309 1315                                  return (EVENT_ROUTING);
1310 1316                          } else {
1311 1317                                  if (DBG(CONFIG, 2)) {
1312 1318                                          idmapdlog(LOG_DEBUG,
1313 1319                                              "Boring routing event");
1314 1320                                  }
1315 1321                                  return (EVENT_NOTHING);
1316 1322                          }
1317 1323                  }
1318 1324                  /* Event on an FD other than the routing FD? Ignore it. */
1319 1325                  break;
1320 1326          }
1321 1327  
1322 1328          return (EVENT_NOTHING);
1323 1329  }
1324 1330  
1325 1331  void *
1326 1332  idmap_cfg_update_thread(void *arg)
1327 1333  {
1328 1334          NOTE(ARGUNUSED(arg))
1329 1335          idmap_pg_config_t *pgcfg = &_idmapdstate.cfg->pgcfg;
1330 1336          const ad_disc_t         ad_ctx = _idmapdstate.cfg->handles.ad_ctx;
1331 1337          int flags = CFG_DISCOVER;
1332 1338  
1333 1339          for (;;) {
1334 1340                  struct timespec timeout;
1335 1341                  struct timespec *timeoutp;
1336 1342                  int             rc;
1337 1343                  int             ttl, max_ttl;
1338 1344  
1339 1345                  (void) ad_disc_SubnetChanged(ad_ctx);
1340 1346  
1341 1347                  rc = idmap_cfg_load(_idmapdstate.cfg, flags);
1342 1348                  if (rc < -1) {
1343 1349                          idmapdlog(LOG_ERR, "Fatal errors while reading "
1344 1350                              "SMF properties");
1345 1351                          exit(1);
1346 1352                  } else if (rc == -1) {
1347 1353                          idmapdlog(LOG_WARNING,
1348 1354                              "Errors re-loading configuration may cause AD "
1349 1355                              "lookups to fail");
1350 1356                  }
1351 1357  
1352 1358                  /*
1353 1359                   * Wait for an interesting event.  Note that we might get
1354 1360                   * boring events between interesting events.  If so, we loop.
1355 1361                   */
1356 1362                  flags = CFG_DISCOVER;
1357 1363                  for (;;) {
1358 1364                          /*
1359 1365                           * If we don't know our domain name, don't bother
1360 1366                           * with rediscovery until the next config change.
1361 1367                           * Avoids hourly noise in workgroup mode.
1362 1368                           */
1363 1369                          if (pgcfg->domain_name == NULL)
1364 1370                                  ttl = -1;
1365 1371                          else
1366 1372                                  ttl = ad_disc_get_TTL(ad_ctx);
1367 1373                          if (ttl < 0) {
1368 1374                                  timeoutp = NULL;
1369 1375                          } else {
1370 1376                                  max_ttl = (int)pgcfg->rediscovery_interval;
1371 1377                                  if (ttl > max_ttl)
1372 1378                                          ttl = max_ttl;
1373 1379                                  if (ttl < MIN_REDISCOVERY_INTERVAL)
1374 1380                                          ttl = MIN_REDISCOVERY_INTERVAL;
1375 1381                                  timeout.tv_sec = ttl;
1376 1382                                  timeout.tv_nsec = 0;
1377 1383                                  timeoutp = &timeout;
1378 1384                          }
1379 1385  
1380 1386                          if (DBG(CONFIG, 1))
1381 1387                                  idmapdlog(LOG_DEBUG,
1382 1388                                      "_cfg_update_thread waiting");
1383 1389  
1384 1390                          switch (wait_for_event(timeoutp)) {
1385 1391                          case EVENT_NOTHING:
1386 1392                                  if (DBG(CONFIG, 2))
1387 1393                                          idmapdlog(LOG_DEBUG, "Boring event.");
1388 1394                                  continue;
1389 1395                          case EVENT_REFRESH:
1390 1396                                  if (DBG(CONFIG, 1))
1391 1397                                          idmapdlog(LOG_INFO, "SMF refresh");
1392 1398                                  /*
1393 1399                                   * Forget any DC we had previously.
1394 1400                                   */
1395 1401                                  flags |= CFG_FORGET_DC;
1396 1402  
1397 1403                                  /*
1398 1404                                   * Blow away the ccache, we might have
1399 1405                                   * re-joined the domain or joined a new one
1400 1406                                   */
1401 1407                                  (void) unlink(IDMAP_CACHEDIR "/ccache");
1402 1408                                  break;
1403 1409                          case EVENT_POKED:
1404 1410                                  if (DBG(CONFIG, 1))
1405 1411                                          idmapdlog(LOG_DEBUG, "poked");
1406 1412                                  break;
1407 1413                          case EVENT_KICKED:
1408 1414                                  if (DBG(CONFIG, 1))
1409 1415                                          idmapdlog(LOG_DEBUG, "kicked");
1410 1416                                  flags |= CFG_FORGET_DC;
1411 1417                                  break;
1412 1418                          case EVENT_TIMEOUT:
1413 1419                                  if (DBG(CONFIG, 1))
1414 1420                                          idmapdlog(LOG_DEBUG, "TTL expired");
1415 1421                                  break;
1416 1422                          case EVENT_ROUTING:
1417 1423                                  /* Already logged to DEBUG */
1418 1424                                  break;
1419 1425                          }
1420 1426                          /* An interesting event! */
1421 1427                          break;
1422 1428                  }
1423 1429          }
1424 1430          /*
1425 1431           * Lint isn't happy with the concept of a function declared to
1426 1432           * return something, that doesn't return.  Of course, merely adding
1427 1433           * the return isn't enough, because it's never reached...
1428 1434           */
1429 1435          /*NOTREACHED*/
1430 1436          return (NULL);
1431 1437  }
1432 1438  
1433 1439  int
1434 1440  idmap_cfg_start_updates(void)
1435 1441  {
1436 1442          if ((idmapd_ev_port = port_create()) < 0) {
1437 1443                  idmapdlog(LOG_ERR, "Failed to create event port: %s",
1438 1444                      strerror(errno));
1439 1445                  return (-1);
1440 1446          }
1441 1447  
1442 1448          if ((rt_sock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
1443 1449                  idmapdlog(LOG_ERR, "Failed to open routing socket: %s",
1444 1450                      strerror(errno));
1445 1451                  (void) close(idmapd_ev_port);
1446 1452                  return (-1);
1447 1453          }
1448 1454  
1449 1455          if (fcntl(rt_sock, F_SETFL, O_NDELAY|O_NONBLOCK) < 0) {
1450 1456                  idmapdlog(LOG_ERR, "Failed to set routing socket flags: %s",
1451 1457                      strerror(errno));
1452 1458                  (void) close(rt_sock);
1453 1459                  (void) close(idmapd_ev_port);
1454 1460                  return (-1);
1455 1461          }
1456 1462  
1457 1463          if (port_associate(idmapd_ev_port, PORT_SOURCE_FD,
1458 1464              rt_sock, POLLIN, NULL) != 0) {
1459 1465                  idmapdlog(LOG_ERR, "Failed to associate the routing "
1460 1466                      "socket with the event port: %s", strerror(errno));
1461 1467                  (void) close(rt_sock);
1462 1468                  (void) close(idmapd_ev_port);
1463 1469                  return (-1);
1464 1470          }
1465 1471  
1466 1472          if ((errno = pthread_create(&update_thread_handle, NULL,
1467 1473              idmap_cfg_update_thread, NULL)) != 0) {
1468 1474                  idmapdlog(LOG_ERR, "Failed to start update thread: %s",
1469 1475                      strerror(errno));
1470 1476                  (void) port_dissociate(idmapd_ev_port, PORT_SOURCE_FD, rt_sock);
1471 1477                  (void) close(rt_sock);
1472 1478                  (void) close(idmapd_ev_port);
1473 1479                  return (-1);
1474 1480          }
1475 1481  
1476 1482          return (0);
1477 1483  }
1478 1484  
1479 1485  /*
1480 1486   * Reject attribute names with invalid characters.
1481 1487   */
1482 1488  static
1483 1489  int
1484 1490  valid_ldap_attr(const char *attr) {
1485 1491          for (; *attr; attr++) {
1486 1492                  if (!isalnum(*attr) && *attr != '-' &&
1487 1493                      *attr != '_' && *attr != '.' && *attr != ';')
1488 1494                          return (0);
1489 1495          }
1490 1496          return (1);
1491 1497  }
1492 1498  
1493 1499  static
1494 1500  void
1495 1501  idmapd_set_debug(
1496 1502      idmap_cfg_handles_t *handles,
1497 1503      enum idmapd_debug item,
1498 1504      const char *name)
1499 1505  {
1500 1506          int val;
1501 1507  
1502 1508          if (item < 0 || item > IDMAPD_DEBUG_MAX)
1503 1509                  return;
1504 1510  
1505 1511          val = get_debug(handles, name);
1506 1512  
1507 1513          if (val != _idmapdstate.debug[item])
1508 1514                  idmapdlog(LOG_DEBUG, "%s/%s = %d", DEBUG_PG, name, val);
1509 1515  
1510 1516          _idmapdstate.debug[item] = val;
1511 1517  }
1512 1518  
1513 1519  static
1514 1520  void
1515 1521  check_smf_debug_mode(idmap_cfg_handles_t *handles)
1516 1522  {
1517 1523          idmapd_set_debug(handles, IDMAPD_DEBUG_ALL, "all");
1518 1524          idmapd_set_debug(handles, IDMAPD_DEBUG_CONFIG, "config");
1519 1525          idmapd_set_debug(handles, IDMAPD_DEBUG_MAPPING, "mapping");
1520 1526          idmapd_set_debug(handles, IDMAPD_DEBUG_DISC, "discovery");
1521 1527          idmapd_set_debug(handles, IDMAPD_DEBUG_DNS, "dns");
1522 1528          idmapd_set_debug(handles, IDMAPD_DEBUG_LDAP, "ldap");
1523 1529  
1524 1530          adutils_set_debug(AD_DEBUG_ALL, _idmapdstate.debug[IDMAPD_DEBUG_ALL]);
1525 1531          adutils_set_debug(AD_DEBUG_DISC, _idmapdstate.debug[IDMAPD_DEBUG_DISC]);
1526 1532          adutils_set_debug(AD_DEBUG_DNS, _idmapdstate.debug[IDMAPD_DEBUG_DNS]);
1527 1533          adutils_set_debug(AD_DEBUG_LDAP, _idmapdstate.debug[IDMAPD_DEBUG_LDAP]);
1528 1534  }
1529 1535  
1530 1536  /*
1531 1537   * This is the half of idmap_cfg_load() that loads property values from
1532 1538   * SMF (using the config/ property group of the idmap FMRI).
1533 1539   *
1534 1540   * Return values: 0 -> success, -1 -> failure, -2 -> hard failures
1535 1541   *               -3 -> hard smf config failures
1536 1542   * reading from SMF.
1537 1543   */
1538 1544  static int
1539 1545  idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg,
1540 1546          int * const errors)
1541 1547  {
1542 1548          int rc;
1543 1549          char *s;
1544 1550  
1545 1551          *errors = 0;
1546 1552  
1547 1553          if (scf_pg_update(handles->config_pg) < 0) {
1548 1554                  idmapdlog(LOG_ERR, "scf_pg_update() failed: %s",
1549 1555                      scf_strerror(scf_error()));
1550 1556                  return (-2);
1551 1557          }
1552 1558  
1553 1559          if (scf_pg_update(handles->debug_pg) < 0) {
1554 1560                  idmapdlog(LOG_ERR, "scf_pg_update() failed: %s",
1555 1561                      scf_strerror(scf_error()));
1556 1562                  return (-2);
1557 1563          }
1558 1564  
1559 1565          check_smf_debug_mode(handles);
1560 1566  
1561 1567          rc = get_val_bool(handles, "unresolvable_sid_mapping",
1562 1568              &pgcfg->eph_map_unres_sids, B_TRUE);
1563 1569          if (rc != 0)
1564 1570                  (*errors)++;
1565 1571  
1566 1572          rc = get_val_bool(handles, "use_ads",
1567 1573              &pgcfg->use_ads, B_TRUE);
1568 1574          if (rc != 0)
1569 1575                  (*errors)++;
1570 1576  
1571 1577          rc = get_val_bool(handles, "use_lsa",
1572 1578              &pgcfg->use_lsa, B_TRUE);
1573 1579          if (rc != 0)
1574 1580                  (*errors)++;
1575 1581  
1576 1582          rc = get_val_bool(handles, "disable_cross_forest_trusts",
1577 1583              &pgcfg->disable_cross_forest_trusts, B_TRUE);
1578 1584          if (rc != 0)
1579 1585                  (*errors)++;
1580 1586  
1581 1587          rc = get_val_astring(handles, "directory_based_mapping", &s);
1582 1588          if (rc != 0)
1583 1589                  (*errors)++;
1584 1590          else if (s == NULL || strcasecmp(s, "none") == 0)
1585 1591                  pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NONE;
1586 1592          else if (strcasecmp(s, "name") == 0)
1587 1593                  pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NAME;
1588 1594          else if (strcasecmp(s, "idmu") == 0)
1589 1595                  pgcfg->directory_based_mapping = DIRECTORY_MAPPING_IDMU;
1590 1596          else {
1591 1597                  pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NONE;
1592 1598                  idmapdlog(LOG_ERR,
1593 1599                  "config/directory_based_mapping:  invalid value \"%s\" ignored",
  
    | 
      ↓ open down ↓ | 
    1504 lines elided | 
    
      ↑ open up ↑ | 
  
1594 1600                      s);
1595 1601                  (*errors)++;
1596 1602          }
1597 1603          free(s);
1598 1604  
1599 1605          rc = get_val_int(handles, "list_size_limit",
1600 1606              &pgcfg->list_size_limit, SCF_TYPE_COUNT);
1601 1607          if (rc != 0)
1602 1608                  (*errors)++;
1603 1609  
     1610 +        rc = get_val_int(handles, "max_threads",
     1611 +            &pgcfg->max_threads, SCF_TYPE_COUNT);
     1612 +        if (rc != 0)
     1613 +                (*errors)++;
     1614 +        if (pgcfg->max_threads == 0)
     1615 +                pgcfg->max_threads = MAX_THREADS_DEFAULT;
     1616 +        if (pgcfg->max_threads > UINT_MAX)
     1617 +                pgcfg->max_threads = UINT_MAX;
     1618 +
1604 1619          rc = get_val_int(handles, "id_cache_timeout",
1605 1620              &pgcfg->id_cache_timeout, SCF_TYPE_COUNT);
1606 1621          if (rc != 0)
1607 1622                  (*errors)++;
1608 1623          if (pgcfg->id_cache_timeout == 0)
1609 1624                  pgcfg->id_cache_timeout = ID_CACHE_TMO_DEFAULT;
1610 1625  
1611 1626          rc = get_val_int(handles, "name_cache_timeout",
1612 1627              &pgcfg->name_cache_timeout, SCF_TYPE_COUNT);
1613 1628          if (rc != 0)
1614 1629                  (*errors)++;
1615 1630          if (pgcfg->name_cache_timeout == 0)
1616 1631                  pgcfg->name_cache_timeout = NAME_CACHE_TMO_DEFAULT;
1617 1632  
1618 1633          rc = get_val_int(handles, "rediscovery_interval",
1619 1634              &pgcfg->rediscovery_interval, SCF_TYPE_COUNT);
1620 1635          if (rc != 0)
1621 1636                  (*errors)++;
1622 1637          if (pgcfg->rediscovery_interval == 0)
1623 1638                  pgcfg->rediscovery_interval = REDISCOVERY_INTERVAL_DEFAULT;
  
    | 
      ↓ open down ↓ | 
    10 lines elided | 
    
      ↑ open up ↑ | 
  
1624 1639  
1625 1640          rc = get_val_astring(handles, "domain_name",
1626 1641              &pgcfg->domain_name);
1627 1642          if (rc != 0)
1628 1643                  (*errors)++;
1629 1644          else {
1630 1645                  if (pgcfg->domain_name != NULL &&
1631 1646                      pgcfg->domain_name[0] == '\0') {
1632 1647                          free(pgcfg->domain_name);
1633 1648                          pgcfg->domain_name = NULL;
     1649 +                } else {
     1650 +                        pgcfg->domain_name_auto_disc = B_FALSE;
1634 1651                  }
1635 1652                  (void) ad_disc_set_DomainName(handles->ad_ctx,
1636 1653                      pgcfg->domain_name);
1637      -                pgcfg->domain_name_auto_disc = B_FALSE;
1638 1654          }
1639 1655  
1640 1656          rc = get_val_astring(handles, "default_domain",
1641 1657              &pgcfg->default_domain);
1642 1658          if (rc != 0) {
1643 1659                  /*
1644 1660                   * SCF failures fetching config/default_domain we treat
1645 1661                   * as fatal as they may leave ID mapping rules that
1646 1662                   * match unqualified winnames flapping in the wind.
1647 1663                   */
1648 1664                  return (-2);
1649 1665          }
1650 1666  
1651 1667          if (pgcfg->default_domain == NULL && pgcfg->domain_name != NULL) {
1652 1668                  pgcfg->default_domain = strdup(pgcfg->domain_name);
1653 1669          }
1654 1670  
1655 1671          rc = get_val_astring(handles, "domain_guid", &s);
1656 1672          if (rc != 0) {
1657 1673                  (*errors)++;
1658 1674          } else if (s == NULL || s[0] == '\0') {
1659 1675                  /* OK, not set. */
1660 1676                  free(s);
1661 1677          } else {
1662 1678                  uuid_t u;
1663 1679  
1664 1680                  if (uuid_parse(s, u) != 0) {
1665 1681                          idmapdlog(LOG_ERR,
1666 1682                  "config/domain_guid: invalid value \"%s\" ignored", s);
1667 1683                          free(s);
1668 1684                          (*errors)++;
1669 1685                  } else {
1670 1686                          pgcfg->domain_guid = s;
1671 1687                          pgcfg->domain_guid_auto_disc = B_FALSE;
1672 1688                          (void) ad_disc_set_DomainGUID(handles->ad_ctx, u);
1673 1689                  }
1674 1690          }
1675 1691  
1676 1692          rc = get_val_astring(handles, "machine_uuid", &pgcfg->machine_uuid);
1677 1693          if (rc != 0)
1678 1694                  (*errors)++;
1679 1695          if (pgcfg->machine_uuid == NULL) {
1680 1696                  /* If machine_uuid not configured, generate one */
1681 1697                  if (generate_machine_uuid(&pgcfg->machine_uuid) < 0)
1682 1698                          return (-2);
1683 1699                  rc = set_val_astring(handles, handles->config_pg,
1684 1700                      "machine_uuid", pgcfg->machine_uuid);
1685 1701                  if (rc != 0)
1686 1702                          (*errors)++;
1687 1703          }
1688 1704  
1689 1705          rc = get_val_astring(handles, "machine_sid", &pgcfg->machine_sid);
1690 1706          if (rc != 0)
1691 1707                  (*errors)++;
1692 1708          if (pgcfg->machine_sid == NULL) {
1693 1709                  /*
1694 1710                   * If machine_sid not configured, generate one
1695 1711                   * from the machine UUID.
1696 1712                   */
1697 1713                  if (generate_machine_sid(&pgcfg->machine_sid,
1698 1714                      pgcfg->machine_uuid) < 0)
1699 1715                          return (-2);
1700 1716                  rc = set_val_astring(handles, handles->config_pg,
1701 1717                      "machine_sid", pgcfg->machine_sid);
1702 1718                  if (rc != 0)
1703 1719                          (*errors)++;
1704 1720          }
1705 1721  
1706 1722          rc = get_val_ds(handles, "domain_controller", 389,
1707 1723              &pgcfg->domain_controller);
1708 1724          if (rc != 0)
1709 1725                  (*errors)++;
1710 1726          else {
1711 1727                  (void) ad_disc_set_DomainController(handles->ad_ctx,
1712 1728                      pgcfg->domain_controller);
1713 1729                  pgcfg->domain_controller_auto_disc = B_FALSE;
1714 1730          }
1715 1731  
1716 1732          rc = get_val_ds(handles, "preferred_dc", 389,
1717 1733              &pgcfg->preferred_dc);
1718 1734          if (rc != 0)
1719 1735                  (*errors)++;
  
    | 
      ↓ open down ↓ | 
    72 lines elided | 
    
      ↑ open up ↑ | 
  
1720 1736          else {
1721 1737                  (void) ad_disc_set_PreferredDC(handles->ad_ctx,
1722 1738                      pgcfg->preferred_dc);
1723 1739                  pgcfg->preferred_dc_auto_disc = B_FALSE;
1724 1740          }
1725 1741  
1726 1742          rc = get_val_astring(handles, "forest_name", &pgcfg->forest_name);
1727 1743          if (rc != 0)
1728 1744                  (*errors)++;
1729 1745          else {
     1746 +                if (pgcfg->forest_name != NULL &&
     1747 +                    pgcfg->forest_name[0] == '\0') {
     1748 +                        free(pgcfg->forest_name);
     1749 +                        pgcfg->forest_name = NULL;
     1750 +                } else {
     1751 +                        pgcfg->forest_name_auto_disc = B_FALSE;
     1752 +                }
1730 1753                  (void) ad_disc_set_ForestName(handles->ad_ctx,
1731 1754                      pgcfg->forest_name);
1732      -                pgcfg->forest_name_auto_disc = B_FALSE;
1733 1755          }
1734 1756  
1735 1757          rc = get_val_astring(handles, "site_name", &pgcfg->site_name);
1736 1758          if (rc != 0)
1737 1759                  (*errors)++;
1738      -        else
     1760 +        else {
     1761 +                if (pgcfg->site_name != NULL &&
     1762 +                    pgcfg->site_name[0] == '\0') {
     1763 +                        free(pgcfg->site_name);
     1764 +                        pgcfg->site_name = NULL;
     1765 +                } else {
     1766 +                        pgcfg->site_name_auto_disc = B_FALSE;
     1767 +                }
1739 1768                  (void) ad_disc_set_SiteName(handles->ad_ctx, pgcfg->site_name);
     1769 +        }
1740 1770  
1741 1771          rc = get_val_ds(handles, "global_catalog", 3268,
1742 1772              &pgcfg->global_catalog);
1743 1773          if (rc != 0)
1744 1774                  (*errors)++;
1745 1775          else {
1746 1776                  (void) ad_disc_set_GlobalCatalog(handles->ad_ctx,
1747 1777                      pgcfg->global_catalog);
1748 1778                  pgcfg->global_catalog_auto_disc = B_FALSE;
1749 1779          }
1750 1780  
1751 1781          /* Unless we're doing directory-based name mapping, we're done. */
1752 1782          if (pgcfg->directory_based_mapping != DIRECTORY_MAPPING_NAME)
1753 1783                  return (0);
1754 1784  
1755 1785          rc = get_val_astring(handles, "ad_unixuser_attr",
1756 1786              &pgcfg->ad_unixuser_attr);
1757 1787          if (rc != 0)
1758 1788                  return (-2);
1759 1789          if (pgcfg->ad_unixuser_attr != NULL &&
1760 1790              !valid_ldap_attr(pgcfg->ad_unixuser_attr)) {
1761 1791                  idmapdlog(LOG_ERR, "config/ad_unixuser_attr=%s is not a "
1762 1792                      "valid LDAP attribute name", pgcfg->ad_unixuser_attr);
1763 1793                  return (-3);
1764 1794          }
1765 1795  
1766 1796          rc = get_val_astring(handles, "ad_unixgroup_attr",
1767 1797              &pgcfg->ad_unixgroup_attr);
1768 1798          if (rc != 0)
1769 1799                  return (-2);
1770 1800          if (pgcfg->ad_unixgroup_attr != NULL &&
1771 1801              !valid_ldap_attr(pgcfg->ad_unixgroup_attr)) {
1772 1802                  idmapdlog(LOG_ERR, "config/ad_unixgroup_attr=%s is not a "
1773 1803                      "valid LDAP attribute name", pgcfg->ad_unixgroup_attr);
1774 1804                  return (-3);
1775 1805          }
1776 1806  
1777 1807          rc = get_val_astring(handles, "nldap_winname_attr",
1778 1808              &pgcfg->nldap_winname_attr);
1779 1809          if (rc != 0)
1780 1810                  return (-2);
1781 1811          if (pgcfg->nldap_winname_attr != NULL &&
1782 1812              !valid_ldap_attr(pgcfg->nldap_winname_attr)) {
1783 1813                  idmapdlog(LOG_ERR, "config/nldap_winname_attr=%s is not a "
1784 1814                      "valid LDAP attribute name", pgcfg->nldap_winname_attr);
1785 1815                  return (-3);
1786 1816          }
1787 1817          if (pgcfg->ad_unixuser_attr == NULL &&
1788 1818              pgcfg->ad_unixgroup_attr == NULL &&
1789 1819              pgcfg->nldap_winname_attr == NULL) {
1790 1820                  idmapdlog(LOG_ERR,
1791 1821                      "If config/directory_based_mapping property is set to "
1792 1822                      "\"name\" then at least one of the following name mapping "
1793 1823                      "attributes must be specified. (config/ad_unixuser_attr OR "
1794 1824                      "config/ad_unixgroup_attr OR config/nldap_winname_attr)");
1795 1825                  return (-3);
1796 1826          }
1797 1827  
1798 1828          return (rc);
1799 1829  }
1800 1830  
1801 1831  static
1802 1832  void
1803 1833  log_if_unable(const void *val, const char *what)
1804 1834  {
1805 1835          if (val == NULL) {
1806 1836                  idmapdlog(LOG_DEBUG, "unable to discover %s", what);
1807 1837          }
1808 1838  }
1809 1839  
1810 1840  static
1811 1841  void
1812 1842  discover_trusted_domains(idmap_pg_config_t *pgcfg, ad_disc_t ad_ctx)
1813 1843  {
1814 1844          ad_disc_t trusted_ctx;
1815 1845          int i, j, k, l;
1816 1846          char *forestname;
1817 1847          int num_trusteddomains;
1818 1848          boolean_t new_forest;
1819 1849          char *trusteddomain;
1820 1850          ad_disc_ds_t *globalcatalog;
1821 1851          idmap_trustedforest_t *trustedforests;
1822 1852          ad_disc_domainsinforest_t *domainsinforest;
1823 1853  
1824 1854          pgcfg->trusted_domains =
1825 1855              ad_disc_get_TrustedDomains(ad_ctx, NULL);
1826 1856  
1827 1857          if (pgcfg->forest_name != NULL && pgcfg->trusted_domains != NULL &&
1828 1858              pgcfg->trusted_domains[0].domain[0] != '\0') {
1829 1859                  /*
1830 1860                   * We have trusted domains.  We need to go through every
1831 1861                   * one and find its forest. If it is a new forest we then need
1832 1862                   * to find its Global Catalog and the domains in the forest
1833 1863                   */
1834 1864                  for (i = 0; pgcfg->trusted_domains[i].domain[0] != '\0'; i++)
1835 1865                          continue;
1836 1866                  num_trusteddomains = i;
1837 1867  
1838 1868                  trustedforests = calloc(num_trusteddomains,
1839 1869                      sizeof (idmap_trustedforest_t));
1840 1870                  j = 0;
1841 1871                  for (i = 0; pgcfg->trusted_domains[i].domain[0] != '\0'; i++) {
1842 1872                          trusteddomain = pgcfg->trusted_domains[i].domain;
1843 1873                          trusted_ctx = ad_disc_init();
1844 1874                          (void) ad_disc_set_DomainName(trusted_ctx,
1845 1875                              trusteddomain);
1846 1876                          forestname =
1847 1877                              ad_disc_get_ForestName(trusted_ctx, NULL);
1848 1878                          if (forestname == NULL) {
1849 1879                                  if (DBG(CONFIG, 1)) {
1850 1880                                          idmapdlog(LOG_DEBUG,
1851 1881                                              "unable to discover Forest Name"
1852 1882                                              " for the trusted domain %s",
1853 1883                                              trusteddomain);
1854 1884                                  }
1855 1885                                  ad_disc_fini(trusted_ctx);
1856 1886                                  continue;
1857 1887                          }
1858 1888  
1859 1889                          if (strcasecmp(forestname, pgcfg->forest_name) == 0) {
1860 1890                                  /*
1861 1891                                   * Ignore the domain as it is part of
1862 1892                                   * the primary forest
1863 1893                                   */
1864 1894                                  free(forestname);
1865 1895                                  ad_disc_fini(trusted_ctx);
1866 1896                                  continue;
1867 1897                          }
1868 1898  
1869 1899                          /* Is this a new forest? */
1870 1900                          new_forest = B_TRUE;
1871 1901                          for (k = 0; k < j; k++) {
1872 1902                                  if (strcasecmp(forestname,
1873 1903                                      trustedforests[k].forest_name) == 0) {
1874 1904                                          new_forest = B_FALSE;
1875 1905                                          domainsinforest =
1876 1906                                              trustedforests[k].domains_in_forest;
1877 1907                                          break;
1878 1908                                  }
1879 1909                          }
1880 1910                          if (!new_forest) {
1881 1911                                  /* Mark the domain as trusted */
1882 1912                                  for (l = 0;
1883 1913                                      domainsinforest[l].domain[0] != '\0'; l++) {
1884 1914                                          if (domain_eq(trusteddomain,
1885 1915                                              domainsinforest[l].domain)) {
1886 1916                                                  domainsinforest[l].trusted =
1887 1917                                                      TRUE;
1888 1918                                                  break;
1889 1919                                          }
1890 1920                                  }
1891 1921                                  free(forestname);
1892 1922                                  ad_disc_fini(trusted_ctx);
1893 1923                                  continue;
1894 1924                          }
1895 1925  
1896 1926                          /*
1897 1927                           * Get the Global Catalog and the domains in
1898 1928                           * this new forest.
1899 1929                           */
1900 1930                          globalcatalog =
1901 1931                              ad_disc_get_GlobalCatalog(trusted_ctx,
1902 1932                              AD_DISC_PREFER_SITE, NULL);
1903 1933                          if (globalcatalog == NULL) {
1904 1934                                  if (DBG(CONFIG, 1)) {
1905 1935                                          idmapdlog(LOG_DEBUG,
1906 1936                                              "unable to discover Global Catalog"
1907 1937                                              " for the trusted domain %s",
1908 1938                                              trusteddomain);
1909 1939                                  }
1910 1940                                  free(forestname);
1911 1941                                  ad_disc_fini(trusted_ctx);
1912 1942                                  continue;
1913 1943                          }
1914 1944                          domainsinforest =
1915 1945                              ad_disc_get_DomainsInForest(trusted_ctx, NULL);
1916 1946                          if (domainsinforest == NULL) {
1917 1947                                  if (DBG(CONFIG, 1)) {
1918 1948                                          idmapdlog(LOG_DEBUG,
1919 1949                                              "unable to discover Domains in the"
1920 1950                                              " Forest for the trusted domain %s",
1921 1951                                              trusteddomain);
1922 1952                                  }
1923 1953                                  free(globalcatalog);
1924 1954                                  free(forestname);
1925 1955                                  ad_disc_fini(trusted_ctx);
1926 1956                                  continue;
1927 1957                          }
1928 1958  
1929 1959                          trustedforests[j].forest_name = forestname;
1930 1960                          trustedforests[j].global_catalog = globalcatalog;
1931 1961                          trustedforests[j].domains_in_forest = domainsinforest;
1932 1962                          j++;
1933 1963                          /* Mark the domain as trusted */
1934 1964                          for (l = 0; domainsinforest[l].domain[0] != '\0';
1935 1965                              l++) {
1936 1966                                  if (domain_eq(trusteddomain,
1937 1967                                      domainsinforest[l].domain)) {
1938 1968                                          domainsinforest[l].trusted = TRUE;
1939 1969                                          break;
1940 1970                                  }
1941 1971                          }
1942 1972                          ad_disc_fini(trusted_ctx);
1943 1973                  }
1944 1974                  if (j > 0) {
1945 1975                          pgcfg->num_trusted_forests = j;
1946 1976                          pgcfg->trusted_forests = trustedforests;
1947 1977                  } else {
1948 1978                          free(trustedforests);
1949 1979                  }
1950 1980          }
1951 1981  }
1952 1982  
1953 1983  /*
1954 1984   * This is the half of idmap_cfg_load() that auto-discovers values of
1955 1985   * discoverable properties that weren't already set via SMF properties.
1956 1986   *
1957 1987   * idmap_cfg_discover() is called *after* idmap_cfg_load_smf(), so it
1958 1988   * needs to be careful not to overwrite any properties set in SMF.
1959 1989   */
1960 1990  static void
1961 1991  idmap_cfg_discover1(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg)
1962 1992  {
1963 1993          ad_disc_t ad_ctx = handles->ad_ctx;
1964 1994          FILE *status_fp = NULL;
1965 1995          time_t t0, t1;
1966 1996  
1967 1997          t0 = time(NULL);
1968 1998          if (DBG(CONFIG, 1))
1969 1999                  idmapdlog(LOG_DEBUG, "Running domain discovery.");
1970 2000  
1971 2001          (void) unlink(IDMAP_CACHEDIR "/discovery.log");
1972 2002          status_fp = fopen(IDMAP_CACHEDIR "/discovery.log", "w");
1973 2003          if (status_fp) {
1974 2004                  (void) fchmod(fileno(status_fp), 0644);
1975 2005                  ad_disc_set_StatusFP(ad_ctx, status_fp);
1976 2006          }
1977 2007  
1978 2008          if (pgcfg->domain_name == NULL) {
1979 2009                  idmapdlog(LOG_DEBUG, "No domain name specified.");
1980 2010                  if (status_fp)
1981 2011                          (void) fprintf(status_fp, "(no domain name)\n");
1982 2012                  goto out;
1983 2013          }
1984 2014  
1985 2015          if (pgcfg->domain_controller == NULL)
1986 2016                  pgcfg->domain_controller =
1987 2017                      ad_disc_get_DomainController(ad_ctx,
1988 2018                      AD_DISC_PREFER_SITE,
1989 2019                      &pgcfg->domain_controller_auto_disc);
1990 2020  
1991 2021          if (pgcfg->domain_guid == NULL) {
1992 2022                  char buf[UUID_PRINTABLE_STRING_LENGTH];
1993 2023                  uchar_t *u = ad_disc_get_DomainGUID(ad_ctx,
1994 2024                      &pgcfg->domain_guid_auto_disc);
1995 2025                  (void) memset(buf, 0, sizeof (buf));
1996 2026                  if (u != NULL) {
1997 2027                          uuid_unparse(u, buf);
1998 2028                          pgcfg->domain_guid = strdup(buf);
1999 2029                  }
2000 2030          }
2001 2031  
2002 2032          if (pgcfg->forest_name == NULL)
2003 2033                  pgcfg->forest_name = ad_disc_get_ForestName(ad_ctx,
2004 2034                      &pgcfg->forest_name_auto_disc);
2005 2035  
2006 2036          if (pgcfg->site_name == NULL)
2007 2037                  pgcfg->site_name = ad_disc_get_SiteName(ad_ctx,
2008 2038                      &pgcfg->site_name_auto_disc);
2009 2039  
2010 2040          if (DBG(CONFIG, 1)) {
2011 2041                  log_if_unable(pgcfg->domain_name, "Domain Name");
2012 2042                  log_if_unable(pgcfg->domain_controller,
2013 2043                      "Domain Controller");
2014 2044                  log_if_unable(pgcfg->domain_guid, "Domain GUID");
2015 2045                  log_if_unable(pgcfg->forest_name, "Forest Name");
2016 2046                  log_if_unable(pgcfg->site_name, "Site Name");
2017 2047          }
2018 2048  
2019 2049  out:
2020 2050          if (status_fp) {
2021 2051                  ad_disc_set_StatusFP(ad_ctx, NULL);
2022 2052                  (void) fclose(status_fp);
2023 2053                  status_fp = NULL;
2024 2054          }
2025 2055  
2026 2056          if (DBG(CONFIG, 1))
2027 2057                  idmapdlog(LOG_DEBUG, "Domain discovery done.");
2028 2058  
2029 2059          /*
2030 2060           * Log when this took more than 15 sec.
2031 2061           */
2032 2062          t1 = time(NULL);
2033 2063          if (t1 > (t0 + 15)) {
2034 2064                  idmapdlog(LOG_NOTICE, "Domain discovery took %d sec.",
2035 2065                      (int)(t1 - t0));
2036 2066                  idmapdlog(LOG_NOTICE, "Check the DNS configuration.");
2037 2067          }
2038 2068  }
2039 2069  
2040 2070  /*
2041 2071   * This is the second part of discovery, which can take a while.
2042 2072   * We don't want to hold up parties who just want to know what
2043 2073   * domain controller we're using (like smbd), so this part runs
2044 2074   * after we've updated that info in the "live" config and told
2045 2075   * such consumers to go ahead.
2046 2076   *
2047 2077   * This is a lot like idmap_cfg_discover(), but used LDAP queries
2048 2078   * get the forest information from the global catalog servers.
2049 2079   *
2050 2080   * Note: the previous update_* calls have usually nuked any
2051 2081   * useful information from pgcfg before we get here, so we
2052 2082   * can only use it store discovery results, not to read.
2053 2083   */
2054 2084  static void
2055 2085  idmap_cfg_discover2(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg)
2056 2086  {
2057 2087          ad_disc_t ad_ctx = handles->ad_ctx;
2058 2088          FILE *status_fp = NULL;
2059 2089          time_t t0, t1;
2060 2090  
2061 2091          t0 = time(NULL);
2062 2092          if (DBG(CONFIG, 1))
2063 2093                  idmapdlog(LOG_DEBUG, "Running forest discovery.");
2064 2094  
2065 2095          status_fp = fopen(IDMAP_CACHEDIR "/discovery.log", "a");
2066 2096          if (status_fp)
2067 2097                  ad_disc_set_StatusFP(ad_ctx, status_fp);
2068 2098  
2069 2099          if (pgcfg->global_catalog == NULL)
2070 2100                  pgcfg->global_catalog =
2071 2101                      ad_disc_get_GlobalCatalog(ad_ctx,
2072 2102                      AD_DISC_PREFER_SITE,
2073 2103                      &pgcfg->global_catalog_auto_disc);
2074 2104  
2075 2105          if (pgcfg->global_catalog != NULL) {
2076 2106                  pgcfg->domains_in_forest =
2077 2107                      ad_disc_get_DomainsInForest(ad_ctx, NULL);
2078 2108  
2079 2109                  if (!pgcfg->disable_cross_forest_trusts)
2080 2110                          discover_trusted_domains(pgcfg, ad_ctx);
2081 2111          }
2082 2112  
2083 2113          if (DBG(CONFIG, 1)) {
2084 2114                  log_if_unable(pgcfg->global_catalog, "Global Catalog");
2085 2115                  log_if_unable(pgcfg->domains_in_forest,
2086 2116                      "Domains in the Forest");
2087 2117                  /* Empty trusted domains list is OK. */
2088 2118          }
2089 2119  
2090 2120          if (status_fp) {
2091 2121                  ad_disc_set_StatusFP(ad_ctx, NULL);
2092 2122                  (void) fclose(status_fp);
2093 2123                  status_fp = NULL;
2094 2124          }
2095 2125  
2096 2126          if (DBG(CONFIG, 1))
2097 2127                  idmapdlog(LOG_DEBUG, "Forest discovery done.");
2098 2128  
2099 2129          /*
2100 2130           * Log when this took more than 30 sec.
2101 2131           */
2102 2132          t1 = time(NULL);
2103 2133          if (t1 > (t0 + 30)) {
2104 2134                  idmapdlog(LOG_NOTICE, "Forest discovery took %d sec.",
2105 2135                      (int)(t1 - t0));
2106 2136                  idmapdlog(LOG_NOTICE, "Check AD join status.");
2107 2137          }
2108 2138  }
2109 2139  
2110 2140  
2111 2141  /*
2112 2142   * idmap_cfg_load() is called at startup, and periodically via the
2113 2143   * update thread when the auto-discovery TTLs expire, as well as part of
2114 2144   * the refresh method, to update the current configuration.  It always
2115 2145   * reads from SMF, but you still have to refresh the service after
2116 2146   * changing the config pg in order for the changes to take effect.
2117 2147   *
2118 2148   * There is one flag:
2119 2149   *
2120 2150   *  - CFG_DISCOVER
2121 2151   *
2122 2152   * If CFG_DISCOVER is set then idmap_cfg_load() calls
2123 2153   * idmap_cfg_discover() to discover, via DNS and LDAP lookups, property
2124 2154   * values that weren't set in SMF.
2125 2155   *
2126 2156   * idmap_cfg_load() will log (to LOG_NOTICE) whether the configuration
2127 2157   * changed.
2128 2158   *
2129 2159   * Return values: 0 -> success, -1 -> failure, -2 -> hard failures
2130 2160   * reading from SMF.
2131 2161   */
2132 2162  int
2133 2163  idmap_cfg_load(idmap_cfg_t *cfg, int flags)
2134 2164  {
2135 2165          const ad_disc_t ad_ctx = cfg->handles.ad_ctx;
2136 2166          int rc = 0;
2137 2167          int errors;
2138 2168          int changed = 0;
2139 2169          int dc_changed = 0;
2140 2170          int ad_reload_required = 0;
2141 2171          idmap_pg_config_t new_pgcfg, *live_pgcfg;
2142 2172  
2143 2173          if (DBG(CONFIG, 1))
2144 2174                  idmapdlog(LOG_DEBUG, "Loading configuration.");
2145 2175  
2146 2176          live_pgcfg = &cfg->pgcfg;
2147 2177          (void) memset(&new_pgcfg, 0, sizeof (new_pgcfg));
2148 2178  
2149 2179          (void) pthread_mutex_lock(&cfg->handles.mutex);
2150 2180  
2151 2181          if ((rc = idmap_cfg_load_smf(&cfg->handles, &new_pgcfg, &errors)) < -1)
2152 2182                  goto err;
2153 2183  
2154 2184          if (flags & CFG_DISCOVER) {
2155 2185  
2156 2186                  ad_disc_refresh(ad_ctx);
2157 2187  
2158 2188                  /*
2159 2189                   * Unless we've been asked to forget the current DC,
2160 2190                   * give preference (in order) to the preferred DC if
2161 2191                   * configured, or the current DC.  These preferences
2162 2192                   * reduce undesirable DC changes.
2163 2193                   */
2164 2194                  if (flags & CFG_FORGET_DC) {
2165 2195                          (void) ad_disc_set_PreferredDC(ad_ctx, NULL);
2166 2196                  } else if (new_pgcfg.preferred_dc != NULL) {
2167 2197                          (void) ad_disc_set_PreferredDC(ad_ctx,
2168 2198                              new_pgcfg.preferred_dc);
2169 2199                  } else if (live_pgcfg->domain_controller != NULL) {
2170 2200                          (void) ad_disc_set_PreferredDC(ad_ctx,
2171 2201                              live_pgcfg->domain_controller);
2172 2202                  } else {
2173 2203                          (void) ad_disc_set_PreferredDC(ad_ctx, NULL);
2174 2204                  }
2175 2205  
2176 2206                  /*
2177 2207                   * We want a way to tell adspriv_getdcname_1_svc()
2178 2208                   * (and others) that discovery is running and therefore
2179 2209                   * they may want to wait a bit or return an error...
2180 2210                   */
2181 2211                  (void) mutex_lock(&_idmapdstate.addisc_lk);
2182 2212                  _idmapdstate.addisc_st |= ADDISC_ST_RUNNING;
2183 2213                  (void) mutex_unlock(&_idmapdstate.addisc_lk);
2184 2214  
2185 2215                  idmap_cfg_discover1(&cfg->handles, &new_pgcfg);
2186 2216  
2187 2217                  WRLOCK_CONFIG();
2188 2218                  (void) mutex_lock(&_idmapdstate.addisc_lk);
2189 2219                  _idmapdstate.addisc_st = 0;
2190 2220                  (void) cond_broadcast(&_idmapdstate.addisc_cv);
  
    | 
      ↓ open down ↓ | 
    441 lines elided | 
    
      ↑ open up ↑ | 
  
2191 2221                  (void) mutex_unlock(&_idmapdstate.addisc_lk);
2192 2222          } else {
2193 2223                  WRLOCK_CONFIG();
2194 2224          }
2195 2225  
2196 2226          /* Non-discoverable props updated here */
2197 2227  
2198 2228          changed += update_uint64(&live_pgcfg->list_size_limit,
2199 2229              &new_pgcfg.list_size_limit, "list_size_limit");
2200 2230  
     2231 +        changed += update_uint64(&live_pgcfg->max_threads,
     2232 +            &new_pgcfg.max_threads, "max_threads");
     2233 +
2201 2234          changed += update_uint64(&live_pgcfg->id_cache_timeout,
2202 2235              &new_pgcfg.id_cache_timeout, "id_cache_timeout");
2203 2236  
2204 2237          changed += update_uint64(&live_pgcfg->name_cache_timeout,
2205 2238              &new_pgcfg.name_cache_timeout, "name_cache_timeout");
2206 2239  
2207 2240          changed += update_uint64(&live_pgcfg->rediscovery_interval,
2208 2241              &new_pgcfg.rediscovery_interval, "rediscovery_interval");
2209 2242  
2210 2243          changed += update_string(&live_pgcfg->machine_sid,
2211 2244              &new_pgcfg.machine_sid, "machine_sid");
2212 2245  
2213 2246          changed += update_bool(&live_pgcfg->eph_map_unres_sids,
2214 2247              &new_pgcfg.eph_map_unres_sids, "unresolvable_sid_mapping");
2215 2248  
2216 2249          changed += update_bool(&live_pgcfg->use_ads,
2217 2250              &new_pgcfg.use_ads, "use_ads");
2218 2251  
2219 2252          changed += update_bool(&live_pgcfg->use_lsa,
2220 2253              &new_pgcfg.use_lsa, "use_lsa");
2221 2254  
2222 2255          changed += update_bool(&live_pgcfg->disable_cross_forest_trusts,
2223 2256              &new_pgcfg.disable_cross_forest_trusts,
2224 2257              "disable_cross_forest_trusts");
2225 2258  
2226 2259          changed += update_enum(&live_pgcfg->directory_based_mapping,
2227 2260              &new_pgcfg.directory_based_mapping, "directory_based_mapping",
2228 2261              directory_mapping_map);
2229 2262  
2230 2263          changed += update_string(&live_pgcfg->ad_unixuser_attr,
2231 2264              &new_pgcfg.ad_unixuser_attr, "ad_unixuser_attr");
2232 2265  
2233 2266          changed += update_string(&live_pgcfg->ad_unixgroup_attr,
2234 2267              &new_pgcfg.ad_unixgroup_attr, "ad_unixgroup_attr");
2235 2268  
2236 2269          changed += update_string(&live_pgcfg->nldap_winname_attr,
2237 2270              &new_pgcfg.nldap_winname_attr, "nldap_winname_attr");
2238 2271  
2239 2272          changed += update_string(&live_pgcfg->default_domain,
2240 2273              &new_pgcfg.default_domain, "default_domain");
2241 2274  
2242 2275          changed += update_dirs(&live_pgcfg->preferred_dc,
2243 2276              &new_pgcfg.preferred_dc, "preferred_dc");
2244 2277  
2245 2278          /* Props that can be discovered or set in SMF updated here */
2246 2279  
2247 2280          if (update_string(&live_pgcfg->domain_name,
2248 2281              &new_pgcfg.domain_name, "domain_name")) {
2249 2282                  changed++;
2250 2283                  ad_reload_required = TRUE;
2251 2284                  idmapd_set_krb5_realm(live_pgcfg->domain_name);
2252 2285          }
2253 2286          live_pgcfg->domain_name_auto_disc = new_pgcfg.domain_name_auto_disc;
2254 2287  
2255 2288          changed += update_string(&live_pgcfg->domain_guid,
2256 2289              &new_pgcfg.domain_guid, "domain_guid");
2257 2290          live_pgcfg->domain_guid_auto_disc = new_pgcfg.domain_guid_auto_disc;
2258 2291  
2259 2292          dc_changed = update_dirs(&live_pgcfg->domain_controller,
2260 2293              &new_pgcfg.domain_controller, "domain_controller");
2261 2294          changed += dc_changed;
2262 2295          live_pgcfg->domain_controller_auto_disc =
2263 2296              new_pgcfg.domain_controller_auto_disc;
2264 2297  
2265 2298          changed += update_string(&live_pgcfg->forest_name,
2266 2299              &new_pgcfg.forest_name, "forest_name");
2267 2300          live_pgcfg->forest_name_auto_disc = new_pgcfg.forest_name_auto_disc;
2268 2301  
2269 2302          changed += update_string(&live_pgcfg->site_name,
2270 2303              &new_pgcfg.site_name, "site_name");
2271 2304          live_pgcfg->site_name_auto_disc = new_pgcfg.site_name_auto_disc;
2272 2305  
2273 2306          if (DBG(CONFIG, 1)) {
2274 2307                  if (changed)
2275 2308                          idmapdlog(LOG_NOTICE, "Configuration changed");
2276 2309                  else
2277 2310                          idmapdlog(LOG_NOTICE, "Configuration unchanged");
2278 2311          }
2279 2312  
2280 2313          UNLOCK_CONFIG();
2281 2314  
2282 2315          if (dc_changed != 0) {
2283 2316                  notify_dc_changed();
2284 2317          }
2285 2318  
2286 2319          /*
2287 2320           * Discovery2 can take a while.
2288 2321           */
2289 2322          if (flags & CFG_DISCOVER) {
2290 2323                  if (live_pgcfg->domain_name != NULL &&
2291 2324                      live_pgcfg->forest_name != NULL)
2292 2325                          idmap_cfg_discover2(&cfg->handles, &new_pgcfg);
2293 2326                  ad_disc_done(ad_ctx);
2294 2327          }
2295 2328  
2296 2329          WRLOCK_CONFIG();
2297 2330  
2298 2331          /* More props that can be discovered or set in SMF */
2299 2332  
2300 2333          changed += update_dirs(&live_pgcfg->global_catalog,
2301 2334              &new_pgcfg.global_catalog, "global_catalog");
2302 2335          live_pgcfg->global_catalog_auto_disc =
2303 2336              new_pgcfg.global_catalog_auto_disc;
2304 2337  
2305 2338          /* Props that are only discovered (never in SMF) */
2306 2339  
2307 2340          if (update_domains_in_forest(&live_pgcfg->domains_in_forest,
2308 2341              &new_pgcfg.domains_in_forest, "domains_in_forest")) {
2309 2342                  changed++;
2310 2343                  ad_reload_required = TRUE;
2311 2344          }
2312 2345  
2313 2346          if (update_trusted_domains(&live_pgcfg->trusted_domains,
2314 2347              &new_pgcfg.trusted_domains, "trusted_domains")) {
2315 2348                  changed++;
2316 2349                  if (live_pgcfg->trusted_domains != NULL &&
2317 2350                      live_pgcfg->trusted_domains[0].domain[0] != '\0')
2318 2351                          ad_reload_required = TRUE;
2319 2352          }
2320 2353  
2321 2354          if (update_trusted_forest(&live_pgcfg->trusted_forests,
2322 2355              &live_pgcfg->num_trusted_forests, &new_pgcfg.trusted_forests,
2323 2356              &new_pgcfg.num_trusted_forests, "trusted_forest")) {
2324 2357                  changed++;
2325 2358                  if (live_pgcfg->trusted_forests != NULL)
2326 2359                          ad_reload_required = TRUE;
2327 2360          }
2328 2361  
2329 2362          if (DBG(CONFIG, 1)) {
2330 2363                  if (changed)
2331 2364                          idmapdlog(LOG_NOTICE, "Configuration changed");
2332 2365                  else
2333 2366                          idmapdlog(LOG_NOTICE, "Configuration unchanged");
2334 2367          }
2335 2368  
2336 2369          UNLOCK_CONFIG();
2337 2370  
2338 2371          if (ad_reload_required)
2339 2372                  reload_ad();
2340 2373  
2341 2374          idmap_cfg_unload(&new_pgcfg);
2342 2375  
2343 2376  err:
2344 2377          (void) pthread_mutex_unlock(&cfg->handles.mutex);
2345 2378  
2346 2379          if (rc < -1)
2347 2380                  return (rc);
2348 2381  
2349 2382          return ((errors == 0) ? 0 : -1);
2350 2383  }
2351 2384  
2352 2385  /*
2353 2386   * Initialize 'cfg'.
2354 2387   */
2355 2388  idmap_cfg_t *
2356 2389  idmap_cfg_init()
2357 2390  {
2358 2391          idmap_cfg_handles_t *handles;
2359 2392  
2360 2393          /* First the smf repository handles: */
2361 2394          idmap_cfg_t *cfg = calloc(1, sizeof (idmap_cfg_t));
2362 2395          if (!cfg) {
2363 2396                  idmapdlog(LOG_ERR, "Out of memory");
2364 2397                  return (NULL);
2365 2398          }
2366 2399          handles = &cfg->handles;
2367 2400  
2368 2401          (void) pthread_mutex_init(&handles->mutex, NULL);
2369 2402  
2370 2403          if (!(handles->main = scf_handle_create(SCF_VERSION))) {
2371 2404                  idmapdlog(LOG_ERR, "scf_handle_create() failed: %s",
2372 2405                      scf_strerror(scf_error()));
2373 2406                  goto error;
2374 2407          }
2375 2408  
2376 2409          if (scf_handle_bind(handles->main) < 0) {
2377 2410                  idmapdlog(LOG_ERR, "scf_handle_bind() failed: %s",
2378 2411                      scf_strerror(scf_error()));
2379 2412                  goto error;
2380 2413          }
2381 2414  
2382 2415          if (!(handles->service = scf_service_create(handles->main)) ||
2383 2416              !(handles->instance = scf_instance_create(handles->main)) ||
2384 2417              !(handles->config_pg = scf_pg_create(handles->main)) ||
2385 2418              !(handles->debug_pg = scf_pg_create(handles->main))) {
2386 2419                  idmapdlog(LOG_ERR, "scf handle creation failed: %s",
2387 2420                      scf_strerror(scf_error()));
2388 2421                  goto error;
2389 2422          }
2390 2423  
2391 2424          if (scf_handle_decode_fmri(handles->main,
2392 2425              FMRI_BASE "/:properties/" CONFIG_PG,
2393 2426              NULL,                               /* scope */
2394 2427              handles->service,           /* service */
2395 2428              handles->instance,          /* instance */
2396 2429              handles->config_pg,         /* pg */
2397 2430              NULL,                               /* prop */
2398 2431              SCF_DECODE_FMRI_EXACT) < 0) {
2399 2432                  idmapdlog(LOG_ERR, "scf_handle_decode_fmri() failed: %s",
2400 2433                      scf_strerror(scf_error()));
2401 2434                  goto error;
2402 2435          }
2403 2436  
2404 2437          if (scf_service_get_pg(handles->service,
2405 2438              DEBUG_PG, handles->debug_pg) < 0) {
2406 2439                  idmapdlog(LOG_ERR, "Property group \"%s\": %s",
2407 2440                      DEBUG_PG, scf_strerror(scf_error()));
2408 2441                  goto error;
2409 2442          }
2410 2443  
2411 2444          check_smf_debug_mode(handles);
2412 2445  
2413 2446          /* Initialize AD Auto Discovery context */
2414 2447          handles->ad_ctx = ad_disc_init();
2415 2448          if (handles->ad_ctx == NULL)
2416 2449                  goto error;
2417 2450  
2418 2451          return (cfg);
2419 2452  
2420 2453  error:
2421 2454          (void) idmap_cfg_fini(cfg);
2422 2455          return (NULL);
2423 2456  }
2424 2457  
2425 2458  void
2426 2459  idmap_cfg_unload(idmap_pg_config_t *pgcfg)
2427 2460  {
2428 2461  
2429 2462          if (pgcfg->default_domain) {
2430 2463                  free(pgcfg->default_domain);
2431 2464                  pgcfg->default_domain = NULL;
2432 2465          }
2433 2466          if (pgcfg->domain_name) {
2434 2467                  free(pgcfg->domain_name);
2435 2468                  pgcfg->domain_name = NULL;
2436 2469          }
2437 2470          if (pgcfg->domain_guid) {
2438 2471                  free(pgcfg->domain_guid);
2439 2472                  pgcfg->domain_guid = NULL;
2440 2473          }
2441 2474          if (pgcfg->machine_sid) {
2442 2475                  free(pgcfg->machine_sid);
2443 2476                  pgcfg->machine_sid = NULL;
2444 2477          }
2445 2478          if (pgcfg->domain_controller) {
2446 2479                  free(pgcfg->domain_controller);
2447 2480                  pgcfg->domain_controller = NULL;
2448 2481          }
2449 2482          if (pgcfg->forest_name) {
2450 2483                  free(pgcfg->forest_name);
2451 2484                  pgcfg->forest_name = NULL;
2452 2485          }
2453 2486          if (pgcfg->site_name) {
2454 2487                  free(pgcfg->site_name);
2455 2488                  pgcfg->site_name = NULL;
2456 2489          }
2457 2490          if (pgcfg->global_catalog) {
2458 2491                  free(pgcfg->global_catalog);
2459 2492                  pgcfg->global_catalog = NULL;
2460 2493          }
2461 2494          if (pgcfg->trusted_domains) {
2462 2495                  free(pgcfg->trusted_domains);
2463 2496                  pgcfg->trusted_domains = NULL;
2464 2497          }
2465 2498          if (pgcfg->trusted_forests)
2466 2499                  free_trusted_forests(&pgcfg->trusted_forests,
2467 2500                      &pgcfg->num_trusted_forests);
2468 2501  
2469 2502          if (pgcfg->ad_unixuser_attr) {
2470 2503                  free(pgcfg->ad_unixuser_attr);
2471 2504                  pgcfg->ad_unixuser_attr = NULL;
2472 2505          }
2473 2506          if (pgcfg->ad_unixgroup_attr) {
2474 2507                  free(pgcfg->ad_unixgroup_attr);
2475 2508                  pgcfg->ad_unixgroup_attr = NULL;
2476 2509          }
2477 2510          if (pgcfg->nldap_winname_attr) {
2478 2511                  free(pgcfg->nldap_winname_attr);
2479 2512                  pgcfg->nldap_winname_attr = NULL;
2480 2513          }
2481 2514  }
2482 2515  
2483 2516  int
2484 2517  idmap_cfg_fini(idmap_cfg_t *cfg)
2485 2518  {
2486 2519          idmap_cfg_handles_t *handles = &cfg->handles;
2487 2520          idmap_cfg_unload(&cfg->pgcfg);
2488 2521  
2489 2522          (void) pthread_mutex_destroy(&handles->mutex);
2490 2523          scf_pg_destroy(handles->config_pg);
2491 2524          if (handles->debug_pg != NULL)
2492 2525                  scf_pg_destroy(handles->debug_pg);
2493 2526          scf_instance_destroy(handles->instance);
2494 2527          scf_service_destroy(handles->service);
2495 2528          scf_handle_destroy(handles->main);
2496 2529          if (handles->ad_ctx != NULL)
2497 2530                  ad_disc_fini(handles->ad_ctx);
2498 2531          free(cfg);
2499 2532  
2500 2533          return (0);
2501 2534  }
2502 2535  
2503 2536  void
2504 2537  idmap_cfg_poke_updates(void)
2505 2538  {
2506 2539          int prev_st;
2507 2540  
2508 2541          if (DBG(CONFIG, 1)) {
2509 2542                  idmapdlog(LOG_INFO, "idmap_cfg_poke_updates");
2510 2543          }
2511 2544  
2512 2545          (void) mutex_lock(&_idmapdstate.addisc_lk);
2513 2546          prev_st = _idmapdstate.addisc_st;
2514 2547          _idmapdstate.addisc_st |= ADDISC_ST_REQUESTED;
2515 2548          (void) mutex_unlock(&_idmapdstate.addisc_lk);
2516 2549  
2517 2550          if (prev_st & ADDISC_ST_REQUESTED) {
2518 2551                  idmapdlog(LOG_DEBUG, "already poked");
2519 2552          } else {
2520 2553                  idmapdlog(LOG_DEBUG, "port send poke");
2521 2554                  (void) port_send(idmapd_ev_port, POKE_AUTO_DISCOVERY, NULL);
2522 2555          }
2523 2556  }
2524 2557  
2525 2558  void
2526 2559  idmap_cfg_force_rediscovery(void)
2527 2560  {
2528 2561          int prev_st;
2529 2562  
2530 2563          if (DBG(CONFIG, 1)) {
2531 2564                  idmapdlog(LOG_INFO, "idmap_cfg_force_rediscovery");
2532 2565          }
2533 2566  
2534 2567          (void) mutex_lock(&_idmapdstate.addisc_lk);
2535 2568          prev_st = _idmapdstate.addisc_st;
2536 2569          _idmapdstate.addisc_st |= ADDISC_ST_REQUESTED;
2537 2570          (void) mutex_unlock(&_idmapdstate.addisc_lk);
2538 2571  
2539 2572          if (prev_st & ADDISC_ST_REQUESTED) {
2540 2573                  idmapdlog(LOG_DEBUG, "already kicked");
2541 2574          } else {
2542 2575                  idmapdlog(LOG_DEBUG, "port send kick");
2543 2576                  (void) port_send(idmapd_ev_port, KICK_AUTO_DISCOVERY, NULL);
2544 2577          }
2545 2578  }
2546 2579  
2547 2580  /*ARGSUSED*/
2548 2581  void
2549 2582  idmap_cfg_hup_handler(int sig)
2550 2583  {
2551 2584          if (idmapd_ev_port >= 0)
2552 2585                  (void) port_send(idmapd_ev_port, RECONFIGURE, NULL);
2553 2586  }
2554 2587  
2555 2588  /*
2556 2589   * Upgrade the debug flags.
2557 2590   *
2558 2591   * We're replacing a single debug flag with a fine-grained mechanism that
2559 2592   * is also capable of considerably more verbosity.  We'll take a stab at
2560 2593   * producing roughly the same level of output.
2561 2594   */
2562 2595  static
2563 2596  int
2564 2597  upgrade_debug(idmap_cfg_handles_t *handles)
2565 2598  {
2566 2599          boolean_t debug_present;
2567 2600          const char DEBUG_PROP[] = "debug";
2568 2601          int rc;
2569 2602  
2570 2603          rc = prop_exists(handles, DEBUG_PROP, &debug_present);
2571 2604  
2572 2605          if (rc != 0)
2573 2606                  return (rc);
2574 2607  
2575 2608          if (!debug_present)
2576 2609                  return (0);
2577 2610  
2578 2611          idmapdlog(LOG_INFO,
2579 2612              "Upgrading old %s/%s setting to %s/* settings.",
2580 2613              CONFIG_PG, DEBUG_PROP, DEBUG_PG);
2581 2614  
2582 2615          rc = set_val_integer(handles, handles->debug_pg, "config", 1);
2583 2616          if (rc != 0)
2584 2617                  return (rc);
2585 2618          rc = set_val_integer(handles, handles->debug_pg, "discovery", 1);
2586 2619          if (rc != 0)
2587 2620                  return (rc);
2588 2621  
2589 2622          rc = del_val(handles, handles->config_pg, DEBUG_PROP);
2590 2623          if (rc != 0)
2591 2624                  return (rc);
2592 2625  
2593 2626          return (0);
2594 2627  }
2595 2628  
2596 2629  /*
2597 2630   * Upgrade the DS mapping flags.
2598 2631   *
2599 2632   * If the old ds_name_mapping_enabled flag is present, then
2600 2633   *     if the new directory_based_mapping value is present, then
2601 2634   *         if the two are compatible, delete the old and note it
2602 2635   *         else delete the old and warn
2603 2636   *     else
2604 2637   *         set the new based on the old, and note it
2605 2638   *         delete the old
2606 2639   */
2607 2640  static
2608 2641  int
2609 2642  upgrade_directory_mapping(idmap_cfg_handles_t *handles)
2610 2643  {
2611 2644          boolean_t legacy_ds_name_mapping_present;
2612 2645          const char DS_NAME_MAPPING_ENABLED[] = "ds_name_mapping_enabled";
2613 2646          const char DIRECTORY_BASED_MAPPING[] = "directory_based_mapping";
2614 2647          int rc;
2615 2648  
2616 2649          rc = prop_exists(handles, DS_NAME_MAPPING_ENABLED,
2617 2650              &legacy_ds_name_mapping_present);
2618 2651  
2619 2652          if (rc != 0)
2620 2653                  return (rc);
2621 2654  
2622 2655          if (!legacy_ds_name_mapping_present)
2623 2656                  return (0);
2624 2657  
2625 2658          boolean_t legacy_ds_name_mapping_enabled;
2626 2659          rc = get_val_bool(handles, DS_NAME_MAPPING_ENABLED,
2627 2660              &legacy_ds_name_mapping_enabled, B_FALSE);
2628 2661          if (rc != 0)
2629 2662                  return (rc);
2630 2663  
2631 2664          char *legacy_mode;
2632 2665          char *legacy_bool_string;
2633 2666          if (legacy_ds_name_mapping_enabled) {
2634 2667                  legacy_mode = "name";
2635 2668                  legacy_bool_string = "true";
2636 2669          } else {
2637 2670                  legacy_mode = "none";
2638 2671                  legacy_bool_string = "false";
2639 2672          }
2640 2673  
2641 2674          char *directory_based_mapping;
2642 2675          rc = get_val_astring(handles, DIRECTORY_BASED_MAPPING,
2643 2676              &directory_based_mapping);
2644 2677          if (rc != 0)
2645 2678                  return (rc);
2646 2679  
2647 2680          if (directory_based_mapping == NULL) {
2648 2681                  idmapdlog(LOG_INFO,
2649 2682                      "Upgrading old %s=%s setting\n"
2650 2683                      "to %s=%s.",
2651 2684                      DS_NAME_MAPPING_ENABLED, legacy_bool_string,
2652 2685                      DIRECTORY_BASED_MAPPING, legacy_mode);
2653 2686                  rc = set_val_astring(handles, handles->config_pg,
2654 2687                      DIRECTORY_BASED_MAPPING, legacy_mode);
2655 2688                  if (rc != 0)
2656 2689                          return (rc);
2657 2690          } else {
2658 2691                  boolean_t new_name_mapping;
2659 2692                  if (strcasecmp(directory_based_mapping, "name") == 0)
2660 2693                          new_name_mapping = B_TRUE;
2661 2694                  else
2662 2695                          new_name_mapping = B_FALSE;
2663 2696  
2664 2697                  if (legacy_ds_name_mapping_enabled == new_name_mapping) {
2665 2698                          idmapdlog(LOG_INFO,
2666 2699                              "Automatically removing old %s=%s setting\n"
2667 2700                              "in favor of %s=%s.",
2668 2701                              DS_NAME_MAPPING_ENABLED, legacy_bool_string,
2669 2702                              DIRECTORY_BASED_MAPPING, directory_based_mapping);
2670 2703                  } else {
2671 2704                          idmapdlog(LOG_WARNING,
2672 2705                              "Removing conflicting %s=%s setting\n"
2673 2706                              "in favor of %s=%s.",
2674 2707                              DS_NAME_MAPPING_ENABLED, legacy_bool_string,
2675 2708                              DIRECTORY_BASED_MAPPING, directory_based_mapping);
2676 2709                  }
2677 2710                  free(directory_based_mapping);
2678 2711          }
2679 2712  
2680 2713          rc = del_val(handles, handles->config_pg, DS_NAME_MAPPING_ENABLED);
2681 2714          if (rc != 0)
2682 2715                  return (rc);
2683 2716  
2684 2717          return (0);
2685 2718  }
2686 2719  
2687 2720  /*
2688 2721   * Do whatever is necessary to upgrade idmap's configuration before
2689 2722   * we load it.
2690 2723   */
2691 2724  int
2692 2725  idmap_cfg_upgrade(idmap_cfg_t *cfg)
2693 2726  {
2694 2727          int rc;
2695 2728  
2696 2729          rc = upgrade_directory_mapping(&cfg->handles);
2697 2730          if (rc != 0)
2698 2731                  return (rc);
2699 2732  
2700 2733          rc = upgrade_debug(&cfg->handles);
2701 2734          if (rc != 0)
2702 2735                  return (rc);
2703 2736  
2704 2737          return (0);
2705 2738  }
2706 2739  
2707 2740  /*
2708 2741   * The LDAP code passes principal names lacking any
2709 2742   * realm information, which causes mech_krb5 to do
2710 2743   * awful things trying to figure out the realm.
2711 2744   * Avoid that by making sure it has a default,
2712 2745   * even when krb5.conf is not configured.
2713 2746   */
2714 2747  static void
2715 2748  idmapd_set_krb5_realm(char *domain)
2716 2749  {
2717 2750          static char realm[MAXHOSTNAMELEN];
2718 2751          size_t ilen, olen;
2719 2752          int err;
2720 2753  
2721 2754          if (domain == NULL) {
2722 2755                  (void) unsetenv("KRB5_DEFAULT_REALM");
2723 2756                  return;
2724 2757          }
2725 2758  
2726 2759          /* Convert to upper case, in place. */
2727 2760          (void) strlcpy(realm, domain, sizeof (realm));
2728 2761          olen = ilen = strlen(realm);
2729 2762          (void) u8_textprep_str(realm, &ilen, realm, &olen,
2730 2763              U8_TEXTPREP_TOUPPER, U8_UNICODE_LATEST, &err);
2731 2764  
2732 2765          (void) setenv("KRB5_DEFAULT_REALM", realm, 1);
2733 2766  }
  
    | 
      ↓ open down ↓ | 
    523 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX