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