[BACK]Return to mandocdb.c CVS log [TXT][DIR] Up to [cvsweb.bsd.lv] / mandoc

Diff for /mandoc/mandocdb.c between version 1.264 and 1.271

version 1.264, 2020/01/25 22:59:22 version 1.271, 2022/04/14 16:43:44
Line 1 
Line 1 
 /*      $Id$ */  /* $Id$ */
 /*  /*
    * Copyright (c) 2011-2021 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>   * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2011-2020 Ingo Schwarze <schwarze@openbsd.org>  
  * Copyright (c) 2016 Ed Maste <emaste@freebsd.org>   * Copyright (c) 2016 Ed Maste <emaste@freebsd.org>
  *   *
  * Permission to use, copy, modify, and distribute this software for any   * Permission to use, copy, modify, and distribute this software for any
Line 15 
Line 15 
  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN   * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF   * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    *
    * Implementation of the makewhatis(8) program.
  */   */
 #include "config.h"  #include "config.h"
   
Line 118  struct mdoc_handler {
Line 120  struct mdoc_handler {
 int              mandocdb(int, char *[]);  int              mandocdb(int, char *[]);
   
 static  void     dbadd(struct dba *, struct mpage *);  static  void     dbadd(struct dba *, struct mpage *);
 static  void     dbadd_mlink(const struct mlink *mlink);  static  void     dbadd_mlink(const struct mlink *);
 static  void     dbprune(struct dba *);  static  void     dbprune(struct dba *);
 static  void     dbwrite(struct dba *);  static  void     dbwrite(struct dba *);
 static  void     filescan(const char *);  static  void     filescan(const char *);
Line 163  static void  putkey(const struct mpage *, char *, uint
Line 165  static void  putkey(const struct mpage *, char *, uint
 static  void     putkeys(const struct mpage *, char *, size_t, uint64_t);  static  void     putkeys(const struct mpage *, char *, size_t, uint64_t);
 static  void     putmdockey(const struct mpage *,  static  void     putmdockey(const struct mpage *,
                         const struct roff_node *, uint64_t, int);                          const struct roff_node *, uint64_t, int);
   #ifdef READ_ALLOWED_PATH
   static  int      read_allowed(const char *);
   #endif
 static  int      render_string(char **, size_t *);  static  int      render_string(char **, size_t *);
 static  void     say(const char *, const char *, ...)  static  void     say(const char *, const char *, ...)
                         __attribute__((__format__ (__printf__, 2, 3)));                          __attribute__((__format__ (__printf__, 2, 3)));
Line 527  out:
Line 532  out:
         mpages_free();          mpages_free();
         ohash_delete(&mpages);          ohash_delete(&mpages);
         ohash_delete(&mlinks);          ohash_delete(&mlinks);
   #if DEBUG_MEMORY
           mandoc_dbg_finish();
   #endif
         return exitcode;          return exitcode;
 usage:  usage:
         progname = getprogname();          progname = getprogname();
Line 610  treescan(void)
Line 618  treescan(void)
                                 continue;                                  continue;
                         }                          }
                         if (strncmp(buf, basedir, basedir_len) != 0                          if (strncmp(buf, basedir, basedir_len) != 0
 #ifdef HOMEBREWDIR  #ifdef READ_ALLOWED_PATH
                             && strncmp(buf, HOMEBREWDIR, strlen(HOMEBREWDIR))                              && !read_allowed(buf)
 #endif  #endif
                         ) {                          ) {
                                 if (warnings) say("",                                  if (warnings) say("",
Line 624  treescan(void)
Line 632  treescan(void)
                                         say(path, "&stat");                                          say(path, "&stat");
                                 continue;                                  continue;
                         }                          }
                           if ((ff->fts_statp->st_mode & S_IFMT) != S_IFREG)
                                   continue;
                         /* FALLTHROUGH */                          /* FALLTHROUGH */
   
                 /*                  /*
Line 778  treescan(void)
Line 788  treescan(void)
  * See treescan() for the fts(3) version of this.   * See treescan() for the fts(3) version of this.
  */   */
 static void  static void
 filescan(const char *file)  filescan(const char *infile)
 {  {
         char             buf[PATH_MAX];  
         struct stat      st;          struct stat      st;
         struct mlink    *mlink;          struct mlink    *mlink;
         char            *p, *start;          char            *linkfile, *p, *realdir, *start, *usefile;
           size_t           realdir_len;
   
         assert(use_all);          assert(use_all);
   
         if (strncmp(file, "./", 2) == 0)          if (strncmp(infile, "./", 2) == 0)
                 file += 2;                  infile += 2;
   
         /*          /*
          * We have to do lstat(2) before realpath(3) loses           * We have to do lstat(2) before realpath(3) loses
Line 797  filescan(const char *file)
Line 807  filescan(const char *file)
          * we want to use the orginal file name, while for           * we want to use the orginal file name, while for
          * regular files, we want to use the real path.           * regular files, we want to use the real path.
          */           */
         if (lstat(file, &st) == -1) {          if (lstat(infile, &st) == -1) {
                 exitcode = (int)MANDOCLEVEL_BADARG;                  exitcode = (int)MANDOCLEVEL_BADARG;
                 say(file, "&lstat");                  say(infile, "&lstat");
                 return;                  return;
         } else if ((st.st_mode & (S_IFREG | S_IFLNK)) == 0) {          } else if (S_ISREG(st.st_mode) == 0 && S_ISLNK(st.st_mode) == 0) {
                 exitcode = (int)MANDOCLEVEL_BADARG;                  exitcode = (int)MANDOCLEVEL_BADARG;
                 say(file, "Not a regular file");                  say(infile, "Not a regular file");
                 return;                  return;
         }          }
   
Line 811  filescan(const char *file)
Line 821  filescan(const char *file)
          * We have to resolve the file name to the real path           * We have to resolve the file name to the real path
          * in any case for the base directory check.           * in any case for the base directory check.
          */           */
         if (realpath(file, buf) == NULL) {          if ((usefile = realpath(infile, NULL)) == NULL) {
                 exitcode = (int)MANDOCLEVEL_BADARG;                  exitcode = (int)MANDOCLEVEL_BADARG;
                 say(file, "&realpath");                  say(infile, "&realpath");
                 return;                  return;
         }          }
   
         if (op == OP_TEST)          if (op == OP_TEST)
                 start = buf;                  start = usefile;
         else if (strncmp(buf, basedir, basedir_len) == 0)          else if (strncmp(usefile, basedir, basedir_len) == 0)
                 start = buf + basedir_len;                  start = usefile + basedir_len;
 #ifdef HOMEBREWDIR  #ifdef READ_ALLOWED_PATH
         else if (strncmp(buf, HOMEBREWDIR, strlen(HOMEBREWDIR)) == 0)          else if (read_allowed(usefile))
                 start = buf;                  start = usefile;
 #endif  #endif
         else {          else {
                 exitcode = (int)MANDOCLEVEL_BADARG;                  exitcode = (int)MANDOCLEVEL_BADARG;
                 say("", "%s: outside base directory", buf);                  say("", "%s: outside base directory", infile);
                   free(usefile);
                 return;                  return;
         }          }
   
Line 835  filescan(const char *file)
Line 846  filescan(const char *file)
          * Now we are sure the file is inside our tree.           * Now we are sure the file is inside our tree.
          * If it is a symbolic link, ignore the real path           * If it is a symbolic link, ignore the real path
          * and use the original name.           * and use the original name.
          * This implies passing stuff like "cat1/../man1/foo.1"  
          * on the command line won't work.  So don't do that.  
          * Note the stat(2) can still fail if the link target  
          * doesn't exist.  
          */           */
         if (st.st_mode & S_IFLNK) {          do {
                 if (stat(buf, &st) == -1) {                  if (S_ISLNK(st.st_mode) == 0)
                           break;
   
                   /*
                    * Some implementations of realpath(3) may succeed
                    * even if the target of the link does not exist,
                    * so check again for extra safety.
                    */
                   if (stat(usefile, &st) == -1) {
                         exitcode = (int)MANDOCLEVEL_BADARG;                          exitcode = (int)MANDOCLEVEL_BADARG;
                         say(file, "&stat");                          say(infile, "&stat");
                           free(usefile);
                         return;                          return;
                 }                  }
                 if (strlcpy(buf, file, sizeof(buf)) >= sizeof(buf)) {                  linkfile = mandoc_strdup(infile);
                         say(file, "Filename too long");                  if (op == OP_TEST) {
                         return;                          free(usefile);
                           start = usefile = linkfile;
                           break;
                 }                  }
                 start = buf;                  if (strncmp(infile, basedir, basedir_len) == 0) {
                 if (op != OP_TEST && strncmp(buf, basedir, basedir_len) == 0)                          free(usefile);
                         start += basedir_len;                          usefile = linkfile;
         }                          start = usefile + basedir_len;
                           break;
                   }
   
                   /*
                    * This symbolic link points into the basedir
                    * from the outside.  Let's see whether any of
                    * the parent directories resolve to the basedir.
                    */
                   p = strchr(linkfile, '\0');
                   do {
                           while (*--p != '/')
                                   continue;
                           *p = '\0';
                           if ((realdir = realpath(linkfile, NULL)) == NULL) {
                                   exitcode = (int)MANDOCLEVEL_BADARG;
                                   say(infile, "&realpath");
                                   free(linkfile);
                                   free(usefile);
                                   return;
                           }
                           realdir_len = strlen(realdir) + 1;
                           free(realdir);
                           *p = '/';
                   } while (realdir_len > basedir_len);
   
                   /*
                    * If one of the directories resolves to the basedir,
                    * use the rest of the original name.
                    * Otherwise, the best we can do
                    * is to use the filename pointed to.
                    */
                   if (realdir_len == basedir_len) {
                           free(usefile);
                           usefile = linkfile;
                           start = p + 1;
                   } else {
                           free(linkfile);
                           start = usefile + basedir_len;
                   }
           } while (/* CONSTCOND */ 0);
   
         mlink = mandoc_calloc(1, sizeof(struct mlink));          mlink = mandoc_calloc(1, sizeof(struct mlink));
         mlink->dform = FORM_NONE;          mlink->dform = FORM_NONE;
         if (strlcpy(mlink->file, start, sizeof(mlink->file)) >=          if (strlcpy(mlink->file, start, sizeof(mlink->file)) >=
             sizeof(mlink->file)) {              sizeof(mlink->file)) {
                 say(start, "Filename too long");                  say(start, "Filename too long");
                 free(mlink);                  free(mlink);
                   free(usefile);
                 return;                  return;
         }          }
   
Line 869  filescan(const char *file)
Line 928  filescan(const char *file)
          * but outside our tree, guess the base directory.           * but outside our tree, guess the base directory.
          */           */
   
         if (op == OP_TEST || (start == buf && *start == '/')) {          if (op == OP_TEST || (start == usefile && *start == '/')) {
                 if (strncmp(buf, "man/", 4) == 0)                  if (strncmp(usefile, "man/", 4) == 0)
                         start = buf + 4;                          start = usefile + 4;
                 else if ((start = strstr(buf, "/man/")) != NULL)                  else if ((start = strstr(usefile, "/man/")) != NULL)
                         start += 5;                          start += 5;
                 else                  else
                         start = buf;                          start = usefile;
         }          }
   
         /*          /*
Line 925  filescan(const char *file)
Line 984  filescan(const char *file)
                 *p = '\0';                  *p = '\0';
         }          }
         mlink_add(mlink, &st);          mlink_add(mlink, &st);
           free(usefile);
 }  }
   
 static void  static void
Line 2194  dbwrite(struct dba *dba)
Line 2254  dbwrite(struct dba *dba)
                 say(tfn, "&dba_write");                  say(tfn, "&dba_write");
                 goto err;                  goto err;
         }          }
         if ((fd1 = open(MANDOC_DB, O_RDONLY, 0)) == -1) {          if ((fd1 = open(MANDOC_DB, O_RDONLY)) == -1) {
                 say(MANDOC_DB, "&open");                  say(MANDOC_DB, "&open");
                 goto err;                  goto err;
         }          }
         if ((fd2 = open(tfn, O_RDONLY, 0)) == -1) {          if ((fd2 = open(tfn, O_RDONLY)) == -1) {
                 say(tfn, "&open");                  say(tfn, "&open");
                 goto err;                  goto err;
         }          }
Line 2328  set_basedir(const char *targetdir, int report_baddir)
Line 2388  set_basedir(const char *targetdir, int report_baddir)
         }          }
         return 1;          return 1;
 }  }
   
   #ifdef READ_ALLOWED_PATH
   static int
   read_allowed(const char *candidate)
   {
           const char      *cp;
           size_t           len;
   
           for (cp = READ_ALLOWED_PATH;; cp += len) {
                   while (*cp == ':')
                           cp++;
                   if (*cp == '\0')
                           return 0;
                   len = strcspn(cp, ":");
                   if (strncmp(candidate, cp, len) == 0)
                           return 1;
           }
   }
   #endif
   
 static void  static void
 say(const char *file, const char *format, ...)  say(const char *file, const char *format, ...)

Legend:
Removed from v.1.264  
changed lines
  Added in v.1.271

CVSweb