1 /* 2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)kern_prot.c 7.8 (Berkeley) 03/31/90 18 */ 19 20 /* 21 * System calls related to processes and protection 22 */ 23 24 #include "param.h" 25 #include "acct.h" 26 #include "systm.h" 27 #include "user.h" 28 #include "proc.h" 29 #include "timeb.h" 30 #include "times.h" 31 #include "reboot.h" 32 #include "mount.h" 33 #include "buf.h" 34 #include "../ufs/quota.h" 35 #include "malloc.h" 36 37 #include "machine/reg.h" 38 39 getpid() 40 { 41 42 u.u_r.r_val1 = u.u_procp->p_pid; 43 u.u_r.r_val2 = u.u_procp->p_ppid; 44 } 45 46 getpgrp() 47 { 48 register struct a { 49 int pid; 50 } *uap = (struct a *)u.u_ap; 51 register struct proc *p; 52 53 if (uap->pid == 0) 54 p = u.u_procp; 55 else if ((p = pfind(uap->pid)) == 0) { 56 u.u_error = ESRCH; 57 return; 58 } 59 u.u_r.r_val1 = p->p_pgrp->pg_id; 60 } 61 62 getuid() 63 { 64 65 u.u_r.r_val1 = u.u_procp->p_ruid; 66 u.u_r.r_val2 = u.u_cred->cr_uid; 67 } 68 69 getgid() 70 { 71 72 u.u_r.r_val1 = u.u_procp->p_rgid; 73 u.u_r.r_val2 = u.u_cred->cr_groups[0]; 74 } 75 76 getgroups() 77 { 78 register struct a { 79 u_int gidsetsize; 80 int *gidset; 81 } *uap = (struct a *)u.u_ap; 82 register gid_t *gp; 83 register int *lp; 84 int groups[NGROUPS]; 85 86 if (uap->gidsetsize == 0) { 87 u.u_r.r_val1 = u.u_cred->cr_ngroups; 88 return; 89 } 90 if (uap->gidsetsize < u.u_cred->cr_ngroups) { 91 u.u_error = EINVAL; 92 return; 93 } 94 uap->gidsetsize = u.u_cred->cr_ngroups; 95 gp = u.u_cred->cr_groups; 96 for (lp = groups; lp < &groups[uap->gidsetsize]; ) 97 *lp++ = *gp++; 98 u.u_error = copyout((caddr_t)groups, (caddr_t)uap->gidset, 99 uap->gidsetsize * sizeof (groups[0])); 100 if (u.u_error) 101 return; 102 u.u_r.r_val1 = uap->gidsetsize; 103 } 104 105 setsid() 106 { 107 register struct proc *p = u.u_procp; 108 109 if ((p->p_pgid == p->p_pid) || pgfind(p->p_pid)) 110 u.u_error = EPERM; 111 else { 112 pgmv(p, p->p_pid, 1); 113 u.u_r.r_val1 = p->p_pid; 114 } 115 return; 116 } 117 118 /* 119 * set process group 120 * 121 * caller does setpgrp(pid, pgid) 122 * 123 * pid must be caller or child of caller (ESRCH) 124 * if a child 125 * pid must be in same session (EPERM) 126 * pid can't have done an exec (EACCES) 127 * if pgid != pid 128 * there must exist some pid in same session having pgid (EPERM) 129 * pid must not be session leader (EPERM) 130 */ 131 setpgrp() 132 { 133 register struct a { 134 int pid; 135 int pgid; 136 } *uap = (struct a *)u.u_ap; 137 register struct proc *p; 138 register struct pgrp *pgrp; 139 140 if (uap->pid == 0) 141 p = u.u_procp; 142 else if ((p = pfind(uap->pid)) == 0 || !inferior(p)) { 143 u.u_error = ESRCH; 144 return; 145 } 146 else if (p != u.u_procp) { 147 if (p->p_session != u.u_procp->p_session) { 148 u.u_error = EPERM; 149 return; 150 } 151 if (p->p_flag&SEXEC) { 152 u.u_error = EACCES; 153 return; 154 } 155 } 156 if (SESS_LEADER(p)) { 157 u.u_error = EPERM; 158 return; 159 } 160 if (uap->pgid == 0) 161 uap->pgid = p->p_pid; 162 else if ((uap->pgid != p->p_pid) && 163 (((pgrp = pgfind(uap->pgid)) == 0) || 164 pgrp->pg_mem == NULL || 165 pgrp->pg_session != u.u_procp->p_session)) { 166 u.u_error = EPERM; 167 return; 168 } 169 /* 170 * done checking, now doit 171 */ 172 pgmv(p, uap->pgid, 0); 173 } 174 175 setreuid() 176 { 177 struct a { 178 int ruid; 179 int euid; 180 } *uap; 181 register struct proc *p = u.u_procp; 182 register int ruid, euid; 183 184 uap = (struct a *)u.u_ap; 185 ruid = uap->ruid; 186 if (ruid == -1) 187 ruid = p->p_ruid; 188 #ifdef COMPAT_43 189 if (ruid != p->p_ruid && ruid != u.u_cred->cr_uid /* XXX */ && 190 (u.u_error = suser(u.u_cred, &u.u_acflag))) 191 #else 192 if (ruid != p->p_ruid && (u.u_error = suser(u.u_cred, &u.u_acflag))) 193 #endif 194 return; 195 euid = uap->euid; 196 if (euid == -1) 197 euid = u.u_cred->cr_uid; 198 if (euid != u.u_cred->cr_uid && euid != p->p_ruid && 199 euid != p->p_svuid && (u.u_error = suser(u.u_cred, &u.u_acflag))) 200 return; 201 /* 202 * Everything's okay, do it. 203 * Copy credentials so other references do not 204 * see our changes. 205 */ 206 #ifdef QUOTA 207 if (u.u_quota->q_uid != ruid) { 208 qclean(); 209 qstart(getquota((uid_t)ruid, 0, 0)); 210 } 211 #endif 212 if (u.u_cred->cr_ref > 1) 213 u.u_cred = crcopy(u.u_cred); 214 u.u_cred->cr_uid = euid; 215 p->p_uid = euid; 216 p->p_ruid = ruid; 217 } 218 219 setregid() 220 { 221 register struct a { 222 int rgid; 223 int egid; 224 } *uap; 225 register int rgid, egid; 226 register struct proc *p = u.u_procp; 227 228 uap = (struct a *)u.u_ap; 229 rgid = uap->rgid; 230 if (rgid == -1) 231 rgid = p->p_rgid; 232 #ifdef COMPAT_43_XXX 233 if (rgid != p->p_rgid && rgid != u.u_cred->cr_groups[0] /* XXX */ && 234 (u.u_error = suser(u.u_cred, &u.u_acflag))) 235 #else 236 if (rgid != p->p_rgid && (u.u_error = suser(u.u_cred, &u.u_acflag))) 237 #endif 238 return; 239 egid = uap->egid; 240 if (egid == -1) 241 egid = u.u_cred->cr_groups[0]; 242 if (egid != u.u_cred->cr_groups[0] && egid != p->p_rgid && 243 egid != p->p_svgid && (u.u_error = suser(u.u_cred, &u.u_acflag))) 244 return; 245 if (u.u_cred->cr_ref > 1) 246 u.u_cred = crcopy(u.u_cred); 247 p->p_rgid = rgid; 248 u.u_cred->cr_groups[0] = egid; 249 } 250 251 setgroups() 252 { 253 register struct a { 254 u_int gidsetsize; 255 int *gidset; 256 } *uap = (struct a *)u.u_ap; 257 register gid_t *gp; 258 register int *lp; 259 int ngrp, groups[NGROUPS]; 260 261 if (u.u_error = suser(u.u_cred, &u.u_acflag)) 262 return; 263 ngrp = uap->gidsetsize; 264 if (ngrp > NGROUPS) { 265 u.u_error = EINVAL; 266 return; 267 } 268 u.u_error = copyin((caddr_t)uap->gidset, (caddr_t)groups, 269 uap->gidsetsize * sizeof (groups[0])); 270 if (u.u_error) 271 return; 272 gp = u.u_cred->cr_groups; 273 for (lp = groups; lp < &groups[uap->gidsetsize]; ) 274 *gp++ = *lp++; 275 u.u_cred->cr_ngroups = ngrp; 276 } 277 278 /* 279 * Check if gid is a member of the group set. 280 */ 281 groupmember(gid, cred) 282 gid_t gid; 283 register struct ucred *cred; 284 { 285 register gid_t *gp; 286 gid_t *egp; 287 288 egp = &(cred->cr_groups[cred->cr_ngroups]); 289 for (gp = cred->cr_groups; gp < egp; gp++) 290 if (*gp == gid) 291 return (1); 292 return (0); 293 } 294 295 /* 296 * Test if the current user is the super user. 297 */ 298 suser(cred, acflag) 299 struct ucred *cred; 300 short *acflag; 301 { 302 303 if (cred->cr_uid == 0) { 304 if (acflag) 305 *acflag |= ASU; 306 return (0); 307 } 308 return (EPERM); 309 } 310 311 /* 312 * Allocate a zeroed cred structure. 313 */ 314 struct ucred * 315 crget() 316 { 317 register struct ucred *cr; 318 319 MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 320 bzero((caddr_t)cr, sizeof(*cr)); 321 cr->cr_ref = 1; 322 return(cr); 323 } 324 325 /* 326 * Free a cred structure. 327 * Throws away space when ref count gets to 0. 328 */ 329 crfree(cr) 330 struct ucred *cr; 331 { 332 int s = splimp(); 333 334 if (--cr->cr_ref != 0) { 335 (void) splx(s); 336 return; 337 } 338 FREE((caddr_t)cr, M_CRED); 339 (void) splx(s); 340 } 341 342 /* 343 * Copy cred structure to a new one and free the old one. 344 */ 345 struct ucred * 346 crcopy(cr) 347 struct ucred *cr; 348 { 349 struct ucred *newcr; 350 351 newcr = crget(); 352 *newcr = *cr; 353 crfree(cr); 354 newcr->cr_ref = 1; 355 return(newcr); 356 } 357 358 /* 359 * Dup cred struct to a new held one. 360 */ 361 struct ucred * 362 crdup(cr) 363 struct ucred *cr; 364 { 365 struct ucred *newcr; 366 367 newcr = crget(); 368 *newcr = *cr; 369 newcr->cr_ref = 1; 370 return(newcr); 371 } 372 373 /* 374 * Get login name, if available. 375 */ 376 getlogin() 377 { 378 struct a { 379 char *namebuf; 380 u_int namelen; 381 } *uap = (struct a *)u.u_ap; 382 383 if (uap->namelen > sizeof (u.u_procp->p_logname)) 384 uap->namelen = sizeof (u.u_procp->p_logname); 385 u.u_error = copyout((caddr_t)u.u_procp->p_logname, 386 (caddr_t)uap->namebuf, uap->namelen); 387 } 388 389 /* 390 * Set login name. 391 */ 392 setlogin() 393 { 394 struct a { 395 char *namebuf; 396 } *uap = (struct a *)u.u_ap; 397 int error; 398 399 if (u.u_error = suser(u.u_cred, &u.u_acflag)) 400 return; 401 error = copyinstr((caddr_t)uap->namebuf, (caddr_t)u.u_procp->p_logname, 402 sizeof (u.u_procp->p_logname) - 1, (int *) 0); 403 if (error == ENOENT) /* name too long */ 404 error = EINVAL; 405 u.u_error = error; 406 } 407