fix bogus implementation of name overflow limiting
[unix-history] / usr / src / usr.sbin / sendmail / src / util.c
index ec7cb09..e06b0fa 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)util.c     8.13 (Berkeley) %G%";
+static char sccsid[] = "@(#)util.c     8.20 (Berkeley) %G%";
 #endif /* not lint */
 
 # include "sendmail.h"
 #endif /* not lint */
 
 # include "sendmail.h"
@@ -326,48 +326,108 @@ makelower(p)
 **             buf -- buffer to store result in.
 **
 **     Returns:
 **             buf -- buffer to store result in.
 **
 **     Returns:
-**             none.
+**             TRUE -- if the resulting message should be a MIME format.
+**             FALSE -- if MIME is not necessary.
 **
 **     Side Effects:
 **             none.
 */
 
 **
 **     Side Effects:
 **             none.
 */
 
-fullname(pw, buf)
-       register struct passwd *pw;
-       char *buf;
+/* values for should_quote */
+#define NO_QUOTE       0
+#define SHOULD_QUOTE   1
+#define SHOULD_MIME    2
+
+int
+       register unsigned char *gecos;
+       const unsigned char *login;
+       unsigned char *buf;
 {
 {
-       register char *p;
-       register char *bp = buf;
-       int l;
+       register unsigned char *bp = buf;
+       unsigned char *p;
+       int should_quote = NO_QUOTE;
        register char *p = pw->pw_gecos;
 
        register char *p = pw->pw_gecos;
 
-       if (*gecos == '*')
-               gecos++;
-
-       /* find length of final string */
-       l = 0;
-       for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++)
+       /* make sure specials, SPACE and CTLs are quoted within " " */
+       for (p = gecos; *p && *p != ',' && *p != ';' && *p != '%'; p++)
        {
        {
-               if (*p == '&')
-                       l += strlen(login);
-               else
-                       l++;
+               if (*p >= 0200)
+               {
+                       should_quote = SHOULD_MIME;
+                       break;
+               }
+               switch (*p)
+               {
+                 case '(':
+                 case ')':
+                 case '<':
+                 case '>':
+                 case '@':
+                 case ':':
+                 case '\\':
+                 case '"':
+                 case '.':
+                 case '[':
+                 case ']':
+                       should_quote = SHOULD_QUOTE;
+                       break;
+               }       
        }
        }
-
-       /* now fill in buf */
-       for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++)
+       if (should_quote == SHOULD_MIME)
        {
        {
-               if (*p == '&')
+               strcpy (bp, "=?iso-8859-1?Q?");
+               bp += 15;
+               for (p = gecos; *p && *p != ',' && *p != ';' && *p != '%'; p++)
                {
                {
-                       (void) strcpy(bp, pw->pw_name);
-                       *bp = toupper(*bp);
-                       while (*bp != '\0')
-                               bp++;
+                       if (*p == ' ')
+                               *bp++ = '_';
+                        else if (*p == '&')
+                        {
+                               (void) strcpy(bp, login);
+                               *bp = toupper(*bp);
+                               bp += strlen (bp);
+                       }
+                       else if (*p < 040 || *p >= 200 || 
+                                strchr("_?()<>@:\\\".[]", *p) != NULL)
+                       {
+                               *bp++ = '=';
+                               *bp++ = "0123456789ABCDEF"[(*p >> 4) & 0xf];
+                               *bp++ = "0123456789ABCDEF"[*p & 0xf];
+                       }
+                       else
+                               *bp++ = *p;
                }
                }
-               else
-                       *bp++ = *p;
+               strcpy (bp, "?= ");
+               bp += 3;
+       }
+       else
+       {
+               if (should_quote)
+                       *bp++ = '"';
+               for (p = gecos; *p && *p != ',' && *p != ';' && *p != '%'; p++)
+               {
+                       if (*p == '&')
+                       {
+                               (void) strcpy(bp, login);
+                               *bp = toupper(*bp);
+                               while (*bp != '\0')
+                                       bp++;
+                       }
+                       else
+                       {
+                               if (*p == '"')
+                                       *bp++ = '\\';
+                               *bp++ = *p;
+                       }
+               }
+               if (bp[-1] == '\\')
+                       *bp++ = '\\';
+               if (should_quote)
+                       *bp++ = '"';
        }
        }
+
        *bp = '\0';
        *bp = '\0';
+       return should_quote == SHOULD_MIME;
 }
 \f/*
 **  SAFEFILE -- return true if a file exists and is safe for a user.
 }
 \f/*
 **  SAFEFILE -- return true if a file exists and is safe for a user.
@@ -378,7 +438,9 @@ fullname(pw, buf)
 **             gid -- group id to compare against.
 **             uname -- user name to compare against (used for group
 **                     sets).
 **             gid -- group id to compare against.
 **             uname -- user name to compare against (used for group
 **                     sets).
-**             mustown -- to be safe, this uid must own the file.
+**             flags -- modifiers:
+**                     SF_MUSTOWN -- "uid" must own this file.
+**                     SF_NOSLINK -- file cannot be a symbolic link.
 **             mode -- mode bits that must match.
 **
 **     Returns:
 **             mode -- mode bits that must match.
 **
 **     Returns:
@@ -404,12 +466,12 @@ fullname(pw, buf)
 #endif
 
 int
 #endif
 
 int
-safefile(fn, uid, gid, uname, mustown, mode)
+safefile(fn, uid, gid, uname, flags, mode)
        char *fn;
        uid_t uid;
        gid_t gid;
        char *uname;
        char *fn;
        uid_t uid;
        gid_t gid;
        char *uname;
-       bool mustown;
+       int flags;
        int mode;
 {
        register char *p;
        int mode;
 {
        register char *p;
@@ -417,8 +479,8 @@ safefile(fn, uid, gid, uname, mustown, mode)
        struct stat stbuf;
 
        if (tTd(54, 4))
        struct stat stbuf;
 
        if (tTd(54, 4))
-               printf("safefile(%s, uid=%d, gid=%d, mustown=%d, mode=%o):\n",
-                       fn, uid, gid, mustown, mode);
+               printf("safefile(%s, uid=%d, gid=%d, flags=%x, mode=%o):\n",
+                       fn, uid, gid, flags, mode);
        errno = 0;
 
        for (p = fn; (p = strchr(++p, '/')) != NULL; *p = '/')
        errno = 0;
 
        for (p = fn; (p = strchr(++p, '/')) != NULL; *p = '/')
@@ -459,7 +521,12 @@ safefile(fn, uid, gid, uname, mustown, mode)
                return ret;
        }
 
                return ret;
        }
 
+#ifdef HASLSTAT
+       if ((bitset(SF_NOSLINK, flags) ? lstat(fn, &stbuf)
+                                      : stat(fn, &stbuf)) < 0)
+#else
        if (stat(fn, &stbuf) < 0)
        if (stat(fn, &stbuf) < 0)
+#endif
        {
                int ret = errno;
 
        {
                int ret = errno;
 
@@ -469,6 +536,16 @@ safefile(fn, uid, gid, uname, mustown, mode)
                errno = 0;
                return ret;
        }
                errno = 0;
                return ret;
        }
+
+#ifdef S_ISLNK
+       if (bitset(SF_NOSLINK, flags) && S_ISLNK(stbuf.st_mode))
+       {
+               if (tTd(54, 4))
+                       printf("\t[mode %o]\tEPERM\n");
+               return EPERM;
+       }
+#endif
+
        if (uid == 0)
                mode >>= 6;
        else if (stbuf.st_uid != uid)
        if (uid == 0)
                mode >>= 6;
        else if (stbuf.st_uid != uid)
@@ -496,7 +573,8 @@ safefile(fn, uid, gid, uname, mustown, mode)
        if (tTd(54, 4))
                printf("\t[uid %d, stat %o, mode %o] ",
                        stbuf.st_uid, stbuf.st_mode, mode);
        if (tTd(54, 4))
                printf("\t[uid %d, stat %o, mode %o] ",
                        stbuf.st_uid, stbuf.st_mode, mode);
-       if ((stbuf.st_uid == uid || uid == 0 || !mustown) &&
+       if ((stbuf.st_uid == uid || stbuf.st_uid == 0 ||
+            !bitset(SF_MUSTOWN, flags)) &&
            (stbuf.st_mode & mode) == mode)
        {
                if (tTd(54, 4))
            (stbuf.st_mode & mode) == mode)
        {
                if (tTd(54, 4))
@@ -1091,18 +1169,23 @@ strcontainedin(a, b)
        register char *a;
        register char *b;
 {
        register char *a;
        register char *b;
 {
-       int l;
-
-       l = strlen(a);
-       for (;;)
+       int la;
+       int lb;
+       int c;
+
+       la = strlen(a);
+       lb = strlen(b);
+       c = *a;
+       if (isascii(c) && isupper(c))
+               c = tolower(c);
+       for (; lb-- >= la; b++)
        {
        {
-               b = strchr(b, a[0]);
-               if (b == NULL)
-                       return FALSE;
-               if (strncmp(a, b, l) == 0)
+               if (*b != c && isascii(*b) && isupper(*b) && tolower(*b) != c)
+                       continue;
+               if (strncasecmp(a, b, la) == 0)
                        return TRUE;
                        return TRUE;
-               b++;
        }
        }
+       return FALSE;
 }
 \f/*
 **  CHECKFD012 -- check low numbered file descriptors
 }
 \f/*
 **  CHECKFD012 -- check low numbered file descriptors
@@ -1160,72 +1243,156 @@ printopenfds(logit)
        bool logit;
 {
        register int fd;
        bool logit;
 {
        register int fd;
-       struct stat st;
+       extern int DtableSize;
+
+       for (fd = 0; fd < DtableSize; fd++)
+               dumpfd(fd, FALSE, logit);
+}
+\f/*
+**  DUMPFD -- dump a file descriptor
+**
+**     Parameters:
+**             fd -- the file descriptor to dump.
+**             printclosed -- if set, print a notification even if
+**                     it is closed; otherwise print nothing.
+**             logit -- if set, send output to syslog instead of stdout.
+*/
+
+dumpfd(fd, printclosed, logit)
+       int fd;
+       bool printclosed;
+       bool logit;
+{
        register struct hostent *hp;
        register char *p;
        register struct hostent *hp;
        register char *p;
+       struct sockaddr_in sin;
+       auto int slen;
+       struct stat st;
        char buf[200];
        char buf[200];
-       extern int DtableSize;
 
 
-       for (fd = 0; fd < DtableSize; fd++)
+       p = buf;
+       sprintf(p, "%3d: ", fd);
+       p += strlen(p);
+
+       if (fstat(fd, &st) < 0)
        {
        {
-               struct sockaddr_in sin;
-               auto int slen;
+               if (printclosed || errno != EBADF)
+               {
+                       sprintf(p, "CANNOT STAT (%s)", errstring(errno));
+                       goto printit;
+               }
+               return;
+       }
 
 
-               if (fstat(fd, &st) < 0)
-                       continue;
+       slen = fcntl(fd, F_GETFL, NULL);
+       if (slen != -1)
+       {
+               sprintf(p, "fl=0x%x, ", slen);
+               p += strlen(p);
+       }
 
 
-               p = buf;
-               sprintf(p, "%3d: mode=%o: ", fd, st.st_mode);
+       sprintf(p, "mode=%o: ", st.st_mode);
+       p += strlen(p);
+       switch (st.st_mode & S_IFMT)
+       {
+#ifdef S_IFSOCK
+         case S_IFSOCK:
+               sprintf(p, "SOCK ");
                p += strlen(p);
                p += strlen(p);
-               switch (st.st_mode & S_IFMT)
+               slen = sizeof sin;
+               if (getsockname(fd, (struct sockaddr *) &sin, &slen) < 0)
+                       sprintf(p, "(badsock)");
+               else
                {
                {
-                 case S_IFSOCK:
-                       sprintf(p, "SOCK ");
-                       p += strlen(p);
-                       slen = sizeof sin;
-                       if (getsockname(fd, (struct sockaddr *) &sin, &slen) < 0)
-                               sprintf(p, "(badsock)");
-                       else
-                       {
-                               hp = gethostbyaddr((char *) &sin.sin_addr, slen, AF_INET);
-                               sprintf(p, "%s/%d", hp == NULL ? inet_ntoa(sin.sin_addr)
-                                                          : hp->h_name, ntohs(sin.sin_port));
-                       }
-                       p += strlen(p);
-                       sprintf(p, "->");
-                       p += strlen(p);
-                       slen = sizeof sin;
-                       if (getpeername(fd, (struct sockaddr *) &sin, &slen) < 0)
-                               sprintf(p, "(badsock)");
-                       else
-                       {
-                               hp = gethostbyaddr((char *) &sin.sin_addr, slen, AF_INET);
-                               sprintf(p, "%s/%d", hp == NULL ? inet_ntoa(sin.sin_addr)
-                                                          : hp->h_name, ntohs(sin.sin_port));
-                       }
-                       break;
+                       hp = gethostbyaddr((char *) &sin.sin_addr, slen, AF_INET);
+                       sprintf(p, "%s/%d", hp == NULL ? inet_ntoa(sin.sin_addr)
+                                                  : hp->h_name, ntohs(sin.sin_port));
+               }
+               p += strlen(p);
+               sprintf(p, "->");
+               p += strlen(p);
+               slen = sizeof sin;
+               if (getpeername(fd, (struct sockaddr *) &sin, &slen) < 0)
+                       sprintf(p, "(badsock)");
+               else
+               {
+                       hp = gethostbyaddr((char *) &sin.sin_addr, slen, AF_INET);
+                       sprintf(p, "%s/%d", hp == NULL ? inet_ntoa(sin.sin_addr)
+                                                  : hp->h_name, ntohs(sin.sin_port));
+               }
+               break;
+#endif
 
 
-                 case S_IFCHR:
-                       sprintf(p, "CHR: ");
-                       p += strlen(p);
-                       goto defprint;
+         case S_IFCHR:
+               sprintf(p, "CHR: ");
+               p += strlen(p);
+               goto defprint;
 
 
-                 case S_IFBLK:
-                       sprintf(p, "BLK: ");
-                       p += strlen(p);
-                       goto defprint;
+         case S_IFBLK:
+               sprintf(p, "BLK: ");
+               p += strlen(p);
+               goto defprint;
 
 
-                 default:
+         default:
 defprint:
 defprint:
-                       sprintf(p, "rdev=%d/%d, ino=%d, nlink=%d, u/gid=%d/%d, size=%ld",
-                               major(st.st_rdev), minor(st.st_rdev), st.st_ino,
-                               st.st_nlink, st.st_uid, st.st_gid, st.st_size);
-                       break;
-               }
+               sprintf(p, "dev=%d/%d, ino=%d, nlink=%d, u/gid=%d/%d, size=%ld",
+                       major(st.st_dev), minor(st.st_dev), st.st_ino,
+                       st.st_nlink, st.st_uid, st.st_gid, st.st_size);
+               break;
+       }
 
 
-               if (logit)
-                       syslog(LOG_INFO, "%s", buf);
-               else
-                       printf("%s\n", buf);
+printit:
+       if (logit)
+               syslog(LOG_DEBUG, "%s", buf);
+       else
+               printf("%s\n", buf);
+}
+\f/*
+**  SHORTENSTRING -- return short version of a string
+**
+**     If the string is already short, just return it.  If it is too
+**     long, return the head and tail of the string.
+**
+**     Parameters:
+**             s -- the string to shorten.
+**             m -- the max length of the string.
+**
+**     Returns:
+**             Either s or a short version of s.
+*/
+
+#ifndef MAXSHORTSTR
+# define MAXSHORTSTR   83
+#endif
+
+char *
+shortenstring(s, m)
+       register char *s;
+       int m;
+{
+       int l;
+       static char buf[MAXSHORTSTR + 1];
+
+       l = strlen(s);
+       if (l < m)
+               return s;
+       if (m > MAXSHORTSTR)
+               m = MAXSHORTSTR;
+       else if (m < 10)
+       {
+               if (m < 5)
+               {
+                       strncpy(buf, s, m);
+                       buf[m] = '\0';
+                       return buf;
+               }
+               strncpy(buf, s, m - 3);
+               strcpy(buf + m - 3, "...");
+               return buf;
        }
        }
+       m = (m - 3) / 2;
+       strncpy(buf, s, m);
+       strcpy(buf + m, "...");
+       strcpy(buf + m + 3, s + l - m);
+       return buf;
 }
 }