17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7b209c2cSacruz * Common Development and Distribution License (the "License"). 6*7b209c2cSacruz * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*7b209c2cSacruz * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <assert.h> 297c478bd9Sstevel@tonic-gate #include <errno.h> 307c478bd9Sstevel@tonic-gate #include <libintl.h> 317c478bd9Sstevel@tonic-gate #include <sys/wait.h> 327c478bd9Sstevel@tonic-gate #include <sys/ctfs.h> 337c478bd9Sstevel@tonic-gate #include <sys/contract/process.h> 347c478bd9Sstevel@tonic-gate #include <libcontract.h> 357c478bd9Sstevel@tonic-gate #include <libcontract_priv.h> 367c478bd9Sstevel@tonic-gate #include <stdlib.h> 377c478bd9Sstevel@tonic-gate #include <string.h> 387c478bd9Sstevel@tonic-gate #include <unistd.h> 397c478bd9Sstevel@tonic-gate #include "inetd_impl.h" 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate /* paths/filenames of contract related files */ 437c478bd9Sstevel@tonic-gate #define CONTRACT_ROOT_PATH CTFS_ROOT "/process/" 447c478bd9Sstevel@tonic-gate #define CONTRACT_TEMPLATE_PATH CONTRACT_ROOT_PATH "template" 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate static int active_tmpl_fd = -1; 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate /* 497c478bd9Sstevel@tonic-gate * Creates and configures the the contract template used for all inetd's 507c478bd9Sstevel@tonic-gate * methods. 517c478bd9Sstevel@tonic-gate * Returns -1 on error, else the fd of the created template. 527c478bd9Sstevel@tonic-gate */ 537c478bd9Sstevel@tonic-gate static int 547c478bd9Sstevel@tonic-gate create_contract_template(void) 557c478bd9Sstevel@tonic-gate { 567c478bd9Sstevel@tonic-gate int fd; 577c478bd9Sstevel@tonic-gate int err; 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate if ((fd = open(CONTRACT_TEMPLATE_PATH, O_RDWR)) == -1) { 607c478bd9Sstevel@tonic-gate error_msg(gettext("Failed to open contract file %s: %s"), 617c478bd9Sstevel@tonic-gate CONTRACT_TEMPLATE_PATH, strerror(errno)); 627c478bd9Sstevel@tonic-gate return (-1); 637c478bd9Sstevel@tonic-gate } 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate /* 667c478bd9Sstevel@tonic-gate * Make contract inheritable and make hardware errors fatal. 677c478bd9Sstevel@tonic-gate * We also limit the scope of fatal events to the process 687c478bd9Sstevel@tonic-gate * group. In order of preference we would have contract-aware 697c478bd9Sstevel@tonic-gate * login services or a property indicating which services need 707c478bd9Sstevel@tonic-gate * such scoping, but for the time being we'll assume that most 717c478bd9Sstevel@tonic-gate * non login-style services run in a single process group. 727c478bd9Sstevel@tonic-gate */ 737c478bd9Sstevel@tonic-gate if (((err = ct_pr_tmpl_set_param(fd, 747c478bd9Sstevel@tonic-gate CT_PR_INHERIT|CT_PR_PGRPONLY)) != 0) || 757c478bd9Sstevel@tonic-gate ((err = ct_pr_tmpl_set_fatal(fd, CT_PR_EV_HWERR)) != 0) || 767c478bd9Sstevel@tonic-gate ((err = ct_tmpl_set_critical(fd, 0)) != 0) || 777c478bd9Sstevel@tonic-gate ((err = ct_tmpl_set_informative(fd, 0)) != 0)) { 787c478bd9Sstevel@tonic-gate error_msg(gettext( 797c478bd9Sstevel@tonic-gate "Failed to set parameter for contract template: %s"), 807c478bd9Sstevel@tonic-gate strerror(err)); 817c478bd9Sstevel@tonic-gate (void) close(fd); 827c478bd9Sstevel@tonic-gate return (-1); 837c478bd9Sstevel@tonic-gate } 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate return (fd); 867c478bd9Sstevel@tonic-gate } 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate /* Returns -1 on error, else 0. */ 897c478bd9Sstevel@tonic-gate int 907c478bd9Sstevel@tonic-gate contract_init(void) 917c478bd9Sstevel@tonic-gate { 927c478bd9Sstevel@tonic-gate if ((active_tmpl_fd = create_contract_template()) == -1) { 937c478bd9Sstevel@tonic-gate error_msg(gettext("Failed to create contract template")); 947c478bd9Sstevel@tonic-gate return (-1); 957c478bd9Sstevel@tonic-gate } 967c478bd9Sstevel@tonic-gate return (0); 977c478bd9Sstevel@tonic-gate } 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate void 1007c478bd9Sstevel@tonic-gate contract_fini(void) 1017c478bd9Sstevel@tonic-gate { 1027c478bd9Sstevel@tonic-gate if (active_tmpl_fd != -1) { 1037c478bd9Sstevel@tonic-gate (void) close(active_tmpl_fd); 1047c478bd9Sstevel@tonic-gate active_tmpl_fd = -1; 1057c478bd9Sstevel@tonic-gate } 1067c478bd9Sstevel@tonic-gate } 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate /* 1097c478bd9Sstevel@tonic-gate * To be called directly before a service method is forked, this function 1107c478bd9Sstevel@tonic-gate * results in the method process being in a new contract based on the active 1117c478bd9Sstevel@tonic-gate * contract template. 1127c478bd9Sstevel@tonic-gate */ 1137c478bd9Sstevel@tonic-gate int 114*7b209c2cSacruz contract_prefork(const char *fmri, int method) 1157c478bd9Sstevel@tonic-gate { 1167c478bd9Sstevel@tonic-gate int err; 1177c478bd9Sstevel@tonic-gate 118*7b209c2cSacruz if ((err = ct_pr_tmpl_set_svc_fmri(active_tmpl_fd, fmri)) != 0) { 119*7b209c2cSacruz error_msg(gettext("Failed to set svc_fmri term: %s"), 120*7b209c2cSacruz strerror(err)); 121*7b209c2cSacruz return (-1); 122*7b209c2cSacruz } 123*7b209c2cSacruz if ((err = ct_pr_tmpl_set_svc_aux(active_tmpl_fd, 124*7b209c2cSacruz methods[method].name)) != 0) { 125*7b209c2cSacruz error_msg(gettext("Failed to set svc_aux term: %s"), 126*7b209c2cSacruz strerror(err)); 127*7b209c2cSacruz return (-1); 128*7b209c2cSacruz } 129*7b209c2cSacruz 1307c478bd9Sstevel@tonic-gate if ((err = ct_tmpl_activate(active_tmpl_fd)) != 0) { 1317c478bd9Sstevel@tonic-gate error_msg(gettext("Failed to activate contract template: %s"), 1327c478bd9Sstevel@tonic-gate strerror(err)); 1337c478bd9Sstevel@tonic-gate return (-1); 1347c478bd9Sstevel@tonic-gate } 1357c478bd9Sstevel@tonic-gate return (0); 1367c478bd9Sstevel@tonic-gate } 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate /* 1397c478bd9Sstevel@tonic-gate * To be called in both processes directly after a service method is forked, 1407c478bd9Sstevel@tonic-gate * this function results in switching off contract creation for any 1417c478bd9Sstevel@tonic-gate * forks done by either process, unless contract_prefork() is called beforehand. 1427c478bd9Sstevel@tonic-gate */ 1437c478bd9Sstevel@tonic-gate void 1447c478bd9Sstevel@tonic-gate contract_postfork(void) 1457c478bd9Sstevel@tonic-gate { 1467c478bd9Sstevel@tonic-gate int err; 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate if ((err = ct_tmpl_clear(active_tmpl_fd)) != 0) 1497c478bd9Sstevel@tonic-gate error_msg("Failed to clear active contract template: %s", 1507c478bd9Sstevel@tonic-gate strerror(err)); 1517c478bd9Sstevel@tonic-gate } 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate /* 1547c478bd9Sstevel@tonic-gate * Fetch the latest created contract id into the space referenced by 'cid'. 1557c478bd9Sstevel@tonic-gate * Returns -1 on error, else 0. 1567c478bd9Sstevel@tonic-gate */ 1577c478bd9Sstevel@tonic-gate int 1587c478bd9Sstevel@tonic-gate get_latest_contract(ctid_t *cid) 1597c478bd9Sstevel@tonic-gate { 1607c478bd9Sstevel@tonic-gate if ((errno = contract_latest(cid)) != 0) { 1617c478bd9Sstevel@tonic-gate error_msg(gettext("Failed to get new contract's id: %s"), 1627c478bd9Sstevel@tonic-gate strerror(errno)); 1637c478bd9Sstevel@tonic-gate return (-1); 1647c478bd9Sstevel@tonic-gate } 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate return (0); 1677c478bd9Sstevel@tonic-gate } 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate /* Returns -1 on error (with errno set), else fd. */ 1707c478bd9Sstevel@tonic-gate static int 1717c478bd9Sstevel@tonic-gate open_contract_ctl_file(ctid_t cid) 1727c478bd9Sstevel@tonic-gate { 1737c478bd9Sstevel@tonic-gate return (contract_open(cid, "process", "ctl", O_WRONLY)); 1747c478bd9Sstevel@tonic-gate } 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate /* 1777c478bd9Sstevel@tonic-gate * Adopt a contract. Emits an error message and returns -1 on failure, else 1787c478bd9Sstevel@tonic-gate * 0. 1797c478bd9Sstevel@tonic-gate */ 1807c478bd9Sstevel@tonic-gate int 1817c478bd9Sstevel@tonic-gate adopt_contract(ctid_t ctid, const char *fmri) 1827c478bd9Sstevel@tonic-gate { 1837c478bd9Sstevel@tonic-gate int fd; 1847c478bd9Sstevel@tonic-gate int err; 1857c478bd9Sstevel@tonic-gate int ret = 0; 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate if ((fd = open_contract_ctl_file(ctid)) == -1) { 1887c478bd9Sstevel@tonic-gate if (errno == EACCES || errno == ENOENT) { 1897c478bd9Sstevel@tonic-gate /* 1907c478bd9Sstevel@tonic-gate * We must not have inherited this contract. That can 1917c478bd9Sstevel@tonic-gate * happen if we were disabled and restarted. 1927c478bd9Sstevel@tonic-gate */ 1937c478bd9Sstevel@tonic-gate debug_msg("Could not adopt contract %ld for %s " 1947c478bd9Sstevel@tonic-gate "(could not open ctl file: permission denied).\n", 1957c478bd9Sstevel@tonic-gate ctid, fmri); 1967c478bd9Sstevel@tonic-gate return (-1); 1977c478bd9Sstevel@tonic-gate } 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate error_msg(gettext("Could not adopt contract id %ld registered " 2007c478bd9Sstevel@tonic-gate "with %s (could not open ctl file: %s). Events will be " 2017c478bd9Sstevel@tonic-gate "ignored."), ctid, fmri, strerror(errno)); 2027c478bd9Sstevel@tonic-gate return (-1); 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate if ((err = ct_ctl_adopt(fd)) != 0) { 2067c478bd9Sstevel@tonic-gate error_msg(gettext("Could not adopt contract id %ld registered " 2077c478bd9Sstevel@tonic-gate "with %s (%s). Events will be ignored."), ctid, fmri, 2087c478bd9Sstevel@tonic-gate strerror(err)); 2097c478bd9Sstevel@tonic-gate ret = -1; 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate err = close(fd); 2137c478bd9Sstevel@tonic-gate if (err != 0) 2147c478bd9Sstevel@tonic-gate error_msg(gettext("Could not close file descriptor %d."), fd); 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate return (ret); 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate /* Returns -1 on error, else 0. */ 2207c478bd9Sstevel@tonic-gate int 2217c478bd9Sstevel@tonic-gate abandon_contract(ctid_t ctid) 2227c478bd9Sstevel@tonic-gate { 2237c478bd9Sstevel@tonic-gate int fd; 2247c478bd9Sstevel@tonic-gate int err; 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate assert(ctid != -1); 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate if ((fd = open_contract_ctl_file(ctid)) == -1) { 2297c478bd9Sstevel@tonic-gate error_msg(gettext("Failed to abandon contract %d: %s"), ctid, 2307c478bd9Sstevel@tonic-gate strerror(errno)); 2317c478bd9Sstevel@tonic-gate return (-1); 2327c478bd9Sstevel@tonic-gate } 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate if ((err = ct_ctl_abandon(fd)) != 0) { 2357c478bd9Sstevel@tonic-gate (void) close(fd); 2367c478bd9Sstevel@tonic-gate error_msg(gettext("Failed to abandon contract %d: %s"), ctid, 2377c478bd9Sstevel@tonic-gate strerror(err)); 2387c478bd9Sstevel@tonic-gate return (-1); 2397c478bd9Sstevel@tonic-gate } 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate (void) close(fd); 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate return (0); 2447c478bd9Sstevel@tonic-gate } 245