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 "mhd_local.h" 30 31 #include <grp.h> 32 #include <pwd.h> 33 #include <signal.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 125 /* set default RT priority */ 126 (void) memset(&pcinfo, 0, sizeof (pcinfo)); 127 (void) strncpy(pcinfo.pc_clname, "RT", sizeof (pcinfo.pc_clname)); 128 if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) < 0) 129 return (mhd_error(mhep, errno, "priocntl(PC_GETCID): \"RT\"")); 130 (void) memset(&pcparms, 0, sizeof (pcparms)); 131 pcparms.pc_cid = pcinfo.pc_cid; 132 rtparmsp->rt_pri = RT_NOCHANGE; 133 rtparmsp->rt_tqsecs = (ulong_t)RT_NOCHANGE; 134 rtparmsp->rt_tqnsecs = RT_NOCHANGE; 135 if (priocntl(P_PID, getpid(), PC_SETPARMS, (caddr_t)&pcparms) != 0) 136 return (mhd_error(mhep, errno, "priocntl(PC_SETPARMS)")); 137 138 /* return success */ 139 return (0); 140 } 141 142 /* 143 * (re)initalize daemon 144 */ 145 static int 146 mhd_init_daemon( 147 mhd_error_t *mhep 148 ) 149 { 150 static int already = 0; 151 152 /* setup */ 153 if (! already) { 154 if (mhd_setup(mhep) != 0) 155 return (-1); 156 openlog(myname, LOG_CONS, LOG_DAEMON); 157 already = 1; 158 } 159 160 /* return success */ 161 return (0); 162 } 163 164 /* 165 * get my nodename 166 */ 167 static char * 168 mynodename() 169 { 170 static struct utsname myuname; 171 static int done = 0; 172 173 if (! done) { 174 if (uname(&myuname) == -1) { 175 mhd_perror("uname"); 176 assert(0); 177 } 178 done = 1; 179 } 180 return (myuname.nodename); 181 } 182 183 /* 184 * check for trusted host and user 185 */ 186 static int 187 check_host( 188 struct svc_req *rqstp /* RPC stuff */ 189 ) 190 { 191 struct authsys_parms *sys_credp; 192 SVCXPRT *transp = rqstp->rq_xprt; 193 struct netconfig *nconfp = NULL; 194 struct nd_hostservlist *hservlistp = NULL; 195 int i; 196 int rval = -1; 197 198 /* check for root */ 199 /*LINTED*/ 200 sys_credp = (struct authsys_parms *)rqstp->rq_clntcred; 201 assert(sys_credp != NULL); 202 if (sys_credp->aup_uid != 0) 203 goto out; 204 205 /* get hostnames */ 206 if (transp->xp_netid == NULL) { 207 mhd_eprintf("transp->xp_netid == NULL\n"); 208 goto out; 209 } 210 if ((nconfp = getnetconfigent(transp->xp_netid)) == NULL) { 211 #ifdef DEBUG 212 nc_perror("getnetconfigent(transp->xp_netid)"); 213 #endif 214 goto out; 215 } 216 if ((__netdir_getbyaddr_nosrv(nconfp, &hservlistp, &transp->xp_rtaddr) 217 != 0) || (hservlistp == NULL)) { 218 #ifdef DEBUG 219 netdir_perror("netdir_getbyaddr(transp->xp_rtaddr)"); 220 #endif 221 goto out; 222 } 223 224 /* check hostnames */ 225 for (i = 0; (i < hservlistp->h_cnt); ++i) { 226 struct nd_hostserv *hservp = &hservlistp->h_hostservs[i]; 227 char *hostname = hservp->h_host; 228 229 /* localhost is OK */ 230 if (strcmp(hostname, mynodename()) == 0) { 231 rval = 0; 232 goto out; 233 } 234 235 /* check for remote root access */ 236 if (ruserok(hostname, 1, "root", "root") == 0) { 237 rval = 0; 238 goto out; 239 } 240 } 241 242 /* cleanup, return success */ 243 out: 244 if (hservlistp != NULL) 245 netdir_free(hservlistp, ND_HOSTSERVLIST); 246 if (nconfp != NULL) 247 Free(nconfp); 248 return (rval); 249 } 250 251 /* 252 * check for user in local group 14 253 */ 254 static int 255 check_gid14( 256 uid_t uid 257 ) 258 { 259 struct passwd *pwp; 260 struct group *grp; 261 char **namep; 262 263 /* get user info, check default GID */ 264 if ((pwp = getpwuid(uid)) == NULL) 265 return (-1); 266 if (pwp->pw_gid == METAMHD_GID) 267 return (0); 268 269 /* check in group */ 270 if ((grp = getgrgid(METAMHD_GID)) == NULL) 271 return (-1); 272 for (namep = grp->gr_mem; ((*namep != NULL) && (**namep != '\0')); 273 ++namep) { 274 if (strcmp(*namep, pwp->pw_name) == 0) 275 return (0); 276 } 277 return (-1); 278 } 279 280 /* 281 * check AUTH_SYS 282 */ 283 static int 284 check_sys( 285 struct svc_req *rqstp, /* RPC stuff */ 286 int amode, /* R_OK | W_OK */ 287 mhd_error_t *mhep /* returned status */ 288 ) 289 { 290 static mutex_t mx = DEFAULTMUTEX; 291 struct authsys_parms *sys_credp; 292 293 /* for read, anything is OK */ 294 if (! (amode & W_OK)) 295 return (0); 296 297 /* single thread (not really needed if daemon stays single threaded) */ 298 mutex_lock(&mx); 299 300 /* check for remote root or METAMHD_GID */ 301 /*LINTED*/ 302 sys_credp = (struct authsys_parms *)rqstp->rq_clntcred; 303 if ((check_gid14(sys_credp->aup_uid) == 0) || 304 (check_host(rqstp) == 0)) { 305 mutex_unlock(&mx); 306 return (0); 307 } 308 309 /* return failure */ 310 mutex_unlock(&mx); 311 return (mhd_error(mhep, EACCES, myname)); 312 } 313 314 /* 315 * setup RPC service 316 * 317 * if can't authenticate return < 0 318 * if any other error return > 0 319 */ 320 int 321 mhd_init( 322 struct svc_req *rqstp, /* RPC stuff */ 323 int amode, /* R_OK | W_OK */ 324 mhd_error_t *mhep /* returned status */ 325 ) 326 { 327 SVCXPRT *transp = rqstp->rq_xprt; 328 329 /* 330 * initialize 331 */ 332 (void) memset(mhep, 0, sizeof (*mhep)); 333 334 /* 335 * check credentials 336 */ 337 switch (rqstp->rq_cred.oa_flavor) { 338 339 /* UNIX flavor */ 340 case AUTH_SYS: 341 { 342 if (check_sys(rqstp, amode, mhep) != 0) 343 return (1); /* error */ 344 break; 345 } 346 347 /* can't authenticate anything else */ 348 default: 349 svcerr_weakauth(transp); 350 return (-1); /* weak authentication */ 351 352 } 353 354 /* 355 * (re)initialize 356 */ 357 if (mhd_init_daemon(mhep) != 0) 358 return (1); /* error */ 359 360 /* return success */ 361 return (0); 362 } 363