1 /* $NetBSD: kern_prot.c,v 1.84 2004/05/04 21:27:28 pk Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * (c) UNIX System Laboratories, Inc. 7 * All or some portions of this file are derived from material licensed 8 * to the University of California by American Telephone and Telegraph 9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 10 * the permission of UNIX System Laboratories, Inc. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)kern_prot.c 8.9 (Berkeley) 2/14/95 37 */ 38 39 /* 40 * System calls related to processes and protection 41 */ 42 43 #include <sys/cdefs.h> 44 __KERNEL_RCSID(0, "$NetBSD: kern_prot.c,v 1.84 2004/05/04 21:27:28 pk Exp $"); 45 46 #include "opt_compat_43.h" 47 48 #include <sys/param.h> 49 #include <sys/acct.h> 50 #include <sys/systm.h> 51 #include <sys/ucred.h> 52 #include <sys/proc.h> 53 #include <sys/timeb.h> 54 #include <sys/times.h> 55 #include <sys/pool.h> 56 #include <sys/syslog.h> 57 #include <sys/resourcevar.h> 58 59 #include <sys/mount.h> 60 #include <sys/sa.h> 61 #include <sys/syscallargs.h> 62 63 POOL_INIT(cred_pool, sizeof(struct ucred), 0, 0, 0, "credpl", 64 &pool_allocator_nointr); 65 66 int sys_getpid(struct lwp *, void *, register_t *); 67 int sys_getpid_with_ppid(struct lwp *, void *, register_t *); 68 int sys_getuid(struct lwp *, void *, register_t *); 69 int sys_getuid_with_euid(struct lwp *, void *, register_t *); 70 int sys_getgid(struct lwp *, void *, register_t *); 71 int sys_getgid_with_egid(struct lwp *, void *, register_t *); 72 73 /* ARGSUSED */ 74 int 75 sys_getpid(struct lwp *l, void *v, register_t *retval) 76 { 77 struct proc *p = l->l_proc; 78 79 *retval = p->p_pid; 80 return (0); 81 } 82 83 /* ARGSUSED */ 84 int 85 sys_getpid_with_ppid(struct lwp *l, void *v, register_t *retval) 86 { 87 struct proc *p = l->l_proc; 88 89 retval[0] = p->p_pid; 90 retval[1] = p->p_pptr->p_pid; 91 return (0); 92 } 93 94 /* ARGSUSED */ 95 int 96 sys_getppid(struct lwp *l, void *v, register_t *retval) 97 { 98 struct proc *p = l->l_proc; 99 100 *retval = p->p_pptr->p_pid; 101 return (0); 102 } 103 104 /* Get process group ID; note that POSIX getpgrp takes no parameter */ 105 int 106 sys_getpgrp(struct lwp *l, void *v, register_t *retval) 107 { 108 struct proc *p = l->l_proc; 109 110 *retval = p->p_pgrp->pg_id; 111 return (0); 112 } 113 114 /* 115 * Return the process group ID of the session leader (session ID) 116 * for the specified process. 117 */ 118 int 119 sys_getsid(struct lwp *l, void *v, register_t *retval) 120 { 121 struct sys_getsid_args /* { 122 syscalldarg(pid_t) pid; 123 } */ *uap = v; 124 struct proc *p = l->l_proc; 125 126 if (SCARG(uap, pid) == 0) 127 goto found; 128 if ((p = pfind(SCARG(uap, pid))) == 0) 129 return (ESRCH); 130 found: 131 *retval = p->p_session->s_sid; 132 return (0); 133 } 134 135 int 136 sys_getpgid(struct lwp *l, void *v, register_t *retval) 137 { 138 struct sys_getpgid_args /* { 139 syscallarg(pid_t) pid; 140 } */ *uap = v; 141 struct proc *p = l->l_proc; 142 143 if (SCARG(uap, pid) == 0) 144 goto found; 145 if ((p = pfind(SCARG(uap, pid))) == 0) 146 return (ESRCH); 147 found: 148 *retval = p->p_pgid; 149 return (0); 150 } 151 152 /* ARGSUSED */ 153 int 154 sys_getuid(struct lwp *l, void *v, register_t *retval) 155 { 156 struct proc *p = l->l_proc; 157 158 *retval = p->p_cred->p_ruid; 159 return (0); 160 } 161 162 /* ARGSUSED */ 163 int 164 sys_getuid_with_euid(struct lwp *l, void *v, register_t *retval) 165 { 166 struct proc *p = l->l_proc; 167 168 retval[0] = p->p_cred->p_ruid; 169 retval[1] = p->p_ucred->cr_uid; 170 return (0); 171 } 172 173 /* ARGSUSED */ 174 int 175 sys_geteuid(struct lwp *l, void *v, register_t *retval) 176 { 177 struct proc *p = l->l_proc; 178 179 *retval = p->p_ucred->cr_uid; 180 return (0); 181 } 182 183 /* ARGSUSED */ 184 int 185 sys_getgid(struct lwp *l, void *v, register_t *retval) 186 { 187 struct proc *p = l->l_proc; 188 189 *retval = p->p_cred->p_rgid; 190 return (0); 191 } 192 193 /* ARGSUSED */ 194 int 195 sys_getgid_with_egid(struct lwp *l, void *v, register_t *retval) 196 { 197 struct proc *p = l->l_proc; 198 199 retval[0] = p->p_cred->p_rgid; 200 retval[1] = p->p_ucred->cr_gid; 201 return (0); 202 } 203 204 /* 205 * Get effective group ID. The "egid" is groups[0], and could be obtained 206 * via getgroups. This syscall exists because it is somewhat painful to do 207 * correctly in a library function. 208 */ 209 /* ARGSUSED */ 210 int 211 sys_getegid(struct lwp *l, void *v, register_t *retval) 212 { 213 struct proc *p = l->l_proc; 214 215 *retval = p->p_ucred->cr_gid; 216 return (0); 217 } 218 219 int 220 sys_getgroups(struct lwp *l, void *v, register_t *retval) 221 { 222 struct sys_getgroups_args /* { 223 syscallarg(int) gidsetsize; 224 syscallarg(gid_t *) gidset; 225 } */ *uap = v; 226 struct proc *p = l->l_proc; 227 struct pcred *pc = p->p_cred; 228 u_int ngrp; 229 int error; 230 231 if (SCARG(uap, gidsetsize) == 0) { 232 *retval = pc->pc_ucred->cr_ngroups; 233 return (0); 234 } else if (SCARG(uap, gidsetsize) < 0) 235 return (EINVAL); 236 ngrp = SCARG(uap, gidsetsize); 237 if (ngrp < pc->pc_ucred->cr_ngroups) 238 return (EINVAL); 239 ngrp = pc->pc_ucred->cr_ngroups; 240 error = copyout((caddr_t)pc->pc_ucred->cr_groups, 241 (caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t)); 242 if (error) 243 return (error); 244 *retval = ngrp; 245 return (0); 246 } 247 248 /* ARGSUSED */ 249 int 250 sys_setsid(struct lwp *l, void *v, register_t *retval) 251 { 252 struct proc *p = l->l_proc; 253 254 if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 255 return (EPERM); 256 } else { 257 (void)enterpgrp(p, p->p_pid, 1); 258 *retval = p->p_pid; 259 return (0); 260 } 261 } 262 263 /* 264 * set process group (setpgid/old setpgrp) 265 * 266 * caller does setpgid(targpid, targpgid) 267 * 268 * pgid must be in valid range (EINVAL) 269 * pid must be caller or child of caller (ESRCH) 270 * if a child 271 * pid must be in same session (EPERM) 272 * pid can't have done an exec (EACCES) 273 * if pgid != pid 274 * there must exist some pid in same session having pgid (EPERM) 275 * pid must not be session leader (EPERM) 276 * 277 * Permission checks now in enterpgrp() 278 */ 279 /* ARGSUSED */ 280 int 281 sys_setpgid(struct lwp *l, void *v, register_t *retval) 282 { 283 struct sys_setpgid_args /* { 284 syscallarg(int) pid; 285 syscallarg(int) pgid; 286 } */ *uap = v; 287 struct proc *curp = l->l_proc; 288 struct proc *targp; /* target process */ 289 290 if (SCARG(uap, pgid) < 0) 291 return EINVAL; 292 293 /* XXX MP - there is a horrid race here with targp exiting! */ 294 if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != curp->p_pid) { 295 targp = pfind(SCARG(uap, pid)); 296 if (targp == NULL) 297 return ESRCH; 298 } else 299 targp = curp; 300 301 if (SCARG(uap, pgid) == 0) 302 SCARG(uap, pgid) = targp->p_pid; 303 return enterpgrp(targp, SCARG(uap, pgid), 0); 304 } 305 306 /* 307 * Set real, effective and saved uids to the requested values. 308 * non-root callers can only ever change uids to values that match 309 * one of the processes current uid values. 310 * This is further restricted by the flags argument. 311 */ 312 313 int 314 do_setresuid(struct lwp *l, uid_t r, uid_t e, uid_t sv, u_int flags) 315 { 316 int error; 317 struct proc *p = l->l_proc; 318 struct pcred *pcred = p->p_cred; 319 struct ucred *cred = pcred->pc_ucred; 320 321 /* Superuser can do anything it wants to.... */ 322 error = suser(cred, &p->p_acflag); 323 if (error) { 324 /* Otherwise check new value is one of the allowed 325 existing values. */ 326 if (r != -1 && !((flags & ID_R_EQ_R) && r == pcred->p_ruid) 327 && !((flags & ID_R_EQ_E) && r == cred->cr_uid) 328 && !((flags & ID_R_EQ_S) && r == pcred->p_svuid)) 329 return error; 330 if (e != -1 && !((flags & ID_E_EQ_R) && e == pcred->p_ruid) 331 && !((flags & ID_E_EQ_E) && e == cred->cr_uid) 332 && !((flags & ID_E_EQ_S) && e == pcred->p_svuid)) 333 return error; 334 if (sv != -1 && !((flags & ID_S_EQ_R) && sv == pcred->p_ruid) 335 && !((flags & ID_S_EQ_E) && sv == cred->cr_uid) 336 && !((flags & ID_S_EQ_S) && sv == pcred->p_svuid)) 337 return error; 338 } 339 340 /* If nothing has changed, short circuit the request */ 341 if ((r == -1 || r == pcred->p_ruid) 342 && (e == -1 || e == cred->cr_uid) 343 && (sv == -1 || sv == pcred->p_svuid)) 344 /* nothing to do */ 345 return 0; 346 347 /* The pcred structure is not actually shared... */ 348 if (r != -1 && r != pcred->p_ruid) { 349 /* Update count of processes for this user */ 350 (void)chgproccnt(pcred->p_ruid, -1); 351 (void)chgproccnt(r, 1); 352 pcred->p_ruid = r; 353 } 354 if (sv != -1) 355 pcred->p_svuid = sv; 356 if (e != -1 && e != cred->cr_uid) { 357 /* Update a clone of the current credentials */ 358 pcred->pc_ucred = cred = crcopy(cred); 359 cred->cr_uid = e; 360 } 361 362 /* Mark process as having changed credentials, stops tracing etc */ 363 p_sugid(p); 364 return 0; 365 } 366 367 /* 368 * Set real, effective and saved gids to the requested values. 369 * non-root callers can only ever change gids to values that match 370 * one of the processes current gid values. 371 * This is further restricted by the flags argument. 372 */ 373 374 int 375 do_setresgid(struct lwp *l, gid_t r, gid_t e, gid_t sv, u_int flags) 376 { 377 int error; 378 struct proc *p = l->l_proc; 379 struct pcred *pcred = p->p_cred; 380 struct ucred *cred = pcred->pc_ucred; 381 382 /* Superuser can do anything it wants to.... */ 383 error = suser(cred, &p->p_acflag); 384 if (error) { 385 /* Otherwise check new value is one of the allowed 386 existing values. */ 387 if (r != -1 && !((flags & ID_R_EQ_R) && r == pcred->p_rgid) 388 && !((flags & ID_R_EQ_E) && r == cred->cr_gid) 389 && !((flags & ID_R_EQ_S) && r == pcred->p_svgid)) 390 return error; 391 if (e != -1 && !((flags & ID_E_EQ_R) && e == pcred->p_rgid) 392 && !((flags & ID_E_EQ_E) && e == cred->cr_gid) 393 && !((flags & ID_E_EQ_S) && e == pcred->p_svgid)) 394 return error; 395 if (sv != -1 && !((flags & ID_S_EQ_R) && sv == pcred->p_rgid) 396 && !((flags & ID_S_EQ_E) && sv == cred->cr_gid) 397 && !((flags & ID_S_EQ_S) && sv == pcred->p_svgid)) 398 return error; 399 } 400 401 /* If nothing has changed, short circuit the request */ 402 if ((r == -1 || r == pcred->p_rgid) 403 && (e == -1 || e == cred->cr_gid) 404 && (sv == -1 || sv == pcred->p_svgid)) 405 /* nothing to do */ 406 return 0; 407 408 /* The pcred structure is not actually shared... */ 409 if (r != -1) 410 pcred->p_rgid = r; 411 if (sv != -1) 412 pcred->p_svgid = sv; 413 if (e != -1 && e != cred->cr_gid) { 414 /* Update a clone of the current credentials */ 415 pcred->pc_ucred = cred = crcopy(cred); 416 cred->cr_gid = e; 417 } 418 419 /* Mark process as having changed credentials, stops tracing etc */ 420 p_sugid(p); 421 return 0; 422 } 423 424 /* ARGSUSED */ 425 int 426 sys_setuid(struct lwp *l, void *v, register_t *retval) 427 { 428 struct sys_setuid_args /* { 429 syscallarg(uid_t) uid; 430 } */ *uap = v; 431 uid_t uid = SCARG(uap, uid); 432 433 return do_setresuid(l, uid, uid, uid, 434 ID_R_EQ_R | ID_E_EQ_R | ID_S_EQ_R); 435 } 436 437 /* ARGSUSED */ 438 int 439 sys_seteuid(struct lwp *l, void *v, register_t *retval) 440 { 441 struct sys_seteuid_args /* { 442 syscallarg(uid_t) euid; 443 } */ *uap = v; 444 445 return do_setresuid(l, -1, SCARG(uap, euid), -1, ID_E_EQ_R | ID_E_EQ_S); 446 } 447 448 int 449 sys_setreuid(struct lwp *l, void *v, register_t *retval) 450 { 451 struct sys_setreuid_args /* { 452 syscallarg(uid_t) ruid; 453 syscallarg(uid_t) euid; 454 } */ *uap = v; 455 struct proc *p = l->l_proc; 456 uid_t ruid, euid, svuid; 457 458 ruid = SCARG(uap, ruid); 459 euid = SCARG(uap, euid); 460 if (ruid == -1) 461 ruid = p->p_cred->p_ruid; 462 if (euid == -1) 463 euid = p->p_ucred->cr_uid; 464 /* Saved uid is set to the new euid if the ruid changed */ 465 svuid = (ruid == p->p_cred->p_ruid) ? -1 : euid; 466 467 return do_setresuid(l, ruid, euid, svuid, 468 ID_R_EQ_R | ID_R_EQ_E | 469 ID_E_EQ_R | ID_E_EQ_E | ID_E_EQ_S | 470 ID_S_EQ_R | ID_S_EQ_E | ID_S_EQ_S); 471 } 472 473 /* ARGSUSED */ 474 int 475 sys_setgid(struct lwp *l, void *v, register_t *retval) 476 { 477 struct sys_setgid_args /* { 478 syscallarg(gid_t) gid; 479 } */ *uap = v; 480 gid_t gid = SCARG(uap, gid); 481 482 return do_setresgid(l, gid, gid, gid, 483 ID_R_EQ_R | ID_E_EQ_R | ID_S_EQ_R); 484 } 485 486 /* ARGSUSED */ 487 int 488 sys_setegid(struct lwp *l, void *v, register_t *retval) 489 { 490 struct sys_setegid_args /* { 491 syscallarg(gid_t) egid; 492 } */ *uap = v; 493 494 return do_setresgid(l, -1, SCARG(uap, egid), -1, ID_E_EQ_R | ID_E_EQ_S); 495 } 496 497 int 498 sys_setregid(struct lwp *l, void *v, register_t *retval) 499 { 500 struct sys_setregid_args /* { 501 syscallarg(gid_t) rgid; 502 syscallarg(gid_t) egid; 503 } */ *uap = v; 504 struct proc *p = l->l_proc; 505 gid_t rgid, egid, svgid; 506 507 rgid = SCARG(uap, rgid); 508 egid = SCARG(uap, egid); 509 if (rgid == -1) 510 rgid = p->p_cred->p_rgid; 511 if (egid == -1) 512 egid = p->p_ucred->cr_gid; 513 /* Saved gid is set to the new egid if the rgid changed */ 514 svgid = rgid == p->p_cred->p_rgid ? -1 : egid; 515 516 return do_setresgid(l, rgid, egid, svgid, 517 ID_R_EQ_R | ID_R_EQ_E | 518 ID_E_EQ_R | ID_E_EQ_E | ID_E_EQ_S | 519 ID_S_EQ_R | ID_S_EQ_E | ID_S_EQ_S); 520 } 521 522 int 523 sys_issetugid(struct lwp *l, void *v, register_t *retval) 524 { 525 struct proc *p = l->l_proc; 526 527 /* 528 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time, 529 * we use P_SUGID because we consider changing the owners as 530 * "tainting" as well. 531 * This is significant for procs that start as root and "become" 532 * a user without an exec - programs cannot know *everything* 533 * that libc *might* have put in their data segment. 534 */ 535 *retval = (p->p_flag & P_SUGID) != 0; 536 return (0); 537 } 538 539 /* ARGSUSED */ 540 int 541 sys_setgroups(struct lwp *l, void *v, register_t *retval) 542 { 543 struct sys_setgroups_args /* { 544 syscallarg(int) gidsetsize; 545 syscallarg(const gid_t *) gidset; 546 } */ *uap = v; 547 struct proc *p = l->l_proc; 548 struct pcred *pc = p->p_cred; 549 int ngrp; 550 int error; 551 gid_t grp[NGROUPS]; 552 size_t grsize; 553 554 if ((error = suser(pc->pc_ucred, &p->p_acflag)) != 0) 555 return (error); 556 557 ngrp = SCARG(uap, gidsetsize); 558 if ((u_int)ngrp > NGROUPS) 559 return (EINVAL); 560 561 grsize = ngrp * sizeof(gid_t); 562 error = copyin(SCARG(uap, gidset), grp, grsize); 563 if (error) 564 return (error); 565 /* 566 * Check if this is a no-op. 567 */ 568 if (pc->pc_ucred->cr_ngroups == (u_int) ngrp && 569 memcmp(grp, pc->pc_ucred->cr_groups, grsize) == 0) 570 return (0); 571 572 pc->pc_ucred = crcopy(pc->pc_ucred); 573 (void)memcpy(pc->pc_ucred->cr_groups, grp, grsize); 574 pc->pc_ucred->cr_ngroups = ngrp; 575 p_sugid(p); 576 return (0); 577 } 578 579 /* 580 * Check if gid is a member of the group set. 581 */ 582 int 583 groupmember(gid_t gid, const struct ucred *cred) 584 { 585 const gid_t *gp; 586 const gid_t *egp; 587 588 egp = &(cred->cr_groups[cred->cr_ngroups]); 589 for (gp = cred->cr_groups; gp < egp; gp++) 590 if (*gp == gid) 591 return (1); 592 return (0); 593 } 594 595 /* 596 * Test whether the specified credentials imply "super-user" 597 * privilege; if so, and we have accounting info, set the flag 598 * indicating use of super-powers. 599 * Returns 0 or error. 600 */ 601 int 602 suser(const struct ucred *cred, u_short *acflag) 603 { 604 605 if (cred->cr_uid == 0) { 606 if (acflag) 607 *acflag |= ASU; 608 return (0); 609 } 610 return (EPERM); 611 } 612 613 /* 614 * Allocate a zeroed cred structure. 615 */ 616 struct ucred * 617 crget(void) 618 { 619 struct ucred *cr; 620 621 cr = pool_get(&cred_pool, PR_WAITOK); 622 memset(cr, 0, sizeof(*cr)); 623 simple_lock_init(&cr->cr_lock); 624 cr->cr_ref = 1; 625 return (cr); 626 } 627 628 /* 629 * Free a cred structure. 630 * Throws away space when ref count gets to 0. 631 */ 632 void 633 crfree(struct ucred *cr) 634 { 635 int n; 636 637 simple_lock(&cr->cr_lock); 638 n = --cr->cr_ref; 639 simple_unlock(&cr->cr_lock); 640 if (n == 0) 641 pool_put(&cred_pool, cr); 642 } 643 644 /* 645 * Compare cred structures and return 0 if they match 646 */ 647 int 648 crcmp(const struct ucred *cr1, const struct uucred *cr2) 649 { 650 return cr1->cr_uid != cr2->cr_uid || 651 cr1->cr_gid != cr2->cr_gid || 652 cr1->cr_ngroups != (uint32_t)cr2->cr_ngroups || 653 memcmp(cr1->cr_groups, cr2->cr_groups, cr1->cr_ngroups); 654 } 655 656 /* 657 * Copy cred structure to a new one and free the old one. 658 */ 659 struct ucred * 660 crcopy(struct ucred *cr) 661 { 662 struct ucred *newcr; 663 664 if (cr->cr_ref == 1) 665 return (cr); 666 667 newcr = crget(); 668 memcpy(&newcr->cr_startcopy, &cr->cr_startcopy, 669 sizeof(struct ucred) - offsetof(struct ucred, cr_startcopy)); 670 crfree(cr); 671 return (newcr); 672 } 673 674 /* 675 * Dup cred struct to a new held one. 676 */ 677 struct ucred * 678 crdup(const struct ucred *cr) 679 { 680 struct ucred *newcr; 681 682 newcr = crget(); 683 memcpy(&newcr->cr_startcopy, &cr->cr_startcopy, 684 sizeof(struct ucred) - offsetof(struct ucred, cr_startcopy)); 685 return (newcr); 686 } 687 688 /* 689 * convert from userland credentials to kernel one 690 */ 691 void 692 crcvt(struct ucred *uc, const struct uucred *uuc) 693 { 694 695 uc->cr_ref = 0; 696 uc->cr_uid = uuc->cr_uid; 697 uc->cr_gid = uuc->cr_gid; 698 uc->cr_ngroups = uuc->cr_ngroups; 699 (void)memcpy(uc->cr_groups, uuc->cr_groups, sizeof(uuc->cr_groups)); 700 } 701 702 /* 703 * Get login name, if available. 704 */ 705 /* ARGSUSED */ 706 int 707 sys___getlogin(struct lwp *l, void *v, register_t *retval) 708 { 709 struct sys___getlogin_args /* { 710 syscallarg(char *) namebuf; 711 syscallarg(size_t) namelen; 712 } */ *uap = v; 713 struct proc *p = l->l_proc; 714 715 if (SCARG(uap, namelen) > sizeof(p->p_pgrp->pg_session->s_login)) 716 SCARG(uap, namelen) = sizeof(p->p_pgrp->pg_session->s_login); 717 return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, 718 (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen))); 719 } 720 721 /* 722 * Set login name. 723 */ 724 /* ARGSUSED */ 725 int 726 sys___setlogin(struct lwp *l, void *v, register_t *retval) 727 { 728 struct sys___setlogin_args /* { 729 syscallarg(const char *) namebuf; 730 } */ *uap = v; 731 struct proc *p = l->l_proc; 732 struct session *s = p->p_pgrp->pg_session; 733 char newname[sizeof s->s_login + 1]; 734 int error; 735 736 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 737 return (error); 738 error = copyinstr(SCARG(uap, namebuf), &newname, sizeof newname, NULL); 739 if (error != 0) 740 return (error == ENAMETOOLONG ? EINVAL : error); 741 742 if (s->s_flags & S_LOGIN_SET && p->p_pid != s->s_sid && 743 strncmp(newname, s->s_login, sizeof s->s_login) != 0) 744 log(LOG_WARNING, "%s (pid %d) changing logname from " 745 "%.*s to %s\n", p->p_comm, p->p_pid, 746 (int)sizeof s->s_login, s->s_login, newname); 747 s->s_flags |= S_LOGIN_SET; 748 strncpy(s->s_login, newname, sizeof s->s_login); 749 return (0); 750 } 751