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 : : }
|