|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 26: /* ! 27: * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993 ! 28: * The Regents of the University of California. All rights reserved. ! 29: * (c) UNIX System Laboratories, Inc. ! 30: * All or some portions of this file are derived from material licensed ! 31: * to the University of California by American Telephone and Telegraph ! 32: * Co. or Unix System Laboratories, Inc. and are reproduced herein with ! 33: * the permission of UNIX System Laboratories, Inc. ! 34: * ! 35: * Redistribution and use in source and binary forms, with or without ! 36: * modification, are permitted provided that the following conditions ! 37: * are met: ! 38: * 1. Redistributions of source code must retain the above copyright ! 39: * notice, this list of conditions and the following disclaimer. ! 40: * 2. Redistributions in binary form must reproduce the above copyright ! 41: * notice, this list of conditions and the following disclaimer in the ! 42: * documentation and/or other materials provided with the distribution. ! 43: * 3. All advertising materials mentioning features or use of this software ! 44: * must display the following acknowledgement: ! 45: * This product includes software developed by the University of ! 46: * California, Berkeley and its contributors. ! 47: * 4. Neither the name of the University nor the names of its contributors ! 48: * may be used to endorse or promote products derived from this software ! 49: * without specific prior written permission. ! 50: * ! 51: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 52: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 53: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 54: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 55: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 56: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 57: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 58: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 59: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 60: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 61: * SUCH DAMAGE. ! 62: * ! 63: * @(#)kern_prot.c 8.9 (Berkeley) 2/14/95 ! 64: */ ! 65: ! 66: /* ! 67: * System calls related to processes and protection ! 68: */ ! 69: ! 70: #include <sys/param.h> ! 71: #include <sys/acct.h> ! 72: #include <sys/systm.h> ! 73: #include <sys/ucred.h> ! 74: #include <sys/proc.h> ! 75: #include <sys/timeb.h> ! 76: #include <sys/times.h> ! 77: #include <sys/malloc.h> ! 78: ! 79: #include <sys/mount.h> ! 80: ! 81: /* ! 82: * setprivexec: (dis)allow this process to hold ! 83: * task, thread, or execption ports of processes about to exec. ! 84: */ ! 85: struct setprivexec_args { ! 86: int flag; ! 87: }; ! 88: int ! 89: setprivexec(p, uap, retval) ! 90: struct proc *p; ! 91: register struct setprivexec_args *uap; ! 92: register_t *retval; ! 93: { ! 94: *retval = p->p_debugger; ! 95: p->p_debugger = (uap->flag != 0); ! 96: return(0); ! 97: } ! 98: ! 99: /* ARGSUSED */ ! 100: getpid(p, uap, retval) ! 101: struct proc *p; ! 102: void *uap; ! 103: register_t *retval; ! 104: { ! 105: ! 106: *retval = p->p_pid; ! 107: #if COMPAT_43 ! 108: retval[1] = p->p_pptr->p_pid; ! 109: #endif ! 110: return (0); ! 111: } ! 112: ! 113: /* ARGSUSED */ ! 114: getppid(p, uap, retval) ! 115: struct proc *p; ! 116: void *uap; ! 117: register_t *retval; ! 118: { ! 119: ! 120: *retval = p->p_pptr->p_pid; ! 121: return (0); ! 122: } ! 123: ! 124: /* Get process group ID; note that POSIX getpgrp takes no parameter */ ! 125: getpgrp(p, uap, retval) ! 126: struct proc *p; ! 127: void *uap; ! 128: register_t *retval; ! 129: { ! 130: ! 131: *retval = p->p_pgrp->pg_id; ! 132: return (0); ! 133: } ! 134: ! 135: /* ARGSUSED */ ! 136: getuid(p, uap, retval) ! 137: struct proc *p; ! 138: void *uap; ! 139: register_t *retval; ! 140: { ! 141: ! 142: *retval = p->p_cred->p_ruid; ! 143: #if COMPAT_43 ! 144: retval[1] = p->p_ucred->cr_uid; ! 145: #endif ! 146: return (0); ! 147: } ! 148: ! 149: /* ARGSUSED */ ! 150: geteuid(p, uap, retval) ! 151: struct proc *p; ! 152: void *uap; ! 153: register_t *retval; ! 154: { ! 155: ! 156: *retval = p->p_ucred->cr_uid; ! 157: return (0); ! 158: } ! 159: ! 160: /* ARGSUSED */ ! 161: getgid(p, uap, retval) ! 162: struct proc *p; ! 163: void *uap; ! 164: register_t *retval; ! 165: { ! 166: ! 167: *retval = p->p_cred->p_rgid; ! 168: #if COMPAT_43 ! 169: retval[1] = p->p_ucred->cr_groups[0]; ! 170: #endif ! 171: return (0); ! 172: } ! 173: ! 174: /* ! 175: * Get effective group ID. The "egid" is groups[0], and could be obtained ! 176: * via getgroups. This syscall exists because it is somewhat painful to do ! 177: * correctly in a library function. ! 178: */ ! 179: /* ARGSUSED */ ! 180: getegid(p, uap, retval) ! 181: struct proc *p; ! 182: void *uap; ! 183: register_t *retval; ! 184: { ! 185: ! 186: *retval = p->p_ucred->cr_groups[0]; ! 187: return (0); ! 188: } ! 189: ! 190: struct getgroups_args { ! 191: u_int gidsetsize; ! 192: gid_t *gidset; ! 193: }; ! 194: getgroups(p, uap, retval) ! 195: struct proc *p; ! 196: register struct getgroups_args *uap; ! 197: register_t *retval; ! 198: { ! 199: register struct pcred *pc = p->p_cred; ! 200: register u_int ngrp; ! 201: int error; ! 202: ! 203: if ((ngrp = uap->gidsetsize) == 0) { ! 204: *retval = pc->pc_ucred->cr_ngroups; ! 205: return (0); ! 206: } ! 207: if (ngrp < pc->pc_ucred->cr_ngroups) ! 208: return (EINVAL); ! 209: pcred_readlock(p); ! 210: ngrp = pc->pc_ucred->cr_ngroups; ! 211: if (error = copyout((caddr_t)pc->pc_ucred->cr_groups, ! 212: (caddr_t)uap->gidset, ngrp * sizeof(gid_t))) { ! 213: pcred_unlock(p); ! 214: return (error); ! 215: } ! 216: pcred_unlock(p); ! 217: *retval = ngrp; ! 218: return (0); ! 219: } ! 220: ! 221: /* ARGSUSED */ ! 222: setsid(p, uap, retval) ! 223: register struct proc *p; ! 224: void *uap; ! 225: register_t *retval; ! 226: { ! 227: ! 228: if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { ! 229: return (EPERM); ! 230: } else { ! 231: (void)enterpgrp(p, p->p_pid, 1); ! 232: *retval = p->p_pid; ! 233: return (0); ! 234: } ! 235: } ! 236: ! 237: /* ! 238: * set process group (setpgid/old setpgrp) ! 239: * ! 240: * caller does setpgid(targpid, targpgid) ! 241: * ! 242: * pid must be caller or child of caller (ESRCH) ! 243: * if a child ! 244: * pid must be in same session (EPERM) ! 245: * pid can't have done an exec (EACCES) ! 246: * if pgid != pid ! 247: * there must exist some pid in same session having pgid (EPERM) ! 248: * pid must not be session leader (EPERM) ! 249: */ ! 250: struct setpgid_args { ! 251: int pid; ! 252: int pgid; ! 253: }; ! 254: /* ARGSUSED */ ! 255: setpgid(curp, uap, retval) ! 256: struct proc *curp; ! 257: register struct setpgid_args *uap; ! 258: register_t *retval; ! 259: { ! 260: register struct proc *targp; /* target process */ ! 261: register struct pgrp *pgrp; /* target pgrp */ ! 262: ! 263: if (uap->pid != 0 && uap->pid != curp->p_pid) { ! 264: if ((targp = pfind(uap->pid)) == 0 || !inferior(targp)) ! 265: return (ESRCH); ! 266: if (targp->p_session != curp->p_session) ! 267: return (EPERM); ! 268: if (targp->p_flag & P_EXEC) ! 269: return (EACCES); ! 270: } else ! 271: targp = curp; ! 272: if (SESS_LEADER(targp)) ! 273: return (EPERM); ! 274: if (uap->pgid == 0) ! 275: uap->pgid = targp->p_pid; ! 276: else if (uap->pgid != targp->p_pid) ! 277: if ((pgrp = pgfind(uap->pgid)) == 0 || ! 278: pgrp->pg_session != curp->p_session) ! 279: return (EPERM); ! 280: return (enterpgrp(targp, uap->pgid, 0)); ! 281: } ! 282: ! 283: struct setuid_args { ! 284: uid_t uid; ! 285: }; ! 286: /* ARGSUSED */ ! 287: setuid(p, uap, retval) ! 288: struct proc *p; ! 289: struct setuid_args *uap; ! 290: register_t *retval; ! 291: { ! 292: register struct pcred *pc = p->p_cred; ! 293: register uid_t uid; ! 294: int error; ! 295: ! 296: uid = uap->uid; ! 297: if (uid != pc->p_ruid && ! 298: (error = suser(pc->pc_ucred, &p->p_acflag))) ! 299: return (error); ! 300: /* ! 301: * Everything's okay, do it. ! 302: * Transfer proc count to new user. ! 303: * Copy credentials so other references do not see our changes. ! 304: */ ! 305: pcred_writelock(p); ! 306: (void)chgproccnt(pc->p_ruid, -1); ! 307: (void)chgproccnt(uid, 1); ! 308: pc->pc_ucred = crcopy(pc->pc_ucred); ! 309: pc->pc_ucred->cr_uid = uid; ! 310: pc->p_ruid = uid; ! 311: pc->p_svuid = uid; ! 312: pcred_unlock(p); ! 313: p->p_flag |= P_SUGID; ! 314: return (0); ! 315: } ! 316: ! 317: struct seteuid_args { ! 318: uid_t euid; ! 319: }; ! 320: /* ARGSUSED */ ! 321: seteuid(p, uap, retval) ! 322: struct proc *p; ! 323: struct seteuid_args *uap; ! 324: register_t *retval; ! 325: { ! 326: register struct pcred *pc = p->p_cred; ! 327: register uid_t euid; ! 328: int error; ! 329: ! 330: euid = uap->euid; ! 331: if (euid != pc->p_ruid && euid != pc->p_svuid && ! 332: (error = suser(pc->pc_ucred, &p->p_acflag))) ! 333: return (error); ! 334: /* ! 335: * Everything's okay, do it. Copy credentials so other references do ! 336: * not see our changes. ! 337: */ ! 338: pcred_writelock(p); ! 339: pc->pc_ucred = crcopy(pc->pc_ucred); ! 340: pc->pc_ucred->cr_uid = euid; ! 341: pcred_unlock(p); ! 342: p->p_flag |= P_SUGID; ! 343: return (0); ! 344: } ! 345: ! 346: struct setgid_args { ! 347: gid_t gid; ! 348: }; ! 349: /* ARGSUSED */ ! 350: setgid(p, uap, retval) ! 351: struct proc *p; ! 352: struct setgid_args *uap; ! 353: register_t *retval; ! 354: { ! 355: register struct pcred *pc = p->p_cred; ! 356: register gid_t gid; ! 357: int error; ! 358: ! 359: gid = uap->gid; ! 360: if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag))) ! 361: return (error); ! 362: pcred_writelock(p); ! 363: pc->pc_ucred = crcopy(pc->pc_ucred); ! 364: pc->pc_ucred->cr_groups[0] = gid; ! 365: pc->p_rgid = gid; ! 366: pc->p_svgid = gid; /* ??? */ ! 367: pcred_unlock(p); ! 368: p->p_flag |= P_SUGID; ! 369: return (0); ! 370: } ! 371: ! 372: struct setegid_args { ! 373: gid_t egid; ! 374: }; ! 375: /* ARGSUSED */ ! 376: setegid(p, uap, retval) ! 377: struct proc *p; ! 378: struct setegid_args *uap; ! 379: register_t *retval; ! 380: { ! 381: register struct pcred *pc = p->p_cred; ! 382: register gid_t egid; ! 383: int error; ! 384: ! 385: egid = uap->egid; ! 386: if (egid != pc->p_rgid && egid != pc->p_svgid && ! 387: (error = suser(pc->pc_ucred, &p->p_acflag))) ! 388: return (error); ! 389: pcred_writelock(p); ! 390: pc->pc_ucred = crcopy(pc->pc_ucred); ! 391: pc->pc_ucred->cr_groups[0] = egid; ! 392: pcred_unlock(p); ! 393: p->p_flag |= P_SUGID; ! 394: return (0); ! 395: } ! 396: ! 397: struct setgroups_args{ ! 398: u_int gidsetsize; ! 399: gid_t *gidset; ! 400: }; ! 401: ! 402: /* ARGSUSED */ ! 403: setgroups(p, uap, retval) ! 404: struct proc *p; ! 405: struct setgroups_args *uap; ! 406: register_t *retval; ! 407: { ! 408: register struct pcred *pc = p->p_cred; ! 409: struct ucred *new, *old; ! 410: register u_int ngrp; ! 411: int error; ! 412: ! 413: if (error = suser(pc->pc_ucred, &p->p_acflag)) ! 414: return (error); ! 415: ngrp = uap->gidsetsize; ! 416: if (ngrp < 1 || ngrp > NGROUPS) ! 417: return (EINVAL); ! 418: new = crget(); ! 419: error = copyin((caddr_t)uap->gidset, ! 420: (caddr_t)new->cr_groups, ngrp * sizeof(gid_t)); ! 421: if (error) { ! 422: crfree(new); ! 423: return (error); ! 424: } ! 425: new->cr_ngroups = ngrp; ! 426: pcred_writelock(p); ! 427: old = pc->pc_ucred; ! 428: new->cr_uid = old->cr_uid; ! 429: pc->pc_ucred = new; ! 430: pcred_unlock(p); ! 431: p->p_flag |= P_SUGID; ! 432: if (old != NOCRED) ! 433: crfree(old); ! 434: return (0); ! 435: } ! 436: ! 437: #if COMPAT_43 ! 438: struct osetreuid_args{ ! 439: int ruid; ! 440: int euid; ! 441: }; ! 442: /* ARGSUSED */ ! 443: osetreuid(p, uap, retval) ! 444: register struct proc *p; ! 445: struct osetreuid_args *uap; ! 446: register_t *retval; ! 447: { ! 448: struct seteuid_args seuidargs; ! 449: struct setuid_args suidargs; ! 450: ! 451: /* ! 452: * There are five cases, and we attempt to emulate them in ! 453: * the following fashion: ! 454: * -1, -1: return 0. This is correct emulation. ! 455: * -1, N: call seteuid(N). This is correct emulation. ! 456: * N, -1: if we called setuid(N), our euid would be changed ! 457: * to N as well. the theory is that we don't want to ! 458: * revoke root access yet, so we call seteuid(N) ! 459: * instead. This is incorrect emulation, but often ! 460: * suffices enough for binary compatibility. ! 461: * N, N: call setuid(N). This is correct emulation. ! 462: * N, M: call setuid(N). This is close to correct emulation. ! 463: */ ! 464: if (uap->ruid == (uid_t)-1) { ! 465: if (uap->euid == (uid_t)-1) ! 466: return (0); /* -1, -1 */ ! 467: seuidargs.euid = uap->euid; /* -1, N */ ! 468: return (seteuid(p, &seuidargs, retval)); ! 469: } ! 470: if (uap->euid == (uid_t)-1) { ! 471: seuidargs.euid = uap->ruid; /* N, -1 */ ! 472: return (seteuid(p, &seuidargs, retval)); ! 473: } ! 474: suidargs.uid = uap->ruid; /* N, N and N, M */ ! 475: return (setuid(p, &suidargs, retval)); ! 476: } ! 477: ! 478: struct osetregid_args { ! 479: int rgid; ! 480: int egid; ! 481: }; ! 482: /* ARGSUSED */ ! 483: osetregid(p, uap, retval) ! 484: register struct proc *p; ! 485: struct osetregid_args *uap; ! 486: register_t *retval; ! 487: { ! 488: struct setegid_args segidargs; ! 489: struct setgid_args sgidargs; ! 490: ! 491: /* ! 492: * There are five cases, described above in osetreuid() ! 493: */ ! 494: if (uap->rgid == (gid_t)-1) { ! 495: if (uap->egid == (gid_t)-1) ! 496: return (0); /* -1, -1 */ ! 497: segidargs.egid = uap->egid; /* -1, N */ ! 498: return (setegid(p, &segidargs, retval)); ! 499: } ! 500: if (uap->egid == (gid_t)-1) { ! 501: segidargs.egid = uap->rgid; /* N, -1 */ ! 502: return (setegid(p, &segidargs, retval)); ! 503: } ! 504: sgidargs.gid = uap->rgid; /* N, N and N, M */ ! 505: return (setgid(p, &sgidargs, retval)); ! 506: } ! 507: #endif /* COMPAT_43 */ ! 508: ! 509: /* ! 510: * Check if gid is a member of the group set. ! 511: */ ! 512: groupmember(gid, cred) ! 513: gid_t gid; ! 514: register struct ucred *cred; ! 515: { ! 516: register gid_t *gp; ! 517: gid_t *egp; ! 518: ! 519: egp = &(cred->cr_groups[cred->cr_ngroups]); ! 520: for (gp = cred->cr_groups; gp < egp; gp++) ! 521: if (*gp == gid) ! 522: return (1); ! 523: return (0); ! 524: } ! 525: ! 526: /* ! 527: * Test whether the specified credentials imply "super-user" ! 528: * privilege; if so, and we have accounting info, set the flag ! 529: * indicating use of super-powers. ! 530: * Returns 0 or error. ! 531: */ ! 532: suser(cred, acflag) ! 533: struct ucred *cred; ! 534: u_short *acflag; ! 535: { ! 536: #if DIAGNOSTIC ! 537: if (cred == NOCRED || cred == FSCRED) ! 538: panic("suser"); ! 539: #endif ! 540: if (cred->cr_uid == 0) { ! 541: if (acflag) ! 542: *acflag |= ASU; ! 543: return (0); ! 544: } ! 545: return (EPERM); ! 546: } ! 547: ! 548: int ! 549: is_suser(void) ! 550: { ! 551: struct proc *p = current_thread()->task->proc; ! 552: ! 553: if (!p) ! 554: return (0); ! 555: ! 556: return (suser(p->p_ucred, &p->p_acflag) == 0); ! 557: } ! 558: ! 559: int ! 560: is_suser1(void) ! 561: { ! 562: struct proc *p = current_thread()->task->proc; ! 563: ! 564: if (!p) ! 565: return (0); ! 566: ! 567: return (suser(p->p_ucred, &p->p_acflag) == 0 || ! 568: p->p_cred->p_ruid == 0 || p->p_cred->p_svuid == 0); ! 569: } ! 570: ! 571: /* ! 572: * Allocate a zeroed cred structure. ! 573: */ ! 574: struct ucred * ! 575: crget() ! 576: { ! 577: register struct ucred *cr; ! 578: ! 579: MALLOC_ZONE(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); ! 580: bzero((caddr_t)cr, sizeof(*cr)); ! 581: cr->cr_ref = 1; ! 582: return (cr); ! 583: } ! 584: ! 585: /* ! 586: * Free a cred structure. ! 587: * Throws away space when ref count gets to 0. ! 588: */ ! 589: void ! 590: crfree(cr) ! 591: struct ucred *cr; ! 592: { ! 593: #if DIAGNOSTIC ! 594: if (cr == NOCRED || cr == FSCRED) ! 595: panic("crfree"); ! 596: #endif ! 597: if (--cr->cr_ref == 0) ! 598: FREE_ZONE((caddr_t)cr, sizeof *cr, M_CRED); ! 599: } ! 600: ! 601: /* ! 602: * Copy cred structure to a new one and free the old one. ! 603: */ ! 604: struct ucred * ! 605: crcopy(cr) ! 606: struct ucred *cr; ! 607: { ! 608: struct ucred *newcr; ! 609: ! 610: #if DIAGNOSTIC ! 611: if (cr == NOCRED || cr == FSCRED) ! 612: panic("crcopy"); ! 613: #endif ! 614: if (cr->cr_ref == 1) ! 615: return (cr); ! 616: newcr = crget(); ! 617: *newcr = *cr; ! 618: crfree(cr); ! 619: newcr->cr_ref = 1; ! 620: return (newcr); ! 621: } ! 622: ! 623: /* ! 624: * Dup cred struct to a new held one. ! 625: */ ! 626: struct ucred * ! 627: crdup(cr) ! 628: struct ucred *cr; ! 629: { ! 630: struct ucred *newcr; ! 631: ! 632: #if DIAGNOSTIC ! 633: if (cr == NOCRED || cr == FSCRED) ! 634: panic("crdup"); ! 635: #endif ! 636: newcr = crget(); ! 637: *newcr = *cr; ! 638: newcr->cr_ref = 1; ! 639: return (newcr); ! 640: } ! 641: ! 642: /* ! 643: * Get login name, if available. ! 644: */ ! 645: struct getlogin_args { ! 646: char *namebuf; ! 647: u_int namelen; ! 648: }; ! 649: /* ARGSUSED */ ! 650: getlogin(p, uap, retval) ! 651: struct proc *p; ! 652: struct getlogin_args *uap; ! 653: register_t *retval; ! 654: { ! 655: ! 656: if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login)) ! 657: uap->namelen = sizeof (p->p_pgrp->pg_session->s_login); ! 658: return (copyout((caddr_t) p->p_pgrp->pg_session->s_login, ! 659: (caddr_t)uap->namebuf, uap->namelen)); ! 660: } ! 661: ! 662: /* ! 663: * Set login name. ! 664: */ ! 665: struct setlogin_args { ! 666: char *namebuf; ! 667: }; ! 668: /* ARGSUSED */ ! 669: setlogin(p, uap, retval) ! 670: struct proc *p; ! 671: struct setlogin_args *uap; ! 672: register_t *retval; ! 673: { ! 674: int error; ! 675: ! 676: if (error = suser(p->p_ucred, &p->p_acflag)) ! 677: return (error); ! 678: error = copyinstr((caddr_t) uap->namebuf, ! 679: (caddr_t) p->p_pgrp->pg_session->s_login, ! 680: sizeof (p->p_pgrp->pg_session->s_login) - 1, (size_t *)0); ! 681: if (error == ENAMETOOLONG) ! 682: error = EINVAL; ! 683: return (error); ! 684: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.