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