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