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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <assert.h> 30 #include <errno.h> 31 #include <libintl.h> 32 #include <sys/wait.h> 33 #include <sys/ctfs.h> 34 #include <sys/contract/process.h> 35 #include <libcontract.h> 36 #include <libcontract_priv.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <unistd.h> 40 #include "inetd_impl.h" 41 42 43 /* paths/filenames of contract related files */ 44 #define CONTRACT_ROOT_PATH CTFS_ROOT "/process/" 45 #define CONTRACT_TEMPLATE_PATH CONTRACT_ROOT_PATH "template" 46 47 static int active_tmpl_fd = -1; 48 49 /* 50 * Creates and configures the the contract template used for all inetd's 51 * methods. 52 * Returns -1 on error, else the fd of the created template. 53 */ 54 static int 55 create_contract_template(void) 56 { 57 int fd; 58 int err; 59 60 debug_msg("Entering create_contract_template"); 61 62 if ((fd = open(CONTRACT_TEMPLATE_PATH, O_RDWR)) == -1) { 63 error_msg(gettext("Failed to open contract file %s: %s"), 64 CONTRACT_TEMPLATE_PATH, strerror(errno)); 65 return (-1); 66 } 67 68 /* 69 * Make contract inheritable and make hardware errors fatal. 70 * We also limit the scope of fatal events to the process 71 * group. In order of preference we would have contract-aware 72 * login services or a property indicating which services need 73 * such scoping, but for the time being we'll assume that most 74 * non login-style services run in a single process group. 75 */ 76 if (((err = ct_pr_tmpl_set_param(fd, 77 CT_PR_INHERIT|CT_PR_PGRPONLY)) != 0) || 78 ((err = ct_pr_tmpl_set_fatal(fd, CT_PR_EV_HWERR)) != 0) || 79 ((err = ct_tmpl_set_critical(fd, 0)) != 0) || 80 ((err = ct_tmpl_set_informative(fd, 0)) != 0)) { 81 error_msg(gettext( 82 "Failed to set parameter for contract template: %s"), 83 strerror(err)); 84 (void) close(fd); 85 return (-1); 86 } 87 88 return (fd); 89 } 90 91 /* Returns -1 on error, else 0. */ 92 int 93 contract_init(void) 94 { 95 debug_msg("Entering contract_init"); 96 97 if ((active_tmpl_fd = create_contract_template()) == -1) { 98 error_msg(gettext("Failed to create contract template")); 99 return (-1); 100 } 101 return (0); 102 } 103 104 void 105 contract_fini(void) 106 { 107 debug_msg("Entering contract_fini"); 108 109 if (active_tmpl_fd != -1) { 110 (void) close(active_tmpl_fd); 111 active_tmpl_fd = -1; 112 } 113 } 114 115 /* 116 * To be called directly before a service method is forked, this function 117 * results in the method process being in a new contract based on the active 118 * contract template. 119 */ 120 int 121 contract_prefork(void) 122 { 123 int err; 124 125 debug_msg("Entering contract_prefork"); 126 127 if ((err = ct_tmpl_activate(active_tmpl_fd)) != 0) { 128 error_msg(gettext("Failed to activate contract template: %s"), 129 strerror(err)); 130 return (-1); 131 } 132 return (0); 133 } 134 135 /* 136 * To be called in both processes directly after a service method is forked, 137 * this function results in switching off contract creation for any 138 * forks done by either process, unless contract_prefork() is called beforehand. 139 */ 140 void 141 contract_postfork(void) 142 { 143 int err; 144 145 debug_msg("Entering contract_postfork"); 146 147 if ((err = ct_tmpl_clear(active_tmpl_fd)) != 0) 148 error_msg("Failed to clear active contract template: %s", 149 strerror(err)); 150 } 151 152 /* 153 * Fetch the latest created contract id into the space referenced by 'cid'. 154 * Returns -1 on error, else 0. 155 */ 156 int 157 get_latest_contract(ctid_t *cid) 158 { 159 debug_msg("Entering get_latest_contract"); 160 161 if ((errno = contract_latest(cid)) != 0) { 162 error_msg(gettext("Failed to get new contract's id: %s"), 163 strerror(errno)); 164 return (-1); 165 } 166 167 return (0); 168 } 169 170 /* Returns -1 on error (with errno set), else fd. */ 171 static int 172 open_contract_ctl_file(ctid_t cid) 173 { 174 debug_msg("Entering open_contract_ctl_file"); 175 176 return (contract_open(cid, "process", "ctl", O_WRONLY)); 177 } 178 179 /* 180 * Adopt a contract. Emits an error message and returns -1 on failure, else 181 * 0. 182 */ 183 int 184 adopt_contract(ctid_t ctid, const char *fmri) 185 { 186 int fd; 187 int err; 188 int ret = 0; 189 190 debug_msg("Entering adopt_contract, id: %d", ctid); 191 192 if ((fd = open_contract_ctl_file(ctid)) == -1) { 193 if (errno == EACCES || errno == ENOENT) { 194 /* 195 * We must not have inherited this contract. That can 196 * happen if we were disabled and restarted. 197 */ 198 debug_msg("Could not adopt contract %ld for %s " 199 "(could not open ctl file: permission denied).\n", 200 ctid, fmri); 201 return (-1); 202 } 203 204 error_msg(gettext("Could not adopt contract id %ld registered " 205 "with %s (could not open ctl file: %s). Events will be " 206 "ignored."), ctid, fmri, strerror(errno)); 207 return (-1); 208 } 209 210 if ((err = ct_ctl_adopt(fd)) != 0) { 211 error_msg(gettext("Could not adopt contract id %ld registered " 212 "with %s (%s). Events will be ignored."), ctid, fmri, 213 strerror(err)); 214 ret = -1; 215 } 216 217 err = close(fd); 218 if (err != 0) 219 error_msg(gettext("Could not close file descriptor %d."), fd); 220 221 return (ret); 222 } 223 224 /* Returns -1 on error, else 0. */ 225 int 226 abandon_contract(ctid_t ctid) 227 { 228 int fd; 229 int err; 230 231 debug_msg("Entering abandon_contract, id: %d", ctid); 232 233 assert(ctid != -1); 234 235 if ((fd = open_contract_ctl_file(ctid)) == -1) { 236 error_msg(gettext("Failed to abandon contract %d: %s"), ctid, 237 strerror(errno)); 238 return (-1); 239 } 240 241 if ((err = ct_ctl_abandon(fd)) != 0) { 242 (void) close(fd); 243 error_msg(gettext("Failed to abandon contract %d: %s"), ctid, 244 strerror(err)); 245 return (-1); 246 } 247 248 (void) close(fd); 249 250 return (0); 251 } 252