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