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