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*26482Skarels static char sccsid[] = "@(#)login.c 5.12 (Berkeley) 03/05/86"; 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) 4425230Smckusick #define HMAX sizeof(utmp.ut_host) 451043Sbill 462822Swnj #define FALSE 0 472822Swnj #define TRUE -1 482822Swnj 492822Swnj char nolog[] = "/etc/nologin"; 502822Swnj char qlog[] = ".hushlogin"; 511043Sbill char maildir[30] = "/usr/spool/mail/"; 521043Sbill char lastlog[] = "/usr/adm/lastlog"; 539867Ssam struct passwd nouser = {"", "nope", -1, -1, -1, "", "", "", "" }; 541043Sbill struct sgttyb ttyb; 551043Sbill struct utmp utmp; 561043Sbill char minusnam[16] = "-"; 5718549Ssam char *envinit[] = { 0 }; /* now set by setenv calls */ 5812687Ssam /* 5912687Ssam * This bounds the time given to login. We initialize it here 6012687Ssam * so it can be patched on machines where it's too small. 6112687Ssam */ 6212687Ssam int timeout = 60; 636005Swnj 6418549Ssam char term[64]; 656005Swnj 661043Sbill struct passwd *pwd; 6718549Ssam char *strcat(), *rindex(), *index(), *malloc(), *realloc(); 6812687Ssam int timedout(); 691043Sbill char *ttyname(); 701043Sbill char *crypt(); 711043Sbill char *getpass(); 721043Sbill char *stypeof(); 731043Sbill extern char **environ; 7412678Ssam extern int errno; 751043Sbill 7613074Ssam struct tchars tc = { 7713074Ssam CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK 781365Sbill }; 7913074Ssam struct ltchars ltc = { 8013074Ssam CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT 8113074Ssam }; 821365Sbill 8318549Ssam struct winsize win = { 0, 0, 0, 0 }; 8418549Ssam 856005Swnj int rflag; 8624712Sbloom int usererr = -1; 876197Sroot char rusername[NMAX+1], lusername[NMAX+1]; 886005Swnj char rpassword[NMAX+1]; 896878Smckusick char name[NMAX+1]; 906197Sroot char *rhost; 916005Swnj 921043Sbill main(argc, argv) 9312687Ssam char *argv[]; 941043Sbill { 951043Sbill register char *namep; 9618549Ssam int pflag = 0, hflag = 0, t, f, c; 9712687Ssam int invalid, quietlog; 982822Swnj FILE *nlfd; 9916453Sroot char *ttyn, *tty; 10018549Ssam int ldisc = 0, zero = 0, i; 10118549Ssam char **envnew; 1021043Sbill 10312687Ssam signal(SIGALRM, timedout); 10412687Ssam alarm(timeout); 1051043Sbill signal(SIGQUIT, SIG_IGN); 1061043Sbill signal(SIGINT, SIG_IGN); 10712687Ssam setpriority(PRIO_PROCESS, 0, 0); 10812678Ssam quota(Q_SETUID, 0, 0, 0); 10912687Ssam /* 11018549Ssam * -p is used by getty to tell login not to destroy the environment 11112687Ssam * -r is used by rlogind to cause the autologin protocol; 11212687Ssam * -h is used by other servers to pass the name of the 11312687Ssam * remote host to login so that it may be placed in utmp and wtmp 11412687Ssam */ 11524712Sbloom while (argc > 1) { 11612687Ssam if (strcmp(argv[1], "-r") == 0) { 11724712Sbloom if (rflag || hflag) { 11824712Sbloom printf("Only one of -r and -h allowed\n"); 11924712Sbloom exit(1); 12024712Sbloom } 12124712Sbloom rflag = 1; 12224712Sbloom usererr = doremotelogin(argv[2]); 12312687Ssam SCPYN(utmp.ut_host, argv[2]); 12424712Sbloom argc -= 2; 12524712Sbloom argv += 2; 12624712Sbloom continue; 1276197Sroot } 12812687Ssam if (strcmp(argv[1], "-h") == 0 && getuid() == 0) { 12924712Sbloom if (rflag || hflag) { 13024712Sbloom printf("Only one of -r and -h allowed\n"); 13124712Sbloom exit(1); 13224712Sbloom } 13318549Ssam hflag = 1; 13412687Ssam SCPYN(utmp.ut_host, argv[2]); 13524712Sbloom argc -= 2; 13624712Sbloom argv += 2; 13724712Sbloom continue; 1386197Sroot } 13918549Ssam if (strcmp(argv[1], "-p") == 0) { 14018549Ssam argc--; 14118549Ssam argv++; 14218549Ssam pflag = 1; 14324712Sbloom continue; 14418549Ssam } 14524712Sbloom break; 1466005Swnj } 14713074Ssam ioctl(0, TIOCLSET, &zero); 1481547Sbill ioctl(0, TIOCNXCL, 0); 1496329Swnj ioctl(0, FIONBIO, &zero); 1506329Swnj ioctl(0, FIOASYNC, &zero); 15113074Ssam ioctl(0, TIOCGETP, &ttyb); 15212687Ssam /* 15312687Ssam * If talking to an rlogin process, 15412687Ssam * propagate the terminal type and 15512687Ssam * baud rate across the network. 15612687Ssam */ 15712687Ssam if (rflag) 15812687Ssam doremoteterm(term, &ttyb); 159*26482Skarels ttyb.sg_erase = CERASE; 160*26482Skarels ttyb.sg_kill = CKILL; 16113074Ssam ioctl(0, TIOCSLTC, <c); 16213074Ssam ioctl(0, TIOCSETC, &tc); 16313074Ssam ioctl(0, TIOCSETP, &ttyb); 16424849Smckusick for (t = getdtablesize(); t > 2; t--) 1651043Sbill close(t); 1661043Sbill ttyn = ttyname(0); 16725426Sbloom if (ttyn == (char *)0 || *ttyn == '\0') 1681043Sbill ttyn = "/dev/tty??"; 16916453Sroot tty = rindex(ttyn, '/'); 17016453Sroot if (tty == NULL) 17116453Sroot tty = ttyn; 17216453Sroot else 17316453Sroot tty++; 17424852Seric openlog("login", LOG_ODELAY, LOG_AUTH); 17516453Sroot t = 0; 17625163Sbloom invalid = FALSE; 1772822Swnj do { 1782822Swnj ldisc = 0; 1792822Swnj ioctl(0, TIOCSETD, &ldisc); 1802822Swnj SCPYN(utmp.ut_name, ""); 18112687Ssam /* 18212687Ssam * Name specified, take it. 18312687Ssam */ 18412687Ssam if (argc > 1) { 1852822Swnj SCPYN(utmp.ut_name, argv[1]); 1862822Swnj argc = 0; 1871043Sbill } 18812687Ssam /* 18912687Ssam * If remote login take given name, 19012687Ssam * otherwise prompt user for something. 19112687Ssam */ 19225163Sbloom if (rflag && !invalid) 1939867Ssam SCPYN(utmp.ut_name, lusername); 19424883Smckusick else 19512687Ssam getloginname(&utmp); 19625163Sbloom invalid = FALSE; 1972822Swnj if (!strcmp(pwd->pw_shell, "/bin/csh")) { 1982822Swnj ldisc = NTTYDISC; 1992822Swnj ioctl(0, TIOCSETD, &ldisc); 2002822Swnj } 20112687Ssam /* 20212687Ssam * If no remote login authentication and 20312687Ssam * a password exists for this user, prompt 20412687Ssam * for one and verify it. 20512687Ssam */ 20624712Sbloom if (usererr == -1 && *pwd->pw_passwd != '\0') { 20712687Ssam char *pp; 20812687Ssam 20912687Ssam setpriority(PRIO_PROCESS, 0, -4); 21012687Ssam pp = getpass("Password:"); 21112687Ssam namep = crypt(pp, pwd->pw_passwd); 21212687Ssam setpriority(PRIO_PROCESS, 0, 0); 21312687Ssam if (strcmp(namep, pwd->pw_passwd)) 21412687Ssam invalid = TRUE; 2152822Swnj } 21612687Ssam /* 21712687Ssam * If user not super-user, check for logins disabled. 21812687Ssam */ 2192822Swnj if (pwd->pw_uid != 0 && (nlfd = fopen(nolog, "r")) > 0) { 2202822Swnj while ((c = getc(nlfd)) != EOF) 2212822Swnj putchar(c); 2222822Swnj fflush(stdout); 2232822Swnj sleep(5); 2242822Swnj exit(0); 2252822Swnj } 22612687Ssam /* 22712687Ssam * If valid so far and root is logging in, 22812687Ssam * see if root logins on this terminal are permitted. 22912687Ssam */ 23016453Sroot if (!invalid && pwd->pw_uid == 0 && !rootterm(tty)) { 23125230Smckusick if (utmp.ut_host[0]) 23225230Smckusick syslog(LOG_CRIT, 23325230Smckusick "ROOT LOGIN REFUSED ON %s FROM %.*s", 23425230Smckusick tty, HMAX, utmp.ut_host); 23525230Smckusick else 23625230Smckusick syslog(LOG_CRIT, 23725230Smckusick "ROOT LOGIN REFUSED ON %s", tty); 2382822Swnj invalid = TRUE; 2392822Swnj } 2402822Swnj if (invalid) { 2411043Sbill printf("Login incorrect\n"); 24216453Sroot if (++t >= 5) { 24325230Smckusick if (utmp.ut_host[0]) 24425230Smckusick syslog(LOG_CRIT, 24525230Smckusick "REPEATED LOGIN FAILURES ON %s FROM %.*s, %.*s", 24625230Smckusick tty, HMAX, utmp.ut_host, 24725230Smckusick NMAX, utmp.ut_name); 24825230Smckusick else 24925230Smckusick syslog(LOG_CRIT, 25025230Smckusick "REPEATED LOGIN FAILURES ON %s, %.*s", 25125230Smckusick tty, NMAX, utmp.ut_name); 25216453Sroot ioctl(0, TIOCHPCL, (struct sgttyb *) 0); 25318549Ssam close(0), close(1), close(2); 25416453Sroot sleep(10); 25516453Sroot exit(1); 25616453Sroot } 2571043Sbill } 2582822Swnj if (*pwd->pw_shell == '\0') 2592822Swnj pwd->pw_shell = "/bin/sh"; 2602822Swnj if (chdir(pwd->pw_dir) < 0 && !invalid ) { 2612822Swnj if (chdir("/") < 0) { 2622822Swnj printf("No directory!\n"); 2632822Swnj invalid = TRUE; 2642822Swnj } else { 26512687Ssam printf("No directory! %s\n", 26612687Ssam "Logging in with home=/"); 2672822Swnj pwd->pw_dir = "/"; 2682822Swnj } 2691043Sbill } 27012687Ssam /* 27112687Ssam * Remote login invalid must have been because 27212687Ssam * of a restriction of some sort, no extra chances. 27312687Ssam */ 27424712Sbloom if (!usererr && invalid) 2756005Swnj exit(1); 2762822Swnj } while (invalid); 27712687Ssam /* committed to login turn off timeout */ 27812687Ssam alarm(0); 2791043Sbill 28021083Smckusick if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) { 28112678Ssam if (errno == EUSERS) 28212678Ssam printf("%s.\n%s.\n", 28312678Ssam "Too many users logged on already", 28412678Ssam "Try again later"); 28512678Ssam else if (errno == EPROCLIM) 28612678Ssam printf("You have too many processes running.\n"); 28712678Ssam else 28817664Sserge perror("quota (Q_SETUID)"); 28912678Ssam sleep(5); 29012678Ssam exit(0); 29112678Ssam } 2921043Sbill time(&utmp.ut_time); 2931043Sbill t = ttyslot(); 29416453Sroot if (t > 0 && (f = open("/etc/utmp", O_WRONLY)) >= 0) { 2951043Sbill lseek(f, (long)(t*sizeof(utmp)), 0); 29616453Sroot SCPYN(utmp.ut_line, tty); 2971043Sbill write(f, (char *)&utmp, sizeof(utmp)); 2981043Sbill close(f); 2991043Sbill } 30016453Sroot if ((f = open("/usr/adm/wtmp", O_WRONLY|O_APPEND)) >= 0) { 3011043Sbill write(f, (char *)&utmp, sizeof(utmp)); 3021043Sbill close(f); 3031043Sbill } 30416453Sroot quietlog = access(qlog, F_OK) == 0; 30516453Sroot if ((f = open(lastlog, O_RDWR)) >= 0) { 3062822Swnj struct lastlog ll; 3072822Swnj 3082822Swnj lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0); 3092822Swnj if (read(f, (char *) &ll, sizeof ll) == sizeof ll && 31012687Ssam ll.ll_time != 0 && !quietlog) { 31112687Ssam printf("Last login: %.*s ", 31212687Ssam 24-5, (char *)ctime(&ll.ll_time)); 31312687Ssam if (*ll.ll_host != '\0') 31412687Ssam printf("from %.*s\n", 31512687Ssam sizeof (ll.ll_host), ll.ll_host); 31612687Ssam else 31712687Ssam printf("on %.*s\n", 31812687Ssam sizeof (ll.ll_line), ll.ll_line); 3192822Swnj } 3202822Swnj lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0); 3212822Swnj time(&ll.ll_time); 32216453Sroot SCPYN(ll.ll_line, tty); 32312687Ssam SCPYN(ll.ll_host, utmp.ut_host); 3242822Swnj write(f, (char *) &ll, sizeof ll); 3252822Swnj close(f); 3262822Swnj } 3271043Sbill chown(ttyn, pwd->pw_uid, pwd->pw_gid); 32824849Smckusick if (!hflag && !rflag) /* XXX */ 32918549Ssam ioctl(0, TIOCSWINSZ, &win); 3309867Ssam chmod(ttyn, 0622); 3311043Sbill setgid(pwd->pw_gid); 3326878Smckusick strncpy(name, utmp.ut_name, NMAX); 3336878Smckusick name[NMAX] = '\0'; 3349224Ssam initgroups(name, pwd->pw_gid); 33512678Ssam quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0); 3361043Sbill setuid(pwd->pw_uid); 33718549Ssam /* destroy environment unless user has asked to preserve it */ 33818549Ssam if (!pflag) 33918549Ssam environ = envinit; 34018549Ssam 34118549Ssam /* set up environment, this time without destruction */ 34218549Ssam /* copy the environment before setenving */ 34318549Ssam i = 0; 34418549Ssam while (environ[i] != NULL) 34518549Ssam i++; 34618549Ssam envnew = (char **) malloc(sizeof (char *) * (i + 1)); 34718549Ssam for (; i >= 0; i--) 34818549Ssam envnew[i] = environ[i]; 34918549Ssam environ = envnew; 35018549Ssam 35124966Skarels setenv("HOME=", pwd->pw_dir, 1); 35224966Skarels setenv("SHELL=", pwd->pw_shell, 1); 35318549Ssam if (term[0] == '\0') 35418549Ssam strncpy(term, stypeof(tty), sizeof(term)); 35524966Skarels setenv("TERM=", term, 0); 35624966Skarels setenv("USER=", pwd->pw_name, 1); 35724966Skarels setenv("PATH=", ":/usr/ucb:/bin:/usr/bin", 0); 35818549Ssam 3591043Sbill if ((namep = rindex(pwd->pw_shell, '/')) == NULL) 3601043Sbill namep = pwd->pw_shell; 3611043Sbill else 3621043Sbill namep++; 3631043Sbill strcat(minusnam, namep); 36416453Sroot if (tty[sizeof("tty")-1] == 'd') 36518549Ssam syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); 36618549Ssam if (pwd->pw_uid == 0) 36725230Smckusick if (utmp.ut_host[0]) 36825230Smckusick syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s", 36925230Smckusick tty, HMAX, utmp.ut_host); 37025230Smckusick else 37125230Smckusick syslog(LOG_NOTICE, "ROOT LOGIN %s", tty); 3726329Swnj if (!quietlog) { 37317664Sserge struct stat st; 37418549Ssam 3752822Swnj showmotd(); 3762822Swnj strcat(maildir, pwd->pw_name); 37717664Sserge if (stat(maildir, &st) == 0 && st.st_size != 0) 37817664Sserge printf("You have %smail.\n", 37918549Ssam (st.st_mtime > st.st_atime) ? "new " : ""); 3802822Swnj } 38112687Ssam signal(SIGALRM, SIG_DFL); 3821043Sbill signal(SIGQUIT, SIG_DFL); 3831043Sbill signal(SIGINT, SIG_DFL); 3843935Sroot signal(SIGTSTP, SIG_IGN); 3851043Sbill execlp(pwd->pw_shell, minusnam, 0); 3862822Swnj perror(pwd->pw_shell); 3871043Sbill printf("No shell\n"); 3881043Sbill exit(0); 3891043Sbill } 3901043Sbill 39112687Ssam getloginname(up) 39212687Ssam register struct utmp *up; 39312687Ssam { 39412687Ssam register char *namep; 39512712Ssam char c; 39612687Ssam 39712687Ssam while (up->ut_name[0] == '\0') { 39814897Sedward namep = up->ut_name; 39912712Ssam printf("login: "); 40012687Ssam while ((c = getchar()) != '\n') { 40112687Ssam if (c == ' ') 40212687Ssam c = '_'; 40312687Ssam if (c == EOF) 40412687Ssam exit(0); 40512687Ssam if (namep < up->ut_name+NMAX) 40612687Ssam *namep++ = c; 40712687Ssam } 40812687Ssam } 40914897Sedward strncpy(lusername, up->ut_name, NMAX); 41014897Sedward lusername[NMAX] = 0; 41114897Sedward if ((pwd = getpwnam(lusername)) == NULL) 41212687Ssam pwd = &nouser; 41312687Ssam } 41412687Ssam 41512687Ssam timedout() 41612687Ssam { 41712687Ssam 41812687Ssam printf("Login timed out after %d seconds\n", timeout); 41912687Ssam exit(0); 42012687Ssam } 42112687Ssam 4221043Sbill int stopmotd; 4231043Sbill catch() 4241043Sbill { 4256466Swnj 4261043Sbill signal(SIGINT, SIG_IGN); 4271043Sbill stopmotd++; 4281043Sbill } 4291043Sbill 4302822Swnj rootterm(tty) 4316466Swnj char *tty; 4322822Swnj { 43316453Sroot register struct ttyent *t; 4342822Swnj 43516453Sroot if ((t = getttynam(tty)) != NULL) { 43616453Sroot if (t->ty_status & TTY_SECURE) 43716453Sroot return (1); 4382822Swnj } 43916453Sroot return (0); 4402822Swnj } 4412822Swnj 4421043Sbill showmotd() 4431043Sbill { 4441043Sbill FILE *mf; 4451043Sbill register c; 4461043Sbill 4471043Sbill signal(SIGINT, catch); 44816453Sroot if ((mf = fopen("/etc/motd", "r")) != NULL) { 4492822Swnj while ((c = getc(mf)) != EOF && stopmotd == 0) 4501043Sbill putchar(c); 4511043Sbill fclose(mf); 4521043Sbill } 4531043Sbill signal(SIGINT, SIG_IGN); 4541043Sbill } 4551043Sbill 4562822Swnj #undef UNKNOWN 4571043Sbill #define UNKNOWN "su" 4581043Sbill 4591043Sbill char * 4601043Sbill stypeof(ttyid) 46112687Ssam char *ttyid; 4621043Sbill { 46316453Sroot register struct ttyent *t; 4641043Sbill 46516453Sroot if (ttyid == NULL || (t = getttynam(ttyid)) == NULL) 4661043Sbill return (UNKNOWN); 46716453Sroot return (t->ty_type); 4681043Sbill } 4696005Swnj 47012687Ssam doremotelogin(host) 47112687Ssam char *host; 47212687Ssam { 47312687Ssam getstr(rusername, sizeof (rusername), "remuser"); 47412687Ssam getstr(lusername, sizeof (lusername), "locuser"); 47518549Ssam getstr(term, sizeof(term), "Terminal type"); 47613470Ssam if (getuid()) { 47713470Ssam pwd = &nouser; 47824712Sbloom return(-1); 47913470Ssam } 48012687Ssam pwd = getpwnam(lusername); 48113470Ssam if (pwd == NULL) { 48213470Ssam pwd = &nouser; 48324712Sbloom return(-1); 48413470Ssam } 48524712Sbloom return(ruserok(host, (pwd->pw_uid == 0), rusername, lusername)); 48612687Ssam } 48712687Ssam 4886005Swnj getstr(buf, cnt, err) 4896005Swnj char *buf; 4906005Swnj int cnt; 4916005Swnj char *err; 4926005Swnj { 4936005Swnj char c; 4946005Swnj 4956005Swnj do { 4966005Swnj if (read(0, &c, 1) != 1) 4976005Swnj exit(1); 4986005Swnj if (--cnt < 0) { 4996005Swnj printf("%s too long\r\n", err); 5006005Swnj exit(1); 5016005Swnj } 5026005Swnj *buf++ = c; 5036005Swnj } while (c != 0); 5046005Swnj } 5056329Swnj 50612687Ssam char *speeds[] = 50712687Ssam { "0", "50", "75", "110", "134", "150", "200", "300", 50812687Ssam "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" }; 50912687Ssam #define NSPEEDS (sizeof (speeds) / sizeof (speeds[0])) 51012687Ssam 51112687Ssam doremoteterm(term, tp) 51212687Ssam char *term; 51312687Ssam struct sgttyb *tp; 51412687Ssam { 51518549Ssam register char *cp = index(term, '/'), **cpp; 51618549Ssam char *speed; 51712687Ssam 51812687Ssam if (cp) { 51918549Ssam *cp++ = '\0'; 52018549Ssam speed = cp; 52118549Ssam cp = index(speed, '/'); 52218549Ssam if (cp) 52318549Ssam *cp++ = '\0'; 52418549Ssam for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++) 52518549Ssam if (strcmp(*cpp, speed) == 0) { 52618549Ssam tp->sg_ispeed = tp->sg_ospeed = cpp-speeds; 52712687Ssam break; 52812687Ssam } 52912687Ssam } 53012687Ssam tp->sg_flags = ECHO|CRMOD|ANYP|XTABS; 53112687Ssam } 53218549Ssam 53318549Ssam /* 53418549Ssam * Set the value of var to be arg in the Unix 4.2 BSD environment env. 53518549Ssam * Var should end with '='. 53618549Ssam * (bindings are of the form "var=value") 53718549Ssam * This procedure assumes the memory for the first level of environ 53818549Ssam * was allocated using malloc. 53918549Ssam */ 54024966Skarels setenv(var, value, clobber) 54118549Ssam char *var, *value; 54218549Ssam { 54318549Ssam extern char **environ; 54418549Ssam int index = 0; 54518549Ssam int varlen = strlen(var); 54618549Ssam int vallen = strlen(value); 54718549Ssam 54818549Ssam for (index = 0; environ[index] != NULL; index++) { 54918549Ssam if (strncmp(environ[index], var, varlen) == 0) { 55018549Ssam /* found it */ 55124966Skarels if (!clobber) 55224966Skarels return; 55318549Ssam environ[index] = malloc(varlen + vallen + 1); 55418549Ssam strcpy(environ[index], var); 55518549Ssam strcat(environ[index], value); 55618549Ssam return; 55718549Ssam } 55818549Ssam } 55918549Ssam environ = (char **) realloc(environ, sizeof (char *) * (index + 2)); 56018549Ssam if (environ == NULL) { 56118549Ssam fprintf(stderr, "login: malloc out of memory\n"); 56218549Ssam exit(1); 56318549Ssam } 56418549Ssam environ[index] = malloc(varlen + vallen + 1); 56518549Ssam strcpy(environ[index], var); 56618549Ssam strcat(environ[index], value); 56718549Ssam environ[++index] = NULL; 56818549Ssam } 569