LCOV - code coverage report
Current view: top level - util - find_uid.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 92 158 58.2 %
Date: 2015-10-19 Functions: 8 8 100.0 %

          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             : #include <dhash.h>
      39             : 
      40             : #include "util/find_uid.h"
      41             : #include "util/util.h"
      42             : #include "util/strtonum.h"
      43             : 
      44             : #ifdef HAVE_SYSTEMD_LOGIN
      45             : #include <systemd/sd-login.h>
      46             : #endif
      47             : 
      48             : #define INITIAL_TABLE_SIZE 64
      49             : #define PATHLEN (NAME_MAX + 14)
      50             : #define BUFSIZE 4096
      51             : 
      52          36 : static void *hash_talloc(const size_t size, void *pvt)
      53             : {
      54          36 :     return talloc_size(pvt, size);
      55             : }
      56             : 
      57           1 : static void hash_talloc_free(void *ptr, void *pvt)
      58             : {
      59           1 :     talloc_free(ptr);
      60           1 : }
      61             : 
      62        1328 : static errno_t get_uid_from_pid(const pid_t pid, uid_t *uid)
      63             : {
      64             :     int ret;
      65             :     char path[PATHLEN];
      66             :     struct stat stat_buf;
      67             :     int fd;
      68             :     char buf[BUFSIZE];
      69             :     char *p;
      70             :     char *e;
      71             :     char *endptr;
      72        1328 :     uint32_t num=0;
      73             :     errno_t error;
      74             : 
      75        1328 :     ret = snprintf(path, PATHLEN, "/proc/%d/status", pid);
      76        1328 :     if (ret < 0) {
      77           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "snprintf failed\n");
      78           0 :         return EINVAL;
      79        1328 :     } else if (ret >= PATHLEN) {
      80           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "path too long?!?!\n");
      81           0 :         return EINVAL;
      82             :     }
      83             : 
      84        1328 :     fd = open(path, O_RDONLY);
      85        1328 :     if (fd == -1) {
      86           0 :         error = errno;
      87           0 :         if (error == ENOENT) {
      88           0 :             DEBUG(SSSDBG_TRACE_LIBS,
      89             :                   "Proc file [%s] is not available anymore, continuing.\n",
      90             :                       path);
      91           0 :             return EOK;
      92             :         }
      93           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
      94             :               "open failed [%d][%s].\n", error, strerror(error));
      95           0 :         return error;
      96             :     }
      97             : 
      98        1328 :     ret = fstat(fd, &stat_buf);
      99        1328 :     if (ret == -1) {
     100           0 :         error = errno;
     101           0 :         if (error == ENOENT) {
     102           0 :             DEBUG(SSSDBG_TRACE_LIBS,
     103             :                   "Proc file [%s] is not available anymore, continuing.\n",
     104             :                       path);
     105           0 :             error = EOK;
     106           0 :             goto fail_fd;
     107             :         }
     108           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     109             :               "fstat failed [%d][%s].\n", error, strerror(error));
     110           0 :         goto fail_fd;
     111             :     }
     112             : 
     113        1328 :     if (!S_ISREG(stat_buf.st_mode)) {
     114           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "not a regular file\n");
     115           0 :         error = EINVAL;
     116           0 :         goto fail_fd;
     117             :     }
     118             : 
     119        1328 :     errno = 0;
     120        1328 :     ret = sss_atomic_read_s(fd, buf, BUFSIZE);
     121        1328 :     if (ret == -1) {
     122           0 :         error = errno;
     123           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     124             :               "read failed [%d][%s].\n", error, strerror(error));
     125           0 :         goto fail_fd;
     126             :     }
     127             : 
     128             :     /* Guarantee NULL-termination in case we read the full BUFSIZE somehow */
     129        1328 :     buf[BUFSIZE-1] = '\0';
     130             : 
     131        1328 :     ret = close(fd);
     132        1328 :     if (ret == -1) {
     133           0 :         error = errno;
     134           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     135             :               "close failed [%d][%s].\n", error, strerror(error));
     136             :     }
     137             : 
     138        1328 :     p = strstr(buf, "\nUid:\t");
     139        1328 :     if (p != NULL) {
     140        1328 :         p += 6;
     141        1328 :         e = strchr(p,'\t');
     142        1328 :         if (e == NULL) {
     143           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "missing delimiter.\n");
     144           0 :             return EINVAL;
     145             :         } else {
     146        1328 :             *e = '\0';
     147             :         }
     148        1328 :         num = (uint32_t) strtoint32(p, &endptr, 10);
     149        1328 :         error = errno;
     150        1328 :         if (error != 0) {
     151           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     152             :                   "strtol failed [%s].\n", strerror(error));
     153           0 :             return error;
     154             :         }
     155        1328 :         if (*endptr != '\0') {
     156           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "uid contains extra characters\n");
     157           0 :             return EINVAL;
     158             :         }
     159             : 
     160             :     } else {
     161           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "format error\n");
     162           0 :         return EINVAL;
     163             :     }
     164             : 
     165        1328 :     *uid = num;
     166             : 
     167        1328 :     return EOK;
     168             : 
     169             : fail_fd:
     170           0 :     close(fd);
     171           0 :     return error;
     172             : }
     173             : 
     174        1328 : static errno_t name_to_pid(const char *name, pid_t *pid)
     175             : {
     176             :     long num;
     177             :     char *endptr;
     178             :     errno_t error;
     179             : 
     180        1328 :     errno = 0;
     181        1328 :     num = strtol(name, &endptr, 10);
     182        1328 :     error = errno;
     183        1328 :     if (error == ERANGE) {
     184           0 :         perror("strtol");
     185           0 :         return error;
     186             :     }
     187             : 
     188        1328 :     if (*endptr != '\0') {
     189           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "pid string contains extra characters.\n");
     190           0 :         return EINVAL;
     191             :     }
     192             : 
     193        1328 :     if (num <= 0 || num >= INT_MAX) {
     194           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "pid out of range.\n");
     195           0 :         return ERANGE;
     196             :     }
     197             : 
     198        1328 :     *pid = num;
     199             : 
     200        1328 :     return EOK;
     201             : }
     202             : 
     203        1576 : static int only_numbers(char *p)
     204             : {
     205        1576 :     while(*p!='\0' && isdigit(*p)) ++p;
     206        1576 :     return *p;
     207             : }
     208             : 
     209           4 : static errno_t get_active_uid_linux(hash_table_t *table, uid_t search_uid)
     210             : {
     211           4 :     DIR *proc_dir = NULL;
     212             :     struct dirent *dirent;
     213             :     int ret, err;
     214           4 :     pid_t pid = -1;
     215             :     uid_t uid;
     216             : 
     217             :     hash_key_t key;
     218             :     hash_value_t value;
     219             : 
     220           4 :     proc_dir = opendir("/proc");
     221           4 :     if (proc_dir == NULL) {
     222           0 :         ret = errno;
     223           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Cannot open proc dir.\n");
     224           0 :         goto done;
     225             :     };
     226             : 
     227           4 :     errno = 0;
     228        1584 :     while ((dirent = readdir(proc_dir)) != NULL) {
     229        1576 :         if (only_numbers(dirent->d_name) != 0) continue;
     230        1328 :         ret = name_to_pid(dirent->d_name, &pid);
     231        1328 :         if (ret != EOK) {
     232           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "name_to_pid failed.\n");
     233           0 :             goto done;
     234             :         }
     235             : 
     236        1328 :         ret = get_uid_from_pid(pid, &uid);
     237        1328 :         if (ret != EOK) {
     238           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "get_uid_from_pid failed.\n");
     239           0 :             goto done;
     240             :         }
     241             : 
     242        1328 :         if (table != NULL) {
     243         664 :             key.type = HASH_KEY_ULONG;
     244         664 :             key.ul = (unsigned long) uid;
     245         664 :             value.type = HASH_VALUE_ULONG;
     246         664 :             value.ul = (unsigned long) uid;
     247             : 
     248         664 :             ret = hash_enter(table, &key, &value);
     249         664 :             if (ret != HASH_SUCCESS) {
     250           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     251             :                       "cannot add to table [%s]\n", hash_error_string(ret));
     252           0 :                 ret = ENOMEM;
     253           0 :                 goto done;
     254             :             }
     255             :         } else {
     256         664 :             if (uid == search_uid) {
     257           0 :                 ret = EOK;
     258           0 :                 goto done;
     259             :             }
     260             :         }
     261             : 
     262             : 
     263        1328 :         errno = 0;
     264             :     }
     265           4 :     if (errno != 0 && dirent == NULL) {
     266           0 :         ret = errno;
     267           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "readdir failed.\n");
     268           0 :         goto done;
     269             :     }
     270             : 
     271           4 :     ret = closedir(proc_dir);
     272           4 :     proc_dir = NULL;
     273           4 :     if (ret == -1) {
     274           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "closedir failed, watch out.\n");
     275             :     }
     276             : 
     277           4 :     if (table != NULL) {
     278           2 :         ret = EOK;
     279             :     } else {
     280           2 :         ret = ENOENT;
     281             :     }
     282             : 
     283             : done:
     284           4 :     if (proc_dir != NULL) {
     285           0 :         err = closedir(proc_dir);
     286           0 :         if (err) {
     287           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "closedir failed, bad dirp?\n");
     288             :         }
     289             :     }
     290           4 :     return ret;
     291             : }
     292             : 
     293           2 : errno_t get_uid_table(TALLOC_CTX *mem_ctx, hash_table_t **table)
     294             : {
     295             : #ifdef __linux__
     296             :     int ret;
     297             : 
     298           2 :     ret = hash_create_ex(INITIAL_TABLE_SIZE, table, 0, 0, 0, 0,
     299             :                          hash_talloc, hash_talloc_free, mem_ctx,
     300             :                          NULL, NULL);
     301           2 :     if (ret != HASH_SUCCESS) {
     302           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     303             :               "hash_create_ex failed [%s]\n", hash_error_string(ret));
     304           0 :         return ENOMEM;
     305             :     }
     306             : 
     307           2 :     return get_active_uid_linux(*table, 0);
     308             : #else
     309             :     return ENOSYS;
     310             : #endif
     311             : }
     312             : 
     313           4 : errno_t check_if_uid_is_active(uid_t uid, bool *result)
     314             : {
     315             :     int ret;
     316             : 
     317             : #ifdef HAVE_SYSTEMD_LOGIN
     318           4 :     ret = sd_uid_get_sessions(uid, 0, NULL);
     319           4 :     if (ret > 0) {
     320           2 :         *result = true;
     321           2 :         return EOK;
     322             :     }
     323           2 :     if (ret == 0) {
     324           2 :         *result = false;
     325             :     }
     326           2 :     if (ret < 0) {
     327           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "systemd-login gave error %d: %s\n",
     328             :                                     -ret, strerror(-ret));
     329             :     }
     330             :     /* fall back to the old method */
     331             : #endif
     332             : 
     333           2 :     ret = get_active_uid_linux(NULL, uid);
     334           2 :     if (ret != EOK && ret != ENOENT) {
     335           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "get_uid_table failed.\n");
     336           0 :         return ret;
     337             :     }
     338             : 
     339           2 :     if (ret == EOK) {
     340           0 :         *result = true;
     341             :     } else {
     342           2 :         *result = false;
     343             :     }
     344             : 
     345           2 :     return EOK;
     346             : }

Generated by: LCOV version 1.10