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