1 /* 2 * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993 3 * Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)kern_prot.c 8.4 (Berkeley) 01/06/94 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 & P_EXEC) 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 |= P_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 |= P_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 |= P_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 |= P_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 |= P_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 != (uid_t)-1 && uap->ruid != pc->p_ruid && 360 uap->ruid != pc->p_svuid) 361 return (EPERM); 362 if (uap->euid == (uid_t)-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 != (gid_t)-1 && uap->rgid != pc->p_rgid && 387 uap->rgid != pc->p_svgid) 388 return (EPERM); 389 if (uap->egid == (gid_t)-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; 453 454 s = splimp(); /* ??? */ 455 if (--cr->cr_ref == 0) 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