GCC Code Coverage Report
Directory: cvmfs/ Exec Total Coverage
File: cvmfs/uid_map.h Lines: 59 60 98.3 %
Date: 2019-02-03 02:48:13 Branches: 39 44 88.6 %

Line Branch Exec Source
1
/**
2
 * This file is part of the CernVM File System.
3
 */
4
5
#ifndef CVMFS_UID_MAP_H_
6
#define CVMFS_UID_MAP_H_
7
8
#include <sys/types.h>
9
10
#include <cerrno>
11
#include <map>
12
#include <string>
13
#include <vector>
14
15
#include "logging.h"
16
#include "sanitizer.h"
17
#include "util/string.h"
18
19
/**
20
 * This reads a mapping file of (roughly) the following format:
21
 * +-------------------------------------------------------------+
22
 * | user_id.map                                                 |
23
 * | ~~~~~~~~~~~                                                 |
24
 * |                                                             |
25
 * | # map UIDs 137 and 138 to 1000 (I am a comment by the way)  |
26
 * | 137  1000                                                   |
27
 * | 138  1000                                                   |
28
 * |                                                             |
29
 * | # swap two UIDs                                             |
30
 * | 101  5                                                      |
31
 * | 5    101                                                    |
32
 * |                                                             |
33
 * | # map everything else to root (wildcard)                    |
34
 * | * 0                                                         |
35
 * +-------------------------------------------------------------+
36
 *
37
 * These files are intended for the definition of UID and GID mappings both on
38
 * the client and the server side of CernVM-FS.
39
 *
40
 * The class takes care of managing these mappings and can be initialised via
41
 * a file read from disk or programmatically through the class's public API.
42
 * When reading from a file, simple consistency checks are performed to ensure
43
 * proper functionality.
44
 */
45
template <typename T>
46
447
class IntegerMap {
47
 public:
48
  typedef T                                       key_type;
49
  typedef T                                       value_type;
50
  typedef typename std::map<key_type, value_type> map_type;
51
52
 public:
53
337
  IntegerMap()
54
    : valid_(true)
55
    , has_default_value_(false)
56
337
    , default_value_(T(0)) {}
57
58
  /**
59
   * Define a mapping from k to v
60
   * @param k  map the given value to v
61
   * @param v  the value given in k is mapped to this
62
   **/
63
60
  void Set(const T k, const T v) { map_[k] = v; }
64
65
  /**
66
   * Sets a default (or fallback) value to be used if no other mapping rule fits
67
   * Note: A previously defined default value is overwritten.
68
   * @param v  the value to be used as a fallback in Map()
69
   */
70
25
  void SetDefault(const T v) {
71
25
    has_default_value_ = true;
72
25
    default_value_     = v;
73
25
  }
74
75
  /**
76
   * Reads mapping rules from a provided file path. The file format is discussed
77
   * in the class description above.
78
   * Note: If a read failure occurs the IntegerMap<> is declared invalid and
79
   *       must not be used anymore.
80
   *
81
   * @param path  the file path to be read
82
   * @return      true if the file was successfully read
83
   */
84
22
  bool Read(const std::string &path) {
85
22
    valid_ = ReadFromFile(path);
86
22
    return IsValid();
87
  }
88
89
  /**
90
   * Checks if a mapping rule for a given value is available
91
   * @param k  the value to be checked
92
   * @return   true if a mapping rule for k exists
93
   */
94
40
  bool Contains(const T k) const {
95
40
    assert(IsValid());
96
40
    return map_.find(k) != map_.end();
97
  }
98
99
  /**
100
   * Applies the mapping rules inside this IntegerMap<> to the given value.
101
   * @param k  the value to be mapped
102
   * @return   the result of the mapping rule application (might be the default)
103
   */
104
55
  T Map(const T k) const {
105
55
    assert(IsValid());
106
55
    typename map_type::const_iterator i = map_.find(k);
107
55
    if (i != map_.end()) {
108
30
      return i->second;
109
    }
110
111
    return (HasDefault())
112
      ? default_value_
113
25
      : k;
114
  }
115
116
158
  bool HasEffect() const {
117

158
    return (map_.size() != 0) || has_default_value_;
118
  }
119
120
20
  bool   IsEmpty()    const { return map_.size() == 0;   }
121
152
  bool   IsValid()    const { return valid_;             }
122
45
  bool   HasDefault() const { return has_default_value_; }
123
20
  size_t RuleCount()  const { return map_.size();        }
124
125
10
  T GetDefault() const { assert(has_default_value_); return default_value_; }
126
  const map_type& GetRuleMap() const { return map_; }
127
128
 protected:
129
22
  bool ReadFromFile(const std::string &path) {
130
22
    FILE *fmap = fopen(path.c_str(), "r");
131
22
    if (!fmap) {
132
2
      LogCvmfs(kLogUtility, kLogDebug, "failed to open %s (errno: %d)",
133
               path.c_str(), errno);
134
2
      return false;
135
    }
136
137
20
    sanitizer::IntegerSanitizer int_sanitizer;
138
139
20
    std::string line;
140
20
    unsigned int line_number = 0;
141

20
    while (GetLineFile(fmap, &line)) {
142
70
      ++line_number;
143
70
      line = Trim(line);
144

70
      if (line.empty() || line[0] == '#') {
145
30
        continue;
146
      }
147
148
40
      std::vector<std::string> components = SplitString(line, ' ');
149
40
      FilterEmptyStrings(&components);
150


40
      if (components.size() != 2                ||
151
          !int_sanitizer.IsValid(components[1]) ||
152
          (components[0] != "*" && !int_sanitizer.IsValid(components[0]))) {
153
15
        fclose(fmap);
154
15
        LogCvmfs(kLogUtility, kLogDebug, "failed to read line %d in %s",
155
                 line_number, path.c_str());
156
15
        return false;
157
      }
158
159
25
      value_type to = String2Uint64(components[1]);
160
25
      if (components[0] == "*") {
161
5
        SetDefault(to);
162
5
        continue;
163
      }
164
165
20
      key_type from = String2Uint64(components[0]);
166
20
      Set(from, to);
167
    }
168
169
5
    fclose(fmap);
170
5
    return true;
171
  }
172
173
40
  void FilterEmptyStrings(std::vector<std::string> *vec) const {
174
40
    std::vector<std::string>::iterator i = vec->begin();
175
170
    for (; i != vec->end(); ) {
176
90
      i = (i->empty()) ? vec->erase(i) : i + 1;
177
    }
178
40
  }
179
180
 private:
181
  bool      valid_;
182
  map_type  map_;
183
184
  bool      has_default_value_;
185
  T         default_value_;
186
};
187
188
typedef IntegerMap<uid_t> UidMap;
189
typedef IntegerMap<gid_t> GidMap;
190
191
#endif  // CVMFS_UID_MAP_H_