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