summaryrefslogtreecommitdiff
path: root/usr.sbin/sendmail/src/util.c
diff options
context:
space:
mode:
authorPeter Wemm <peter@FreeBSD.org>1997-06-27 14:53:01 +0000
committerPeter Wemm <peter@FreeBSD.org>1997-06-27 14:53:01 +0000
commitf3a1fc342b4423150f71e23e50f24d073a6d238b (patch)
treea5e7dee2f9ff41f2d43580f859a6e8970722fa7d /usr.sbin/sendmail/src/util.c
parent52c4d6f5d6bb1ffd8b30c0429fc18d371856a062 (diff)
Notes
Diffstat (limited to 'usr.sbin/sendmail/src/util.c')
-rw-r--r--usr.sbin/sendmail/src/util.c669
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);
+}