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 1999-2002 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 "med_local.h"
30 #include <sdssc.h>
31
32 #include <grp.h>
33 #include <pwd.h>
34 #include <signal.h>
35 #include <syslog.h>
36 #include <netdir.h>
37 #include <netdb.h>
38 #include <sys/resource.h>
39 #include <sys/priocntl.h>
40 #include <sys/rtpriocntl.h>
41 #include <sys/utsname.h>
42
43 extern void nc_perror(const char *msg);
44
45 /* daemon name */
46 static char *medname = MED_SERVNAME;
47
48 /*
49 * reset and exit daemon
50 */
51 void
med_exit(int eval)52 med_exit(
53 int eval
54 )
55 {
56 med_err_t status = med_null_err;
57
58 if (med_db_finit(&status))
59 medde_perror(&status, "med_db_finit");
60
61 /* log exit */
62 med_eprintf("exiting with %d\n", eval);
63
64 /* exit with value */
65 exit(eval);
66 }
67
68 /*
69 * signal catchers
70 */
71 static void
med_catcher(int sig)72 med_catcher(
73 int sig
74 )
75 {
76 char buf[128];
77 char *msg;
78
79 /* log signal */
80 if ((msg = strsignal(sig)) == NULL) {
81 (void) sprintf(buf, "unknown signal %d", sig);
82 msg = buf;
83 }
84 med_eprintf("%s\n", msg);
85
86 /* let default handler do it's thing */
87 (void) sigset(sig, SIG_DFL);
88 if (kill(getpid(), sig) != 0) {
89 med_perror("kill(getpid())");
90 med_exit(-sig);
91 }
92 }
93
94 /*
95 * initialize daemon
96 */
97 static int
med_setup(med_err_t * medep)98 med_setup(
99 med_err_t *medep
100 )
101 {
102 /* catch common signals */
103 if ((sigset(SIGHUP, med_catcher) == SIG_ERR) ||
104 (sigset(SIGINT, med_catcher) == SIG_ERR) ||
105 (sigset(SIGABRT, med_catcher) == SIG_ERR) ||
106 (sigset(SIGBUS, med_catcher) == SIG_ERR) ||
107 (sigset(SIGSEGV, med_catcher) == SIG_ERR) ||
108 (sigset(SIGPIPE, med_catcher) == SIG_ERR) ||
109 (sigset(SIGTERM, med_catcher) == SIG_ERR)) {
110 return (med_error(medep, errno, "sigset"));
111 }
112
113 /* ignore SIGALRM (used in med_cv_timedwait) */
114 if (sigset(SIGALRM, SIG_IGN) == SIG_ERR) {
115 return (med_error(medep, errno, "sigset"));
116 }
117
118 /* return success */
119 return (0);
120 }
121
122 /*
123 * (re)initalize daemon
124 */
125 static int
med_init_daemon(med_err_t * medep)126 med_init_daemon(
127 med_err_t *medep
128 )
129 {
130 static int already = 0;
131
132 /* setup */
133 if (! already) {
134 if (med_setup(medep) != 0)
135 return (-1);
136 openlog(medname, LOG_CONS, LOG_DAEMON);
137 already = 1;
138 }
139
140 /* return success */
141 return (0);
142 }
143
144 /*
145 * get my nodename
146 */
147 char *
mynode(void)148 mynode(void)
149 {
150 static struct utsname myuname;
151 static int done = 0;
152
153 if (! done) {
154 if (uname(&myuname) == -1) {
155 med_perror("uname");
156 assert(0);
157 }
158 done = 1;
159 }
160 return (myuname.nodename);
161 }
162
163 /*
164 * check for trusted host and user
165 */
166 static int
check_host(struct svc_req * rqstp)167 check_host(
168 struct svc_req *rqstp /* RPC stuff */
169 )
170 {
171 struct authsys_parms *sys_credp;
172 SVCXPRT *transp = rqstp->rq_xprt;
173 struct netconfig *nconfp = NULL;
174 struct nd_hostservlist *hservlistp = NULL;
175 int i;
176 int rval = -1;
177 char *inplace = NULL;
178
179 /* check for root */
180 /*LINTED*/
181 sys_credp = (struct authsys_parms *)rqstp->rq_clntcred;
182 assert(sys_credp != NULL);
183 if (sys_credp->aup_uid != 0)
184 goto out;
185
186 /* get hostnames */
187 if (transp->xp_netid == NULL) {
188 med_eprintf("transp->xp_netid == NULL\n");
189 goto out;
190 }
191 if ((nconfp = getnetconfigent(transp->xp_netid)) == NULL) {
192 #ifdef DEBUG
193 nc_perror("getnetconfigent(transp->xp_netid)");
194 #endif
195 goto out;
196 }
197 if ((__netdir_getbyaddr_nosrv(nconfp, &hservlistp, &transp->xp_rtaddr)
198 != 0) || (hservlistp == NULL)) {
199 #ifdef DEBUG
200 netdir_perror("netdir_getbyaddr(transp->xp_rtaddr)");
201 #endif
202 goto out;
203 }
204
205 /* check hostnames */
206 for (i = 0; (i < hservlistp->h_cnt); ++i) {
207 struct nd_hostserv *hservp = &hservlistp->h_hostservs[i];
208 char *hostname = hservp->h_host;
209
210 inplace = strdup(hostname);
211 sdssc_cm_nm2nid(inplace);
212 if (strcmp(inplace, hostname)) {
213
214 /*
215 * If the names are now different it indicates
216 * that hostname was converted to a nodeid. This
217 * will only occur if hostname is part of the same
218 * cluster that the current node is in.
219 * If the machine is not running in a cluster than
220 * sdssc_cm_nm2nid is a noop which leaves inplace
221 * alone.
222 */
223 rval = 0;
224 goto out;
225 }
226
227 /* localhost is OK */
228 if (strcmp(hostname, mynode()) == 0) {
229 rval = 0;
230 goto out;
231 }
232
233 if (strcmp(hostname, "localhost") == 0) {
234 rval = 0;
235 goto out;
236 }
237
238 /* check for remote root access */
239 if (ruserok(hostname, 1, "root", "root") == 0) {
240 rval = 0;
241 goto out;
242 }
243 }
244
245 /* cleanup, return success */
246 out:
247 if (inplace)
248 free(inplace);
249 if (hservlistp != NULL)
250 netdir_free(hservlistp, ND_HOSTSERVLIST);
251 if (nconfp != NULL)
252 Free(nconfp);
253 return (rval);
254 }
255
256 /*
257 * check for user in local group 14
258 */
259 static int
check_gid14(uid_t uid)260 check_gid14(
261 uid_t uid
262 )
263 {
264 struct passwd *pwp;
265 struct group *grp;
266 char **namep;
267
268 /* get user info, check default GID */
269 if ((pwp = getpwuid(uid)) == NULL)
270 return (-1);
271 if (pwp->pw_gid == MED_GID)
272 return (0);
273
274 /* check in group */
275 if ((grp = getgrgid(MED_GID)) == NULL)
276 return (-1);
277 for (namep = grp->gr_mem; ((*namep != NULL) && (**namep != '\0'));
278 ++namep) {
279 if (strcmp(*namep, pwp->pw_name) == 0)
280 return (0);
281 }
282 return (-1);
283 }
284
285 /*
286 * check AUTH_SYS
287 */
288 static int
check_sys(struct svc_req * rqstp,int amode,med_err_t * medep)289 check_sys(
290 struct svc_req *rqstp, /* RPC stuff */
291 int amode, /* R_OK | W_OK */
292 med_err_t *medep /* returned status */
293 )
294 {
295 #ifdef _REENTRANT
296 static mutex_t mx = DEFAULTMUTEX;
297 #endif /* _REENTRANT */
298 struct authsys_parms *sys_credp;
299
300 /* for read, anything is OK */
301 if (! (amode & W_OK))
302 return (0);
303
304 #ifdef _REENTRANT
305 /* single thread (not really needed if daemon stays single threaded) */
306 mutex_lock(&mx);
307 #endif /* _REENTRANT */
308
309 /* check for remote root or METAMED_GID */
310 /*LINTED*/
311 sys_credp = (struct authsys_parms *)rqstp->rq_clntcred;
312 if ((check_gid14(sys_credp->aup_uid) == 0) ||
313 (check_host(rqstp) == 0)) {
314 #ifdef _REENTRANT
315 mutex_unlock(&mx);
316 #endif /* _REENTRANT */
317 return (0);
318 }
319
320 /* return failure */
321 #ifdef _REENTRANT
322 mutex_unlock(&mx);
323 #endif /* _REENTRANT */
324 return (med_error(medep, EACCES, medname));
325 }
326
327 /*
328 * setup RPC service
329 *
330 * if can't authenticate return < 0
331 * if any other error return > 0
332 */
333 int
med_init(struct svc_req * rqstp,int amode,med_err_t * medep)334 med_init(
335 struct svc_req *rqstp, /* RPC stuff */
336 int amode, /* R_OK | W_OK */
337 med_err_t *medep /* returned status */
338 )
339 {
340 SVCXPRT *transp = rqstp->rq_xprt;
341
342 /*
343 * initialize
344 */
345 (void) memset(medep, 0, sizeof (*medep));
346
347 if (sdssc_bind_library() == SDSSC_ERROR) {
348 (void) med_error(medep, EACCES,
349 "can't bind to cluster library");
350 return (1);
351 }
352
353 /*
354 * check credentials
355 */
356 switch (rqstp->rq_cred.oa_flavor) {
357
358 /* UNIX flavor */
359 case AUTH_SYS:
360 {
361 if (check_sys(rqstp, amode, medep) != 0)
362 return (1); /* error */
363 break;
364 }
365
366 /* can't authenticate anything else */
367 default:
368 svcerr_weakauth(transp);
369 return (-1); /* weak authentication */
370
371 }
372
373 /*
374 * (re)initialize
375 */
376 if (med_init_daemon(medep) != 0)
377 return (1); /* error */
378
379 /* return success */
380 return (0);
381 }
382