xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.lib/inetd/contracts.c (revision 4fe85d41bb4eb0db41934722f4b06c8acec2d25a)
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 2008 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  #include <assert.h>
29  #include <errno.h>
30  #include <libintl.h>
31  #include <sys/wait.h>
32  #include <sys/ctfs.h>
33  #include <sys/contract/process.h>
34  #include <libcontract.h>
35  #include <libcontract_priv.h>
36  #include <stdlib.h>
37  #include <string.h>
38  #include <unistd.h>
39  #include "inetd_impl.h"
40  
41  
42  /* paths/filenames of contract related files */
43  #define	CONTRACT_ROOT_PATH	CTFS_ROOT "/process/"
44  #define	CONTRACT_TEMPLATE_PATH  CONTRACT_ROOT_PATH "template"
45  
46  static int active_tmpl_fd = -1;
47  
48  /*
49   * Creates and configures the the contract template used for all inetd's
50   * methods.
51   * Returns -1 on error, else the fd of the created template.
52   */
53  static int
54  create_contract_template(void)
55  {
56  	int		fd;
57  	int		err;
58  
59  	if ((fd = open(CONTRACT_TEMPLATE_PATH, O_RDWR)) == -1) {
60  		error_msg(gettext("Failed to open contract file %s: %s"),
61  		    CONTRACT_TEMPLATE_PATH, strerror(errno));
62  		return (-1);
63  	}
64  
65  	/*
66  	 * Make contract inheritable and make hardware errors fatal.
67  	 * We also limit the scope of fatal events to the process
68  	 * group.  In order of preference we would have contract-aware
69  	 * login services or a property indicating which services need
70  	 * such scoping, but for the time being we'll assume that most
71  	 * non login-style services run in a single process group.
72  	 */
73  	if (((err = ct_pr_tmpl_set_param(fd,
74  	    CT_PR_INHERIT|CT_PR_PGRPONLY)) != 0) ||
75  	    ((err = ct_pr_tmpl_set_fatal(fd, CT_PR_EV_HWERR)) != 0) ||
76  	    ((err = ct_tmpl_set_critical(fd, 0)) != 0) ||
77  	    ((err = ct_tmpl_set_informative(fd, 0)) != 0)) {
78  		error_msg(gettext(
79  		    "Failed to set parameter for contract template: %s"),
80  		    strerror(err));
81  		(void) close(fd);
82  		return (-1);
83  	}
84  
85  	return (fd);
86  }
87  
88  /* Returns -1 on error, else 0. */
89  int
90  contract_init(void)
91  {
92  	if ((active_tmpl_fd = create_contract_template()) == -1) {
93  		error_msg(gettext("Failed to create contract template"));
94  		return (-1);
95  	}
96  	return (0);
97  }
98  
99  void
100  contract_fini(void)
101  {
102  	if (active_tmpl_fd != -1) {
103  		(void) close(active_tmpl_fd);
104  		active_tmpl_fd = -1;
105  	}
106  }
107  
108  /*
109   * To be called directly before a service method is forked, this function
110   * results in the method process being in a new contract based on the active
111   * contract template.
112   */
113  int
114  contract_prefork(const char *fmri, int method)
115  {
116  	int err;
117  
118  	if ((err = ct_pr_tmpl_set_svc_fmri(active_tmpl_fd, fmri)) != 0) {
119  		error_msg(gettext("Failed to set svc_fmri term: %s"),
120  		    strerror(err));
121  		return (-1);
122  	}
123  	if ((err = ct_pr_tmpl_set_svc_aux(active_tmpl_fd,
124  	    methods[method].name)) != 0) {
125  		error_msg(gettext("Failed to set svc_aux term: %s"),
126  		    strerror(err));
127  		return (-1);
128  	}
129  
130  	if ((err = ct_tmpl_activate(active_tmpl_fd)) != 0) {
131  		error_msg(gettext("Failed to activate contract template: %s"),
132  		    strerror(err));
133  		return (-1);
134  	}
135  	return (0);
136  }
137  
138  /*
139   * To be called in both processes directly after a service method is forked,
140   * this function results in switching off contract creation for any
141   * forks done by either process, unless contract_prefork() is called beforehand.
142   */
143  void
144  contract_postfork(void)
145  {
146  	int err;
147  
148  	if ((err = ct_tmpl_clear(active_tmpl_fd)) != 0)
149  		error_msg("Failed to clear active contract template: %s",
150  		    strerror(err));
151  }
152  
153  /*
154   * Fetch the latest created contract id into the space referenced by 'cid'.
155   * Returns -1 on error, else 0.
156   */
157  int
158  get_latest_contract(ctid_t *cid)
159  {
160  	if ((errno = contract_latest(cid)) != 0) {
161  		error_msg(gettext("Failed to get new contract's id: %s"),
162  		    strerror(errno));
163  		return (-1);
164  	}
165  
166  	return (0);
167  }
168  
169  /* Returns -1 on error (with errno set), else fd. */
170  static int
171  open_contract_ctl_file(ctid_t cid)
172  {
173  	return (contract_open(cid, "process", "ctl", O_WRONLY));
174  }
175  
176  /*
177   * Adopt a contract.  Emits an error message and returns -1 on failure, else
178   * 0.
179   */
180  int
181  adopt_contract(ctid_t ctid, const char *fmri)
182  {
183  	int fd;
184  	int err;
185  	int ret = 0;
186  
187  	if ((fd = open_contract_ctl_file(ctid)) == -1) {
188  		if (errno == EACCES || errno == ENOENT) {
189  			/*
190  			 * We must not have inherited this contract.  That can
191  			 * happen if we were disabled and restarted.
192  			 */
193  			debug_msg("Could not adopt contract %ld for %s "
194  			    "(could not open ctl file: permission denied).\n",
195  			    ctid, fmri);
196  			return (-1);
197  		}
198  
199  		error_msg(gettext("Could not adopt contract id %ld registered "
200  		    "with %s (could not open ctl file: %s).  Events will be "
201  		    "ignored."), ctid, fmri, strerror(errno));
202  		return (-1);
203  	}
204  
205  	if ((err = ct_ctl_adopt(fd)) != 0) {
206  		error_msg(gettext("Could not adopt contract id %ld registered "
207  		    "with %s (%s).  Events will be ignored."), ctid, fmri,
208  		    strerror(err));
209  		ret = -1;
210  	}
211  
212  	err = close(fd);
213  	if (err != 0)
214  		error_msg(gettext("Could not close file descriptor %d."), fd);
215  
216  	return (ret);
217  }
218  
219  /* Returns -1 on error, else 0. */
220  int
221  abandon_contract(ctid_t ctid)
222  {
223  	int fd;
224  	int err;
225  
226  	assert(ctid != -1);
227  
228  	if ((fd = open_contract_ctl_file(ctid)) == -1) {
229  		error_msg(gettext("Failed to abandon contract %d: %s"), ctid,
230  		    strerror(errno));
231  		return (-1);
232  	}
233  
234  	if ((err = ct_ctl_abandon(fd)) != 0) {
235  		(void) close(fd);
236  		error_msg(gettext("Failed to abandon contract %d: %s"), ctid,
237  		    strerror(err));
238  		return (-1);
239  	}
240  
241  	(void) close(fd);
242  
243  	return (0);
244  }
245