1 /* 2 * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. 9 * 10 * %sccs.include.redist.c% 11 * 12 * @(#)kern_prot.c 8.9 (Berkeley) 02/14/95 13 */ 14 15 /* 16 * System calls related to processes and protection 17 */ 18 19 #include <sys/param.h> 20 #include <sys/acct.h> 21 #include <sys/systm.h> 22 #include <sys/ucred.h> 23 #include <sys/proc.h> 24 #include <sys/timeb.h> 25 #include <sys/times.h> 26 #include <sys/malloc.h> 27 28 #include <sys/mount.h> 29 #include <sys/syscallargs.h> 30 31 /* ARGSUSED */ 32 int 33 getpid(p, uap, retval) 34 struct proc *p; 35 void *uap; 36 register_t *retval; 37 { 38 39 *retval = p->p_pid; 40 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 41 retval[1] = p->p_pptr->p_pid; 42 #endif 43 return (0); 44 } 45 46 /* ARGSUSED */ 47 int 48 getppid(p, uap, retval) 49 struct proc *p; 50 void *uap; 51 register_t *retval; 52 { 53 54 *retval = p->p_pptr->p_pid; 55 return (0); 56 } 57 58 /* Get process group ID; note that POSIX getpgrp takes no parameter */ 59 int 60 getpgrp(p, uap, retval) 61 struct proc *p; 62 void *uap; 63 register_t *retval; 64 { 65 66 *retval = p->p_pgrp->pg_id; 67 return (0); 68 } 69 70 /* ARGSUSED */ 71 int 72 getuid(p, uap, retval) 73 struct proc *p; 74 void *uap; 75 register_t *retval; 76 { 77 78 *retval = p->p_cred->p_ruid; 79 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 80 retval[1] = p->p_ucred->cr_uid; 81 #endif 82 return (0); 83 } 84 85 /* ARGSUSED */ 86 int 87 geteuid(p, uap, retval) 88 struct proc *p; 89 void *uap; 90 register_t *retval; 91 { 92 93 *retval = p->p_ucred->cr_uid; 94 return (0); 95 } 96 97 /* ARGSUSED */ 98 int 99 getgid(p, uap, retval) 100 struct proc *p; 101 void *uap; 102 register_t *retval; 103 { 104 105 *retval = p->p_cred->p_rgid; 106 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 107 retval[1] = p->p_ucred->cr_groups[0]; 108 #endif 109 return (0); 110 } 111 112 /* 113 * Get effective group ID. The "egid" is groups[0], and could be obtained 114 * via getgroups. This syscall exists because it is somewhat painful to do 115 * correctly in a library function. 116 */ 117 /* ARGSUSED */ 118 int 119 getegid(p, uap, retval) 120 struct proc *p; 121 void *uap; 122 register_t *retval; 123 { 124 125 *retval = p->p_ucred->cr_groups[0]; 126 return (0); 127 } 128 129 int 130 getgroups(p, uap, retval) 131 struct proc *p; 132 register struct getgroups_args /* { 133 syscallarg(u_int) gidsetsize; 134 syscallarg(gid_t *) gidset; 135 } */ *uap; 136 register_t *retval; 137 { 138 register struct pcred *pc = p->p_cred; 139 register u_int ngrp; 140 int error; 141 142 if ((ngrp = SCARG(uap, gidsetsize)) == 0) { 143 *retval = pc->pc_ucred->cr_ngroups; 144 return (0); 145 } 146 if (ngrp < pc->pc_ucred->cr_ngroups) 147 return (EINVAL); 148 ngrp = pc->pc_ucred->cr_ngroups; 149 if (error = copyout((caddr_t)pc->pc_ucred->cr_groups, 150 (caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t))) 151 return (error); 152 *retval = ngrp; 153 return (0); 154 } 155 156 /* ARGSUSED */ 157 int 158 setsid(p, uap, retval) 159 register struct proc *p; 160 void *uap; 161 register_t *retval; 162 { 163 164 if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 165 return (EPERM); 166 } else { 167 (void)enterpgrp(p, p->p_pid, 1); 168 *retval = p->p_pid; 169 return (0); 170 } 171 } 172 173 /* 174 * set process group (setpgid/old setpgrp) 175 * 176 * caller does setpgid(targpid, targpgid) 177 * 178 * pid must be caller or child of caller (ESRCH) 179 * if a child 180 * pid must be in same session (EPERM) 181 * pid can't have done an exec (EACCES) 182 * if pgid != pid 183 * there must exist some pid in same session having pgid (EPERM) 184 * pid must not be session leader (EPERM) 185 */ 186 /* ARGSUSED */ 187 int 188 setpgid(curp, uap, retval) 189 struct proc *curp; 190 register struct setpgid_args /* { 191 syscallarg(int) pid; 192 syscallarg(int) pgid; 193 } */ *uap; 194 register_t *retval; 195 { 196 register struct proc *targp; /* target process */ 197 register struct pgrp *pgrp; /* target pgrp */ 198 199 if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != curp->p_pid) { 200 if ((targp = pfind(SCARG(uap, pid))) == 0 || !inferior(targp)) 201 return (ESRCH); 202 if (targp->p_session != curp->p_session) 203 return (EPERM); 204 if (targp->p_flag & P_EXEC) 205 return (EACCES); 206 } else 207 targp = curp; 208 if (SESS_LEADER(targp)) 209 return (EPERM); 210 if (SCARG(uap, pgid) == 0) 211 SCARG(uap, pgid) = targp->p_pid; 212 else if (SCARG(uap, pgid) != targp->p_pid) 213 if ((pgrp = pgfind(SCARG(uap, pgid))) == 0 || 214 pgrp->pg_session != curp->p_session) 215 return (EPERM); 216 return (enterpgrp(targp, SCARG(uap, pgid), 0)); 217 } 218 219 /* ARGSUSED */ 220 int 221 setuid(p, uap, retval) 222 struct proc *p; 223 struct setuid_args /* { 224 syscallarg(uid_t) uid; 225 } */ *uap; 226 register_t *retval; 227 { 228 register struct pcred *pc = p->p_cred; 229 register uid_t uid; 230 int error; 231 232 uid = SCARG(uap, uid); 233 if (uid != pc->p_ruid && 234 (error = suser(pc->pc_ucred, &p->p_acflag))) 235 return (error); 236 /* 237 * Everything's okay, do it. 238 * Transfer proc count to new user. 239 * Copy credentials so other references do not see our changes. 240 */ 241 (void)chgproccnt(pc->p_ruid, -1); 242 (void)chgproccnt(uid, 1); 243 pc->pc_ucred = crcopy(pc->pc_ucred); 244 pc->pc_ucred->cr_uid = uid; 245 pc->p_ruid = uid; 246 pc->p_svuid = uid; 247 p->p_flag |= P_SUGID; 248 return (0); 249 } 250 251 /* ARGSUSED */ 252 int 253 seteuid(p, uap, retval) 254 struct proc *p; 255 struct seteuid_args /* { 256 syscallarg(uid_t) euid; 257 } */ *uap; 258 register_t *retval; 259 { 260 register struct pcred *pc = p->p_cred; 261 register uid_t euid; 262 int error; 263 264 euid = SCARG(uap, euid); 265 if (euid != pc->p_ruid && euid != pc->p_svuid && 266 (error = suser(pc->pc_ucred, &p->p_acflag))) 267 return (error); 268 /* 269 * Everything's okay, do it. Copy credentials so other references do 270 * not see our changes. 271 */ 272 pc->pc_ucred = crcopy(pc->pc_ucred); 273 pc->pc_ucred->cr_uid = euid; 274 p->p_flag |= P_SUGID; 275 return (0); 276 } 277 278 /* ARGSUSED */ 279 int 280 setgid(p, uap, retval) 281 struct proc *p; 282 struct setgid_args /* { 283 syscallarg(gid_t) gid; 284 } */ *uap; 285 register_t *retval; 286 { 287 register struct pcred *pc = p->p_cred; 288 register gid_t gid; 289 int error; 290 291 gid = SCARG(uap, gid); 292 if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag))) 293 return (error); 294 pc->pc_ucred = crcopy(pc->pc_ucred); 295 pc->pc_ucred->cr_groups[0] = gid; 296 pc->p_rgid = gid; 297 pc->p_svgid = gid; /* ??? */ 298 p->p_flag |= P_SUGID; 299 return (0); 300 } 301 302 /* ARGSUSED */ 303 int 304 setegid(p, uap, retval) 305 struct proc *p; 306 struct setegid_args /* { 307 syscallarg(gid_t) egid; 308 } */ *uap; 309 register_t *retval; 310 { 311 register struct pcred *pc = p->p_cred; 312 register gid_t egid; 313 int error; 314 315 egid = SCARG(uap, egid); 316 if (egid != pc->p_rgid && egid != pc->p_svgid && 317 (error = suser(pc->pc_ucred, &p->p_acflag))) 318 return (error); 319 pc->pc_ucred = crcopy(pc->pc_ucred); 320 pc->pc_ucred->cr_groups[0] = egid; 321 p->p_flag |= P_SUGID; 322 return (0); 323 } 324 325 /* ARGSUSED */ 326 int 327 setgroups(p, uap, retval) 328 struct proc *p; 329 struct setgroups_args /* { 330 syscallarg(u_int) gidsetsize; 331 syscallarg(gid_t *) gidset; 332 } */ *uap; 333 register_t *retval; 334 { 335 register struct pcred *pc = p->p_cred; 336 register u_int ngrp; 337 int error; 338 339 if (error = suser(pc->pc_ucred, &p->p_acflag)) 340 return (error); 341 ngrp = SCARG(uap, gidsetsize); 342 if (ngrp < 1 || ngrp > NGROUPS) 343 return (EINVAL); 344 pc->pc_ucred = crcopy(pc->pc_ucred); 345 if (error = copyin((caddr_t)SCARG(uap, gidset), 346 (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t))) 347 return (error); 348 pc->pc_ucred->cr_ngroups = ngrp; 349 p->p_flag |= P_SUGID; 350 return (0); 351 } 352 353 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 354 /* ARGSUSED */ 355 int 356 compat_43_setreuid(p, uap, retval) 357 register struct proc *p; 358 struct compat_43_setreuid_args /* { 359 syscallarg(int) ruid; 360 syscallarg(int) euid; 361 } */ *uap; 362 register_t *retval; 363 { 364 register struct pcred *pc = p->p_cred; 365 union { 366 struct setuid_args sa; 367 struct seteuid_args ea; 368 } args; 369 370 /* 371 * If ruid == euid then setreuid is being used to emulate setuid, 372 * just do it. 373 */ 374 if (SCARG(uap, ruid) != -1 && SCARG(uap, ruid) == SCARG(uap, euid)) { 375 SCARG(&args.sa, uid) = SCARG(uap, ruid); 376 return (setuid(p, &args.sa, retval)); 377 } 378 /* 379 * Otherwise we assume that the intent of setting ruid is to be 380 * able to get back ruid priviledge (i.e. swapping ruid and euid). 381 * So we make sure that we will be able to do so, but do not 382 * actually set the ruid. 383 */ 384 if (SCARG(uap, ruid) != (uid_t)-1 && SCARG(uap, ruid) != pc->p_ruid && 385 SCARG(uap, ruid) != pc->p_svuid) 386 return (EPERM); 387 if (SCARG(uap, euid) == (uid_t)-1) 388 return (0); 389 SCARG(&args.ea, euid) = SCARG(uap, euid); 390 return (seteuid(p, &args.ea, retval)); 391 } 392 393 /* ARGSUSED */ 394 int 395 compat_43_setregid(p, uap, retval) 396 register struct proc *p; 397 struct compat_43_setregid_args /* { 398 syscallarg(int) rgid; 399 syscallarg(int) egid; 400 } */ *uap; 401 register_t *retval; 402 { 403 register struct pcred *pc = p->p_cred; 404 union { 405 struct setgid_args sa; 406 struct setegid_args ea; 407 } args; 408 409 /* 410 * If rgid == egid then setreuid is being used to emulate setgid, 411 * just do it. 412 */ 413 if (SCARG(uap, rgid) != -1 && SCARG(uap, rgid) == SCARG(uap, egid)) { 414 SCARG(&args.sa, gid) = SCARG(uap, rgid); 415 return (setgid(p, &args.sa, retval)); 416 } 417 /* 418 * Otherwise we assume that the intent of setting rgid is to be 419 * able to get back rgid priviledge (i.e. swapping rgid and egid). 420 * So we make sure that we will be able to do so, but do not 421 * actually set the rgid. 422 */ 423 if (SCARG(uap, rgid) != (gid_t)-1 && SCARG(uap, rgid) != pc->p_rgid && 424 SCARG(uap, rgid) != pc->p_svgid) 425 return (EPERM); 426 if (SCARG(uap, egid) == (gid_t)-1) 427 return (0); 428 SCARG(&args.ea, egid) = SCARG(uap, egid); 429 return (setegid(p, &args.ea, retval)); 430 } 431 #endif /* defined(COMPAT_43) || defined(COMPAT_SUNOS) */ 432 433 /* 434 * Check if gid is a member of the group set. 435 */ 436 int 437 groupmember(gid, cred) 438 gid_t gid; 439 register struct ucred *cred; 440 { 441 register gid_t *gp; 442 gid_t *egp; 443 444 egp = &(cred->cr_groups[cred->cr_ngroups]); 445 for (gp = cred->cr_groups; gp < egp; gp++) 446 if (*gp == gid) 447 return (1); 448 return (0); 449 } 450 451 /* 452 * Test whether the specified credentials imply "super-user" 453 * privilege; if so, and we have accounting info, set the flag 454 * indicating use of super-powers. 455 * Returns 0 or error. 456 */ 457 int 458 suser(cred, acflag) 459 struct ucred *cred; 460 u_short *acflag; 461 { 462 if (cred->cr_uid == 0) { 463 if (acflag) 464 *acflag |= ASU; 465 return (0); 466 } 467 return (EPERM); 468 } 469 470 /* 471 * Allocate a zeroed cred structure. 472 */ 473 struct ucred * 474 crget() 475 { 476 register struct ucred *cr; 477 478 MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 479 bzero((caddr_t)cr, sizeof(*cr)); 480 cr->cr_ref = 1; 481 return (cr); 482 } 483 484 /* 485 * Free a cred structure. 486 * Throws away space when ref count gets to 0. 487 */ 488 void 489 crfree(cr) 490 struct ucred *cr; 491 { 492 int s; 493 494 s = splimp(); /* ??? */ 495 if (--cr->cr_ref == 0) 496 FREE((caddr_t)cr, M_CRED); 497 (void) splx(s); 498 } 499 500 /* 501 * Copy cred structure to a new one and free the old one. 502 */ 503 struct ucred * 504 crcopy(cr) 505 struct ucred *cr; 506 { 507 struct ucred *newcr; 508 509 if (cr->cr_ref == 1) 510 return (cr); 511 newcr = crget(); 512 *newcr = *cr; 513 crfree(cr); 514 newcr->cr_ref = 1; 515 return (newcr); 516 } 517 518 /* 519 * Dup cred struct to a new held one. 520 */ 521 struct ucred * 522 crdup(cr) 523 struct ucred *cr; 524 { 525 struct ucred *newcr; 526 527 newcr = crget(); 528 *newcr = *cr; 529 newcr->cr_ref = 1; 530 return (newcr); 531 } 532 533 /* 534 * Get login name, if available. 535 */ 536 /* ARGSUSED */ 537 int 538 getlogin(p, uap, retval) 539 struct proc *p; 540 struct getlogin_args /* { 541 syscallarg(char *) namebuf; 542 syscallarg(u_int) namelen; 543 } */ *uap; 544 register_t *retval; 545 { 546 547 if (SCARG(uap, namelen) > sizeof (p->p_pgrp->pg_session->s_login)) 548 SCARG(uap, namelen) = sizeof (p->p_pgrp->pg_session->s_login); 549 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 550 (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen))); 551 } 552 553 /* 554 * Set login name. 555 */ 556 /* ARGSUSED */ 557 int 558 setlogin(p, uap, retval) 559 struct proc *p; 560 struct setlogin_args /* { 561 syscallarg(char *) namebuf; 562 } */ *uap; 563 register_t *retval; 564 { 565 int error; 566 567 if (error = suser(p->p_ucred, &p->p_acflag)) 568 return (error); 569 error = copyinstr((caddr_t) SCARG(uap, namebuf), 570 (caddr_t) p->p_pgrp->pg_session->s_login, 571 sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0); 572 if (error == ENAMETOOLONG) 573 error = EINVAL; 574 return (error); 575 } 576