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.13 (Berkeley) 06/28/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 int *lp; 410 int error, ngrp, groups[NGROUPS]; 411 412 if (error = suser(u.u_cred, &u.u_acflag)) 413 return (error); 414 ngrp = uap->gidsetsize; 415 if (ngrp > NGROUPS) 416 return (EINVAL); 417 error = copyin((caddr_t)uap->gidset, (caddr_t)groups, 418 uap->gidsetsize * sizeof (groups[0])); 419 if (error) 420 return (error); 421 gp = u.u_cred->cr_groups; 422 for (lp = groups; lp < &groups[uap->gidsetsize]; ) 423 *gp++ = *lp++; 424 u.u_cred->cr_ngroups = ngrp; 425 return (0); 426 } 427 428 /* 429 * Check if gid is a member of the group set. 430 */ 431 groupmember(gid, cred) 432 gid_t gid; 433 register struct ucred *cred; 434 { 435 register gid_t *gp; 436 gid_t *egp; 437 438 egp = &(cred->cr_groups[cred->cr_ngroups]); 439 for (gp = cred->cr_groups; gp < egp; gp++) 440 if (*gp == gid) 441 return (1); 442 return (0); 443 } 444 445 /* 446 * Test if the current user is the super user. 447 */ 448 suser(cred, acflag) 449 struct ucred *cred; 450 short *acflag; 451 { 452 453 if (cred->cr_uid == 0) { 454 if (acflag) 455 *acflag |= ASU; 456 return (0); 457 } 458 return (EPERM); 459 } 460 461 /* 462 * Allocate a zeroed cred structure. 463 */ 464 struct ucred * 465 crget() 466 { 467 register struct ucred *cr; 468 469 MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 470 bzero((caddr_t)cr, sizeof(*cr)); 471 cr->cr_ref = 1; 472 return (cr); 473 } 474 475 /* 476 * Free a cred structure. 477 * Throws away space when ref count gets to 0. 478 */ 479 crfree(cr) 480 struct ucred *cr; 481 { 482 int s = splimp(); 483 484 if (--cr->cr_ref != 0) { 485 (void) splx(s); 486 return; 487 } 488 FREE((caddr_t)cr, M_CRED); 489 (void) splx(s); 490 } 491 492 /* 493 * Copy cred structure to a new one and free the old one. 494 */ 495 struct ucred * 496 crcopy(cr) 497 struct ucred *cr; 498 { 499 struct ucred *newcr; 500 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 /* ARGSUSED */ 527 getlogin(p, uap, retval) 528 struct proc *p; 529 struct args { 530 char *namebuf; 531 u_int namelen; 532 } *uap; 533 int *retval; 534 { 535 536 if (uap->namelen > sizeof (p->p_logname)) 537 uap->namelen = sizeof (p->p_logname); 538 return (copyout((caddr_t)p->p_logname, (caddr_t)uap->namebuf, 539 uap->namelen)); 540 } 541 542 /* 543 * Set login name. 544 */ 545 /* ARGSUSED */ 546 setlogin(p, uap, retval) 547 struct proc *p; 548 struct args { 549 char *namebuf; 550 } *uap; 551 int *retval; 552 { 553 int error; 554 555 if (error = suser(u.u_cred, &u.u_acflag)) 556 return (error); 557 error = copyinstr((caddr_t)uap->namebuf, (caddr_t)p->p_logname, 558 sizeof (p->p_logname) - 1, (int *) 0); 559 if (error == ENOENT) /* name too long */ 560 error = EINVAL; 561 return (error); 562 } 563