~ubuntu-branches/ubuntu/saucy/sssd/saucy

« back to all changes in this revision

Viewing changes to src/util/find_uid.c

  • Committer: Stéphane Graber
  • Date: 2011-06-15 16:23:14 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: stgraber@ubuntu.com-20110615162314-rbhoppnpaxfqo5q7
Merge 1.5.8

Show diffs side-by-side

added added

removed removed

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