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