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