1 /* 2 * Copyright (c) 1982, 1986, 1989, 1990 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)kern_prot.c 7.14 (Berkeley) 07/23/90 8 */ 9 10 /* 11 * System calls related to processes and protection 12 */ 13 14 #include "param.h" 15 #include "acct.h" 16 #include "systm.h" 17 #include "user.h" 18 #include "proc.h" 19 #include "timeb.h" 20 #include "times.h" 21 #include "malloc.h" 22 23 /* ARGSUSED */ 24 getpid(p, uap, retval) 25 struct proc *p; 26 void *uap; 27 int *retval; 28 { 29 30 *retval = p->p_pid; 31 #ifdef COMPAT_43 32 retval[1] = p->p_ppid; 33 #endif 34 return (0); 35 } 36 37 /* ARGSUSED */ 38 getppid(p, uap, retval) 39 struct proc *p; 40 void *uap; 41 int *retval; 42 { 43 44 *retval = p->p_ppid; 45 return (0); 46 } 47 48 getpgrp(p, uap, retval) 49 struct proc *p; 50 struct args { 51 int pid; 52 } *uap; 53 int *retval; 54 { 55 56 if (uap->pid != 0 && (p = pfind(uap->pid)) == 0) 57 return (ESRCH); 58 *retval = p->p_pgrp->pg_id; 59 return (0); 60 } 61 62 /* ARGSUSED */ 63 getuid(p, uap, retval) 64 struct proc *p; 65 void *uap; 66 int *retval; 67 { 68 69 *retval = p->p_ruid; 70 #ifdef COMPAT_43 71 retval[1] = u.u_cred->cr_uid; 72 #endif 73 return (0); 74 } 75 76 /* ARGSUSED */ 77 geteuid(p, uap, retval) 78 struct proc *p; 79 void *uap; 80 int *retval; 81 { 82 83 *retval = u.u_cred->cr_uid; 84 return (0); 85 } 86 87 /* ARGSUSED */ 88 getgid(p, uap, retval) 89 struct proc *p; 90 void *uap; 91 int *retval; 92 { 93 94 *retval = p->p_rgid; 95 #ifdef COMPAT_43 96 retval[1] = u.u_cred->cr_groups[0]; 97 #endif 98 return (0); 99 } 100 101 /* 102 * Get effective group ID. 103 * The "egid" is groups[0], and thus could be obtained via getgroups; 104 * this is somewhat painful to do correctly in a library function, 105 * this the existence of this syscall. 106 */ 107 /* ARGSUSED */ 108 getegid(p, uap, retval) 109 struct proc *p; 110 void *uap; 111 int *retval; 112 { 113 114 *retval = u.u_cred->cr_groups[0]; 115 return (0); 116 } 117 118 getgroups(p, uap, retval) 119 struct proc *p; 120 register struct arg { 121 u_int gidsetsize; 122 int *gidset; /* XXX not yet POSIX */ 123 } *uap; 124 int *retval; 125 { 126 register gid_t *gp; 127 register int *lp; 128 int groups[NGROUPS]; 129 int error; 130 131 if (uap->gidsetsize == 0) { 132 *retval = u.u_cred->cr_ngroups; 133 return (0); 134 } 135 if (uap->gidsetsize < u.u_cred->cr_ngroups) 136 return (EINVAL); 137 uap->gidsetsize = u.u_cred->cr_ngroups; 138 gp = u.u_cred->cr_groups; 139 for (lp = groups; lp < &groups[uap->gidsetsize]; ) 140 *lp++ = *gp++; 141 if (error = copyout((caddr_t)groups, (caddr_t)uap->gidset, 142 uap->gidsetsize * sizeof (groups[0]))) 143 return (error); 144 *retval = uap->gidsetsize; 145 return (0); 146 } 147 148 /* ARGSUSED */ 149 setsid(p, uap, retval) 150 struct proc *p; 151 void *uap; 152 int *retval; 153 { 154 155 if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 156 return (EPERM); 157 } else { 158 pgmv(p, p->p_pid, 1); 159 *retval = p->p_pid; 160 return (0); 161 } 162 } 163 164 /* 165 * set process group (setpgrp/setpgid) 166 * 167 * caller does setpgrp(pid, pgid) 168 * 169 * pid must be caller or child of caller (ESRCH) 170 * if a child 171 * pid must be in same session (EPERM) 172 * pid can't have done an exec (EACCES) 173 * if pgid != pid 174 * there must exist some pid in same session having pgid (EPERM) 175 * pid must not be session leader (EPERM) 176 */ 177 /* ARGSUSED */ 178 setpgrp(cp, uap, retval) 179 struct proc *cp; 180 register struct args { 181 int pid; 182 int pgid; 183 } *uap; 184 int *retval; 185 { 186 register struct proc *p; 187 register struct pgrp *pgrp; 188 189 if (uap->pid != 0) { 190 if ((p = pfind(uap->pid)) == 0 || !inferior(p)) 191 return (ESRCH); 192 if (p->p_session != cp->p_session) 193 return (EPERM); 194 if (p->p_flag&SEXEC) 195 return (EACCES); 196 } else 197 p = cp; 198 if (SESS_LEADER(p)) 199 return (EPERM); 200 if (uap->pgid == 0) 201 uap->pgid = p->p_pid; 202 else if ((uap->pgid != p->p_pid) && 203 (((pgrp = pgfind(uap->pgid)) == 0) || 204 pgrp->pg_mem == NULL || 205 pgrp->pg_session != u.u_procp->p_session)) 206 return (EPERM); 207 /* 208 * done checking, now do it 209 */ 210 pgmv(p, uap->pgid, 0); 211 return (0); 212 } 213 214 /* ARGSUSED */ 215 setuid(p, uap, retval) 216 register struct proc *p; 217 struct args { 218 int uid; 219 } *uap; 220 int *retval; 221 { 222 register uid_t uid; 223 int error; 224 225 uid = uap->uid; 226 if (uid != p->p_ruid && (error = suser(u.u_cred, &u.u_acflag))) 227 return (error); 228 /* 229 * Everything's okay, do it. 230 * Copy credentials so other references do not 231 * see our changes. 232 */ 233 if (u.u_cred->cr_ref > 1) 234 u.u_cred = crcopy(u.u_cred); 235 u.u_cred->cr_uid = uid; 236 p->p_uid = uid; 237 p->p_ruid = uid; 238 p->p_svuid = uid; 239 return (0); 240 } 241 242 /* ARGSUSED */ 243 seteuid(p, uap, retval) 244 register struct proc *p; 245 struct args { 246 int euid; 247 } *uap; 248 int *retval; 249 { 250 register uid_t euid; 251 int error; 252 253 euid = uap->euid; 254 if (euid != p->p_ruid && euid != p->p_svuid && 255 (error = suser(u.u_cred, &u.u_acflag))) 256 return (error); 257 /* 258 * Everything's okay, do it. 259 * Copy credentials so other references do not 260 * see our changes. 261 */ 262 if (u.u_cred->cr_ref > 1) 263 u.u_cred = crcopy(u.u_cred); 264 u.u_cred->cr_uid = euid; 265 p->p_uid = euid; 266 return (0); 267 } 268 269 /* ARGSUSED */ 270 setgid(p, uap, retval) 271 struct proc *p; 272 struct args { 273 int gid; 274 } *uap; 275 int *retval; 276 { 277 register gid_t gid; 278 int error; 279 280 gid = uap->gid; 281 if (gid != p->p_rgid && (error = suser(u.u_cred, &u.u_acflag))) 282 return (error); 283 if (u.u_cred->cr_ref > 1) 284 u.u_cred = crcopy(u.u_cred); 285 p->p_rgid = gid; 286 u.u_cred->cr_groups[0] = gid; 287 p->p_svgid = gid; /* ??? */ 288 return (0); 289 } 290 291 /* ARGSUSED */ 292 setegid(p, uap, retval) 293 struct proc *p; 294 struct args { 295 int egid; 296 } *uap; 297 int *retval; 298 { 299 register gid_t egid; 300 int error; 301 302 egid = uap->egid; 303 if (egid != p->p_rgid && egid != p->p_svgid && 304 (error = suser(u.u_cred, &u.u_acflag))) 305 return (error); 306 if (u.u_cred->cr_ref > 1) 307 u.u_cred = crcopy(u.u_cred); 308 u.u_cred->cr_groups[0] = egid; 309 return (0); 310 } 311 312 #ifdef COMPAT_43 313 /* ARGSUSED */ 314 osetreuid(p, uap, retval) 315 register struct proc *p; 316 struct args { 317 int ruid; 318 int euid; 319 } *uap; 320 int *retval; 321 { 322 register uid_t ruid, euid; 323 int error; 324 325 if (uap->ruid == -1) 326 ruid = p->p_ruid; 327 else 328 ruid = uap->ruid; 329 /* 330 * Allow setting real uid to previous effective, 331 * for swapping real and effective. 332 * This should be: 333 * if (ruid != p->p_ruid && (error = suser(u.u_cred, &u.u_acflag))) 334 */ 335 if (ruid != p->p_ruid && ruid != u.u_cred->cr_uid /* XXX */ && 336 (error = suser(u.u_cred, &u.u_acflag))) 337 return (error); 338 if (uap->euid == -1) 339 euid = u.u_cred->cr_uid; 340 else 341 euid = uap->euid; 342 if (euid != u.u_cred->cr_uid && euid != p->p_ruid && 343 euid != p->p_svuid && (error = suser(u.u_cred, &u.u_acflag))) 344 return (error); 345 /* 346 * Everything's okay, do it. 347 * Copy credentials so other references do not 348 * see our changes. 349 */ 350 if (u.u_cred->cr_ref > 1) 351 u.u_cred = crcopy(u.u_cred); 352 u.u_cred->cr_uid = euid; 353 p->p_uid = euid; 354 p->p_ruid = ruid; 355 return (0); 356 } 357 358 /* ARGSUSED */ 359 osetregid(p, uap, retval) 360 struct proc *p; 361 struct args { 362 int rgid; 363 int egid; 364 } *uap; 365 int *retval; 366 { 367 register gid_t rgid, egid; 368 int error; 369 370 if (uap->rgid == -1) 371 rgid = p->p_rgid; 372 else 373 rgid = uap->rgid; 374 /* 375 * Allow setting real gid to previous effective, 376 * for swapping real and effective. This didn't really work 377 * correctly in 4.[23], but is preserved so old stuff doesn't fail. 378 * This should be: 379 * if (rgid != p->p_rgid && (error = suser(u.u_cred, &u.u_acflag))) 380 */ 381 if (rgid != p->p_rgid && rgid != u.u_cred->cr_groups[0] /* XXX */ && 382 (error = suser(u.u_cred, &u.u_acflag))) 383 return (error); 384 if (uap->egid == -1) 385 egid = u.u_cred->cr_groups[0]; 386 else 387 egid = uap->egid; 388 if (egid != u.u_cred->cr_groups[0] && egid != p->p_rgid && 389 egid != p->p_svgid && (error = suser(u.u_cred, &u.u_acflag))) 390 return (error); 391 if (u.u_cred->cr_ref > 1) 392 u.u_cred = crcopy(u.u_cred); 393 p->p_rgid = rgid; 394 u.u_cred->cr_groups[0] = egid; 395 return (0); 396 } 397 #endif 398 399 /* ARGSUSED */ 400 setgroups(p, uap, retval) 401 struct proc *p; 402 struct args { 403 u_int gidsetsize; 404 int *gidset; 405 } *uap; 406 int *retval; 407 { 408 register gid_t *gp; 409 register u_int ngrps; 410 register int *lp; 411 int error, groups[NGROUPS]; 412 413 if (error = suser(u.u_cred, &u.u_acflag)) 414 return (error); 415 if ((ngrps = uap->gidsetsize) > NGROUPS) 416 return (EINVAL); 417 if (error = copyin((caddr_t)uap->gidset, (caddr_t)groups, 418 ngrps * sizeof (groups[0]))) 419 return (error); 420 u.u_cred->cr_ngroups = ngrps; 421 /* convert from int's to gid_t's */ 422 for (gp = u.u_cred->cr_groups, lp = groups; ngrps--; *gp++ = *lp++) 423 /* void */; 424 return (0); 425 } 426 427 /* 428 * Check if gid is a member of the group set. 429 */ 430 groupmember(gid, cred) 431 gid_t gid; 432 register struct ucred *cred; 433 { 434 register gid_t *gp; 435 gid_t *egp; 436 437 egp = &(cred->cr_groups[cred->cr_ngroups]); 438 for (gp = cred->cr_groups; gp < egp; gp++) 439 if (*gp == gid) 440 return (1); 441 return (0); 442 } 443 444 /* 445 * Test if the current user is the super user. 446 */ 447 suser(cred, acflag) 448 struct ucred *cred; 449 short *acflag; 450 { 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 crfree(cr) 479 struct ucred *cr; 480 { 481 int s = splimp(); 482 483 if (--cr->cr_ref != 0) { 484 (void) splx(s); 485 return; 486 } 487 FREE((caddr_t)cr, M_CRED); 488 (void) splx(s); 489 } 490 491 /* 492 * Copy cred structure to a new one and free the old one. 493 */ 494 struct ucred * 495 crcopy(cr) 496 struct ucred *cr; 497 { 498 struct ucred *newcr; 499 500 newcr = crget(); 501 *newcr = *cr; 502 crfree(cr); 503 newcr->cr_ref = 1; 504 return (newcr); 505 } 506 507 /* 508 * Dup cred struct to a new held one. 509 */ 510 struct ucred * 511 crdup(cr) 512 struct ucred *cr; 513 { 514 struct ucred *newcr; 515 516 newcr = crget(); 517 *newcr = *cr; 518 newcr->cr_ref = 1; 519 return (newcr); 520 } 521 522 /* 523 * Get login name, if available. 524 */ 525 /* ARGSUSED */ 526 getlogin(p, uap, retval) 527 struct proc *p; 528 struct args { 529 char *namebuf; 530 u_int namelen; 531 } *uap; 532 int *retval; 533 { 534 535 if (uap->namelen > sizeof (p->p_logname)) 536 uap->namelen = sizeof (p->p_logname); 537 return (copyout((caddr_t)p->p_logname, (caddr_t)uap->namebuf, 538 uap->namelen)); 539 } 540 541 /* 542 * Set login name. 543 */ 544 /* ARGSUSED */ 545 setlogin(p, uap, retval) 546 struct proc *p; 547 struct args { 548 char *namebuf; 549 } *uap; 550 int *retval; 551 { 552 int error; 553 554 if (error = suser(u.u_cred, &u.u_acflag)) 555 return (error); 556 error = copyinstr((caddr_t)uap->namebuf, (caddr_t)p->p_logname, 557 sizeof (p->p_logname) - 1, (int *) 0); 558 if (error == ENOENT) /* name too long */ 559 error = EINVAL; 560 return (error); 561 } 562