1 /* $NetBSD: kern_prot.c,v 1.31 1995/10/10 01:26:53 mycroft Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * (c) UNIX System Laboratories, Inc. 7 * All or some portions of this file are derived from material licensed 8 * to the University of California by American Telephone and Telegraph 9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 10 * the permission of UNIX System Laboratories, Inc. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * @(#)kern_prot.c 8.6 (Berkeley) 1/21/94 41 */ 42 43 /* 44 * System calls related to processes and protection 45 */ 46 47 #include <sys/param.h> 48 #include <sys/acct.h> 49 #include <sys/systm.h> 50 #include <sys/ucred.h> 51 #include <sys/proc.h> 52 #include <sys/timeb.h> 53 #include <sys/times.h> 54 #include <sys/malloc.h> 55 56 #include <sys/mount.h> 57 #include <sys/syscallargs.h> 58 59 /* ARGSUSED */ 60 sys_getpid(p, v, retval) 61 struct proc *p; 62 void *v; 63 register_t *retval; 64 { 65 66 *retval = p->p_pid; 67 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \ 68 defined(COMPAT_FREEBSD) 69 retval[1] = p->p_pptr->p_pid; 70 #endif 71 return (0); 72 } 73 74 /* ARGSUSED */ 75 sys_getppid(p, v, retval) 76 struct proc *p; 77 void *v; 78 register_t *retval; 79 { 80 81 *retval = p->p_pptr->p_pid; 82 return (0); 83 } 84 85 /* Get process group ID; note that POSIX getpgrp takes no parameter */ 86 sys_getpgrp(p, v, retval) 87 struct proc *p; 88 void *v; 89 register_t *retval; 90 { 91 92 *retval = p->p_pgrp->pg_id; 93 return (0); 94 } 95 96 /* ARGSUSED */ 97 sys_getuid(p, v, retval) 98 struct proc *p; 99 void *v; 100 register_t *retval; 101 { 102 103 *retval = p->p_cred->p_ruid; 104 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \ 105 defined(COMPAT_FREEBSD) 106 retval[1] = p->p_ucred->cr_uid; 107 #endif 108 return (0); 109 } 110 111 /* ARGSUSED */ 112 sys_geteuid(p, v, retval) 113 struct proc *p; 114 void *v; 115 register_t *retval; 116 { 117 118 *retval = p->p_ucred->cr_uid; 119 return (0); 120 } 121 122 /* ARGSUSED */ 123 sys_getgid(p, v, retval) 124 struct proc *p; 125 void *v; 126 register_t *retval; 127 { 128 129 *retval = p->p_cred->p_rgid; 130 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_FREEBSD) 131 retval[1] = p->p_ucred->cr_gid; 132 #endif 133 return (0); 134 } 135 136 /* 137 * Get effective group ID. The "egid" is groups[0], and could be obtained 138 * via getgroups. This syscall exists because it is somewhat painful to do 139 * correctly in a library function. 140 */ 141 /* ARGSUSED */ 142 sys_getegid(p, v, retval) 143 struct proc *p; 144 void *v; 145 register_t *retval; 146 { 147 148 *retval = p->p_ucred->cr_gid; 149 return (0); 150 } 151 152 sys_getgroups(p, v, retval) 153 struct proc *p; 154 void *v; 155 register_t *retval; 156 { 157 register struct sys_getgroups_args /* { 158 syscallarg(u_int) gidsetsize; 159 syscallarg(gid_t *) gidset; 160 } */ *uap = v; 161 register struct pcred *pc = p->p_cred; 162 register u_int ngrp; 163 int error; 164 165 if ((ngrp = SCARG(uap, gidsetsize)) == 0) { 166 *retval = pc->pc_ucred->cr_ngroups; 167 return (0); 168 } 169 if (ngrp < pc->pc_ucred->cr_ngroups) 170 return (EINVAL); 171 ngrp = pc->pc_ucred->cr_ngroups; 172 if (error = copyout((caddr_t)pc->pc_ucred->cr_groups, 173 (caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t))) 174 return (error); 175 *retval = ngrp; 176 return (0); 177 } 178 179 /* ARGSUSED */ 180 sys_setsid(p, v, retval) 181 register struct proc *p; 182 void *v; 183 register_t *retval; 184 { 185 186 if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 187 return (EPERM); 188 } else { 189 (void)enterpgrp(p, p->p_pid, 1); 190 *retval = p->p_pid; 191 return (0); 192 } 193 } 194 195 /* 196 * set process group (setpgid/old setpgrp) 197 * 198 * caller does setpgid(targpid, targpgid) 199 * 200 * pid must be caller or child of caller (ESRCH) 201 * if a child 202 * pid must be in same session (EPERM) 203 * pid can't have done an exec (EACCES) 204 * if pgid != pid 205 * there must exist some pid in same session having pgid (EPERM) 206 * pid must not be session leader (EPERM) 207 */ 208 /* ARGSUSED */ 209 sys_setpgid(curp, v, retval) 210 struct proc *curp; 211 void *v; 212 register_t *retval; 213 { 214 register struct sys_setpgid_args /* { 215 syscallarg(int) pid; 216 syscallarg(int) pgid; 217 } */ *uap = v; 218 register struct proc *targp; /* target process */ 219 register struct pgrp *pgrp; /* target pgrp */ 220 221 #ifdef COMPAT_09 222 SCARG(uap, pid) = (short) SCARG(uap, pid); /* XXX */ 223 SCARG(uap, pgid) = (short) SCARG(uap, pgid); /* XXX */ 224 #endif 225 226 if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != curp->p_pid) { 227 if ((targp = pfind(SCARG(uap, pid))) == 0 || !inferior(targp)) 228 return (ESRCH); 229 if (targp->p_session != curp->p_session) 230 return (EPERM); 231 if (targp->p_flag & P_EXEC) 232 return (EACCES); 233 } else 234 targp = curp; 235 if (SESS_LEADER(targp)) 236 return (EPERM); 237 if (SCARG(uap, pgid) == 0) 238 SCARG(uap, pgid) = targp->p_pid; 239 else if (SCARG(uap, pgid) != targp->p_pid) 240 if ((pgrp = pgfind(SCARG(uap, pgid))) == 0 || 241 pgrp->pg_session != curp->p_session) 242 return (EPERM); 243 return (enterpgrp(targp, SCARG(uap, pgid), 0)); 244 } 245 246 /* ARGSUSED */ 247 sys_setuid(p, v, retval) 248 struct proc *p; 249 void *v; 250 register_t *retval; 251 { 252 struct sys_setuid_args /* { 253 syscallarg(uid_t) uid; 254 } */ *uap = v; 255 register struct pcred *pc = p->p_cred; 256 register uid_t uid; 257 int error; 258 259 #ifdef COMPAT_09 /* XXX */ 260 uid = (u_short)SCARG(uap, uid); 261 #else 262 uid = SCARG(uap, uid); 263 #endif 264 if (uid != pc->p_ruid && 265 (error = suser(pc->pc_ucred, &p->p_acflag))) 266 return (error); 267 /* 268 * Everything's okay, do it. 269 * Transfer proc count to new user. 270 * Copy credentials so other references do not see our changes. 271 */ 272 (void)chgproccnt(pc->p_ruid, -1); 273 (void)chgproccnt(uid, 1); 274 pc->pc_ucred = crcopy(pc->pc_ucred); 275 pc->pc_ucred->cr_uid = uid; 276 pc->p_ruid = uid; 277 pc->p_svuid = uid; 278 p->p_flag |= P_SUGID; 279 return (0); 280 } 281 282 /* ARGSUSED */ 283 sys_seteuid(p, v, retval) 284 struct proc *p; 285 void *v; 286 register_t *retval; 287 { 288 struct sys_seteuid_args /* { 289 syscallarg(uid_t) euid; 290 } */ *uap = v; 291 register struct pcred *pc = p->p_cred; 292 register uid_t euid; 293 int error; 294 295 #ifdef COMPAT_09 /* XXX */ 296 euid = (u_short)SCARG(uap, euid); 297 #else 298 euid = SCARG(uap, euid); 299 #endif 300 if (euid != pc->p_ruid && euid != pc->p_svuid && 301 (error = suser(pc->pc_ucred, &p->p_acflag))) 302 return (error); 303 /* 304 * Everything's okay, do it. Copy credentials so other references do 305 * not see our changes. 306 */ 307 pc->pc_ucred = crcopy(pc->pc_ucred); 308 pc->pc_ucred->cr_uid = euid; 309 p->p_flag |= P_SUGID; 310 return (0); 311 } 312 313 /* ARGSUSED */ 314 sys_setgid(p, v, retval) 315 struct proc *p; 316 void *v; 317 register_t *retval; 318 { 319 struct sys_setgid_args /* { 320 syscallarg(gid_t) gid; 321 } */ *uap = v; 322 register struct pcred *pc = p->p_cred; 323 register gid_t gid; 324 int error; 325 326 #ifdef COMPAT_09 /* XXX */ 327 gid = (u_short)SCARG(uap, gid); 328 #else 329 gid = SCARG(uap, gid); 330 #endif 331 if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag))) 332 return (error); 333 pc->pc_ucred = crcopy(pc->pc_ucred); 334 pc->pc_ucred->cr_gid = gid; 335 pc->p_rgid = gid; 336 pc->p_svgid = gid; /* ??? */ 337 p->p_flag |= P_SUGID; 338 return (0); 339 } 340 341 /* ARGSUSED */ 342 sys_setegid(p, v, retval) 343 struct proc *p; 344 void *v; 345 register_t *retval; 346 { 347 struct sys_setegid_args /* { 348 syscallarg(gid_t) egid; 349 } */ *uap = v; 350 register struct pcred *pc = p->p_cred; 351 register gid_t egid; 352 int error; 353 354 #ifdef COMPAT_09 /* XXX */ 355 egid = (u_short)SCARG(uap, egid); 356 #else 357 egid = SCARG(uap, egid); 358 #endif 359 if (egid != pc->p_rgid && egid != pc->p_svgid && 360 (error = suser(pc->pc_ucred, &p->p_acflag))) 361 return (error); 362 pc->pc_ucred = crcopy(pc->pc_ucred); 363 pc->pc_ucred->cr_gid = egid; 364 p->p_flag |= P_SUGID; 365 return (0); 366 } 367 368 /* ARGSUSED */ 369 sys_setgroups(p, v, retval) 370 struct proc *p; 371 void *v; 372 register_t *retval; 373 { 374 struct sys_setgroups_args /* { 375 syscallarg(u_int) gidsetsize; 376 syscallarg(gid_t *) gidset; 377 } */ *uap = v; 378 register struct pcred *pc = p->p_cred; 379 register u_int ngrp; 380 int error; 381 382 if (error = suser(pc->pc_ucred, &p->p_acflag)) 383 return (error); 384 ngrp = SCARG(uap, gidsetsize); 385 if (ngrp > NGROUPS) 386 return (EINVAL); 387 pc->pc_ucred = crcopy(pc->pc_ucred); 388 if (error = copyin((caddr_t)SCARG(uap, gidset), 389 (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t))) 390 return (error); 391 pc->pc_ucred->cr_ngroups = ngrp; 392 p->p_flag |= P_SUGID; 393 return (0); 394 } 395 396 /* 397 * Check if gid is a member of the group set. 398 */ 399 groupmember(gid, cred) 400 gid_t gid; 401 register struct ucred *cred; 402 { 403 register gid_t *gp; 404 gid_t *egp; 405 406 egp = &(cred->cr_groups[cred->cr_ngroups]); 407 for (gp = cred->cr_groups; gp < egp; gp++) 408 if (*gp == gid) 409 return (1); 410 return (0); 411 } 412 413 /* 414 * Test whether the specified credentials imply "super-user" 415 * privilege; if so, and we have accounting info, set the flag 416 * indicating use of super-powers. 417 * Returns 0 or error. 418 */ 419 suser(cred, acflag) 420 struct ucred *cred; 421 u_short *acflag; 422 { 423 if (cred->cr_uid == 0) { 424 if (acflag) 425 *acflag |= ASU; 426 return (0); 427 } 428 return (EPERM); 429 } 430 431 /* 432 * Allocate a zeroed cred structure. 433 */ 434 struct ucred * 435 crget() 436 { 437 register struct ucred *cr; 438 439 MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 440 bzero((caddr_t)cr, sizeof(*cr)); 441 cr->cr_ref = 1; 442 return (cr); 443 } 444 445 /* 446 * Free a cred structure. 447 * Throws away space when ref count gets to 0. 448 */ 449 void 450 crfree(cr) 451 struct ucred *cr; 452 { 453 int s; 454 455 s = splimp(); /* ??? */ 456 if (--cr->cr_ref == 0) 457 FREE((caddr_t)cr, M_CRED); 458 (void) splx(s); 459 } 460 461 /* 462 * Copy cred structure to a new one and free the old one. 463 */ 464 struct ucred * 465 crcopy(cr) 466 struct ucred *cr; 467 { 468 struct ucred *newcr; 469 470 if (cr->cr_ref == 1) 471 return (cr); 472 newcr = crget(); 473 *newcr = *cr; 474 crfree(cr); 475 newcr->cr_ref = 1; 476 return (newcr); 477 } 478 479 /* 480 * Dup cred struct to a new held one. 481 */ 482 struct ucred * 483 crdup(cr) 484 struct ucred *cr; 485 { 486 struct ucred *newcr; 487 488 newcr = crget(); 489 *newcr = *cr; 490 newcr->cr_ref = 1; 491 return (newcr); 492 } 493 494 /* 495 * Get login name, if available. 496 */ 497 /* ARGSUSED */ 498 sys_getlogin(p, v, retval) 499 struct proc *p; 500 void *v; 501 register_t *retval; 502 { 503 struct sys_getlogin_args /* { 504 syscallarg(char *) namebuf; 505 syscallarg(u_int) namelen; 506 } */ *uap = v; 507 508 if (SCARG(uap, namelen) > sizeof (p->p_pgrp->pg_session->s_login)) 509 SCARG(uap, namelen) = sizeof (p->p_pgrp->pg_session->s_login); 510 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 511 (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen))); 512 } 513 514 /* 515 * Set login name. 516 */ 517 /* ARGSUSED */ 518 sys_setlogin(p, v, retval) 519 struct proc *p; 520 void *v; 521 register_t *retval; 522 { 523 struct sys_setlogin_args /* { 524 syscallarg(char *) namebuf; 525 } */ *uap = v; 526 int error; 527 528 if (error = suser(p->p_ucred, &p->p_acflag)) 529 return (error); 530 error = copyinstr((caddr_t) SCARG(uap, namebuf), 531 (caddr_t) p->p_pgrp->pg_session->s_login, 532 sizeof (p->p_pgrp->pg_session->s_login) - 1, (size_t *)0); 533 if (error == ENAMETOOLONG) 534 error = EINVAL; 535 return (error); 536 } 537