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 /* 23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include <libscf.h> 27 #include <netinet/in.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <strings.h> 31 #include <sys/types.h> 32 #include "ksslcfg.h" 33 34 void 35 usage_create(boolean_t do_print) 36 { 37 if (do_print) 38 (void) fprintf(stderr, gettext("Usage:\n")); 39 (void) fprintf(stderr, "ksslcfg create" 40 " -f pkcs11 [-d softtoken_directory] -T <token_label>" 41 " -C <certificate_label> -x <proxy_port>" 42 " [-h <ca_certchain_file>]" 43 " [options] [<server_address>] <server_port>\n"); 44 45 (void) fprintf(stderr, "ksslcfg create" 46 " -f pkcs12 -i <cert_and_key_pk12file> -x <proxy_port>" 47 " [options] [<server_address>] <server_port>\n"); 48 49 (void) fprintf(stderr, "ksslcfg create" 50 " -f pem -i <cert_and_key_pemfile> -x <proxy_port>" 51 " [options] [<server_address>] <server_port>\n"); 52 53 (void) fprintf(stderr, gettext("options are:\n")); 54 (void) fprintf(stderr, "\t[-c <ciphersuites>]\n" 55 "\t[-p <password_file>]\n" 56 "\t[-t <ssl_session_cache_timeout>]\n" 57 "\t[-u <username>]\n" 58 "\t[-z <ssl_session_cache_size>]\n" 59 "\t[-v]\n"); 60 } 61 62 static scf_propertygroup_t * 63 add_property_group_to_instance(scf_handle_t *handle, scf_instance_t *instance, 64 const char *pg_name, const char *pg_type) 65 { 66 scf_propertygroup_t *pg; 67 68 pg = scf_pg_create(handle); 69 if (pg == NULL) { 70 KSSL_DEBUG("scf_pg_create failed: %s\n", 71 scf_strerror(scf_error())); 72 (void) fprintf(stderr, gettext( 73 "Unexpected fatal libscf error: %s. Exiting.\n"), 74 scf_strerror(scf_error())); 75 return (NULL); 76 } 77 78 if (scf_instance_add_pg(instance, pg_name, pg_type, 0, pg) != 0) { 79 KSSL_DEBUG("ERROR: scf_instance_add_pg failed: %s\n", 80 scf_strerror(scf_error())); 81 if (scf_error() == SCF_ERROR_EXISTS) 82 (void) fprintf(stderr, gettext( 83 "Error: another process is modifying this instance." 84 " Exiting.\n")); 85 else 86 (void) fprintf(stderr, gettext( 87 "Unexpected fatal libscf error: %s. Exiting.\n"), 88 scf_strerror(scf_error())); 89 scf_pg_destroy(pg); 90 return (NULL); 91 } else { 92 KSSL_DEBUG("property group created\n"); 93 } 94 95 return (pg); 96 } 97 98 static int 99 add_new_property(scf_handle_t *handle, const char *prop_name, 100 scf_type_t type, const char *val, scf_transaction_t *tx) 101 { 102 scf_value_t *value = NULL; 103 scf_transaction_entry_t *entry = NULL; 104 int status = FAILURE; 105 106 entry = scf_entry_create(handle); 107 if (entry == NULL) { 108 KSSL_DEBUG("scf_entry_create failed: %s\n", 109 scf_strerror(scf_error())); 110 goto out; 111 } 112 KSSL_DEBUG("scf_entry_create succeeded\n"); 113 114 value = scf_value_create(handle); 115 if (value == NULL) { 116 goto out; 117 } 118 KSSL_DEBUG("scf_value_create succeeded\n"); 119 120 if (scf_transaction_property_new(tx, entry, prop_name, type) != 0) { 121 goto out; 122 } 123 KSSL_DEBUG("scf_transaction_property_new succeeded\n"); 124 125 if (scf_value_set_from_string(value, type, val) != 0) { 126 goto out; 127 } 128 KSSL_DEBUG("scf_value_set_from_string \'%s\' succeeded\n", val); 129 130 if (scf_entry_add_value(entry, value) != 0) { 131 KSSL_DEBUG( 132 "scf_entry_add_value failed: %s\n", 133 scf_strerror(scf_error())); 134 goto out; 135 } 136 KSSL_DEBUG("scf_entry_add_value succeeded\n"); 137 138 status = SUCCESS; 139 140 out: 141 if (status != SUCCESS) 142 (void) fprintf(stderr, gettext( 143 "Unexpected fatal libscf error: %s. Exiting.\n"), 144 scf_strerror(scf_error())); 145 return (status); 146 } 147 148 static int 149 set_method_context(scf_handle_t *handle, scf_transaction_t *tran, 150 const char *value_str) 151 { 152 if ((add_new_property(handle, SCF_PROPERTY_USE_PROFILE, 153 SCF_TYPE_BOOLEAN, "false", tran) != SUCCESS) || 154 (add_new_property(handle, SCF_PROPERTY_USER, SCF_TYPE_ASTRING, 155 value_str, tran) != SUCCESS) || 156 (add_new_property(handle, SCF_PROPERTY_GROUP, SCF_TYPE_ASTRING, 157 ":default", tran) != SUCCESS) || 158 (add_new_property(handle, SCF_PROPERTY_LIMIT_PRIVILEGES, 159 SCF_TYPE_ASTRING, ":default", tran) != SUCCESS) || 160 (add_new_property(handle, SCF_PROPERTY_WORKING_DIRECTORY, 161 SCF_TYPE_ASTRING, ":default", tran) != SUCCESS) || 162 (add_new_property(handle, SCF_PROPERTY_SUPP_GROUPS, 163 SCF_TYPE_ASTRING, ":default", tran) != SUCCESS) || 164 (add_new_property(handle, SCF_PROPERTY_RESOURCE_POOL, 165 SCF_TYPE_ASTRING, ":default", tran) != SUCCESS) || 166 (add_new_property(handle, SCF_PROPERTY_PROJECT, SCF_TYPE_ASTRING, 167 ":default", tran) != SUCCESS) || 168 (add_new_property(handle, SCF_PROPERTY_PRIVILEGES, 169 SCF_TYPE_ASTRING, "basic,sys_net_config", tran) != SUCCESS)) 170 return (FAILURE); 171 172 return (SUCCESS); 173 } 174 175 static int 176 add_pg_method(scf_handle_t *handle, scf_instance_t *instance, 177 const char *kssl_entry, const char *pg_name, const char *flags, 178 const char *value_str) 179 { 180 int len, rv; 181 char *command; 182 const char *base_command; 183 int status = FAILURE; 184 boolean_t errflag = B_FALSE; 185 scf_transaction_t *tran; 186 scf_propertygroup_t *pg; 187 188 pg = add_property_group_to_instance(handle, instance, 189 pg_name, SCF_GROUP_METHOD); 190 if (pg == NULL) { 191 /* flag is false to suppress duplicate error messages */ 192 errflag = B_FALSE; 193 goto out0; 194 } 195 KSSL_DEBUG("%s method added\n", pg_name); 196 197 tran = scf_transaction_create(handle); 198 if (tran == NULL) { 199 KSSL_DEBUG("scf_transaction_create failed: %s\n", 200 scf_strerror(scf_error())); 201 errflag = B_TRUE; 202 goto out0; 203 } 204 KSSL_DEBUG("scf_transaction_create succeeded\n"); 205 206 do { 207 if (scf_transaction_start(tran, pg) != 0) { 208 KSSL_DEBUG("scf_transaction_start failed: %s\n", 209 scf_strerror(scf_error())); 210 if (scf_error() == SCF_ERROR_PERMISSION_DENIED) { 211 (void) fprintf(stderr, gettext( 212 "Error: Permission denied.\n")); 213 errflag = B_FALSE; 214 } else if (scf_error() == SCF_ERROR_DELETED) { 215 (void) fprintf(stderr, gettext( 216 "Error: property group %s has" 217 " been deleted.\n"), pg_name); 218 errflag = B_FALSE; 219 } else 220 errflag = B_TRUE; 221 goto out1; 222 } 223 KSSL_DEBUG("scf_transaction_start succeeded\n"); 224 225 if (strcmp(pg_name, "stop") == 0) 226 base_command = "/usr/lib/kssladm delete"; 227 else 228 base_command = "/usr/lib/kssladm create"; 229 230 len = strlen(base_command) + strlen(flags) + 231 strlen(kssl_entry) + 3; 232 233 command = malloc(len); 234 if (command == NULL) { 235 goto out2; 236 } 237 238 (void) snprintf(command, len, "%s %s %s", 239 base_command, flags, kssl_entry); 240 KSSL_DEBUG("command=%s\n", command); 241 242 if (add_new_property(handle, SCF_PROPERTY_EXEC, 243 SCF_TYPE_ASTRING, command, tran) != SUCCESS) { 244 free(command); 245 goto out2; 246 } 247 free(command); 248 249 if (add_new_property(handle, SCF_PROPERTY_TIMEOUT, 250 SCF_TYPE_COUNT, "60", tran) != SUCCESS) 251 goto out2; 252 253 if (set_method_context(handle, tran, value_str) != SUCCESS) 254 goto out2; 255 256 rv = scf_transaction_commit(tran); 257 switch (rv) { 258 case 1: 259 KSSL_DEBUG("scf_transaction_commit succeeded\n"); 260 status = SUCCESS; 261 goto out2; 262 case 0: 263 scf_transaction_reset(tran); 264 if (scf_pg_update(pg) == -1) { 265 goto out2; 266 } 267 break; 268 case -1: 269 default: 270 KSSL_DEBUG("ERROR: scf_transaction_commit failed: %s\n", 271 scf_strerror(scf_error())); 272 if (scf_error() == SCF_ERROR_PERMISSION_DENIED) { 273 (void) fprintf(stderr, gettext( 274 "Error: Permission denied.\n")); 275 errflag = B_FALSE; 276 } else { 277 errflag = B_TRUE; 278 } 279 goto out2; 280 } 281 } while (rv == 0); 282 283 out2: 284 scf_transaction_reset(tran); 285 out1: 286 scf_transaction_destroy_children(tran); 287 scf_transaction_destroy(tran); 288 out0: 289 if (pg != NULL) 290 scf_pg_destroy(pg); 291 if (errflag) 292 (void) fprintf(stderr, gettext( 293 "Unexpected fatal libscf error: %s. Exiting.\n"), 294 scf_strerror(scf_error())); 295 return (status); 296 } 297 298 static int 299 create_instance(scf_handle_t *handle, scf_service_t *svc, 300 const char *instance_name, const char *kssl_entry, const char *command, 301 const char *username, char *inaddr_any_name) 302 { 303 int status = FAILURE; 304 char *buf; 305 boolean_t errflag = B_FALSE; 306 ssize_t max_fmri_len; 307 scf_instance_t *instance; 308 309 instance = scf_instance_create(handle); 310 if (instance == NULL) { 311 errflag = B_TRUE; 312 KSSL_DEBUG("scf_instance_create failed: %s\n", 313 scf_strerror(scf_error())); 314 goto out; 315 } 316 KSSL_DEBUG("scf_instance_create succeeded\n"); 317 318 if (scf_service_get_instance(svc, inaddr_any_name, instance) == 0) { 319 /* Let the caller deal with the duplicate instance */ 320 status = INSTANCE_ANY_EXISTS; 321 goto out; 322 } 323 324 if (scf_service_add_instance(svc, instance_name, instance) != 0) { 325 if (scf_error() == SCF_ERROR_EXISTS) { 326 /* Let the caller deal with the duplicate instance */ 327 status = INSTANCE_OTHER_EXISTS; 328 goto out; 329 } 330 331 errflag = B_TRUE; 332 KSSL_DEBUG("scf_service_add_instance failed: %s\n", 333 scf_strerror(scf_error())); 334 goto out; 335 } 336 KSSL_DEBUG("scf_service_add_instance succeeded\n"); 337 338 if ((add_pg_method(handle, instance, kssl_entry, "start", 339 command, username) != SUCCESS) || 340 (add_pg_method(handle, instance, kssl_entry, "refresh", 341 command, username) != SUCCESS) || 342 (add_pg_method(handle, instance, kssl_entry, "stop", 343 "", username) != SUCCESS)) { 344 scf_instance_destroy(instance); 345 return (status); 346 } 347 348 /* enabling the instance */ 349 max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH); 350 if ((buf = malloc(max_fmri_len + 1)) == NULL) 351 goto out; 352 353 if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) { 354 KSSL_DEBUG("instance_fmri=%s\n", buf); 355 if (smf_enable_instance(buf, 0) != 0) { 356 errflag = B_TRUE; 357 KSSL_DEBUG( 358 "smf_enable_instance failed: %s\n", 359 scf_strerror(scf_error())); 360 goto out; 361 } 362 status = SUCCESS; 363 } 364 365 out: 366 if (instance != NULL) 367 scf_instance_destroy(instance); 368 if (errflag) 369 (void) fprintf(stderr, gettext( 370 "Unexpected fatal libscf error: %s. Exiting.\n"), 371 scf_strerror(scf_error())); 372 return (status); 373 } 374 375 static int 376 create_service(const char *instance_name, const char *kssl_entry, 377 const char *command, const char *username, char *inaddr_any_name) 378 { 379 int status = FAILURE; 380 scf_scope_t *scope; 381 scf_service_t *svc; 382 scf_handle_t *handle; 383 boolean_t errflag = B_TRUE; 384 385 handle = scf_handle_create(SCF_VERSION); 386 if (handle == NULL) { 387 KSSL_DEBUG("scf_handle_create failed: %s\n", 388 scf_strerror(scf_error())); 389 goto out1; 390 } 391 KSSL_DEBUG("scf_handle_create succeeded\n"); 392 393 if (scf_handle_bind(handle) == -1) { 394 KSSL_DEBUG("scf_handle_bind failed: %s\n", 395 scf_strerror(scf_error())); 396 goto out1; 397 } 398 KSSL_DEBUG("scf_handle_bind succeeded\n"); 399 400 if ((scope = scf_scope_create(handle)) == NULL) { 401 KSSL_DEBUG("scf_scope_create failed: %s\n", 402 scf_strerror(scf_error())); 403 goto out2; 404 } 405 KSSL_DEBUG("scf_scope_create succeeded\n"); 406 407 if ((svc = scf_service_create(handle)) == NULL) { 408 KSSL_DEBUG("scf_service_create failed: %s\n", 409 scf_strerror(scf_error())); 410 goto out3; 411 } 412 KSSL_DEBUG("scf_service_create succeeded\n"); 413 414 if (scf_handle_decode_fmri(handle, SERVICE_NAME, NULL, svc, 415 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) { 416 KSSL_DEBUG("scf_handle_decode_fmri failed: %s\n", 417 scf_strerror(scf_error())); 418 if (scf_error() == SCF_ERROR_NOT_FOUND) { 419 (void) fprintf(stderr, gettext( 420 "service %s not found in the repository." 421 " Exiting.\n"), SERVICE_NAME); 422 errflag = B_FALSE; 423 } 424 goto out4; 425 } 426 427 status = create_instance(handle, svc, instance_name, kssl_entry, 428 command, username, inaddr_any_name); 429 430 out4: 431 scf_service_destroy(svc); 432 out3: 433 scf_scope_destroy(scope); 434 out2: 435 (void) scf_handle_unbind(handle); 436 out1: 437 if (handle != NULL) 438 scf_handle_destroy(handle); 439 440 if (status != SUCCESS && status != INSTANCE_OTHER_EXISTS && 441 status != INSTANCE_ANY_EXISTS && errflag) 442 (void) fprintf(stderr, gettext( 443 "Unexpected fatal libscf error: %s. Exiting.\n"), 444 scf_strerror(scf_error())); 445 return (status); 446 } 447 448 int 449 do_create(int argc, char *argv[]) 450 { 451 char c; 452 char *buf, *ptr, *instance_name; 453 char *inaddr_any_name = NULL; 454 int i, status, len, pcnt; 455 const char *token_label = NULL; 456 const char *filename = NULL; 457 const char *certname = NULL; 458 const char *username = NULL; 459 const char *proxy_port = NULL; 460 char *format = NULL; 461 boolean_t quote_next; 462 char address_port[MAX_ADRPORT_LEN + 1]; 463 464 argc -= 1; 465 argv += 1; 466 467 /* 468 * Many of these arguments are passed on to kssladm command 469 * in the start method of the SMF instance created. So, we do only 470 * the basic usage checks here and let kssladm check the validity 471 * of the arguments. This is the reason we ignore optarg 472 * for some of the cases below. 473 */ 474 while ((c = getopt(argc, argv, "vT:d:f:h:i:p:c:C:t:u:x:z:")) != -1) { 475 switch (c) { 476 case 'd': 477 break; 478 case 'c': 479 break; 480 case 'C': 481 certname = optarg; 482 break; 483 case 'f': 484 format = optarg; 485 break; 486 case 'h': 487 break; 488 case 'i': 489 filename = optarg; 490 break; 491 case 'T': 492 token_label = optarg; 493 break; 494 case 'p': 495 break; 496 case 't': 497 break; 498 case 'u': 499 username = optarg; 500 break; 501 case 'x': 502 proxy_port = optarg; 503 break; 504 case 'v': 505 verbose = B_TRUE; 506 break; 507 case 'z': 508 break; 509 default: 510 goto err; 511 } 512 } 513 514 if (format == NULL || proxy_port == NULL) { 515 goto err; 516 } 517 518 if (get_portnum(proxy_port, NULL) == 0) { 519 (void) fprintf(stderr, 520 gettext("Error: Invalid proxy port value %s\n"), 521 proxy_port); 522 goto err; 523 } 524 525 if (strcmp(format, "pkcs11") == 0) { 526 if (token_label == NULL || certname == NULL) { 527 goto err; 528 } 529 } else if (strcmp(format, "pkcs12") == 0 || 530 strcmp(format, "pem") == 0) { 531 if (filename == NULL) { 532 goto err; 533 } 534 } else { 535 goto err; 536 } 537 538 pcnt = argc - optind; 539 if (pcnt == 1) { 540 if (strlen(argv[optind]) < MAX_ADRPORT_LEN) { 541 (void) strcpy(address_port, argv[optind]); 542 } else { 543 (void) fprintf(stderr, gettext( 544 "argument too long -- %s\n"), 545 argv[optind]); 546 return (FAILURE); 547 } 548 } else if (pcnt == 2) { 549 if ((len = strlen(argv[optind])) + 550 (strlen(argv[optind + 1])) < MAX_ADRPORT_LEN) { 551 (void) strcpy(address_port, argv[optind]); 552 address_port[len] = ' '; 553 (void) strcpy(address_port + len + 1, argv[optind + 1]); 554 } else { 555 (void) fprintf(stderr, gettext( 556 "arguments too long -- %s %s\n"), 557 argv[optind], argv[optind + 1]); 558 return (FAILURE); 559 } 560 } else { 561 goto err; 562 } 563 564 /* 565 * We need to create the kssladm command line in 566 * the SMF instance from the current arguments. 567 * 568 * Construct a buffer with all the arguments except 569 * the -u argument. We have to quote the string arguments, 570 * -T and -C, as they can contain white space. 571 */ 572 len = 0; 573 for (i = 1; i < optind; i++) { 574 len += strlen(argv[i]) + 3; 575 } 576 577 if ((buf = malloc(len)) == NULL) { 578 return (FAILURE); 579 } 580 581 ptr = buf; 582 quote_next = B_FALSE; 583 for (i = 1; i < optind; i++) { 584 int arglen = strlen(argv[i]) + 1; 585 586 if (strncmp(argv[i], "-u", 2) == 0) { 587 i++; 588 continue; 589 } 590 591 if (quote_next) { 592 (void) snprintf(ptr, len, "\"%s\" ", argv[i]); 593 quote_next = B_FALSE; 594 arglen += 2; 595 } else { 596 (void) snprintf(ptr, len, "%s ", argv[i]); 597 } 598 599 quote_next = (strncmp(argv[i], "-T", 2) == 0 || 600 strncmp(argv[i], "-C", 2) == 0); 601 602 ptr += arglen; 603 len -= arglen; 604 } 605 KSSL_DEBUG("buf=%s\n", buf); 606 607 instance_name = create_instance_name(address_port, 608 &inaddr_any_name, B_TRUE); 609 if (instance_name == NULL || inaddr_any_name == NULL) { 610 free(buf); 611 return (FAILURE); 612 } 613 KSSL_DEBUG("instance_name=%s\n", instance_name); 614 KSSL_DEBUG("inaddr_any_name=%s\n", inaddr_any_name); 615 616 if (username == NULL) 617 username = "root"; 618 status = create_service(instance_name, address_port, 619 buf, username, inaddr_any_name); 620 if (status == INSTANCE_OTHER_EXISTS || status == INSTANCE_ANY_EXISTS) { 621 if (status == INSTANCE_ANY_EXISTS && 622 (strcmp(instance_name, inaddr_any_name) != SUCCESS)) { 623 /* 624 * The following could result in a misconfiguration. 625 * Better bail out with an error. 626 */ 627 (void) fprintf(stderr, 628 gettext("Error: INADDR_ANY instance exists." 629 " Can not create a new instance %s.\n"), 630 instance_name); 631 free(instance_name); 632 free(inaddr_any_name); 633 free(buf); 634 return (status); 635 } 636 637 /* 638 * Delete the existing instance and create a new instance 639 * with the supplied arguments. 640 */ 641 KSSL_DEBUG("Deleting duplicate instance\n"); 642 if (delete_instance(instance_name) != SUCCESS) { 643 (void) fprintf(stderr, 644 gettext( 645 "Error: Can not delete existing instance %s.\n"), 646 instance_name); 647 } else { 648 (void) fprintf(stdout, gettext( 649 "Note: reconfiguring the existing instance %s.\n"), 650 instance_name); 651 status = create_service(instance_name, address_port, 652 buf, username, inaddr_any_name); 653 } 654 } 655 656 /* 657 * network/ssl/proxy depends on network/socket-filter:kssl; 658 * enable that service now. 659 */ 660 if (smf_enable_instance(KSSL_FILTER_SVC_NAME, 0) != 0) { 661 KSSL_DEBUG( 662 "smf_enable_instance failed: %s\n" KSSL_FILTER_SVC_NAME); 663 (void) fprintf(stderr, gettext( 664 "Unable to enable required service \"%s\". Error: %s"), 665 KSSL_FILTER_SVC_NAME, scf_strerror(scf_error())); 666 status = FAILURE; 667 } 668 669 free(instance_name); 670 free(inaddr_any_name); 671 free(buf); 672 return (status); 673 674 err: 675 usage_create(B_TRUE); 676 return (ERROR_USAGE); 677 } 678