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