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.25 (Berkeley) 07/10/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 int *gidset; /* XXX not yet POSIX */ 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 gid_t *gp; 129 register int *lp; 130 register u_int ngrp; 131 int groups[NGROUPS]; 132 int error; 133 134 if ((ngrp = uap->gidsetsize) == 0) { 135 *retval = pc->pc_ucred->cr_ngroups; 136 return (0); 137 } 138 if (ngrp < pc->pc_ucred->cr_ngroups) 139 return (EINVAL); 140 ngrp = pc->pc_ucred->cr_ngroups; 141 for (gp = pc->pc_ucred->cr_groups, lp = groups; lp < &groups[ngrp]; ) 142 *lp++ = *gp++; 143 if (error = copyout((caddr_t)groups, (caddr_t)uap->gidset, 144 ngrp * sizeof (groups[0]))) 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 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&SEXEC) 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 enterpgrp(targp, uap->pgid, 0); 210 return (0); 211 } 212 213 struct setuid_args { 214 int uid; 215 }; 216 /* ARGSUSED */ 217 setuid(p, uap, retval) 218 struct proc *p; 219 struct setuid_args *uap; 220 int *retval; 221 { 222 register struct pcred *pc = p->p_cred; 223 register uid_t uid; 224 int error; 225 226 uid = uap->uid; 227 if (uid != pc->p_ruid && 228 (error = suser(pc->pc_ucred, &p->p_acflag))) 229 return (error); 230 /* 231 * Everything's okay, do it. Copy credentials so other references do 232 * not see our changes. 233 */ 234 pc->pc_ucred = crcopy(pc->pc_ucred); 235 pc->pc_ucred->cr_uid = uid; 236 pc->p_ruid = uid; 237 pc->p_svuid = uid; 238 p->p_flag |= SUGID; 239 return (0); 240 } 241 242 struct seteuid_args { 243 int euid; 244 }; 245 /* ARGSUSED */ 246 seteuid(p, uap, retval) 247 struct proc *p; 248 struct seteuid_args *uap; 249 int *retval; 250 { 251 register struct pcred *pc = p->p_cred; 252 register uid_t euid; 253 int error; 254 255 euid = uap->euid; 256 if (euid != pc->p_ruid && euid != pc->p_svuid && 257 (error = suser(pc->pc_ucred, &p->p_acflag))) 258 return (error); 259 /* 260 * Everything's okay, do it. Copy credentials so other references do 261 * not see our changes. 262 */ 263 pc->pc_ucred = crcopy(pc->pc_ucred); 264 pc->pc_ucred->cr_uid = euid; 265 p->p_flag |= SUGID; 266 return (0); 267 } 268 269 struct setgid_args { 270 int gid; 271 }; 272 /* ARGSUSED */ 273 setgid(p, uap, retval) 274 struct proc *p; 275 struct setgid_args *uap; 276 int *retval; 277 { 278 register struct pcred *pc = p->p_cred; 279 register gid_t gid; 280 int error; 281 282 gid = uap->gid; 283 if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag))) 284 return (error); 285 pc->pc_ucred = crcopy(pc->pc_ucred); 286 pc->pc_ucred->cr_groups[0] = gid; 287 pc->p_rgid = gid; 288 pc->p_svgid = gid; /* ??? */ 289 p->p_flag |= SUGID; 290 return (0); 291 } 292 293 struct setegid_args { 294 int egid; 295 }; 296 /* ARGSUSED */ 297 setegid(p, uap, retval) 298 struct proc *p; 299 struct setegid_args *uap; 300 int *retval; 301 { 302 register struct pcred *pc = p->p_cred; 303 register gid_t egid; 304 int error; 305 306 egid = uap->egid; 307 if (egid != pc->p_rgid && egid != pc->p_svgid && 308 (error = suser(pc->pc_ucred, &p->p_acflag))) 309 return (error); 310 pc->pc_ucred = crcopy(pc->pc_ucred); 311 pc->pc_ucred->cr_groups[0] = egid; 312 p->p_flag |= SUGID; 313 return (0); 314 } 315 316 struct setgroups_args { 317 u_int gidsetsize; 318 int *gidset; 319 }; 320 /* ARGSUSED */ 321 setgroups(p, uap, retval) 322 struct proc *p; 323 struct setgroups_args *uap; 324 int *retval; 325 { 326 register struct pcred *pc = p->p_cred; 327 register gid_t *gp; 328 register u_int ngrp; 329 register int *lp; 330 int error, groups[NGROUPS]; 331 332 if (error = suser(pc->pc_ucred, &p->p_acflag)) 333 return (error); 334 if ((ngrp = uap->gidsetsize) > NGROUPS) 335 return (EINVAL); 336 if (error = copyin((caddr_t)uap->gidset, (caddr_t)groups, 337 ngrp * sizeof (groups[0]))) 338 return (error); 339 pc->pc_ucred = crcopy(pc->pc_ucred); 340 pc->pc_ucred->cr_ngroups = ngrp; 341 /* convert from int's to gid_t's */ 342 for (gp = pc->pc_ucred->cr_groups, lp = groups; ngrp--; ) 343 *gp++ = *lp++; 344 p->p_flag |= SUGID; 345 return (0); 346 } 347 348 /* 349 * Check if gid is a member of the group set. 350 */ 351 groupmember(gid, cred) 352 gid_t gid; 353 register struct ucred *cred; 354 { 355 register gid_t *gp; 356 gid_t *egp; 357 358 egp = &(cred->cr_groups[cred->cr_ngroups]); 359 for (gp = cred->cr_groups; gp < egp; gp++) 360 if (*gp == gid) 361 return (1); 362 return (0); 363 } 364 365 /* 366 * Test whether the specified credentials imply "super-user" 367 * privilege; if so, and we have accounting info, set the flag 368 * indicating use of super-powers. 369 * Returns 0 or error. 370 */ 371 suser(cred, acflag) 372 struct ucred *cred; 373 short *acflag; 374 { 375 if (cred->cr_uid == 0) { 376 if (acflag) 377 *acflag |= ASU; 378 return (0); 379 } 380 return (EPERM); 381 } 382 383 /* 384 * Allocate a zeroed cred structure. 385 */ 386 struct ucred * 387 crget() 388 { 389 register struct ucred *cr; 390 391 MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 392 bzero((caddr_t)cr, sizeof(*cr)); 393 cr->cr_ref = 1; 394 return (cr); 395 } 396 397 /* 398 * Free a cred structure. 399 * Throws away space when ref count gets to 0. 400 */ 401 crfree(cr) 402 struct ucred *cr; 403 { 404 int s = splimp(); /* ??? */ 405 406 if (--cr->cr_ref != 0) { 407 (void) splx(s); 408 return; 409 } 410 FREE((caddr_t)cr, M_CRED); 411 (void) splx(s); 412 } 413 414 /* 415 * Copy cred structure to a new one and free the old one. 416 */ 417 struct ucred * 418 crcopy(cr) 419 struct ucred *cr; 420 { 421 struct ucred *newcr; 422 423 if (cr->cr_ref == 1) 424 return (cr); 425 newcr = crget(); 426 *newcr = *cr; 427 crfree(cr); 428 newcr->cr_ref = 1; 429 return (newcr); 430 } 431 432 /* 433 * Dup cred struct to a new held one. 434 */ 435 struct ucred * 436 crdup(cr) 437 struct ucred *cr; 438 { 439 struct ucred *newcr; 440 441 newcr = crget(); 442 *newcr = *cr; 443 newcr->cr_ref = 1; 444 return (newcr); 445 } 446 447 /* 448 * Get login name, if available. 449 */ 450 struct getlogin_args { 451 char *namebuf; 452 u_int namelen; 453 }; 454 /* ARGSUSED */ 455 getlogin(p, uap, retval) 456 struct proc *p; 457 struct getlogin_args *uap; 458 int *retval; 459 { 460 461 if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login)) 462 uap->namelen = sizeof (p->p_pgrp->pg_session->s_login); 463 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 464 (caddr_t) uap->namebuf, uap->namelen)); 465 } 466 467 /* 468 * Set login name. 469 */ 470 struct setlogin_args { 471 char *namebuf; 472 }; 473 /* ARGSUSED */ 474 setlogin(p, uap, retval) 475 struct proc *p; 476 struct setlogin_args *uap; 477 int *retval; 478 { 479 int error; 480 481 if (error = suser(p->p_ucred, &p->p_acflag)) 482 return (error); 483 error = copyinstr((caddr_t) uap->namebuf, 484 (caddr_t) p->p_pgrp->pg_session->s_login, 485 sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0); 486 if (error == ENAMETOOLONG) 487 error = EINVAL; 488 return (error); 489 } 490