119843Sdist /* 219843Sdist * Copyright (c) 1980 Regents of the University of California. 319843Sdist * All rights reserved. The Berkeley software License Agreement 419843Sdist * specifies the terms and conditions for redistribution. 519843Sdist */ 619843Sdist 712678Ssam #ifndef lint 819843Sdist char copyright[] = 919843Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 1019843Sdist All rights reserved.\n"; 1119843Sdist #endif not lint 1212678Ssam 1319843Sdist #ifndef lint 14*24883Smckusick static char sccsid[] = "@(#)login.c 5.6 (Berkeley) 09/17/85"; 1519843Sdist #endif not lint 1619843Sdist 171043Sbill /* 181043Sbill * login [ name ] 1912687Ssam * login -r hostname (for rlogind) 2012687Ssam * login -h hostname (for telnetd, etc.) 211043Sbill */ 221043Sbill 2312984Ssam #include <sys/param.h> 2412687Ssam #include <sys/quota.h> 2512687Ssam #include <sys/stat.h> 2612687Ssam #include <sys/time.h> 2712687Ssam #include <sys/resource.h> 2816453Sroot #include <sys/file.h> 2912687Ssam 301043Sbill #include <sgtty.h> 311043Sbill #include <utmp.h> 321043Sbill #include <signal.h> 331043Sbill #include <pwd.h> 341043Sbill #include <stdio.h> 351043Sbill #include <lastlog.h> 3612678Ssam #include <errno.h> 3716453Sroot #include <ttyent.h> 3816453Sroot #include <syslog.h> 391043Sbill 4016453Sroot #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 412822Swnj #define SCPYN(a, b) strncpy(a, b, sizeof(a)) 422822Swnj 436197Sroot #define NMAX sizeof(utmp.ut_name) 441043Sbill 452822Swnj #define FALSE 0 462822Swnj #define TRUE -1 472822Swnj 482822Swnj char nolog[] = "/etc/nologin"; 492822Swnj char qlog[] = ".hushlogin"; 501043Sbill char maildir[30] = "/usr/spool/mail/"; 511043Sbill char lastlog[] = "/usr/adm/lastlog"; 529867Ssam struct passwd nouser = {"", "nope", -1, -1, -1, "", "", "", "" }; 531043Sbill struct sgttyb ttyb; 541043Sbill struct utmp utmp; 551043Sbill char minusnam[16] = "-"; 5618549Ssam char *envinit[] = { 0 }; /* now set by setenv calls */ 5712687Ssam /* 5812687Ssam * This bounds the time given to login. We initialize it here 5912687Ssam * so it can be patched on machines where it's too small. 6012687Ssam */ 6112687Ssam int timeout = 60; 626005Swnj 6318549Ssam char term[64]; 646005Swnj 651043Sbill struct passwd *pwd; 6618549Ssam char *strcat(), *rindex(), *index(), *malloc(), *realloc(); 6712687Ssam int timedout(); 681043Sbill char *ttyname(); 691043Sbill char *crypt(); 701043Sbill char *getpass(); 711043Sbill char *stypeof(); 721043Sbill extern char **environ; 7312678Ssam extern int errno; 741043Sbill 7513074Ssam struct tchars tc = { 7613074Ssam CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK 771365Sbill }; 7813074Ssam struct ltchars ltc = { 7913074Ssam CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT 8013074Ssam }; 811365Sbill 8218549Ssam struct winsize win = { 0, 0, 0, 0 }; 8318549Ssam 846005Swnj int rflag; 8524712Sbloom int usererr = -1; 866197Sroot char rusername[NMAX+1], lusername[NMAX+1]; 876005Swnj char rpassword[NMAX+1]; 886878Smckusick char name[NMAX+1]; 896197Sroot char *rhost; 906005Swnj 911043Sbill main(argc, argv) 9212687Ssam char *argv[]; 931043Sbill { 941043Sbill register char *namep; 9518549Ssam int pflag = 0, hflag = 0, t, f, c; 9612687Ssam int invalid, quietlog; 972822Swnj FILE *nlfd; 9816453Sroot char *ttyn, *tty; 9918549Ssam int ldisc = 0, zero = 0, i; 10018549Ssam char **envnew; 1011043Sbill 10212687Ssam signal(SIGALRM, timedout); 10312687Ssam alarm(timeout); 1041043Sbill signal(SIGQUIT, SIG_IGN); 1051043Sbill signal(SIGINT, SIG_IGN); 10612687Ssam setpriority(PRIO_PROCESS, 0, 0); 10712678Ssam quota(Q_SETUID, 0, 0, 0); 10812687Ssam /* 10918549Ssam * -p is used by getty to tell login not to destroy the environment 11012687Ssam * -r is used by rlogind to cause the autologin protocol; 11112687Ssam * -h is used by other servers to pass the name of the 11212687Ssam * remote host to login so that it may be placed in utmp and wtmp 11312687Ssam */ 11424712Sbloom while (argc > 1) { 11512687Ssam if (strcmp(argv[1], "-r") == 0) { 11624712Sbloom if (rflag || hflag) { 11724712Sbloom printf("Only one of -r and -h allowed\n"); 11824712Sbloom exit(1); 11924712Sbloom } 12024712Sbloom rflag = 1; 12124712Sbloom usererr = doremotelogin(argv[2]); 12212687Ssam SCPYN(utmp.ut_host, argv[2]); 12324712Sbloom argc -= 2; 12424712Sbloom argv += 2; 12524712Sbloom continue; 1266197Sroot } 12712687Ssam if (strcmp(argv[1], "-h") == 0 && getuid() == 0) { 12824712Sbloom if (rflag || hflag) { 12924712Sbloom printf("Only one of -r and -h allowed\n"); 13024712Sbloom exit(1); 13124712Sbloom } 13218549Ssam hflag = 1; 13312687Ssam SCPYN(utmp.ut_host, argv[2]); 13424712Sbloom argc -= 2; 13524712Sbloom argv += 2; 13624712Sbloom continue; 1376197Sroot } 13818549Ssam if (strcmp(argv[1], "-p") == 0) { 13918549Ssam argc--; 14018549Ssam argv++; 14118549Ssam pflag = 1; 14224712Sbloom continue; 14318549Ssam } 14424712Sbloom break; 1456005Swnj } 14613074Ssam ioctl(0, TIOCLSET, &zero); 1471547Sbill ioctl(0, TIOCNXCL, 0); 1486329Swnj ioctl(0, FIONBIO, &zero); 1496329Swnj ioctl(0, FIOASYNC, &zero); 15013074Ssam ioctl(0, TIOCGETP, &ttyb); 15112687Ssam /* 15212687Ssam * If talking to an rlogin process, 15312687Ssam * propagate the terminal type and 15412687Ssam * baud rate across the network. 15512687Ssam */ 15612687Ssam if (rflag) 15712687Ssam doremoteterm(term, &ttyb); 15813074Ssam ioctl(0, TIOCSLTC, <c); 15913074Ssam ioctl(0, TIOCSETC, &tc); 16013074Ssam ioctl(0, TIOCSETP, &ttyb); 16124849Smckusick for (t = getdtablesize(); t > 2; t--) 1621043Sbill close(t); 1631043Sbill ttyn = ttyname(0); 16416453Sroot if (ttyn == (char *)0) 1651043Sbill ttyn = "/dev/tty??"; 16616453Sroot tty = rindex(ttyn, '/'); 16716453Sroot if (tty == NULL) 16816453Sroot tty = ttyn; 16916453Sroot else 17016453Sroot tty++; 17124852Seric openlog("login", LOG_ODELAY, LOG_AUTH); 17216453Sroot t = 0; 1732822Swnj do { 1742822Swnj ldisc = 0; 1752822Swnj ioctl(0, TIOCSETD, &ldisc); 1762822Swnj invalid = FALSE; 1772822Swnj SCPYN(utmp.ut_name, ""); 17812687Ssam /* 17912687Ssam * Name specified, take it. 18012687Ssam */ 18112687Ssam if (argc > 1) { 1822822Swnj SCPYN(utmp.ut_name, argv[1]); 1832822Swnj argc = 0; 1841043Sbill } 18512687Ssam /* 18612687Ssam * If remote login take given name, 18712687Ssam * otherwise prompt user for something. 18812687Ssam */ 189*24883Smckusick if (rflag) 1909867Ssam SCPYN(utmp.ut_name, lusername); 191*24883Smckusick else 19212687Ssam getloginname(&utmp); 1932822Swnj if (!strcmp(pwd->pw_shell, "/bin/csh")) { 1942822Swnj ldisc = NTTYDISC; 1952822Swnj ioctl(0, TIOCSETD, &ldisc); 1962822Swnj } 19712687Ssam /* 19812687Ssam * If no remote login authentication and 19912687Ssam * a password exists for this user, prompt 20012687Ssam * for one and verify it. 20112687Ssam */ 20224712Sbloom if (usererr == -1 && *pwd->pw_passwd != '\0') { 20312687Ssam char *pp; 20412687Ssam 20512687Ssam setpriority(PRIO_PROCESS, 0, -4); 20612687Ssam pp = getpass("Password:"); 20712687Ssam namep = crypt(pp, pwd->pw_passwd); 20812687Ssam setpriority(PRIO_PROCESS, 0, 0); 20912687Ssam if (strcmp(namep, pwd->pw_passwd)) 21012687Ssam invalid = TRUE; 2112822Swnj } 21212687Ssam /* 21312687Ssam * If user not super-user, check for logins disabled. 21412687Ssam */ 2152822Swnj if (pwd->pw_uid != 0 && (nlfd = fopen(nolog, "r")) > 0) { 2162822Swnj while ((c = getc(nlfd)) != EOF) 2172822Swnj putchar(c); 2182822Swnj fflush(stdout); 2192822Swnj sleep(5); 2202822Swnj exit(0); 2212822Swnj } 22212687Ssam /* 22312687Ssam * If valid so far and root is logging in, 22412687Ssam * see if root logins on this terminal are permitted. 22512687Ssam */ 22616453Sroot if (!invalid && pwd->pw_uid == 0 && !rootterm(tty)) { 22724852Seric syslog(LOG_CRIT, "ROOT LOGIN REFUSED %s", tty); 2282822Swnj invalid = TRUE; 2292822Swnj } 2302822Swnj if (invalid) { 2311043Sbill printf("Login incorrect\n"); 23216453Sroot if (++t >= 5) { 23324852Seric syslog(LOG_CRIT, 23416453Sroot "REPEATED LOGIN FAILURES %s, %s", 23516453Sroot tty, utmp.ut_name); 23616453Sroot ioctl(0, TIOCHPCL, (struct sgttyb *) 0); 23718549Ssam close(0), close(1), close(2); 23816453Sroot sleep(10); 23916453Sroot exit(1); 24016453Sroot } 2411043Sbill } 2422822Swnj if (*pwd->pw_shell == '\0') 2432822Swnj pwd->pw_shell = "/bin/sh"; 2442822Swnj if (chdir(pwd->pw_dir) < 0 && !invalid ) { 2452822Swnj if (chdir("/") < 0) { 2462822Swnj printf("No directory!\n"); 2472822Swnj invalid = TRUE; 2482822Swnj } else { 24912687Ssam printf("No directory! %s\n", 25012687Ssam "Logging in with home=/"); 2512822Swnj pwd->pw_dir = "/"; 2522822Swnj } 2531043Sbill } 25412687Ssam /* 25512687Ssam * Remote login invalid must have been because 25612687Ssam * of a restriction of some sort, no extra chances. 25712687Ssam */ 25824712Sbloom if (!usererr && invalid) 2596005Swnj exit(1); 2602822Swnj } while (invalid); 26112687Ssam /* committed to login turn off timeout */ 26212687Ssam alarm(0); 2631043Sbill 26421083Smckusick if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) { 26512678Ssam if (errno == EUSERS) 26612678Ssam printf("%s.\n%s.\n", 26712678Ssam "Too many users logged on already", 26812678Ssam "Try again later"); 26912678Ssam else if (errno == EPROCLIM) 27012678Ssam printf("You have too many processes running.\n"); 27112678Ssam else 27217664Sserge perror("quota (Q_SETUID)"); 27312678Ssam sleep(5); 27412678Ssam exit(0); 27512678Ssam } 2761043Sbill time(&utmp.ut_time); 2771043Sbill t = ttyslot(); 27816453Sroot if (t > 0 && (f = open("/etc/utmp", O_WRONLY)) >= 0) { 2791043Sbill lseek(f, (long)(t*sizeof(utmp)), 0); 28016453Sroot SCPYN(utmp.ut_line, tty); 2811043Sbill write(f, (char *)&utmp, sizeof(utmp)); 2821043Sbill close(f); 2831043Sbill } 28416453Sroot if ((f = open("/usr/adm/wtmp", O_WRONLY|O_APPEND)) >= 0) { 2851043Sbill write(f, (char *)&utmp, sizeof(utmp)); 2861043Sbill close(f); 2871043Sbill } 28816453Sroot quietlog = access(qlog, F_OK) == 0; 28916453Sroot if ((f = open(lastlog, O_RDWR)) >= 0) { 2902822Swnj struct lastlog ll; 2912822Swnj 2922822Swnj lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0); 2932822Swnj if (read(f, (char *) &ll, sizeof ll) == sizeof ll && 29412687Ssam ll.ll_time != 0 && !quietlog) { 29512687Ssam printf("Last login: %.*s ", 29612687Ssam 24-5, (char *)ctime(&ll.ll_time)); 29712687Ssam if (*ll.ll_host != '\0') 29812687Ssam printf("from %.*s\n", 29912687Ssam sizeof (ll.ll_host), ll.ll_host); 30012687Ssam else 30112687Ssam printf("on %.*s\n", 30212687Ssam sizeof (ll.ll_line), ll.ll_line); 3032822Swnj } 3042822Swnj lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0); 3052822Swnj time(&ll.ll_time); 30616453Sroot SCPYN(ll.ll_line, tty); 30712687Ssam SCPYN(ll.ll_host, utmp.ut_host); 3082822Swnj write(f, (char *) &ll, sizeof ll); 3092822Swnj close(f); 3102822Swnj } 3111043Sbill chown(ttyn, pwd->pw_uid, pwd->pw_gid); 31224849Smckusick if (!hflag && !rflag) /* XXX */ 31318549Ssam ioctl(0, TIOCSWINSZ, &win); 3149867Ssam chmod(ttyn, 0622); 3151043Sbill setgid(pwd->pw_gid); 3166878Smckusick strncpy(name, utmp.ut_name, NMAX); 3176878Smckusick name[NMAX] = '\0'; 3189224Ssam initgroups(name, pwd->pw_gid); 31912678Ssam quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0); 3201043Sbill setuid(pwd->pw_uid); 32118549Ssam /* destroy environment unless user has asked to preserve it */ 32218549Ssam if (!pflag) 32318549Ssam environ = envinit; 32418549Ssam 32518549Ssam /* set up environment, this time without destruction */ 32618549Ssam /* copy the environment before setenving */ 32718549Ssam i = 0; 32818549Ssam while (environ[i] != NULL) 32918549Ssam i++; 33018549Ssam envnew = (char **) malloc(sizeof (char *) * (i + 1)); 33118549Ssam for (; i >= 0; i--) 33218549Ssam envnew[i] = environ[i]; 33318549Ssam environ = envnew; 33418549Ssam 33518549Ssam setenv("HOME=", pwd->pw_dir); 33618549Ssam setenv("SHELL=", pwd->pw_shell); 33718549Ssam if (term[0] == '\0') 33818549Ssam strncpy(term, stypeof(tty), sizeof(term)); 33918549Ssam setenv("TERM=", term); 34018549Ssam setenv("USER=", pwd->pw_name); 34118549Ssam setenv("PATH=", ":/usr/ucb:/bin:/usr/bin"); 34218549Ssam 3431043Sbill if ((namep = rindex(pwd->pw_shell, '/')) == NULL) 3441043Sbill namep = pwd->pw_shell; 3451043Sbill else 3461043Sbill namep++; 3471043Sbill strcat(minusnam, namep); 34816453Sroot if (tty[sizeof("tty")-1] == 'd') 34918549Ssam syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); 35018549Ssam if (pwd->pw_uid == 0) 35124852Seric syslog(LOG_NOTICE, "ROOT LOGIN %s", tty); 3526329Swnj if (!quietlog) { 35317664Sserge struct stat st; 35418549Ssam 3552822Swnj showmotd(); 3562822Swnj strcat(maildir, pwd->pw_name); 35717664Sserge if (stat(maildir, &st) == 0 && st.st_size != 0) 35817664Sserge printf("You have %smail.\n", 35918549Ssam (st.st_mtime > st.st_atime) ? "new " : ""); 3602822Swnj } 36112687Ssam signal(SIGALRM, SIG_DFL); 3621043Sbill signal(SIGQUIT, SIG_DFL); 3631043Sbill signal(SIGINT, SIG_DFL); 3643935Sroot signal(SIGTSTP, SIG_IGN); 3651043Sbill execlp(pwd->pw_shell, minusnam, 0); 3662822Swnj perror(pwd->pw_shell); 3671043Sbill printf("No shell\n"); 3681043Sbill exit(0); 3691043Sbill } 3701043Sbill 37112687Ssam getloginname(up) 37212687Ssam register struct utmp *up; 37312687Ssam { 37412687Ssam register char *namep; 37512712Ssam char c; 37612687Ssam 37712687Ssam while (up->ut_name[0] == '\0') { 37814897Sedward namep = up->ut_name; 37912712Ssam printf("login: "); 38012687Ssam while ((c = getchar()) != '\n') { 38112687Ssam if (c == ' ') 38212687Ssam c = '_'; 38312687Ssam if (c == EOF) 38412687Ssam exit(0); 38512687Ssam if (namep < up->ut_name+NMAX) 38612687Ssam *namep++ = c; 38712687Ssam } 38812687Ssam } 38914897Sedward strncpy(lusername, up->ut_name, NMAX); 39014897Sedward lusername[NMAX] = 0; 39114897Sedward if ((pwd = getpwnam(lusername)) == NULL) 39212687Ssam pwd = &nouser; 39312687Ssam } 39412687Ssam 39512687Ssam timedout() 39612687Ssam { 39712687Ssam 39812687Ssam printf("Login timed out after %d seconds\n", timeout); 39912687Ssam exit(0); 40012687Ssam } 40112687Ssam 4021043Sbill int stopmotd; 4031043Sbill catch() 4041043Sbill { 4056466Swnj 4061043Sbill signal(SIGINT, SIG_IGN); 4071043Sbill stopmotd++; 4081043Sbill } 4091043Sbill 4102822Swnj rootterm(tty) 4116466Swnj char *tty; 4122822Swnj { 41316453Sroot register struct ttyent *t; 4142822Swnj 41516453Sroot if ((t = getttynam(tty)) != NULL) { 41616453Sroot if (t->ty_status & TTY_SECURE) 41716453Sroot return (1); 4182822Swnj } 41916453Sroot return (0); 4202822Swnj } 4212822Swnj 4221043Sbill showmotd() 4231043Sbill { 4241043Sbill FILE *mf; 4251043Sbill register c; 4261043Sbill 4271043Sbill signal(SIGINT, catch); 42816453Sroot if ((mf = fopen("/etc/motd", "r")) != NULL) { 4292822Swnj while ((c = getc(mf)) != EOF && stopmotd == 0) 4301043Sbill putchar(c); 4311043Sbill fclose(mf); 4321043Sbill } 4331043Sbill signal(SIGINT, SIG_IGN); 4341043Sbill } 4351043Sbill 4362822Swnj #undef UNKNOWN 4371043Sbill #define UNKNOWN "su" 4381043Sbill 4391043Sbill char * 4401043Sbill stypeof(ttyid) 44112687Ssam char *ttyid; 4421043Sbill { 44316453Sroot register struct ttyent *t; 4441043Sbill 44516453Sroot if (ttyid == NULL || (t = getttynam(ttyid)) == NULL) 4461043Sbill return (UNKNOWN); 44716453Sroot return (t->ty_type); 4481043Sbill } 4496005Swnj 45012687Ssam doremotelogin(host) 45112687Ssam char *host; 45212687Ssam { 45312687Ssam getstr(rusername, sizeof (rusername), "remuser"); 45412687Ssam getstr(lusername, sizeof (lusername), "locuser"); 45518549Ssam getstr(term, sizeof(term), "Terminal type"); 45613470Ssam if (getuid()) { 45713470Ssam pwd = &nouser; 45824712Sbloom return(-1); 45913470Ssam } 46012687Ssam pwd = getpwnam(lusername); 46113470Ssam if (pwd == NULL) { 46213470Ssam pwd = &nouser; 46324712Sbloom return(-1); 46413470Ssam } 46524712Sbloom return(ruserok(host, (pwd->pw_uid == 0), rusername, lusername)); 46612687Ssam } 46712687Ssam 4686005Swnj getstr(buf, cnt, err) 4696005Swnj char *buf; 4706005Swnj int cnt; 4716005Swnj char *err; 4726005Swnj { 4736005Swnj char c; 4746005Swnj 4756005Swnj do { 4766005Swnj if (read(0, &c, 1) != 1) 4776005Swnj exit(1); 4786005Swnj if (--cnt < 0) { 4796005Swnj printf("%s too long\r\n", err); 4806005Swnj exit(1); 4816005Swnj } 4826005Swnj *buf++ = c; 4836005Swnj } while (c != 0); 4846005Swnj } 4856329Swnj 48612687Ssam char *speeds[] = 48712687Ssam { "0", "50", "75", "110", "134", "150", "200", "300", 48812687Ssam "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" }; 48912687Ssam #define NSPEEDS (sizeof (speeds) / sizeof (speeds[0])) 49012687Ssam 49112687Ssam doremoteterm(term, tp) 49212687Ssam char *term; 49312687Ssam struct sgttyb *tp; 49412687Ssam { 49518549Ssam register char *cp = index(term, '/'), **cpp; 49618549Ssam char *speed; 49712687Ssam 49812687Ssam if (cp) { 49918549Ssam *cp++ = '\0'; 50018549Ssam speed = cp; 50118549Ssam cp = index(speed, '/'); 50218549Ssam if (cp) 50318549Ssam *cp++ = '\0'; 50418549Ssam for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++) 50518549Ssam if (strcmp(*cpp, speed) == 0) { 50618549Ssam tp->sg_ispeed = tp->sg_ospeed = cpp-speeds; 50712687Ssam break; 50812687Ssam } 50924849Smckusick compatsiz(cp); 51012687Ssam } 51112687Ssam tp->sg_flags = ECHO|CRMOD|ANYP|XTABS; 51212687Ssam } 51318549Ssam 51424849Smckusick /* BEGIN TRASH 51524849Smckusick * 51624849Smckusick * This is here only long enough to get us by to the revised rlogin 51724849Smckusick */ 51824849Smckusick compatsiz(cp) 51924849Smckusick char *cp; 52024849Smckusick { 52124849Smckusick struct winsize ws; 52224849Smckusick 52324849Smckusick ws.ws_row = ws.ws_col = -1; 52424849Smckusick ws.ws_xpixel = ws.ws_ypixel = -1; 52524849Smckusick if (cp) { 52624849Smckusick ws.ws_row = atoi(cp); 52724849Smckusick cp = index(cp, ','); 52824849Smckusick if (cp == 0) 52924849Smckusick goto done; 53024849Smckusick ws.ws_col = atoi(++cp); 53124849Smckusick cp = index(cp, ','); 53224849Smckusick if (cp == 0) 53324849Smckusick goto done; 53424849Smckusick ws.ws_xpixel = atoi(++cp); 53524849Smckusick cp = index(cp, ','); 53624849Smckusick if (cp == 0) 53724849Smckusick goto done; 53824849Smckusick ws.ws_ypixel = atoi(++cp); 53924849Smckusick } 54024849Smckusick done: 54124849Smckusick if (ws.ws_row != -1 && ws.ws_col != -1 && 54224849Smckusick ws.ws_xpixel != -1 && ws.ws_ypixel != -1) 54324849Smckusick ioctl(0, TIOCSWINSZ, &ws); 54424849Smckusick } 54524849Smckusick /* END TRASH */ 54624849Smckusick 54718549Ssam /* 54818549Ssam * Set the value of var to be arg in the Unix 4.2 BSD environment env. 54918549Ssam * Var should end with '='. 55018549Ssam * (bindings are of the form "var=value") 55118549Ssam * This procedure assumes the memory for the first level of environ 55218549Ssam * was allocated using malloc. 55318549Ssam */ 55418549Ssam setenv(var, value) 55518549Ssam char *var, *value; 55618549Ssam { 55718549Ssam extern char **environ; 55818549Ssam int index = 0; 55918549Ssam int varlen = strlen(var); 56018549Ssam int vallen = strlen(value); 56118549Ssam 56218549Ssam for (index = 0; environ[index] != NULL; index++) { 56318549Ssam if (strncmp(environ[index], var, varlen) == 0) { 56418549Ssam /* found it */ 56518549Ssam environ[index] = malloc(varlen + vallen + 1); 56618549Ssam strcpy(environ[index], var); 56718549Ssam strcat(environ[index], value); 56818549Ssam return; 56918549Ssam } 57018549Ssam } 57118549Ssam environ = (char **) realloc(environ, sizeof (char *) * (index + 2)); 57218549Ssam if (environ == NULL) { 57318549Ssam fprintf(stderr, "login: malloc out of memory\n"); 57418549Ssam exit(1); 57518549Ssam } 57618549Ssam environ[index] = malloc(varlen + vallen + 1); 57718549Ssam strcpy(environ[index], var); 57818549Ssam strcat(environ[index], value); 57918549Ssam environ[++index] = NULL; 58018549Ssam } 581