diff options
| author | Peter Wemm <peter@FreeBSD.org> | 1997-06-27 14:53:01 +0000 | 
|---|---|---|
| committer | Peter Wemm <peter@FreeBSD.org> | 1997-06-27 14:53:01 +0000 | 
| commit | f3a1fc342b4423150f71e23e50f24d073a6d238b (patch) | |
| tree | a5e7dee2f9ff41f2d43580f859a6e8970722fa7d /usr.sbin/sendmail/src/util.c | |
| parent | 52c4d6f5d6bb1ffd8b30c0429fc18d371856a062 (diff) | |
Notes
Diffstat (limited to 'usr.sbin/sendmail/src/util.c')
| -rw-r--r-- | usr.sbin/sendmail/src/util.c | 669 | 
1 files changed, 174 insertions, 495 deletions
| diff --git a/usr.sbin/sendmail/src/util.c b/usr.sbin/sendmail/src/util.c index dbe76552394a6..98435f3aa7fef 100644 --- a/usr.sbin/sendmail/src/util.c +++ b/usr.sbin/sendmail/src/util.c @@ -1,5 +1,5 @@  /* - * Copyright (c) 1983, 1995, 1996 Eric P. Allman + * Copyright (c) 1983, 1995-1997 Eric P. Allman   * Copyright (c) 1988, 1993   *	The Regents of the University of California.  All rights reserved.   * @@ -33,7 +33,7 @@   */  #ifndef lint -static char sccsid[] = "@(#)util.c	8.115 (Berkeley) 1/5/97"; +static char sccsid[] = "@(#)util.c	8.129 (Berkeley) 6/11/97";  #endif /* not lint */  # include "sendmail.h" @@ -449,352 +449,6 @@ buildfname(gecos, login, buf, buflen)  	*bp = '\0';  }  /* -**  SAFEFILE -- return true if a file exists and is safe for a user. -** -**	Parameters: -**		fn -- filename to check. -**		uid -- user id to compare against. -**		gid -- group id to compare against. -**		uname -- user name to compare against (used for group -**			sets). -**		flags -- modifiers: -**			SFF_MUSTOWN -- "uid" must own this file. -**			SFF_NOSLINK -- file cannot be a symbolic link. -**		mode -- mode bits that must match. -**		st -- if set, points to a stat structure that will -**			get the stat info for the file. -** -**	Returns: -**		0 if fn exists, is owned by uid, and matches mode. -**		An errno otherwise.  The actual errno is cleared. -** -**	Side Effects: -**		none. -*/ - -#include <grp.h> - -#ifndef S_IXOTH -# define S_IXOTH	(S_IEXEC >> 6) -#endif - -#ifndef S_IXGRP -# define S_IXGRP	(S_IEXEC >> 3) -#endif - -#ifndef S_IXUSR -# define S_IXUSR	(S_IEXEC) -#endif - -#define ST_MODE_NOFILE	0171147		/* unlikely to occur */ - -int -safefile(fn, uid, gid, uname, flags, mode, st) -	char *fn; -	UID_T uid; -	GID_T gid; -	char *uname; -	int flags; -	int mode; -	struct stat *st; -{ -	register char *p; -	register struct group *gr = NULL; -	int file_errno = 0; -	struct stat stbuf; -	struct stat fstbuf; - -	if (tTd(44, 4)) -		printf("safefile(%s, uid=%d, gid=%d, flags=%x, mode=%o):\n", -			fn, (int) uid, (int) gid, flags, mode); -	errno = 0; -	if (st == NULL) -		st = &fstbuf; - -	/* first check to see if the file exists at all */ -#ifdef HASLSTAT -	if ((bitset(SFF_NOSLINK, flags) ? lstat(fn, st) -					: stat(fn, st)) < 0) -#else -	if (stat(fn, st) < 0) -#endif -	{ -		file_errno = errno; -	} -	else if (bitset(SFF_SETUIDOK, flags) && -		 !bitset(S_IXUSR|S_IXGRP|S_IXOTH, st->st_mode) && -		 S_ISREG(st->st_mode)) -	{ -		/* -		**  If final file is setuid, run as the owner of that -		**  file.  Gotta be careful not to reveal anything too -		**  soon here! -		*/ - -#ifdef SUID_ROOT_FILES_OK -		if (bitset(S_ISUID, st->st_mode)) -#else -		if (bitset(S_ISUID, st->st_mode) && st->st_uid != 0) -#endif -		{ -			uid = st->st_uid; -			uname = NULL; -		} -#ifdef SUID_ROOT_FILES_OK -		if (bitset(S_ISGID, st->st_mode)) -#else -		if (bitset(S_ISGID, st->st_mode) && st->st_gid != 0) -#endif -			gid = st->st_gid; -	} - -	if (!bitset(SFF_NOPATHCHECK, flags) || -	    (uid == 0 && !bitset(SFF_ROOTOK, flags))) -	{ -		/* check the path to the file for acceptability */ -		for (p = fn; (p = strchr(++p, '/')) != NULL; *p = '/') -		{ -			*p = '\0'; -			if (stat(fn, &stbuf) < 0) -				break; -			if (uid == 0 && bitset(S_IWGRP|S_IWOTH, stbuf.st_mode)) -				message("051 WARNING: writable directory %s", -					fn); -			if (uid == 0 && !bitset(SFF_ROOTOK, flags)) -			{ -				if (bitset(S_IXOTH, stbuf.st_mode)) -					continue; -				break; -			} -			if (stbuf.st_uid == uid && -			    bitset(S_IXUSR, stbuf.st_mode)) -				continue; -			if (stbuf.st_gid == gid && -			    bitset(S_IXGRP, stbuf.st_mode)) -				continue; -#ifndef NO_GROUP_SET -			if (uname != NULL && !DontInitGroups && -			    ((gr != NULL && gr->gr_gid == stbuf.st_gid) || -			     (gr = getgrgid(stbuf.st_gid)) != NULL)) -			{ -				register char **gp; - -				for (gp = gr->gr_mem; gp != NULL && *gp != NULL; gp++) -					if (strcmp(*gp, uname) == 0) -						break; -				if (gp != NULL && *gp != NULL && -				    bitset(S_IXGRP, stbuf.st_mode)) -					continue; -			} -#endif -			if (!bitset(S_IXOTH, stbuf.st_mode)) -				break; -		} -		if (p != NULL) -		{ -			int ret = errno; - -			if (ret == 0) -				ret = EACCES; -			if (tTd(44, 4)) -				printf("\t[dir %s] %s\n", fn, errstring(ret)); -			*p = '/'; -			return ret; -		} -	} - -	/* -	**  If the target file doesn't exist, check the directory to -	**  ensure that it is writable by this user. -	*/ - -	if (file_errno != 0) -	{ -		int ret = file_errno; - -		if (tTd(44, 4)) -			printf("\t%s\n", errstring(ret)); - -		errno = 0; -		if (!bitset(SFF_CREAT, flags)) -			return ret; - -		/* check to see if legal to create the file */ -		p = strrchr(fn, '/'); -		if (p == NULL) -			return ENOTDIR; -		*p = '\0'; -		if (stat(fn, &stbuf) >= 0) -		{ -			int md = S_IWRITE|S_IEXEC; -			if (stbuf.st_uid != uid) -				md >>= 6; -			if ((stbuf.st_mode & md) != md) -				errno = EACCES; -		} -		ret = errno; -		if (tTd(44, 4)) -			printf("\t[final dir %s uid %d mode %lo] %s\n", -				fn, (int) stbuf.st_uid, (u_long) stbuf.st_mode, -				errstring(ret)); -		*p = '/'; -		st->st_mode = ST_MODE_NOFILE; -		return ret; -	} - -#ifdef S_ISLNK -	if (bitset(SFF_NOSLINK, flags) && S_ISLNK(st->st_mode)) -	{ -		if (tTd(44, 4)) -			printf("\t[slink mode %o]\tEPERM\n", st->st_mode); -		return EPERM; -	} -#endif -	if (bitset(SFF_REGONLY, flags) && !S_ISREG(st->st_mode)) -	{ -		if (tTd(44, 4)) -			printf("\t[non-reg mode %o]\tEPERM\n", st->st_mode); -		return EPERM; -	} -	if (bitset(S_IWUSR|S_IWGRP|S_IWOTH, mode) && -	    bitset(S_IXUSR|S_IXGRP|S_IXOTH, st->st_mode)) -	{ -		if (tTd(44, 4)) -			printf("\t[exec bits %o]\tEPERM]\n", st->st_mode); -		return EPERM; -	} -	if (st->st_nlink > 1) -	{ -		if (tTd(44, 4)) -			printf("\t[link count %d]\tEPERM\n", st->st_nlink); -		return EPERM; -	} - -	if (uid == 0 && bitset(SFF_OPENASROOT, flags)) -		; -	else if (uid == 0 && !bitset(SFF_ROOTOK, flags)) -		mode >>= 6; -	else if (st->st_uid != uid) -	{ -		mode >>= 3; -		if (st->st_gid == gid) -			; -#ifndef NO_GROUP_SET -		else if (uname != NULL && !DontInitGroups && -			 ((gr != NULL && gr->gr_gid == st->st_gid) || -			  (gr = getgrgid(st->st_gid)) != NULL)) -		{ -			register char **gp; - -			for (gp = gr->gr_mem; *gp != NULL; gp++) -				if (strcmp(*gp, uname) == 0) -					break; -			if (*gp == NULL) -				mode >>= 3; -		} -#endif -		else -			mode >>= 3; -	} -	if (tTd(44, 4)) -		printf("\t[uid %d, nlink %d, stat %lo, mode %lo] ", -			(int) st->st_uid, (int) st->st_nlink, -			(u_long) st->st_mode, (u_long) mode); -	if ((st->st_uid == uid || st->st_uid == 0 || -	     !bitset(SFF_MUSTOWN, flags)) && -	    (st->st_mode & mode) == mode) -	{ -		if (tTd(44, 4)) -			printf("\tOK\n"); -		return 0; -	} -	if (tTd(44, 4)) -		printf("\tEACCES\n"); -	return EACCES; -} -/* -**  SAFEFOPEN -- do a file open with extra checking -** -**	Parameters: -**		fn -- the file name to open. -**		omode -- the open-style mode flags. -**		cmode -- the create-style mode flags. -**		sff -- safefile flags. -** -**	Returns: -**		Same as fopen. -*/ - -#ifndef O_ACCMODE -# define O_ACCMODE	(O_RDONLY|O_WRONLY|O_RDWR) -#endif - -FILE * -safefopen(fn, omode, cmode, sff) -	char *fn; -	int omode; -	int cmode; -	int sff; -{ -	int rval; -	FILE *fp; -	int smode; -	struct stat stb, sta; - -	if (bitset(O_CREAT, omode)) -		sff |= SFF_CREAT; -	smode = 0; -	switch (omode & O_ACCMODE) -	{ -	  case O_RDONLY: -		smode = S_IREAD; -		break; - -	  case O_WRONLY: -		smode = S_IWRITE; -		break; - -	  case O_RDWR: -		smode = S_IREAD|S_IWRITE; -		break; - -	  default: -		smode = 0; -		break; -	} -	if (bitset(SFF_OPENASROOT, sff)) -		rval = safefile(fn, 0, 0, NULL, sff, smode, &stb); -	else -		rval = safefile(fn, RealUid, RealGid, RealUserName, -				sff, smode, &stb); -	if (rval != 0) -	{ -		errno = rval; -		return NULL; -	} -	if (stb.st_mode == ST_MODE_NOFILE) -		omode |= O_EXCL; - -	fp = dfopen(fn, omode, cmode); -	if (fp == NULL) -		return NULL; -	if (bitset(O_EXCL, omode)) -		return fp; -	if (fstat(fileno(fp), &sta) < 0 || -	    sta.st_nlink != stb.st_nlink || -	    sta.st_dev != stb.st_dev || -	    sta.st_ino != stb.st_ino || -	    sta.st_uid != stb.st_uid || -	    sta.st_gid != stb.st_gid) -	{ -		syserr("554 cannot open: file %s changed after open", fn); -		fclose(fp); -		errno = EPERM; -		return NULL; -	} -	return fp; -} -/*  **  FIXCRLF -- fix <CR><LF> in line.  **  **	Looks for the <CR><LF> combination and turns it into the @@ -830,80 +484,6 @@ fixcrlf(line, stripnl)  	*p = '\0';  }  /* -**  DFOPEN -- determined file open -** -**	This routine has the semantics of fopen, except that it will -**	keep trying a few times to make this happen.  The idea is that -**	on very loaded systems, we may run out of resources (inodes, -**	whatever), so this tries to get around it. -*/ - -struct omodes -{ -	int	mask; -	int	mode; -	char	*farg; -} OpenModes[] = -{ -	{ O_ACCMODE,		O_RDONLY,		"r"	}, -	{ O_ACCMODE|O_APPEND,	O_WRONLY,		"w"	}, -	{ O_ACCMODE|O_APPEND,	O_WRONLY|O_APPEND,	"a"	}, -	{ O_TRUNC,		0,			"w+"	}, -	{ O_APPEND,		O_APPEND,		"a+"	}, -	{ 0,			0,			"r+"	}, -}; - -FILE * -dfopen(filename, omode, cmode) -	char *filename; -	int omode; -	int cmode; -{ -	register int tries; -	int fd; -	register struct omodes *om; -	struct stat st; - -	for (om = OpenModes; om->mask != 0; om++) -		if ((omode & om->mask) == om->mode) -			break; - -	for (tries = 0; tries < 10; tries++) -	{ -		sleep((unsigned) (10 * tries)); -		errno = 0; -		fd = open(filename, omode, cmode); -		if (fd >= 0) -			break; -		switch (errno) -		{ -		  case ENFILE:		/* system file table full */ -		  case EINTR:		/* interrupted syscall */ -#ifdef ETXTBSY -		  case ETXTBSY:		/* Apollo: net file locked */ -#endif -			continue; -		} -		break; -	} -	if (fd >= 0 && fstat(fd, &st) >= 0 && S_ISREG(st.st_mode)) -	{ -		int locktype; - -		/* lock the file to avoid accidental conflicts */ -		if ((omode & O_ACCMODE) != O_RDONLY) -			locktype = LOCK_EX; -		else -			locktype = LOCK_SH; -		(void) lockfile(fd, filename, NULL, locktype); -		errno = 0; -	} -	if (fd < 0) -		return NULL; -	else -		return fdopen(fd, om->farg); -} -/*  **  PUTLINE -- put a line like fputs obeying SMTP conventions  **  **	This routine always guarantees outputing a newline (or CRLF, @@ -925,7 +505,7 @@ putline(l, mci)  	register char *l;  	register MCI *mci;  { -	putxline(l, mci, PXLF_MAPFROM); +	putxline(l, strlen(l), mci, PXLF_MAPFROM);  }  /*  **  PUTXLINE -- putline with flags bits. @@ -935,6 +515,7 @@ putline(l, mci)  **  **	Parameters:  **		l -- line to put. +**		len -- the length of the line.  **		mci -- the mailer connection information.  **		pxflags -- flag bits:  **		    PXLF_MAPFROM -- map From_ to >From_. @@ -948,12 +529,13 @@ putline(l, mci)  */  void -putxline(l, mci, pxflags) +putxline(l, len, mci, pxflags)  	register char *l; +	size_t len;  	register MCI *mci;  	int pxflags;  { -	register char *p; +	register char *p, *end;  	register char svchar;  	int slop = 0; @@ -966,12 +548,13 @@ putxline(l, mci, pxflags)  				*p = svchar &~ 0200;  	} +	end = l + len;  	do  	{  		/* find the end of the line */ -		p = strchr(l, '\n'); +		p = memchr(l, '\n', end - l);  		if (p == NULL) -			p = &l[strlen(l)]; +			p = end;  		if (TrafficLogFile != NULL)  			fprintf(TrafficLogFile, "%05d >>> ", (int) getpid()); @@ -1005,8 +588,12 @@ putxline(l, mci, pxflags)  			fputs(mci->mci_mailer->m_eol, mci->mci_out);  			(void) putc(' ', mci->mci_out);  			if (TrafficLogFile != NULL) -				fprintf(TrafficLogFile, "%s!\n%05d >>>  ", -					l, (int) getpid()); +			{ +				for ( ; l < q; ++l)	 +					(void) putc(*l, TrafficLogFile); +				fprintf(TrafficLogFile, "!\n%05d >>>  ", +					(int) getpid()); +			}  			*q = svchar;  			l = q;  			slop = 1; @@ -1029,10 +616,14 @@ putxline(l, mci, pxflags)  			if (TrafficLogFile != NULL)  				(void) putc('>', TrafficLogFile);  		} -		if (TrafficLogFile != NULL) -			fprintf(TrafficLogFile, "%.*s\n", p - l, l);  		for ( ; l < p; ++l) +		{ +			if (TrafficLogFile != NULL) +				(void) putc(*l, TrafficLogFile);  			(void) putc(*l, mci->mci_out); +		} +		if (TrafficLogFile != NULL) +			(void) putc('\n', TrafficLogFile);  		fputs(mci->mci_mailer->m_eol, mci->mci_out);  		if (*l == '\n')  		{ @@ -1043,7 +634,7 @@ putxline(l, mci, pxflags)  					(void) putc(' ', TrafficLogFile);  			}  		} -	} while (l[0] != '\0'); +	} while (l < end);  }  /*  **  XUNLINK -- unlink a file, doing logging as appropriate. @@ -1064,16 +655,16 @@ xunlink(f)  {  	register int i; -# ifdef LOG  	if (LogLevel > 98) -		syslog(LOG_DEBUG, "%s: unlink %s", CurEnv->e_id, f); -# endif /* LOG */ +		sm_syslog(LOG_DEBUG, CurEnv->e_id, +			"unlink %s", +			f);  	i = unlink(f); -# ifdef LOG  	if (i < 0 && LogLevel > 97) -		syslog(LOG_DEBUG, "%s: unlink-fail %d", f, errno); -# endif /* LOG */ +		sm_syslog(LOG_DEBUG, CurEnv->e_id, +			"%s: unlink-fail %d", +			f, errno);  }  /*  **  XFCLOSE -- close a file, doing logging as appropriate. @@ -1147,20 +738,19 @@ sfgets(buf, siz, fp, timeout, during)  	{  		if (setjmp(CtxReadTimeout) != 0)  		{ -# ifdef LOG  			if (LogLevel > 1) -				syslog(LOG_NOTICE, +				sm_syslog(LOG_NOTICE, CurEnv->e_id,  				       "timeout waiting for input from %.100s during %s",  				       CurHostName ? CurHostName : "local",  				       during); -# endif  			errno = 0; -			usrerr("451 timeout waiting for input during %s", -				during);  			buf[0] = '\0';  #if XDEBUG  			checkfd012(during);  #endif +			if (TrafficLogFile != NULL) +				fprintf(TrafficLogFile, "%05d <<< [TIMEOUT]\n", +					(int) getpid());  			return (NULL);  		}  		ev = setevent(timeout, readtimeout, 0); @@ -1365,46 +955,6 @@ atooct(s)  	return (i);  }  /* -**  WAITFOR -- wait for a particular process id. -** -**	Parameters: -**		pid -- process id to wait for. -** -**	Returns: -**		status of pid. -**		-1 if pid never shows up. -** -**	Side Effects: -**		none. -*/ - -int -waitfor(pid) -	pid_t pid; -{ -#ifdef WAITUNION -	union wait st; -#else -	auto int st; -#endif -	pid_t i; - -	do -	{ -		errno = 0; -		i = wait(&st); -		if (i > 0) -			proc_list_drop(i); -	} while ((i >= 0 || errno == EINTR) && i != pid); -	if (i < 0) -		return -1; -#ifdef WAITUNION -	return st.w_status; -#else -	return st; -#endif -} -/*  **  BITINTERSECT -- tell if two bitmaps intersect  **  **	Parameters: @@ -1606,7 +1156,9 @@ checkfds(where)  			continue;  		if (printhdr)  		{ -			syslog(LOG_DEBUG, "%s: changed fds:", where); +			sm_syslog(LOG_DEBUG, CurEnv->e_id, +				"%s: changed fds:", +				where);  			printhdr = FALSE;  		}  		dumpfd(fd, TRUE, TRUE); @@ -1772,11 +1324,10 @@ defprint:  	}  printit: -#ifdef LOG  	if (logit) -		syslog(LOG_DEBUG, "%.800s", buf); +		sm_syslog(LOG_DEBUG, CurEnv->e_id, +			"%.800s", buf);  	else -#endif  		printf("%s\n", buf);  }  /* @@ -2084,10 +1635,8 @@ cleanstrcpy(t, f, l)  	register char *f;  	int l;  { -#ifdef LOG  	/* check for newlines and log if necessary */  	(void) denlstring(f, TRUE, TRUE); -#endif  	l--;  	while (l > 0 && *f != '\0') @@ -2146,20 +1695,23 @@ denlstring(s, strict, logattacks)  	for (p = bp; (p = strchr(p, '\n')) != NULL; )  		*p++ = ' '; -#ifdef LOG  	if (logattacks)  	{ -		syslog(LOG_NOTICE, "POSSIBLE ATTACK from %.100s: newline in string \"%s\"", +		sm_syslog(LOG_NOTICE, CurEnv->e_id, +			"POSSIBLE ATTACK from %.100s: newline in string \"%s\"",  			RealHostName == NULL ? "[UNKNOWN]" : RealHostName,  			shortenstring(bp, 203));  	} -#endif  	return bp;  }  /*  **  PATH_IS_DIR -- check to see if file exists and is a directory.  ** +**	There are some additional checks for security violations in +**	here.  This routine is intended to be used for the host status +**	support. +**  **	Parameters:  **		pathname -- pathname to check for directory-ness.  **		createflag -- if set, create directory if needed. @@ -2176,7 +1728,11 @@ path_is_dir(pathname, createflag)  {  	struct stat statbuf; +#if HASLSTAT +	if (lstat(pathname, &statbuf) < 0) +#else  	if (stat(pathname, &statbuf) < 0) +#endif  	{  		if (errno != ENOENT || !createflag)  			return FALSE; @@ -2189,6 +1745,14 @@ path_is_dir(pathname, createflag)  		errno = ENOTDIR;  		return FALSE;  	} + +	/* security: don't allow writable directories */ +	if (bitset(S_IWGRP|S_IWOTH, statbuf.st_mode)) +	{ +		errno = EACCES; +		return FALSE; +	} +  	return TRUE;  }  /* @@ -2320,11 +1884,10 @@ proc_list_probe()  			continue;  		if (kill(ProcListVec[i], 0) < 0)  		{ -#ifdef LOG  			if (LogLevel > 3) -				syslog(LOG_DEBUG, "proc_list_probe: lost pid %d", +				sm_syslog(LOG_DEBUG, CurEnv->e_id, +					"proc_list_probe: lost pid %d",  					ProcListVec[i]); -#endif  			ProcListVec[i] = NO_PID;  			CurChildren--;  		} @@ -2332,3 +1895,119 @@ proc_list_probe()  	if (CurChildren < 0)  		CurChildren = 0;  } +/* +**  SM_STRCASECMP -- 8-bit clean version of strcasecmp +** +**	Thank you, vendors, for making this all necessary. +*/ + +/* + * Copyright (c) 1987, 1993 + *	The Regents of the University of California.  All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + *    must display the following acknowledgement: + *	This product includes software developed by the University of + *	California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + *    may be used to endorse or promote products derived from this software + *    without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strcasecmp.c	8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +/* + * This array is designed for mapping upper and lower case letter + * together for a case independent comparison.  The mappings are + * based upon ascii character sequences. + */ +static const u_char charmap[] = { +	0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007, +	0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017, +	0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027, +	0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037, +	0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047, +	0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057, +	0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067, +	0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077, +	0100, 0141, 0142, 0143, 0144, 0145, 0146, 0147, +	0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157, +	0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167, +	0170, 0171, 0172, 0133, 0134, 0135, 0136, 0137, +	0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147, +	0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157, +	0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167, +	0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177, +	0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207, +	0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217, +	0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227, +	0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237, +	0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247, +	0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257, +	0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, +	0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, +	0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307, +	0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317, +	0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327, +	0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, +	0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, +	0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357, +	0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, +	0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377, +}; + +int +sm_strcasecmp(s1, s2) +	const char *s1, *s2; +{ +	register const u_char *cm = charmap, +			*us1 = (const u_char *)s1, +			*us2 = (const u_char *)s2; + +	while (cm[*us1] == cm[*us2++]) +		if (*us1++ == '\0') +			return (0); +	return (cm[*us1] - cm[*--us2]); +} + +int +sm_strncasecmp(s1, s2, n) +	const char *s1, *s2; +	register size_t n; +{ +	if (n != 0) { +		register const u_char *cm = charmap, +				*us1 = (const u_char *)s1, +				*us2 = (const u_char *)s2; + +		do { +			if (cm[*us1] != cm[*us2++]) +				return (cm[*us1] - cm[*--us2]); +			if (*us1++ == '\0') +				break; +		} while (--n != 0); +	} +	return (0); +} | 
