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