1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  24  */
  25 
  26 /*
  27  * Initialization routines
  28  */
  29 
  30 #include "idmapd.h"
  31 #include <signal.h>
  32 #include <thread.h>
  33 #include <string.h>
  34 #include <errno.h>
  35 #include <assert.h>
  36 #include <unistd.h>
  37 #include <sys/types.h>
  38 #include <sys/stat.h>
  39 #include <rpcsvc/daemon_utils.h>
  40 
  41 
  42 int
  43 init_mapping_system()
  44 {
  45         int rc = 0;
  46 
  47         if ((rc = load_config()) < 0)
  48                 return (rc);
  49 
  50         (void) setegid(DAEMON_GID);
  51         (void) seteuid(DAEMON_UID);
  52         if (init_dbs() < 0) {
  53                 rc = -1;
  54                 fini_mapping_system();
  55         }
  56         (void) seteuid(0);
  57         (void) setegid(0);
  58 
  59         return (rc);
  60 }
  61 
  62 void
  63 fini_mapping_system()
  64 {
  65         fini_dbs();
  66 }
  67 
  68 int
  69 load_config()
  70 {
  71         int rc;
  72         if ((_idmapdstate.cfg = idmap_cfg_init()) == NULL) {
  73                 degrade_svc(0, "failed to initialize config");
  74                 return (-1);
  75         }
  76 
  77         rc = idmap_cfg_upgrade(_idmapdstate.cfg);
  78         if (rc != 0) {
  79                 degrade_svc(0, "fatal error while upgrading configuration");
  80                 return (rc);
  81         }
  82 
  83         rc = idmap_cfg_load(_idmapdstate.cfg, 0);
  84         if (rc < -1) {
  85                 /* Total failure */
  86                 degrade_svc(0, "fatal error while loading configuration");
  87                 return (rc);
  88         }
  89 
  90         if (rc != 0)
  91                 /* Partial failure */
  92                 idmapdlog(LOG_ERR, "Various errors occurred while loading "
  93                     "the configuration; check the logs");
  94 
  95         if ((rc = idmap_cfg_start_updates()) < 0) {
  96                 /* Total failure */
  97                 degrade_svc(0, "could not start config updater");
  98                 return (rc);
  99         }
 100 
 101         if (DBG(CONFIG, 1))
 102                 idmapdlog(LOG_DEBUG, "Initial configuration loaded");
 103 
 104         return (0);
 105 }
 106 
 107 
 108 void
 109 reload_gcs()
 110 {
 111         int             i, j;
 112         adutils_ad_t    **new_gcs;
 113         adutils_ad_t    **old_gcs = _idmapdstate.gcs;
 114         int             new_num_gcs;
 115         int             old_num_gcs = _idmapdstate.num_gcs;
 116         idmap_pg_config_t *pgcfg = &_idmapdstate.cfg->pgcfg;
 117         idmap_trustedforest_t *trustfor = pgcfg->trusted_forests;
 118         int             num_trustfor = pgcfg->num_trusted_forests;
 119         ad_disc_domainsinforest_t *domain_in_forest;
 120 
 121         if (pgcfg->use_ads == B_FALSE ||
 122             pgcfg->domain_name == NULL) {
 123                 /*
 124                  * ADS disabled, or no domain name specified.
 125                  * Not using adutils. (but still can use lsa)
 126                  */
 127                 new_gcs = NULL;
 128                 new_num_gcs = 0;
 129                 goto out;
 130         }
 131 
 132         if (pgcfg->global_catalog == NULL ||
 133             pgcfg->global_catalog[0].host[0] == '\0') {
 134                 /*
 135                  * No GCs.  Continue to use the previous AD config in case
 136                  * that's still good but auto-discovery had a transient failure.
 137                  * If that stops working we'll go into degraded mode anyways
 138                  * when it does.
 139                  */
 140                 idmapdlog(LOG_INFO,
 141                     "Global Catalog servers not configured/discoverable");
 142                 return;
 143         }
 144 
 145         new_num_gcs = 1 + num_trustfor;
 146         new_gcs = calloc(new_num_gcs, sizeof (adutils_ad_t *));
 147         if (new_gcs == NULL) {
 148                 degrade_svc(0, "could not allocate AD context array "
 149                     "(out of memory)");
 150                 return;
 151         }
 152 
 153         if (adutils_ad_alloc(&new_gcs[0], NULL, ADUTILS_AD_GLOBAL_CATALOG) !=
 154             ADUTILS_SUCCESS) {
 155                 free(new_gcs);
 156                 degrade_svc(0, "could not initialize AD context "
 157                     "(out of memory)");
 158                 return;
 159         }
 160 
 161         for (i = 0; pgcfg->global_catalog[i].host[0] != '\0'; i++) {
 162                 if (idmap_add_ds(new_gcs[0],
 163                     pgcfg->global_catalog[i].host,
 164                     pgcfg->global_catalog[i].port) != 0) {
 165                         adutils_ad_free(&new_gcs[0]);
 166                         free(new_gcs);
 167                         degrade_svc(0, "could not set AD hosts "
 168                             "(out of memory)");
 169                         return;
 170                 }
 171         }
 172 
 173         if (pgcfg->domains_in_forest != NULL) {
 174                 for (i = 0; pgcfg->domains_in_forest[i].domain[0] != '\0';
 175                     i++) {
 176                         if (adutils_add_domain(new_gcs[0],
 177                             pgcfg->domains_in_forest[i].domain,
 178                             pgcfg->domains_in_forest[i].sid) != 0) {
 179                                 adutils_ad_free(&new_gcs[0]);
 180                                 free(new_gcs);
 181                                 degrade_svc(0, "could not set AD domains "
 182                                     "(out of memory)");
 183                                 return;
 184                         }
 185                 }
 186         }
 187 
 188         for (i = 0; i < num_trustfor; i++) {
 189                 if (adutils_ad_alloc(&new_gcs[i + 1], NULL,
 190                     ADUTILS_AD_GLOBAL_CATALOG) != ADUTILS_SUCCESS) {
 191                         degrade_svc(0, "could not initialize trusted AD "
 192                             "context (out of memory)");
 193                                 new_num_gcs = i + 1;
 194                                 goto out;
 195                 }
 196                 for (j = 0; trustfor[i].global_catalog[j].host[0] != '\0';
 197                     j++) {
 198                         if (idmap_add_ds(new_gcs[i + 1],
 199                             trustfor[i].global_catalog[j].host,
 200                             trustfor[i].global_catalog[j].port) != 0) {
 201                                 adutils_ad_free(&new_gcs[i + 1]);
 202                                 degrade_svc(0, "could not set trusted "
 203                                     "AD hosts (out of memory)");
 204                                 new_num_gcs = i + 1;
 205                                 goto out;
 206                         }
 207                 }
 208                 for (j = 0; trustfor[i].domains_in_forest[j].domain[0] != '\0';
 209                     j++) {
 210                         domain_in_forest = &trustfor[i].domains_in_forest[j];
 211                         /* Only add domains which are marked */
 212                         if (domain_in_forest->trusted) {
 213                                 if (adutils_add_domain(new_gcs[i + 1],
 214                                     domain_in_forest->domain,
 215                                     domain_in_forest->sid) != 0) {
 216                                         adutils_ad_free(&new_gcs[i + 1]);
 217                                         degrade_svc(0, "could not set trusted "
 218                                             "AD domains (out of memory)");
 219                                         new_num_gcs = i + 1;
 220                                         goto out;
 221                                 }
 222                         }
 223                 }
 224         }
 225 
 226 out:
 227         _idmapdstate.gcs = new_gcs;
 228         _idmapdstate.num_gcs = new_num_gcs;
 229 
 230         if (old_gcs != NULL) {
 231                 for (i = 0; i < old_num_gcs; i++)
 232                         adutils_ad_free(&old_gcs[i]);
 233                 free(old_gcs);
 234         }
 235 }
 236 
 237 /*
 238  * NEEDSWORK:  This should load entries for domain servers for all known
 239  * domains - the joined domain, other domains in the forest, and trusted
 240  * domains in other forests.  However, we don't yet discover any DCs other
 241  * than the DCs for the joined domain.
 242  */
 243 static
 244 void
 245 reload_dcs(void)
 246 {
 247         int             i;
 248         adutils_ad_t    **new_dcs;
 249         adutils_ad_t    **old_dcs = _idmapdstate.dcs;
 250         int             new_num_dcs;
 251         int             old_num_dcs = _idmapdstate.num_dcs;
 252         idmap_pg_config_t *pgcfg = &_idmapdstate.cfg->pgcfg;
 253 
 254         if (pgcfg->use_ads == B_FALSE ||
 255             pgcfg->domain_name == NULL) {
 256                 /*
 257                  * ADS disabled, or no domain name specified.
 258                  * Not using adutils. (but still can use lsa)
 259                  */
 260                 new_dcs = NULL;
 261                 new_num_dcs = 0;
 262                 goto out;
 263         }
 264 
 265         if (pgcfg->domain_controller == NULL ||
 266             pgcfg->domain_controller[0].host[0] == '\0') {
 267                 /*
 268                  * No DCs.  Continue to use the previous AD config in case
 269                  * that's still good but auto-discovery had a transient failure.
 270                  * If that stops working we'll go into degraded mode anyways
 271                  * when it does.
 272                  */
 273                 idmapdlog(LOG_INFO,
 274                     "Domain controller servers not configured/discoverable");
 275                 return;
 276         }
 277 
 278         new_num_dcs = 1;
 279         new_dcs = calloc(new_num_dcs, sizeof (adutils_ad_t *));
 280         if (new_dcs == NULL)
 281                 goto nomem;
 282 
 283         if (adutils_ad_alloc(&new_dcs[0], pgcfg->domain_name,
 284             ADUTILS_AD_DATA) != ADUTILS_SUCCESS)
 285                 goto nomem;
 286 
 287         for (i = 0; pgcfg->domain_controller[i].host[0] != '\0'; i++) {
 288                 if (idmap_add_ds(new_dcs[0],
 289                     pgcfg->domain_controller[i].host,
 290                     pgcfg->domain_controller[i].port) != 0)
 291                         goto nomem;
 292         }
 293 
 294         /*
 295          * NEEDSWORK:  All we need here is to add the domain and SID for
 296          * this DC to the list of domains supported by this entry.  Isn't
 297          * there an easier way to find the SID than to walk through the list
 298          * of all of the domains in the forest?
 299          */
 300         ad_disc_domainsinforest_t *dif = pgcfg->domains_in_forest;
 301         if (dif != NULL) {
 302                 for (; dif->domain[0] != '\0'; dif++) {
 303                         if (domain_eq(pgcfg->domain_name, dif->domain)) {
 304                                 if (adutils_add_domain(new_dcs[0],
 305                                     dif->domain, dif->sid) != 0)
 306                                         goto nomem;
 307                                 break;
 308                         }
 309                 }
 310         }
 311 
 312 out:
 313         _idmapdstate.dcs = new_dcs;
 314         _idmapdstate.num_dcs = new_num_dcs;
 315 
 316         if (old_dcs != NULL) {
 317                 for (i = 0; i < old_num_dcs; i++)
 318                         adutils_ad_free(&old_dcs[i]);
 319                 free(old_dcs);
 320         }
 321 
 322         return;
 323 
 324 nomem:
 325         degrade_svc(0, "out of memory");
 326 
 327         if (new_dcs != NULL) {
 328                 if (new_dcs[0] != NULL)
 329                         adutils_ad_free(&new_dcs[0]);
 330                 free(new_dcs);
 331         }
 332 }
 333 
 334 
 335 void
 336 reload_ad(void)
 337 {
 338         reload_gcs();
 339         reload_dcs();
 340 }
 341 
 342 void
 343 print_idmapdstate(void)
 344 {
 345         int i, j;
 346         idmap_pg_config_t *pgcfg;
 347         idmap_trustedforest_t *tf;
 348 
 349         RDLOCK_CONFIG();
 350 
 351         if (_idmapdstate.cfg == NULL) {
 352                 idmapdlog(LOG_INFO, "Null configuration");
 353                 UNLOCK_CONFIG();
 354                 return;
 355         }
 356 
 357         pgcfg = &_idmapdstate.cfg->pgcfg;
 358 
 359         idmapdlog(LOG_DEBUG, "list_size_limit=%llu", pgcfg->list_size_limit);
 360         idmapdlog(LOG_DEBUG, "max_threads=%llu", pgcfg->max_threads);
 361         idmapdlog(LOG_DEBUG, "default_domain=%s",
 362             CHECK_NULL(pgcfg->default_domain));
 363         idmapdlog(LOG_DEBUG, "domain_name=%s", CHECK_NULL(pgcfg->domain_name));
 364         idmapdlog(LOG_DEBUG, "machine_sid=%s", CHECK_NULL(pgcfg->machine_sid));
 365         if (pgcfg->domain_controller == NULL ||
 366             pgcfg->domain_controller[0].host[0] == '\0') {
 367                 idmapdlog(LOG_DEBUG, "No domain controllers known");
 368         } else {
 369                 for (i = 0; pgcfg->domain_controller[i].host[0] != '\0'; i++)
 370                         idmapdlog(LOG_DEBUG, "domain_controller=%s port=%d",
 371                             pgcfg->domain_controller[i].host,
 372                             pgcfg->domain_controller[i].port);
 373         }
 374         idmapdlog(LOG_DEBUG, "forest_name=%s", CHECK_NULL(pgcfg->forest_name));
 375         idmapdlog(LOG_DEBUG, "site_name=%s", CHECK_NULL(pgcfg->site_name));
 376         if (pgcfg->global_catalog == NULL ||
 377             pgcfg->global_catalog[0].host[0] == '\0') {
 378                 idmapdlog(LOG_DEBUG, "No global catalog servers known");
 379         } else {
 380                 for (i = 0; pgcfg->global_catalog[i].host[0] != '\0'; i++)
 381                         idmapdlog(LOG_DEBUG, "global_catalog=%s port=%d",
 382                             pgcfg->global_catalog[i].host,
 383                             pgcfg->global_catalog[i].port);
 384         }
 385         if (pgcfg->domains_in_forest == NULL ||
 386             pgcfg->domains_in_forest[0].domain[0] == '\0') {
 387                 idmapdlog(LOG_DEBUG, "No domains in forest %s known",
 388                     CHECK_NULL(pgcfg->forest_name));
 389         } else {
 390                 for (i = 0; pgcfg->domains_in_forest[i].domain[0] != '\0'; i++)
 391                         idmapdlog(LOG_DEBUG, "domains in forest %s = %s",
 392                             CHECK_NULL(pgcfg->forest_name),
 393                             pgcfg->domains_in_forest[i].domain);
 394         }
 395         if (pgcfg->trusted_domains == NULL ||
 396             pgcfg->trusted_domains[0].domain[0] == '\0') {
 397                 idmapdlog(LOG_DEBUG, "No trusted domains known");
 398         } else {
 399                 for (i = 0; pgcfg->trusted_domains[i].domain[0] != '\0'; i++)
 400                         idmapdlog(LOG_DEBUG, "trusted domain = %s",
 401                             pgcfg->trusted_domains[i].domain);
 402         }
 403 
 404         for (i = 0; i < pgcfg->num_trusted_forests; i++) {
 405                 tf = &pgcfg->trusted_forests[i];
 406                 for (j = 0; tf->global_catalog[j].host[0] != '\0'; j++)
 407                         idmapdlog(LOG_DEBUG,
 408                             "trusted forest %s global_catalog=%s port=%d",
 409                             tf->forest_name,
 410                             tf->global_catalog[j].host,
 411                             tf->global_catalog[j].port);
 412                 for (j = 0; tf->domains_in_forest[j].domain[0] != '\0'; j++) {
 413                         if (tf->domains_in_forest[j].trusted) {
 414                                 idmapdlog(LOG_DEBUG,
 415                                     "trusted forest %s domain=%s",
 416                                     tf->forest_name,
 417                                     tf->domains_in_forest[j].domain);
 418                         }
 419                 }
 420         }
 421 
 422         idmapdlog(LOG_DEBUG, "directory_based_mapping=%s",
 423             enum_lookup(pgcfg->directory_based_mapping, directory_mapping_map));
 424         idmapdlog(LOG_DEBUG, "ad_unixuser_attr=%s",
 425             CHECK_NULL(pgcfg->ad_unixuser_attr));
 426         idmapdlog(LOG_DEBUG, "ad_unixgroup_attr=%s",
 427             CHECK_NULL(pgcfg->ad_unixgroup_attr));
 428         idmapdlog(LOG_DEBUG, "nldap_winname_attr=%s",
 429             CHECK_NULL(pgcfg->nldap_winname_attr));
 430 
 431         UNLOCK_CONFIG();
 432 }
 433 
 434 int
 435 create_directory(const char *path, uid_t uid, gid_t gid)
 436 {
 437         int     rc;
 438 
 439         if ((rc = mkdir(path, 0700)) < 0 && errno != EEXIST) {
 440                 idmapdlog(LOG_ERR, "Error creating directory %s (%s)",
 441                     path, strerror(errno));
 442                 return (-1);
 443         }
 444 
 445         if (lchown(path, uid, gid) < 0) {
 446                 idmapdlog(LOG_ERR, "Error creating directory %s (%s)",
 447                     path, strerror(errno));
 448                 if (rc == 0)
 449                         (void) rmdir(path);
 450                 return (-1);
 451         }
 452         return (0);
 453 }