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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Config routines common to idmap(1M) and idmapd(1M) 30 */ 31 32 #include <stdlib.h> 33 #include <synch.h> 34 #include <assert.h> 35 #include <sys/varargs.h> 36 #include <sys/systeminfo.h> 37 #include <strings.h> 38 #include <libintl.h> 39 #include <ctype.h> 40 #include <errno.h> 41 #include "idmapd.h" 42 #include <stdio.h> 43 #include <stdarg.h> 44 #include <uuid/uuid.h> 45 46 #define MACHINE_SID_LEN (9 + UUID_LEN/4 * 11) 47 #define FMRI_BASE "svc:/system/idmap" 48 #define CONFIG_PG "config" 49 #define GENERAL_PG "general" 50 /* initial length of the array for policy options/attributes: */ 51 #define DEF_ARRAY_LENGTH 16 52 53 static const char *me = "idmapd"; 54 55 static int 56 generate_machine_sid(char **machine_sid) { 57 char *p; 58 uuid_t uu; 59 int i, j, len, rlen; 60 uint32_t rid; 61 62 /* 63 * Generate and split 128-bit UUID into four 32-bit RIDs 64 * The machine_sid will be of the form S-1-5-N1-N2-N3-N4 65 * We depart from Windows here, which instead of 128 66 * bits worth of random numbers uses 96 bits. 67 */ 68 69 *machine_sid = calloc(1, MACHINE_SID_LEN); 70 if (*machine_sid == NULL) { 71 idmapdlog(LOG_ERR, "%s: Out of memory", me); 72 return (-1); 73 } 74 (void) strcpy(*machine_sid, "S-1-5-21"); 75 p = *machine_sid + strlen("S-1-5-21"); 76 len = MACHINE_SID_LEN - strlen("S-1-5-21"); 77 78 uuid_clear(uu); 79 uuid_generate_random(uu); 80 81 for (i = 0; i < UUID_LEN/4; i++) { 82 j = i * 4; 83 rid = (uu[j] << 24) | (uu[j + 1] << 16) | 84 (uu[j + 2] << 8) | (uu[j + 3]); 85 rlen = snprintf(p, len, "-%u", rid); 86 p += rlen; 87 len -= rlen; 88 } 89 90 return (0); 91 } 92 93 /* Check if in the case of failure the original value of *val is preserved */ 94 static int 95 get_val_int(idmap_cfg_t *cfg, char *name, void *val, scf_type_t type) 96 { 97 int rc = 0; 98 99 scf_property_t *scf_prop = scf_property_create(cfg->handles.main); 100 scf_value_t *value = scf_value_create(cfg->handles.main); 101 102 103 if (0 > scf_pg_get_property(cfg->handles.config_pg, name, scf_prop)) 104 /* this is OK: the property is just undefined */ 105 goto destruction; 106 107 108 if (0 > scf_property_get_value(scf_prop, value)) 109 /* It is still OK when a property doesn't have any value */ 110 goto destruction; 111 112 switch (type) { 113 case SCF_TYPE_BOOLEAN: 114 rc = scf_value_get_boolean(value, val); 115 break; 116 case SCF_TYPE_COUNT: 117 rc = scf_value_get_count(value, val); 118 break; 119 case SCF_TYPE_INTEGER: 120 rc = scf_value_get_integer(value, val); 121 break; 122 default: 123 idmapdlog(LOG_ERR, "%s: Invalid scf integer type (%d)", 124 me, type); 125 rc = -1; 126 break; 127 } 128 129 130 destruction: 131 scf_value_destroy(value); 132 scf_property_destroy(scf_prop); 133 134 return (rc); 135 } 136 137 static char * 138 scf_value2string(scf_value_t *value) { 139 int rc = -1; 140 char buf_size = 127; 141 int length; 142 char *buf = NULL; 143 buf = (char *) malloc(sizeof (char) * buf_size); 144 145 for (;;) { 146 length = scf_value_get_astring(value, buf, buf_size); 147 if (length < 0) { 148 rc = -1; 149 goto destruction; 150 } 151 152 if (length == buf_size - 1) { 153 buf_size *= 2; 154 buf = (char *)realloc(buf, buf_size * sizeof (char)); 155 if (!buf) { 156 idmapdlog(LOG_ERR, "%s: Out of memory", me); 157 rc = -1; 158 goto destruction; 159 } 160 } else { 161 rc = 0; 162 break; 163 } 164 } 165 166 destruction: 167 if (rc < 0) { 168 if (buf) 169 free(buf); 170 buf = NULL; 171 } 172 173 return (buf); 174 } 175 176 177 static int 178 get_val_astring(idmap_cfg_t *cfg, char *name, char **val) 179 { 180 int rc = 0; 181 182 scf_property_t *scf_prop = scf_property_create(cfg->handles.main); 183 scf_value_t *value = scf_value_create(cfg->handles.main); 184 185 186 if (0 > scf_pg_get_property(cfg->handles.config_pg, name, scf_prop)) 187 /* this is OK: the property is just undefined */ 188 goto destruction; 189 190 if (0 > scf_property_get_value(scf_prop, value)) { 191 idmapdlog(LOG_ERR, 192 "%s: scf_property_get_value(%s) failed: %s", 193 me, name, scf_strerror(scf_error())); 194 rc = -1; 195 goto destruction; 196 } 197 198 if (!(*val = scf_value2string(value))) { 199 rc = -1; 200 idmapdlog(LOG_ERR, 201 "%s: scf_value2string(%s) failed: %s", 202 me, name, scf_strerror(scf_error())); 203 } 204 205 destruction: 206 scf_value_destroy(value); 207 scf_property_destroy(scf_prop); 208 209 if (rc < 0) { 210 if (*val) 211 free(*val); 212 *val = NULL; 213 } 214 215 return (rc); 216 } 217 218 static int 219 set_val_astring(idmap_cfg_t *cfg, char *name, const char *val) 220 { 221 int rc = 0, i; 222 scf_property_t *scf_prop = NULL; 223 scf_value_t *value = NULL; 224 scf_transaction_t *tx = NULL; 225 scf_transaction_entry_t *ent = NULL; 226 227 if ((scf_prop = scf_property_create(cfg->handles.main)) == NULL || 228 (value = scf_value_create(cfg->handles.main)) == NULL || 229 (tx = scf_transaction_create(cfg->handles.main)) == NULL || 230 (ent = scf_entry_create(cfg->handles.main)) == NULL) { 231 idmapdlog(LOG_ERR, "%s: Unable to set property %s: %s", 232 me, name, scf_strerror(scf_error())); 233 rc = -1; 234 goto destruction; 235 } 236 237 for (i = 0; i < MAX_TRIES && rc == 0; i++) { 238 if (scf_transaction_start(tx, cfg->handles.config_pg) == -1) { 239 idmapdlog(LOG_ERR, 240 "%s: scf_transaction_start(%s) failed: %s", 241 me, name, scf_strerror(scf_error())); 242 rc = -1; 243 goto destruction; 244 } 245 246 rc = scf_transaction_property_new(tx, ent, name, 247 SCF_TYPE_ASTRING); 248 if (rc == -1) { 249 idmapdlog(LOG_ERR, 250 "%s: scf_transaction_property_new() failed: %s", 251 me, scf_strerror(scf_error())); 252 goto destruction; 253 } 254 255 if (scf_value_set_astring(value, val) == -1) { 256 idmapdlog(LOG_ERR, 257 "%s: scf_value_set_astring() failed: %s", 258 me, scf_strerror(scf_error())); 259 rc = -1; 260 goto destruction; 261 } 262 263 if (scf_entry_add_value(ent, value) == -1) { 264 idmapdlog(LOG_ERR, 265 "%s: scf_entry_add_value() failed: %s", 266 me, scf_strerror(scf_error())); 267 rc = -1; 268 goto destruction; 269 } 270 271 rc = scf_transaction_commit(tx); 272 if (rc == 0 && i < MAX_TRIES - 1) { 273 /* 274 * Property group set in scf_transaction_start() 275 * is not the most recent. Update pg, reset tx and 276 * retry tx. 277 */ 278 idmapdlog(LOG_WARNING, 279 "%s: scf_transaction_commit(%s) failed - Retry: %s", 280 me, name, scf_strerror(scf_error())); 281 if (scf_pg_update(cfg->handles.config_pg) == -1) { 282 idmapdlog(LOG_ERR, 283 "%s: scf_pg_update() failed: %s", 284 me, scf_strerror(scf_error())); 285 rc = -1; 286 goto destruction; 287 } 288 scf_transaction_reset(tx); 289 } 290 } 291 292 /* Log failure message if all retries failed */ 293 if (rc == 0) { 294 idmapdlog(LOG_ERR, 295 "%s: scf_transaction_commit(%s) failed: %s", 296 me, name, scf_strerror(scf_error())); 297 rc = -1; 298 } 299 300 destruction: 301 scf_value_destroy(value); 302 scf_entry_destroy(ent); 303 scf_transaction_destroy(tx); 304 scf_property_destroy(scf_prop); 305 return (rc); 306 } 307 308 int 309 idmap_cfg_load(idmap_cfg_t *cfg) 310 { 311 int rc = 0; 312 313 cfg->pgcfg.list_size_limit = 0; 314 cfg->pgcfg.mapping_domain = NULL; 315 cfg->pgcfg.machine_sid = NULL; 316 cfg->pgcfg.domain_controller = NULL; 317 cfg->pgcfg.global_catalog = NULL; 318 319 if (0 > scf_pg_update(cfg->handles.config_pg)) { 320 idmapdlog(LOG_ERR, "%s: scf_pg_update() failed: %s", 321 me, scf_strerror(scf_error())); 322 return (-1); 323 } 324 325 if (0 > scf_pg_update(cfg->handles.general_pg)) { 326 idmapdlog(LOG_ERR, "%s: scf_pg_update() failed: %s", 327 me, scf_strerror(scf_error())); 328 return (-1); 329 } 330 331 rc = get_val_int(cfg, "list_size_limit", 332 &cfg->pgcfg.list_size_limit, SCF_TYPE_COUNT); 333 if (rc != 0) 334 return (-1); 335 336 rc = get_val_astring(cfg, "mapping_domain", 337 &cfg->pgcfg.mapping_domain); 338 if (rc != 0) 339 return (-1); 340 341 /* 342 * If there is no mapping_domain in idmap's smf config then 343 * set it to the joined domain. 344 * Till domain join is implemented, temporarily set it to 345 * the system domain for testing purposes. 346 */ 347 if (!cfg->pgcfg.mapping_domain) { 348 char test[1]; 349 long dname_size = sysinfo(SI_SRPC_DOMAIN, test, 1); 350 if (dname_size > 0) { 351 cfg->pgcfg.mapping_domain = 352 (char *)malloc(dname_size * sizeof (char)); 353 dname_size = sysinfo(SI_SRPC_DOMAIN, 354 cfg->pgcfg.mapping_domain, dname_size); 355 } 356 if (dname_size <= 0) { 357 idmapdlog(LOG_ERR, 358 "%s: unable to get name service domain", me); 359 if (cfg->pgcfg.mapping_domain) 360 free(cfg->pgcfg.mapping_domain); 361 cfg->pgcfg.mapping_domain = NULL; 362 } 363 } 364 365 rc = get_val_astring(cfg, "machine_sid", &cfg->pgcfg.machine_sid); 366 if (rc != 0) 367 return (-1); 368 if (cfg->pgcfg.machine_sid == NULL) { 369 /* If machine_sid not configured, generate one */ 370 if (generate_machine_sid(&cfg->pgcfg.machine_sid) < 0) 371 return (-1); 372 rc = set_val_astring(cfg, "machine_sid", 373 cfg->pgcfg.machine_sid); 374 if (rc < 0) { 375 free(cfg->pgcfg.machine_sid); 376 cfg->pgcfg.machine_sid = NULL; 377 return (-1); 378 } 379 } 380 381 rc = get_val_astring(cfg, "global_catalog", &cfg->pgcfg.global_catalog); 382 if (rc != 0) 383 return (-1); 384 385 rc = get_val_astring(cfg, "domain_controller", 386 &cfg->pgcfg.domain_controller); 387 if (rc != 0) 388 return (-1); 389 390 return (rc); 391 } 392 393 /* 394 * Initialize 'cfg'. 395 */ 396 idmap_cfg_t * 397 idmap_cfg_init() { 398 399 /* First the smf repository handles: */ 400 idmap_cfg_t *cfg = calloc(1, sizeof (idmap_cfg_t)); 401 if (!cfg) { 402 idmapdlog(LOG_ERR, "%s: Out of memory", me); 403 return (NULL); 404 } 405 406 if (!(cfg->handles.main = scf_handle_create(SCF_VERSION))) { 407 idmapdlog(LOG_ERR, "%s: scf_handle_create() failed: %s", 408 me, scf_strerror(scf_error())); 409 goto error; 410 } 411 412 if (0 > scf_handle_bind(cfg->handles.main)) { 413 idmapdlog(LOG_ERR, "%s: scf_handle_bind() failed: %s", 414 me, scf_strerror(scf_error())); 415 goto error; 416 } 417 418 if (!(cfg->handles.service = scf_service_create(cfg->handles.main)) || 419 !(cfg->handles.instance = scf_instance_create(cfg->handles.main)) || 420 !(cfg->handles.config_pg = scf_pg_create(cfg->handles.main)) || 421 !(cfg->handles.general_pg = scf_pg_create(cfg->handles.main))) { 422 idmapdlog(LOG_ERR, "%s: scf handle creation failed: %s", 423 me, scf_strerror(scf_error())); 424 goto error; 425 } 426 427 if (0 > scf_handle_decode_fmri(cfg->handles.main, 428 FMRI_BASE "/:properties/" CONFIG_PG, 429 NULL, /* scope */ 430 cfg->handles.service, /* service */ 431 cfg->handles.instance, /* instance */ 432 cfg->handles.config_pg, /* pg */ 433 NULL, /* prop */ 434 SCF_DECODE_FMRI_EXACT)) { 435 idmapdlog(LOG_ERR, "%s: scf_handle_decode_fmri() failed: %s", 436 me, scf_strerror(scf_error())); 437 goto error; 438 439 } 440 441 if (0 > scf_service_get_pg(cfg->handles.service, 442 GENERAL_PG, cfg->handles.general_pg)) { 443 idmapdlog(LOG_ERR, "%s: scf_service_get_pg() failed: %s", 444 me, scf_strerror(scf_error())); 445 goto error; 446 } 447 448 return (cfg); 449 450 error: 451 (void) idmap_cfg_fini(cfg); 452 return (NULL); 453 } 454 455 /* ARGSUSED */ 456 static void 457 idmap_pgcfg_fini(idmap_pg_config_t *pgcfg) { 458 if (pgcfg->mapping_domain) 459 free(pgcfg->mapping_domain); 460 if (pgcfg->machine_sid) 461 free(pgcfg->mapping_domain); 462 if (pgcfg->global_catalog) 463 free(pgcfg->global_catalog); 464 if (pgcfg->domain_controller) 465 free(pgcfg->domain_controller); 466 } 467 468 int 469 idmap_cfg_fini(idmap_cfg_t *cfg) 470 { 471 idmap_pgcfg_fini(&cfg->pgcfg); 472 473 scf_pg_destroy(cfg->handles.config_pg); 474 scf_pg_destroy(cfg->handles.general_pg); 475 scf_instance_destroy(cfg->handles.instance); 476 scf_service_destroy(cfg->handles.service); 477 scf_handle_destroy(cfg->handles.main); 478 free(cfg); 479 480 return (0); 481 } 482