]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/nfsidmap/nfsidmap.c
nfsidmap: Allow verbosity level to be set in the config file
[nfs-utils.git] / utils / nfsidmap / nfsidmap.c
1
2 #include <stdarg.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <errno.h>
7
8 #include <pwd.h>
9 #include <grp.h>
10 #include <keyutils.h>
11 #include <nfsidmap.h>
12
13 #include <unistd.h>
14 #include "xlog.h"
15 #include "conffile.h"
16
17 int verbose = 0;
18 char *usage="Usage: %s [-v] [-c || [-u|-g|-r key] || [-t timeout] key desc]";
19
20 #define MAX_ID_LEN   11
21 #define IDMAP_NAMESZ 128
22 #define USER  1
23 #define GROUP 0
24
25 #define PROCKEYS "/proc/keys"
26 #ifndef DEFAULT_KEYRING
27 #define DEFAULT_KEYRING "id_resolver"
28 #endif
29
30 #ifndef PATH_IDMAPDCONF
31 #define PATH_IDMAPDCONF "/etc/idmapd.conf"
32 #endif
33
34 static int keyring_clear(char *keyring);
35
36 #define UIDKEYS 0x1
37 #define GIDKEYS 0x2
38
39 /*
40  * Check to the config file for the verbosity level
41  */
42 int
43 get_config_verbose(char *path)
44 {
45         conf_path = path;
46         conf_init();
47         return conf_get_num("General", "Verbosity", 0);
48 }
49
50 /*
51  * Find either a user or group id based on the name@domain string
52  */
53 int id_lookup(char *name_at_domain, key_serial_t key, int type)
54 {
55         char id[MAX_ID_LEN];
56         uid_t uid = 0;
57         gid_t gid = 0;
58         int rc;
59
60         if (type == USER) {
61                 rc = nfs4_owner_to_uid(name_at_domain, &uid);
62                 sprintf(id, "%u", uid);
63         } else {
64                 rc = nfs4_group_owner_to_gid(name_at_domain, &gid);
65                 sprintf(id, "%u", gid);
66         }
67         if (rc < 0)
68                 xlog_err("id_lookup: %s: failed: %m",
69                         (type == USER ? "nfs4_owner_to_uid" : "nfs4_group_owner_to_gid"));
70
71         if (rc == 0) {
72                 rc = keyctl_instantiate(key, id, strlen(id) + 1, 0);
73                 if (rc < 0) {
74                         switch(rc) {
75                         case -EDQUOT:
76                         case -ENFILE:
77                         case -ENOMEM:
78                                 /*
79                                  * The keyring is full. Clear the keyring and try again
80                                  */
81                                 rc = keyring_clear(DEFAULT_KEYRING);
82                                 if (rc == 0)
83                                         rc = keyctl_instantiate(key, id, strlen(id) + 1, 0);
84                                 break;
85                         default:
86                                 break;
87                         }
88                 }
89                 if (rc < 0)
90                         xlog_err("id_lookup: keyctl_instantiate failed: %m");
91         }
92
93         return rc;
94 }
95
96 /*
97  * Find the name@domain string from either a user or group id
98  */
99 int name_lookup(char *id, key_serial_t key, int type)
100 {
101         char name[IDMAP_NAMESZ];
102         char domain[NFS4_MAX_DOMAIN_LEN];
103         uid_t uid;
104         gid_t gid;
105         int rc;
106
107         rc = nfs4_get_default_domain(NULL, domain, NFS4_MAX_DOMAIN_LEN);
108         if (rc != 0) {
109                 rc = -1;
110                 xlog_err("name_lookup: nfs4_get_default_domain failed: %m");
111                 goto out;
112         }
113
114         if (type == USER) {
115                 uid = atoi(id);
116                 rc = nfs4_uid_to_name(uid, domain, name, IDMAP_NAMESZ);
117         } else {
118                 gid = atoi(id);
119                 rc = nfs4_gid_to_name(gid, domain, name, IDMAP_NAMESZ);
120         }
121         if (rc < 0)
122                 xlog_err("name_lookup: %s: failed: %m",
123                         (type == USER ? "nfs4_uid_to_name" : "nfs4_gid_to_name"));
124
125         if (rc == 0) {
126                 rc = keyctl_instantiate(key, &name, strlen(name), 0);
127                 if (rc < 0)
128                         xlog_err("name_lookup: keyctl_instantiate failed: %m");
129         }
130 out:
131         return rc;
132 }
133 /*
134  * Clear all the keys on the given keyring
135  */
136 static int keyring_clear(char *keyring)
137 {
138         FILE *fp;
139         char buf[BUFSIZ];
140         key_serial_t key;
141
142         if (keyring == NULL)
143                 keyring = DEFAULT_KEYRING;
144
145         if ((fp = fopen(PROCKEYS, "r")) == NULL) {
146                 xlog_err("fopen(%s) failed: %m", PROCKEYS);
147                 return 1;
148         }
149
150         while(fgets(buf, BUFSIZ, fp) != NULL) {
151                 if (strstr(buf, "keyring") == NULL)
152                         continue;
153                 if (strstr(buf, keyring) == NULL)
154                         continue;
155                 if (verbose) {
156                         *(strchr(buf, '\n')) = '\0';
157                         xlog_warn("clearing '%s'", buf);
158                 }
159                 /*
160                  * The key is the first arugment in the string
161                  */
162                 *(strchr(buf, ' ')) = '\0';
163                 sscanf(buf, "%x", &key);
164                 if (keyctl_clear(key) < 0) {
165                         xlog_err("keyctl_clear(0x%x) failed: %m", key);
166                         fclose(fp);
167                         return 1;
168                 }
169                 fclose(fp);
170                 return 0;
171         }
172         xlog_err("'%s' keyring was not found.", keyring);
173         fclose(fp);
174         return 1;
175 }
176 /*
177  * Revoke a key 
178  */
179 static int key_revoke(char *keystr, int keymask)
180 {
181         FILE *fp;
182         char buf[BUFSIZ], *ptr;
183         key_serial_t key;
184         int mask;
185
186         xlog_syslog(0);
187
188         if ((fp = fopen(PROCKEYS, "r")) == NULL) {
189                 xlog_err("fopen(%s) failed: %m", PROCKEYS);
190                 return 1;
191         }
192
193         while(fgets(buf, BUFSIZ, fp) != NULL) {
194                 if (strstr(buf, "keyring") != NULL)
195                         continue;
196
197                 mask = 0;
198                 if ((ptr = strstr(buf, "uid:")) != NULL)
199                         mask = UIDKEYS;
200                 else if ((ptr = strstr(buf, "gid:")) != NULL)
201                         mask = GIDKEYS;
202                 else 
203                         continue;
204
205                 if ((keymask & mask) == 0)
206                         continue;
207
208                 if (strncmp(ptr+4, keystr, strlen(keystr)) != 0)
209                         continue;
210
211                 if (verbose) {
212                         *(strchr(buf, '\n')) = '\0';
213                         xlog_warn("revoking '%s'", buf);
214                 }
215                 /*
216                  * The key is the first arugment in the string
217                  */
218                 *(strchr(buf, ' ')) = '\0';
219                 sscanf(buf, "%x", &key);
220
221                 if (keyctl_revoke(key) < 0) {
222                         xlog_err("keyctl_revoke(0x%x) failed: %m", key);
223                         fclose(fp);
224                         return 1;
225                 }
226
227                 keymask &= ~mask;
228                 if (keymask == 0) {
229                         fclose(fp);
230                         return 0;
231                 }
232         }
233         xlog_err("'%s' key was not found.", keystr);
234         fclose(fp);
235         return 1;
236 }
237
238 int main(int argc, char **argv)
239 {
240         char *arg;
241         char *value;
242         char *type;
243         int rc = 1, opt;
244         int timeout = 600;
245         key_serial_t key;
246         char *progname, *keystr = NULL;
247         int clearing = 0, keymask = 0;
248
249         /* Set the basename */
250         if ((progname = strrchr(argv[0], '/')) != NULL)
251                 progname++;
252         else
253                 progname = argv[0];
254
255         xlog_open(progname);
256
257         while ((opt = getopt(argc, argv, "u:g:r:ct:v")) != -1) {
258                 switch (opt) {
259                 case 'u':
260                         keymask = UIDKEYS;
261                         keystr = strdup(optarg);
262                         break;
263                 case 'g':
264                         keymask = GIDKEYS;
265                         keystr = strdup(optarg);
266                         break;
267                 case 'r':
268                         keymask = GIDKEYS|UIDKEYS;
269                         keystr = strdup(optarg);
270                         break;
271                 case 'c':
272                         clearing++;
273                         break;
274                 case 'v':
275                         verbose++;
276                         break;
277                 case 't':
278                         timeout = atoi(optarg);
279                         break;
280                 default:
281                         xlog_warn(usage, progname);
282                         break;
283                 }
284         }
285         if (!verbose) {
286                 verbose = get_config_verbose(PATH_IDMAPDCONF);
287         }
288         if (keystr) {
289                 rc = key_revoke(keystr, keymask);
290                 return rc;              
291         }
292         if (clearing) {
293                 xlog_syslog(0);
294                 rc = keyring_clear(DEFAULT_KEYRING);
295                 return rc;              
296         }
297
298         xlog_stderr(0);
299         if ((argc - optind) != 2) {
300                 xlog_err("Bad arg count. Check /etc/request-key.conf");
301                 xlog_warn(usage, progname);
302                 return 1;
303         }
304
305         if (verbose)
306                 nfs4_set_debug(verbose, NULL);
307
308         key = strtol(argv[optind++], NULL, 10);
309
310         arg = strdup(argv[optind]);
311         if (arg == NULL) {
312                 xlog_err("strdup failed: %m");
313                 return 1;
314         }
315         type = strtok(arg, ":");
316         value = strtok(NULL, ":");
317
318         if (verbose) {
319                 xlog_warn("key: 0x%lx type: %s value: %s timeout %ld",
320                         key, type, value, timeout);
321         }
322
323         if (strcmp(type, "uid") == 0)
324                 rc = id_lookup(value, key, USER);
325         else if (strcmp(type, "gid") == 0)
326                 rc = id_lookup(value, key, GROUP);
327         else if (strcmp(type, "user") == 0)
328                 rc = name_lookup(value, key, USER);
329         else if (strcmp(type, "group") == 0)
330                 rc = name_lookup(value, key, GROUP);
331
332         /* Set timeout to 10 (600 seconds) minutes */
333         if (rc == 0)
334                 keyctl_set_timeout(key, timeout);
335
336         free(arg);
337         return rc;
338 }