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