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.28 (Berkeley) 07/19/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. 227 * Transfer proc count to new user. 228 * Copy credentials so other references do not see our changes. 229 */ 230 (void)chgproccnt(pc->p_ruid, -1); 231 (void)chgproccnt(uid, 1); 232 pc->pc_ucred = crcopy(pc->pc_ucred); 233 pc->pc_ucred->cr_uid = uid; 234 pc->p_ruid = uid; 235 pc->p_svuid = uid; 236 p->p_flag |= SUGID; 237 return (0); 238 } 239 240 struct seteuid_args { 241 uid_t euid; 242 }; 243 /* ARGSUSED */ 244 seteuid(p, uap, retval) 245 struct proc *p; 246 struct seteuid_args *uap; 247 int *retval; 248 { 249 register struct pcred *pc = p->p_cred; 250 register uid_t euid; 251 int error; 252 253 euid = uap->euid; 254 if (euid != pc->p_ruid && euid != pc->p_svuid && 255 (error = suser(pc->pc_ucred, &p->p_acflag))) 256 return (error); 257 /* 258 * Everything's okay, do it. Copy credentials so other references do 259 * not see our changes. 260 */ 261 pc->pc_ucred = crcopy(pc->pc_ucred); 262 pc->pc_ucred->cr_uid = euid; 263 p->p_flag |= SUGID; 264 return (0); 265 } 266 267 struct setgid_args { 268 gid_t gid; 269 }; 270 /* ARGSUSED */ 271 setgid(p, uap, retval) 272 struct proc *p; 273 struct setgid_args *uap; 274 int *retval; 275 { 276 register struct pcred *pc = p->p_cred; 277 register gid_t gid; 278 int error; 279 280 gid = uap->gid; 281 if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag))) 282 return (error); 283 pc->pc_ucred = crcopy(pc->pc_ucred); 284 pc->pc_ucred->cr_groups[0] = gid; 285 pc->p_rgid = gid; 286 pc->p_svgid = gid; /* ??? */ 287 p->p_flag |= SUGID; 288 return (0); 289 } 290 291 struct setegid_args { 292 gid_t egid; 293 }; 294 /* ARGSUSED */ 295 setegid(p, uap, retval) 296 struct proc *p; 297 struct setegid_args *uap; 298 int *retval; 299 { 300 register struct pcred *pc = p->p_cred; 301 register gid_t egid; 302 int error; 303 304 egid = uap->egid; 305 if (egid != pc->p_rgid && egid != pc->p_svgid && 306 (error = suser(pc->pc_ucred, &p->p_acflag))) 307 return (error); 308 pc->pc_ucred = crcopy(pc->pc_ucred); 309 pc->pc_ucred->cr_groups[0] = egid; 310 p->p_flag |= SUGID; 311 return (0); 312 } 313 314 struct setgroups_args { 315 u_int gidsetsize; 316 gid_t *gidset; 317 }; 318 /* ARGSUSED */ 319 setgroups(p, uap, retval) 320 struct proc *p; 321 struct setgroups_args *uap; 322 int *retval; 323 { 324 register struct pcred *pc = p->p_cred; 325 register u_int ngrp; 326 int error; 327 328 if (error = suser(pc->pc_ucred, &p->p_acflag)) 329 return (error); 330 if ((ngrp = uap->gidsetsize) > NGROUPS) 331 return (EINVAL); 332 pc->pc_ucred = crcopy(pc->pc_ucred); 333 if (error = copyin((caddr_t)uap->gidset, 334 (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t))) 335 return (error); 336 pc->pc_ucred->cr_ngroups = ngrp; 337 p->p_flag |= SUGID; 338 return (0); 339 } 340 341 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 342 struct setreuid_args { 343 int ruid; 344 int euid; 345 }; 346 /* ARGSUSED */ 347 osetreuid(p, uap, retval) 348 register struct proc *p; 349 struct setreuid_args *uap; 350 int *retval; 351 { 352 register struct pcred *pc = p->p_cred; 353 struct seteuid_args args; 354 355 /* 356 * we assume that the intent of setting ruid is to be able to get 357 * back ruid priviledge. So we make sure that we will be able to 358 * do so, but do not actually set the ruid. 359 */ 360 if (uap->ruid != -1 && uap->ruid != pc->p_ruid && 361 uap->ruid != pc->p_svuid) 362 return (EPERM); 363 if (uap->euid == -1) 364 return (0); 365 args.euid = uap->euid; 366 return (seteuid(p, &args, retval)); 367 } 368 369 struct setregid_args { 370 int rgid; 371 int egid; 372 }; 373 /* ARGSUSED */ 374 osetregid(p, uap, retval) 375 register struct proc *p; 376 struct setregid_args *uap; 377 int *retval; 378 { 379 register struct pcred *pc = p->p_cred; 380 struct setegid_args args; 381 382 /* 383 * we assume that the intent of setting rgid is to be able to get 384 * back rgid priviledge. So we make sure that we will be able to 385 * do so, but do not actually set the rgid. 386 */ 387 if (uap->rgid != -1 && uap->rgid != pc->p_rgid && 388 uap->rgid != pc->p_svgid) 389 return (EPERM); 390 if (uap->egid == -1) 391 return (0); 392 args.egid = uap->egid; 393 return (setegid(p, &args, retval)); 394 } 395 #endif /* defined(COMPAT_43) || defined(COMPAT_SUNOS) */ 396 397 /* 398 * Check if gid is a member of the group set. 399 */ 400 groupmember(gid, cred) 401 gid_t gid; 402 register struct ucred *cred; 403 { 404 register gid_t *gp; 405 gid_t *egp; 406 407 egp = &(cred->cr_groups[cred->cr_ngroups]); 408 for (gp = cred->cr_groups; gp < egp; gp++) 409 if (*gp == gid) 410 return (1); 411 return (0); 412 } 413 414 /* 415 * Test whether the specified credentials imply "super-user" 416 * privilege; if so, and we have accounting info, set the flag 417 * indicating use of super-powers. 418 * Returns 0 or error. 419 */ 420 suser(cred, acflag) 421 struct ucred *cred; 422 short *acflag; 423 { 424 if (cred->cr_uid == 0) { 425 if (acflag) 426 *acflag |= ASU; 427 return (0); 428 } 429 return (EPERM); 430 } 431 432 /* 433 * Allocate a zeroed cred structure. 434 */ 435 struct ucred * 436 crget() 437 { 438 register struct ucred *cr; 439 440 MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 441 bzero((caddr_t)cr, sizeof(*cr)); 442 cr->cr_ref = 1; 443 return (cr); 444 } 445 446 /* 447 * Free a cred structure. 448 * Throws away space when ref count gets to 0. 449 */ 450 crfree(cr) 451 struct ucred *cr; 452 { 453 int s = splimp(); /* ??? */ 454 455 if (--cr->cr_ref != 0) { 456 (void) splx(s); 457 return; 458 } 459 FREE((caddr_t)cr, M_CRED); 460 (void) splx(s); 461 } 462 463 /* 464 * Copy cred structure to a new one and free the old one. 465 */ 466 struct ucred * 467 crcopy(cr) 468 struct ucred *cr; 469 { 470 struct ucred *newcr; 471 472 if (cr->cr_ref == 1) 473 return (cr); 474 newcr = crget(); 475 *newcr = *cr; 476 crfree(cr); 477 newcr->cr_ref = 1; 478 return (newcr); 479 } 480 481 /* 482 * Dup cred struct to a new held one. 483 */ 484 struct ucred * 485 crdup(cr) 486 struct ucred *cr; 487 { 488 struct ucred *newcr; 489 490 newcr = crget(); 491 *newcr = *cr; 492 newcr->cr_ref = 1; 493 return (newcr); 494 } 495 496 /* 497 * Get login name, if available. 498 */ 499 struct getlogin_args { 500 char *namebuf; 501 u_int namelen; 502 }; 503 /* ARGSUSED */ 504 getlogin(p, uap, retval) 505 struct proc *p; 506 struct getlogin_args *uap; 507 int *retval; 508 { 509 510 if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login)) 511 uap->namelen = sizeof (p->p_pgrp->pg_session->s_login); 512 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 513 (caddr_t) uap->namebuf, uap->namelen)); 514 } 515 516 /* 517 * Set login name. 518 */ 519 struct setlogin_args { 520 char *namebuf; 521 }; 522 /* ARGSUSED */ 523 setlogin(p, uap, retval) 524 struct proc *p; 525 struct setlogin_args *uap; 526 int *retval; 527 { 528 int error; 529 530 if (error = suser(p->p_ucred, &p->p_acflag)) 531 return (error); 532 error = copyinstr((caddr_t) uap->namebuf, 533 (caddr_t) p->p_pgrp->pg_session->s_login, 534 sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0); 535 if (error == ENAMETOOLONG) 536 error = EINVAL; 537 return (error); 538 } 539