xref: /titanic_41/usr/src/cmd/lvm/rpc.metamhd/mhd_init.c (revision 8b464eb836173b92f2b7a65623cd06c8c3c59289)
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 2006 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 "mhd_local.h"
29 
30 #include <grp.h>
31 #include <pwd.h>
32 #include <signal.h>
33 #include <stdio_ext.h>
34 #include <syslog.h>
35 #include <netdir.h>
36 #include <netdb.h>
37 #include <sys/resource.h>
38 #include <sys/priocntl.h>
39 #include <sys/rtpriocntl.h>
40 #include <sys/utsname.h>
41 
42 extern	void	nc_perror(const char *msg);
43 
44 /* daemon name */
45 static char	*myname = "rpc.metamhd";
46 
47 /*
48  * reset and exit daemon
49  */
50 void
51 mhd_exit(
52 	int	eval
53 )
54 {
55 	/* log exit */
56 	mhd_eprintf("exiting with %d\n", eval);
57 
58 	/* exit with value */
59 	exit(eval);
60 }
61 
62 /*
63  * signal catchers
64  */
65 static void
66 mhd_catcher(
67 	int	sig
68 )
69 {
70 	char	buf[128];
71 	char	*msg;
72 
73 	/* log signal */
74 	if ((msg = strsignal(sig)) == NULL) {
75 		(void) sprintf(buf, "unknown signal %d", sig);
76 		msg = buf;
77 	}
78 	mhd_eprintf("%s\n", msg);
79 
80 	/* let default handler do it's thing */
81 	(void) sigset(sig, SIG_DFL);
82 	if (kill(getpid(), sig) != 0) {
83 		mhd_perror("kill(getpid())");
84 		mhd_exit(-sig);
85 	}
86 }
87 
88 /*
89  * initialize daemon
90  */
91 static int
92 mhd_setup(
93 	mhd_error_t	*mhep
94 )
95 {
96 	struct rlimit	rlimit;
97 	pcinfo_t	pcinfo;
98 	pcparms_t	pcparms;
99 	rtparms_t	*rtparmsp = (rtparms_t *)pcparms.pc_clparms;
100 
101 	/* catch common signals */
102 	if ((sigset(SIGHUP, mhd_catcher) == SIG_ERR) ||
103 	    (sigset(SIGINT, mhd_catcher) == SIG_ERR) ||
104 	    (sigset(SIGABRT, mhd_catcher) == SIG_ERR) ||
105 	    (sigset(SIGBUS, mhd_catcher) == SIG_ERR) ||
106 	    (sigset(SIGSEGV, mhd_catcher) == SIG_ERR) ||
107 	    (sigset(SIGPIPE, mhd_catcher) == SIG_ERR) ||
108 	    (sigset(SIGTERM, mhd_catcher) == SIG_ERR)) {
109 		return (mhd_error(mhep, errno, "sigset"));
110 	}
111 
112 	/* ignore SIGHUP (used in mhd_cv_timedwait) */
113 	if (sigset(SIGALRM, SIG_IGN) == SIG_ERR) {
114 		return (mhd_error(mhep, errno, "sigset"));
115 	}
116 
117 	/* increase number of file descriptors */
118 	(void) memset(&rlimit, 0, sizeof (rlimit));
119 	if (getrlimit(RLIMIT_NOFILE, &rlimit) != 0)
120 		return (mhd_error(mhep, errno, "getrlimit(RLIMIT_NOFILE)"));
121 	rlimit.rlim_cur = rlimit.rlim_max = 1024;
122 	if (setrlimit(RLIMIT_NOFILE, &rlimit) != 0)
123 		return (mhd_error(mhep, errno, "setrlimit(RLIMIT_NOFILE)"));
124 	(void) enable_extended_FILE_stdio(-1, -1);
125 
126 	/* set default RT priority */
127 	(void) memset(&pcinfo, 0, sizeof (pcinfo));
128 	(void) strncpy(pcinfo.pc_clname, "RT", sizeof (pcinfo.pc_clname));
129 	if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) < 0)
130 		return (mhd_error(mhep, errno, "priocntl(PC_GETCID): \"RT\""));
131 	(void) memset(&pcparms, 0, sizeof (pcparms));
132 	pcparms.pc_cid = pcinfo.pc_cid;
133 	rtparmsp->rt_pri = RT_NOCHANGE;
134 	rtparmsp->rt_tqsecs = (ulong_t)RT_NOCHANGE;
135 	rtparmsp->rt_tqnsecs = RT_NOCHANGE;
136 	if (priocntl(P_PID, getpid(), PC_SETPARMS, (caddr_t)&pcparms) != 0)
137 		return (mhd_error(mhep, errno, "priocntl(PC_SETPARMS)"));
138 
139 	/* return success */
140 	return (0);
141 }
142 
143 /*
144  * (re)initalize daemon
145  */
146 static int
147 mhd_init_daemon(
148 	mhd_error_t	*mhep
149 )
150 {
151 	static int	already = 0;
152 
153 	/* setup */
154 	if (! already) {
155 		if (mhd_setup(mhep) != 0)
156 			return (-1);
157 		openlog(myname, LOG_CONS, LOG_DAEMON);
158 		already = 1;
159 	}
160 
161 	/* return success */
162 	return (0);
163 }
164 
165 /*
166  * get my nodename
167  */
168 static char *
169 mynodename()
170 {
171 	static struct utsname	myuname;
172 	static int		done = 0;
173 
174 	if (! done) {
175 		if (uname(&myuname) == -1) {
176 			mhd_perror("uname");
177 			assert(0);
178 		}
179 		done = 1;
180 	}
181 	return (myuname.nodename);
182 }
183 
184 /*
185  * check for trusted host and user
186  */
187 static int
188 check_host(
189 	struct svc_req		*rqstp		/* RPC stuff */
190 )
191 {
192 	struct authsys_parms	*sys_credp;
193 	SVCXPRT			*transp = rqstp->rq_xprt;
194 	struct netconfig	*nconfp = NULL;
195 	struct nd_hostservlist	*hservlistp = NULL;
196 	int			i;
197 	int			rval = -1;
198 
199 	/* check for root */
200 	/*LINTED*/
201 	sys_credp = (struct authsys_parms *)rqstp->rq_clntcred;
202 	assert(sys_credp != NULL);
203 	if (sys_credp->aup_uid != 0)
204 		goto out;
205 
206 	/* get hostnames */
207 	if (transp->xp_netid == NULL) {
208 		mhd_eprintf("transp->xp_netid == NULL\n");
209 		goto out;
210 	}
211 	if ((nconfp = getnetconfigent(transp->xp_netid)) == NULL) {
212 #ifdef	DEBUG
213 		nc_perror("getnetconfigent(transp->xp_netid)");
214 #endif
215 		goto out;
216 	}
217 	if ((__netdir_getbyaddr_nosrv(nconfp, &hservlistp, &transp->xp_rtaddr)
218 	    != 0) || (hservlistp == NULL)) {
219 #ifdef	DEBUG
220 		netdir_perror("netdir_getbyaddr(transp->xp_rtaddr)");
221 #endif
222 		goto out;
223 	}
224 
225 	/* check hostnames */
226 	for (i = 0; (i < hservlistp->h_cnt); ++i) {
227 		struct nd_hostserv	*hservp = &hservlistp->h_hostservs[i];
228 		char			*hostname = hservp->h_host;
229 
230 		/* localhost is OK */
231 		if (strcmp(hostname, mynodename()) == 0) {
232 			rval = 0;
233 			goto out;
234 		}
235 
236 		/* check for remote root access */
237 		if (ruserok(hostname, 1, "root", "root") == 0) {
238 			rval = 0;
239 			goto out;
240 		}
241 	}
242 
243 	/* cleanup, return success */
244 out:
245 	if (hservlistp != NULL)
246 		netdir_free(hservlistp, ND_HOSTSERVLIST);
247 	if (nconfp != NULL)
248 		Free(nconfp);
249 	return (rval);
250 }
251 
252 /*
253  * check for user in local group 14
254  */
255 static int
256 check_gid14(
257 	uid_t		uid
258 )
259 {
260 	struct passwd	*pwp;
261 	struct group	*grp;
262 	char		**namep;
263 
264 	/* get user info, check default GID */
265 	if ((pwp = getpwuid(uid)) == NULL)
266 		return (-1);
267 	if (pwp->pw_gid == METAMHD_GID)
268 		return (0);
269 
270 	/* check in group */
271 	if ((grp = getgrgid(METAMHD_GID)) == NULL)
272 		return (-1);
273 	for (namep = grp->gr_mem; ((*namep != NULL) && (**namep != '\0'));
274 	    ++namep) {
275 		if (strcmp(*namep, pwp->pw_name) == 0)
276 			return (0);
277 	}
278 	return (-1);
279 }
280 
281 /*
282  * check AUTH_SYS
283  */
284 static int
285 check_sys(
286 	struct svc_req		*rqstp,		/* RPC stuff */
287 	int			amode,		/* R_OK | W_OK */
288 	mhd_error_t		*mhep		/* returned status */
289 )
290 {
291 	static mutex_t		mx = DEFAULTMUTEX;
292 	struct authsys_parms	*sys_credp;
293 
294 	/* for read, anything is OK */
295 	if (! (amode & W_OK))
296 		return (0);
297 
298 	/* single thread (not really needed if daemon stays single threaded) */
299 	mutex_lock(&mx);
300 
301 	/* check for remote root or METAMHD_GID */
302 	/*LINTED*/
303 	sys_credp = (struct authsys_parms *)rqstp->rq_clntcred;
304 	if ((check_gid14(sys_credp->aup_uid) == 0) ||
305 	    (check_host(rqstp) == 0)) {
306 		mutex_unlock(&mx);
307 		return (0);
308 	}
309 
310 	/* return failure */
311 	mutex_unlock(&mx);
312 	return (mhd_error(mhep, EACCES, myname));
313 }
314 
315 /*
316  * setup RPC service
317  *
318  * if can't authenticate return < 0
319  * if any other error return > 0
320  */
321 int
322 mhd_init(
323 	struct svc_req	*rqstp,		/* RPC stuff */
324 	int		amode,		/* R_OK | W_OK */
325 	mhd_error_t	*mhep		/* returned status */
326 )
327 {
328 	SVCXPRT		*transp = rqstp->rq_xprt;
329 
330 	/*
331 	 * initialize
332 	 */
333 	(void) memset(mhep, 0, sizeof (*mhep));
334 
335 	/*
336 	 * check credentials
337 	 */
338 	switch (rqstp->rq_cred.oa_flavor) {
339 
340 	/* UNIX flavor */
341 	case AUTH_SYS:
342 	{
343 		if (check_sys(rqstp, amode, mhep) != 0)
344 			return (1);	/* error */
345 		break;
346 	}
347 
348 	/* can't authenticate anything else */
349 	default:
350 		svcerr_weakauth(transp);
351 		return (-1);		/* weak authentication */
352 
353 	}
354 
355 	/*
356 	 * (re)initialize
357 	 */
358 	if (mhd_init_daemon(mhep) != 0)
359 		return (1);		/* error */
360 
361 	/* return success */
362 	return (0);
363 }
364