LCOV - code coverage report
Current view: top level - util - find_uid.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 82 119 68.9 %
Date: 2012-11-29 Functions: 7 8 87.5 %
Branches: 41 310 13.2 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :     SSSD
       3                 :            : 
       4                 :            :     Create uid table
       5                 :            : 
       6                 :            :     Authors:
       7                 :            :         Sumit Bose <sbose@redhat.com>
       8                 :            : 
       9                 :            :     Copyright (C) 2009 Red Hat
      10                 :            : 
      11                 :            :     This program is free software; you can redistribute it and/or modify
      12                 :            :     it under the terms of the GNU General Public License as published by
      13                 :            :     the Free Software Foundation; either version 3 of the License, or
      14                 :            :     (at your option) any later version.
      15                 :            : 
      16                 :            :     This program is distributed in the hope that it will be useful,
      17                 :            :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      18                 :            :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19                 :            :     GNU General Public License for more details.
      20                 :            : 
      21                 :            :     You should have received a copy of the GNU General Public License
      22                 :            :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      23                 :            : */
      24                 :            : 
      25                 :            : #include <stdio.h>
      26                 :            : #include <sys/types.h>
      27                 :            : #include <dirent.h>
      28                 :            : #include <errno.h>
      29                 :            : #include <sys/stat.h>
      30                 :            : #include <unistd.h>
      31                 :            : #include <fcntl.h>
      32                 :            : #include <stdlib.h>
      33                 :            : #include <string.h>
      34                 :            : #include <limits.h>
      35                 :            : #include <talloc.h>
      36                 :            : #include <ctype.h>
      37                 :            : #include <sys/time.h>
      38                 :            : 
      39                 :            : #include "dhash.h"
      40                 :            : #include "util/util.h"
      41                 :            : #include "util/strtonum.h"
      42                 :            : 
      43                 :            : #define INITIAL_TABLE_SIZE 64
      44                 :            : #define PATHLEN (NAME_MAX + 14)
      45                 :            : #define BUFSIZE 4096
      46                 :            : 
      47                 :         15 : static void *hash_talloc(const size_t size, void *pvt)
      48                 :            : {
      49                 :         15 :     return talloc_size(pvt, size);
      50                 :            : }
      51                 :            : 
      52                 :          0 : static void hash_talloc_free(void *ptr, void *pvt)
      53                 :            : {
      54                 :          0 :     talloc_free(ptr);
      55                 :          0 : }
      56                 :            : 
      57                 :        579 : static errno_t get_uid_from_pid(const pid_t pid, uid_t *uid)
      58                 :            : {
      59                 :            :     int ret;
      60                 :            :     char path[PATHLEN];
      61                 :            :     struct stat stat_buf;
      62                 :            :     int fd;
      63                 :            :     char buf[BUFSIZE];
      64                 :            :     char *p;
      65                 :            :     char *e;
      66                 :            :     char *endptr;
      67                 :        579 :     uint32_t num=0;
      68                 :            :     errno_t error;
      69                 :            : 
      70                 :        579 :     ret = snprintf(path, PATHLEN, "/proc/%d/status", pid);
      71         [ -  + ]:        579 :     if (ret < 0) {
      72 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("snprintf failed"));
         [ #  # ][ #  # ]
                 [ #  # ]
      73                 :            :         return EINVAL;
      74         [ -  + ]:        579 :     } else if (ret >= PATHLEN) {
      75 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("path too long?!?!\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
      76                 :            :         return EINVAL;
      77                 :            :     }
      78                 :            : 
      79                 :        579 :     fd = open(path, O_RDONLY);
      80         [ -  + ]:        579 :     if (fd == -1) {
      81                 :          0 :         error = errno;
      82         [ #  # ]:          0 :         if (error == ENOENT) {
      83 [ #  # ][ #  # ]:          0 :             DEBUG(7, ("Proc file [%s] is not available anymore, continuing.\n",
         [ #  # ][ #  # ]
                 [ #  # ]
      84                 :            :                       path));
      85                 :            :             return EOK;
      86                 :            :         }
      87 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("open failed [%d][%s].\n", error, strerror(error)));
         [ #  # ][ #  # ]
                 [ #  # ]
      88                 :            :         return error;
      89                 :            :     }
      90                 :            : 
      91                 :        579 :     ret = fstat(fd, &stat_buf);
      92         [ -  + ]:        579 :     if (ret == -1) {
      93                 :          0 :         error = errno;
      94         [ #  # ]:          0 :         if (error == ENOENT) {
      95 [ #  # ][ #  # ]:          0 :             DEBUG(7, ("Proc file [%s] is not available anymore, continuing.\n",
         [ #  # ][ #  # ]
                 [ #  # ]
      96                 :            :                       path));
      97                 :            :             error = EOK;
      98                 :            :             goto fail_fd;
      99                 :            :         }
     100 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("fstat failed [%d][%s].\n", error, strerror(error)));
         [ #  # ][ #  # ]
                 [ #  # ]
     101                 :            :         goto fail_fd;
     102                 :            :     }
     103                 :            : 
     104         [ -  + ]:        579 :     if (!S_ISREG(stat_buf.st_mode)) {
     105 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("not a regular file\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     106                 :            :         error = EINVAL;
     107                 :            :         goto fail_fd;
     108                 :            :     }
     109                 :            : 
     110                 :        579 :     errno = 0;
     111                 :        579 :     ret = sss_atomic_read_s(fd, buf, BUFSIZE);
     112         [ -  + ]:        579 :     if (ret == -1) {
     113                 :          0 :         error = errno;
     114 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE,
         [ #  # ][ #  # ]
                 [ #  # ]
     115                 :            :               ("read failed [%d][%s].\n", error, strerror(error)));
     116                 :            :         goto fail_fd;
     117                 :            :     }
     118                 :            : 
     119                 :            :     /* Guarantee NULL-termination in case we read the full BUFSIZE somehow */
     120                 :        579 :     buf[BUFSIZE-1] = '\0';
     121                 :            : 
     122                 :        579 :     ret = close(fd);
     123         [ -  + ]:        579 :     if (ret == -1) {
     124                 :          0 :         error = errno;
     125 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("close failed [%d][%s].\n", error, strerror(error)));
         [ #  # ][ #  # ]
                 [ #  # ]
     126                 :            :     }
     127                 :            : 
     128                 :        579 :     p = strstr(buf, "\nUid:\t");
     129         [ +  - ]:        579 :     if (p != NULL) {
     130                 :        579 :         p += 6;
     131                 :        579 :         e = strchr(p,'\t');
     132         [ -  + ]:        579 :         if (e == NULL) {
     133 [ #  # ][ #  # ]:          0 :             DEBUG(1, ("missing delimiter.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     134                 :            :             return EINVAL;
     135                 :            :         } else {
     136                 :        579 :             *e = '\0';
     137                 :            :         }
     138                 :        579 :         num = (uint32_t) strtoint32(p, &endptr, 10);
     139                 :        579 :         error = errno;
     140         [ -  + ]:        579 :         if (error != 0) {
     141 [ #  # ][ #  # ]:          0 :             DEBUG(1, ("strtol failed [%s].\n", strerror(error)));
         [ #  # ][ #  # ]
                 [ #  # ]
     142                 :            :             return error;
     143                 :            :         }
     144         [ -  + ]:        579 :         if (*endptr != '\0') {
     145 [ #  # ][ #  # ]:          0 :             DEBUG(1, ("uid contains extra characters\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     146                 :            :             return EINVAL;
     147                 :            :         }
     148                 :            : 
     149                 :            :     } else {
     150 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("format error\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     151                 :            :         return EINVAL;
     152                 :            :     }
     153                 :            : 
     154                 :        579 :     *uid = num;
     155                 :            : 
     156                 :            :     return EOK;
     157                 :            : 
     158                 :            : fail_fd:
     159                 :        579 :     close(fd);
     160                 :            :     return error;
     161                 :            : }
     162                 :            : 
     163                 :        579 : static errno_t name_to_pid(const char *name, pid_t *pid)
     164                 :            : {
     165                 :            :     long num;
     166                 :            :     char *endptr;
     167                 :            :     errno_t error;
     168                 :            : 
     169                 :        579 :     errno = 0;
     170                 :        579 :     num = strtol(name, &endptr, 10);
     171                 :        579 :     error = errno;
     172         [ -  + ]:        579 :     if (error == ERANGE) {
     173                 :          0 :         perror("strtol");
     174                 :            :         return error;
     175                 :            :     }
     176                 :            : 
     177         [ -  + ]:        579 :     if (*endptr != '\0') {
     178 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("pid string contains extra characters.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     179                 :            :         return EINVAL;
     180                 :            :     }
     181                 :            : 
     182         [ -  + ]:        579 :     if (num <= 0 || num >= INT_MAX) {
     183 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("pid out of range.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     184                 :            :         return ERANGE;
     185                 :            :     }
     186                 :            : 
     187                 :        579 :     *pid = num;
     188                 :            : 
     189                 :            :     return EOK;
     190                 :            : }
     191                 :            : 
     192                 :        765 : static int only_numbers(char *p)
     193                 :            : {
     194 [ +  + ][ +  + ]:       2826 :     while(*p!='\0' && isdigit(*p)) ++p;
     195                 :        765 :     return *p;
     196                 :            : }
     197                 :            : 
     198                 :          3 : static errno_t get_active_uid_linux(hash_table_t *table, uid_t search_uid)
     199                 :            : {
     200                 :          3 :     DIR *proc_dir = NULL;
     201                 :            :     struct dirent *dirent;
     202                 :            :     int ret, err;
     203                 :          3 :     pid_t pid = -1;
     204                 :            :     uid_t uid;
     205                 :            : 
     206                 :            :     hash_key_t key;
     207                 :            :     hash_value_t value;
     208                 :            : 
     209                 :          3 :     proc_dir = opendir("/proc");
     210         [ -  + ]:          3 :     if (proc_dir == NULL) {
     211                 :          0 :         ret = errno;
     212 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("Cannot open proc dir.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     213                 :            :         goto done;
     214                 :            :     };
     215                 :            : 
     216                 :          3 :     errno = 0;
     217         [ +  + ]:        767 :     while ((dirent = readdir(proc_dir)) != NULL) {
     218         [ +  + ]:        765 :         if (only_numbers(dirent->d_name) != 0) continue;
     219                 :        579 :         ret = name_to_pid(dirent->d_name, &pid);
     220         [ -  + ]:        579 :         if (ret != EOK) {
     221 [ #  # ][ #  # ]:          0 :             DEBUG(1, ("name_to_pid failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     222                 :            :             goto done;
     223                 :            :         }
     224                 :            : 
     225                 :        579 :         ret = get_uid_from_pid(pid, &uid);
     226         [ -  + ]:        579 :         if (ret != EOK) {
     227 [ #  # ][ #  # ]:          0 :             DEBUG(1, ("get_uid_from_pid failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     228                 :            :             goto done;
     229                 :            :         }
     230                 :            : 
     231         [ +  + ]:        579 :         if (table != NULL) {
     232                 :        251 :             key.type = HASH_KEY_ULONG;
     233                 :        251 :             key.ul = (unsigned long) uid;
     234                 :        251 :             value.type = HASH_VALUE_ULONG;
     235                 :        251 :             value.ul = (unsigned long) uid;
     236                 :            : 
     237                 :        251 :             ret = hash_enter(table, &key, &value);
     238         [ -  + ]:        251 :             if (ret != HASH_SUCCESS) {
     239 [ #  # ][ #  # ]:          0 :                 DEBUG(1, ("cannot add to table [%s]\n", hash_error_string(ret)));
         [ #  # ][ #  # ]
                 [ #  # ]
     240                 :            :                 ret = ENOMEM;
     241                 :            :                 goto done;
     242                 :            :             }
     243                 :            :         } else {
     244         [ +  + ]:        328 :             if (uid == search_uid) {
     245                 :            :                 ret = EOK;
     246                 :            :                 goto done;
     247                 :            :             }
     248                 :            :         }
     249                 :            : 
     250                 :            : 
     251                 :        764 :         errno = 0;
     252                 :            :     }
     253 [ -  + ][ #  # ]:          2 :     if (errno != 0 && dirent == NULL) {
     254                 :          0 :         ret = errno;
     255 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("readdir failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     256                 :            :         goto done;
     257                 :            :     }
     258                 :            : 
     259                 :          2 :     ret = closedir(proc_dir);
     260                 :          2 :     proc_dir = NULL;
     261         [ -  + ]:          2 :     if (ret == -1) {
     262 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("closedir failed, watch out.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     263                 :            :     }
     264                 :            : 
     265         [ +  + ]:          2 :     if (table != NULL) {
     266                 :            :         ret = EOK;
     267                 :            :     } else {
     268                 :          1 :         ret = ENOENT;
     269                 :            :     }
     270                 :            : 
     271                 :            : done:
     272         [ +  + ]:          3 :     if (proc_dir != NULL) {
     273                 :          1 :         err = closedir(proc_dir);
     274         [ -  + ]:          1 :         if (err) {
     275 [ #  # ][ #  # ]:          0 :             DEBUG(1, ("closedir failed, bad dirp?\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     276                 :            :         }
     277                 :            :     }
     278                 :          3 :     return ret;
     279                 :            : }
     280                 :            : 
     281                 :          1 : errno_t get_uid_table(TALLOC_CTX *mem_ctx, hash_table_t **table)
     282                 :            : {
     283                 :            : #ifdef __linux__
     284                 :            :     int ret;
     285                 :            : 
     286                 :          1 :     ret = hash_create_ex(INITIAL_TABLE_SIZE, table, 0, 0, 0, 0,
     287                 :            :                          hash_talloc, hash_talloc_free, mem_ctx,
     288                 :            :                          NULL, NULL);
     289         [ -  + ]:          1 :     if (ret != HASH_SUCCESS) {
     290 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("hash_create_ex failed [%s]\n", hash_error_string(ret)));
         [ #  # ][ #  # ]
                 [ #  # ]
     291                 :            :         return ENOMEM;
     292                 :            :     }
     293                 :            : 
     294                 :          1 :     return get_active_uid_linux(*table, 0);
     295                 :            : #else
     296                 :            :     return ENOSYS;
     297                 :            : #endif
     298                 :            : }
     299                 :            : 
     300                 :          2 : errno_t check_if_uid_is_active(uid_t uid, bool *result)
     301                 :            : {
     302                 :            :     int ret;
     303                 :            : 
     304                 :          2 :     ret = get_active_uid_linux(NULL, uid);
     305         [ -  + ]:          2 :     if (ret != EOK && ret != ENOENT) {
     306 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("get_uid_table failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     307                 :          0 :         return ret;
     308                 :            :     }
     309                 :            : 
     310         [ +  + ]:          2 :     if (ret == EOK) {
     311                 :          1 :         *result = true;
     312                 :            :     } else {
     313                 :          2 :         *result = false;
     314                 :            :     }
     315                 :            : 
     316                 :            :     return EOK;
     317                 :            : }

Generated by: LCOV version 1.9