LCOV - code coverage report
Current view: top level - lib/dpkg - db-fsys-override.c (source / functions) Hit Total Coverage
Test: dpkg 1.21.11 C code coverage Lines: 0 118 0.0 %
Date: 2022-12-03 00:40:01 Functions: 0 4 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 88 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * libdpkg - Debian packaging suite library routines
       3                 :            :  * db-fsys-override.c - management of filesystem stat overrides database
       4                 :            :  *
       5                 :            :  * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
       6                 :            :  * Copyright © 2000, 2001 Wichert Akkerman <wakkerma@debian.org>
       7                 :            :  * Copyright © 2008-2012 Guillem Jover <guillem@debian.org>
       8                 :            :  *
       9                 :            :  * This is free software; you can redistribute it and/or modify
      10                 :            :  * it under the terms of the GNU General Public License as published by
      11                 :            :  * the Free Software Foundation; either version 2 of the License, or
      12                 :            :  * (at your option) any later version.
      13                 :            :  *
      14                 :            :  * This is distributed in the hope that it will be useful,
      15                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17                 :            :  * GNU General Public License for more details.
      18                 :            :  *
      19                 :            :  * You should have received a copy of the GNU General Public License
      20                 :            :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21                 :            :  */
      22                 :            : 
      23                 :            : #include <config.h>
      24                 :            : #include <compat.h>
      25                 :            : 
      26                 :            : #include <sys/types.h>
      27                 :            : #include <sys/stat.h>
      28                 :            : 
      29                 :            : #include <errno.h>
      30                 :            : #include <string.h>
      31                 :            : #include <pwd.h>
      32                 :            : #include <grp.h>
      33                 :            : #include <fcntl.h>
      34                 :            : #include <unistd.h>
      35                 :            : #include <stdlib.h>
      36                 :            : 
      37                 :            : #include <dpkg/i18n.h>
      38                 :            : #include <dpkg/dpkg.h>
      39                 :            : #include <dpkg/dpkg-db.h>
      40                 :            : #include <dpkg/fdio.h>
      41                 :            : #include <dpkg/debug.h>
      42                 :            : #include <dpkg/db-fsys.h>
      43                 :            : 
      44                 :            : static char *statoverridename;
      45                 :            : 
      46                 :            : uid_t
      47                 :          0 : statdb_parse_uid(const char *str)
      48                 :            : {
      49                 :            :         char *endptr;
      50                 :            :         uid_t uid;
      51                 :            : 
      52         [ #  # ]:          0 :         if (str[0] == '#') {
      53                 :            :                 long int value;
      54                 :            : 
      55                 :          0 :                 errno = 0;
      56                 :          0 :                 value = strtol(str + 1, &endptr, 10);
      57   [ #  #  #  #  :          0 :                 if (str + 1 == endptr || *endptr || value < 0 || errno != 0)
             #  #  #  # ]
      58                 :          0 :                         ohshit(_("invalid statoverride uid %s"), str);
      59                 :          0 :                 uid = (uid_t)value;
      60                 :            :         } else {
      61                 :          0 :                 struct passwd *pw = getpwnam(str);
      62                 :            : 
      63         [ #  # ]:          0 :                 if (pw == NULL)
      64                 :          0 :                         uid = (uid_t)-1;
      65                 :            :                 else
      66                 :          0 :                         uid = pw->pw_uid;
      67                 :            :         }
      68                 :            : 
      69                 :          0 :         return uid;
      70                 :            : }
      71                 :            : 
      72                 :            : gid_t
      73                 :          0 : statdb_parse_gid(const char *str)
      74                 :            : {
      75                 :            :         char *endptr;
      76                 :            :         gid_t gid;
      77                 :            : 
      78         [ #  # ]:          0 :         if (str[0] == '#') {
      79                 :            :                 long int value;
      80                 :            : 
      81                 :          0 :                 errno = 0;
      82                 :          0 :                 value = strtol(str + 1, &endptr, 10);
      83   [ #  #  #  #  :          0 :                 if (str + 1 == endptr || *endptr || value < 0 || errno != 0)
             #  #  #  # ]
      84                 :          0 :                         ohshit(_("invalid statoverride gid %s"), str);
      85                 :          0 :                 gid = (gid_t)value;
      86                 :            :         } else {
      87                 :          0 :                 struct group *gr = getgrnam(str);
      88                 :            : 
      89         [ #  # ]:          0 :                 if (gr == NULL)
      90                 :          0 :                         gid = (gid_t)-1;
      91                 :            :                 else
      92                 :          0 :                         gid = gr->gr_gid;
      93                 :            :         }
      94                 :            : 
      95                 :          0 :         return gid;
      96                 :            : }
      97                 :            : 
      98                 :            : mode_t
      99                 :          0 : statdb_parse_mode(const char *str)
     100                 :            : {
     101                 :            :         char *endptr;
     102                 :            :         long int mode;
     103                 :            : 
     104                 :          0 :         mode = strtol(str, &endptr, 8);
     105   [ #  #  #  #  :          0 :         if (str == endptr || *endptr || mode < 0 || mode > 07777)
             #  #  #  # ]
     106                 :          0 :                 ohshit(_("invalid statoverride mode %s"), str);
     107                 :            : 
     108                 :          0 :         return (mode_t)mode;
     109                 :            : }
     110                 :            : 
     111                 :            : void
     112                 :          0 : ensure_statoverrides(enum statdb_parse_flags flags)
     113                 :            : {
     114                 :            :         static struct stat sb_prev;
     115                 :            :         struct stat sb_next;
     116                 :            :         static FILE *file_prev;
     117                 :            :         FILE *file;
     118                 :            :         char *loaded_list, *loaded_list_end, *thisline, *nextline, *ptr;
     119                 :            :         struct file_stat *fso;
     120                 :            :         struct fsys_namenode *fnn;
     121                 :            :         struct fsys_hash_iter *iter;
     122                 :            : 
     123         [ #  # ]:          0 :         if (statoverridename == NULL)
     124                 :          0 :                 statoverridename = dpkg_db_get_path(STATOVERRIDEFILE);
     125                 :            : 
     126                 :          0 :         onerr_abort++;
     127                 :            : 
     128                 :          0 :         file = fopen(statoverridename, "r");
     129         [ #  # ]:          0 :         if (!file) {
     130         [ #  # ]:          0 :                 if (errno != ENOENT)
     131                 :          0 :                         ohshite(_("failed to open statoverride file"));
     132                 :            :         } else {
     133                 :          0 :                 setcloexec(fileno(file), statoverridename);
     134                 :            : 
     135         [ #  # ]:          0 :                 if (fstat(fileno(file), &sb_next))
     136                 :          0 :                         ohshite(_("failed to fstat statoverride file"));
     137                 :            : 
     138                 :            :                 /*
     139                 :            :                  * We need to keep the database file open so that the
     140                 :            :                  * filesystem cannot reuse the inode number (f.ex. during
     141                 :            :                  * multiple dpkg-statoverride invocations in a maintainer
     142                 :            :                  * script), otherwise the following check might turn true,
     143                 :            :                  * and we would skip reloading a modified database.
     144                 :            :                  */
     145         [ #  # ]:          0 :                 if (file_prev &&
     146         [ #  # ]:          0 :                     sb_prev.st_dev == sb_next.st_dev &&
     147         [ #  # ]:          0 :                     sb_prev.st_ino == sb_next.st_ino) {
     148                 :          0 :                         fclose(file);
     149                 :          0 :                         onerr_abort--;
     150                 :          0 :                         debug(dbg_general, "%s: same, skipping", __func__);
     151                 :          0 :                         return;
     152                 :            :                 }
     153                 :          0 :                 sb_prev = sb_next;
     154                 :            :         }
     155         [ #  # ]:          0 :         if (file_prev)
     156                 :          0 :                 fclose(file_prev);
     157                 :          0 :         file_prev = file;
     158                 :            : 
     159                 :            :         /* Reset statoverride information. */
     160                 :          0 :         iter = fsys_hash_iter_new();
     161         [ #  # ]:          0 :         while ((fnn = fsys_hash_iter_next(iter)))
     162                 :          0 :                 fnn->statoverride = NULL;
     163                 :          0 :         fsys_hash_iter_free(iter);
     164                 :            : 
     165         [ #  # ]:          0 :         if (!file) {
     166                 :          0 :                 onerr_abort--;
     167                 :          0 :                 debug(dbg_general, "%s: none, resetting", __func__);
     168                 :          0 :                 return;
     169                 :            :         }
     170                 :          0 :         debug(dbg_general, "%s: new, (re)loading", __func__);
     171                 :            : 
     172                 :            :         /* If the statoverride list is empty we don't need to bother
     173                 :            :          * reading it. */
     174         [ #  # ]:          0 :         if (!sb_next.st_size) {
     175                 :          0 :                 onerr_abort--;
     176                 :          0 :                 return;
     177                 :            :         }
     178                 :            : 
     179                 :          0 :         loaded_list = m_malloc(sb_next.st_size);
     180                 :          0 :         loaded_list_end = loaded_list + sb_next.st_size;
     181                 :            : 
     182         [ #  # ]:          0 :         if (fd_read(fileno(file), loaded_list, sb_next.st_size) < 0)
     183                 :          0 :                 ohshite(_("reading statoverride file '%.250s'"), statoverridename);
     184                 :            : 
     185                 :          0 :         thisline = loaded_list;
     186         [ #  # ]:          0 :         while (thisline < loaded_list_end) {
     187                 :          0 :                 fso = nfmalloc(sizeof(*fso));
     188                 :            : 
     189                 :          0 :                 ptr = memchr(thisline, '\n', loaded_list_end - thisline);
     190         [ #  # ]:          0 :                 if (ptr == NULL)
     191                 :          0 :                         ohshit(_("statoverride file is missing final newline"));
     192                 :            :                 /* Where to start next time around. */
     193                 :          0 :                 nextline = ptr + 1;
     194         [ #  # ]:          0 :                 if (ptr == thisline)
     195                 :          0 :                         ohshit(_("statoverride file contains empty line"));
     196                 :          0 :                 *ptr = '\0';
     197                 :            : 
     198                 :            :                 /* Extract the uid. */
     199                 :          0 :                 ptr = memchr(thisline, ' ', nextline - thisline);
     200         [ #  # ]:          0 :                 if (ptr == NULL)
     201                 :          0 :                         ohshit(_("syntax error in statoverride file"));
     202                 :          0 :                 *ptr = '\0';
     203                 :            : 
     204                 :          0 :                 fso->uid = statdb_parse_uid(thisline);
     205         [ #  # ]:          0 :                 if (fso->uid == (uid_t)-1)
     206                 :          0 :                         fso->uname = nfstrsave(thisline);
     207                 :            :                 else
     208                 :          0 :                         fso->uname = NULL;
     209                 :            : 
     210   [ #  #  #  # ]:          0 :                 if (fso->uid == (uid_t)-1 && !(flags & STATDB_PARSE_LAX))
     211                 :          0 :                         ohshit(_("unknown system user '%s' in statoverride file; the system user got removed\n"
     212                 :            :                                  "before the override, which is most probably a packaging bug, to recover you\n"
     213                 :            :                                  "can remove the override manually with %s"), thisline, DPKGSTAT);
     214                 :            : 
     215                 :            :                 /* Move to the next bit */
     216                 :          0 :                 thisline = ptr + 1;
     217         [ #  # ]:          0 :                 if (thisline >= loaded_list_end)
     218                 :          0 :                         ohshit(_("unexpected end of line in statoverride file"));
     219                 :            : 
     220                 :            :                 /* Extract the gid */
     221                 :          0 :                 ptr = memchr(thisline, ' ', nextline - thisline);
     222         [ #  # ]:          0 :                 if (ptr == NULL)
     223                 :          0 :                         ohshit(_("syntax error in statoverride file"));
     224                 :          0 :                 *ptr = '\0';
     225                 :            : 
     226                 :          0 :                 fso->gid = statdb_parse_gid(thisline);
     227         [ #  # ]:          0 :                 if (fso->gid == (gid_t)-1)
     228                 :          0 :                         fso->gname = nfstrsave(thisline);
     229                 :            :                 else
     230                 :          0 :                         fso->gname = NULL;
     231                 :            : 
     232   [ #  #  #  # ]:          0 :                 if (fso->gid == (gid_t)-1 && !(flags & STATDB_PARSE_LAX))
     233                 :          0 :                         ohshit(_("unknown system group '%s' in statoverride file; the system group got removed\n"
     234                 :            :                                  "before the override, which is most probably a packaging bug, to recover you\n"
     235                 :            :                                  "can remove the override manually with %s"), thisline, DPKGSTAT);
     236                 :            : 
     237                 :            :                 /* Move to the next bit */
     238                 :          0 :                 thisline = ptr + 1;
     239         [ #  # ]:          0 :                 if (thisline >= loaded_list_end)
     240                 :          0 :                         ohshit(_("unexpected end of line in statoverride file"));
     241                 :            : 
     242                 :            :                 /* Extract the mode */
     243                 :          0 :                 ptr = memchr(thisline, ' ', nextline - thisline);
     244         [ #  # ]:          0 :                 if (ptr == NULL)
     245                 :          0 :                         ohshit(_("syntax error in statoverride file"));
     246                 :          0 :                 *ptr = '\0';
     247                 :            : 
     248                 :          0 :                 fso->mode = statdb_parse_mode(thisline);
     249                 :            : 
     250                 :            :                 /* Move to the next bit */
     251                 :          0 :                 thisline = ptr + 1;
     252         [ #  # ]:          0 :                 if (thisline >= loaded_list_end)
     253                 :          0 :                         ohshit(_("unexpected end of line in statoverride file"));
     254                 :            : 
     255                 :          0 :                 fnn = fsys_hash_find_node(thisline, 0);
     256         [ #  # ]:          0 :                 if (fnn->statoverride)
     257                 :          0 :                         ohshit(_("multiple statoverrides present for file '%.250s'"),
     258                 :            :                                thisline);
     259                 :          0 :                 fnn->statoverride = fso;
     260                 :            : 
     261                 :            :                 /* Moving on... */
     262                 :          0 :                 thisline = nextline;
     263                 :            :         }
     264                 :            : 
     265                 :          0 :         free(loaded_list);
     266                 :            : 
     267                 :          0 :         onerr_abort--;
     268                 :            : }

Generated by: LCOV version 1.16