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