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