1    	/* keyutils.c: key utility library
2    	 *
3    	 * Copyright (C) 2005,2011 Red Hat, Inc. All Rights Reserved.
4    	 * Written by David Howells (dhowells@redhat.com)
5    	 *
6    	 * This program is free software; you can redistribute it and/or
7    	 * modify it under the terms of the GNU Lesser General Public License
8    	 * as published by the Free Software Foundation; either version
9    	 * 2 of the License, or (at your option) any later version.
10   	 */
11   	
12   	#include <stdio.h>
13   	#include <stdlib.h>
14   	#include <stdint.h>
15   	#include <stdarg.h>
16   	#include <string.h>
17   	#include <unistd.h>
18   	#include <dlfcn.h>
19   	#include <sys/uio.h>
20   	#include <errno.h>
21   	#include <asm/unistd.h>
22   	#include "keyutils.h"
23   	
24   	const char keyutils_version_string[] = PKGVERSION;
25   	const char keyutils_build_string[] = PKGBUILD;
26   	
27   	#ifdef NO_GLIBC_KEYERR
28   	static int error_inited;
29   	static void (*libc_perror)(const char *msg);
30   	static char *(*libc_strerror_r)(int errnum, char *buf, size_t n);
31   	//static int (*libc_xpg_strerror_r)(int errnum, char *buf, size_t n);
32   	#define RTLD_NEXT      ((void *) -1L)
33   	#endif
34   	
35   	#define __weak __attribute__((weak))
36   	
37   	key_serial_t __weak add_key(const char *type,
38   				    const char *description,
39   				    const void *payload,
40   				    size_t plen,
41   				    key_serial_t ringid)
42   	{
43   		return syscall(__NR_add_key,
44   			       type, description, payload, plen, ringid);
45   	}
46   	
47   	key_serial_t __weak request_key(const char *type,
48   					const char *description,
49   					const char * callout_info,
50   					key_serial_t destringid)
51   	{
52   		return syscall(__NR_request_key,
53   			       type, description, callout_info, destringid);
54   	}
55   	
56   	static inline long __keyctl(int cmd,
57   				    unsigned long arg2,
58   				    unsigned long arg3,
59   				    unsigned long arg4,
60   				    unsigned long arg5)
61   	{
62   		return syscall(__NR_keyctl,
63   			       cmd, arg2, arg3, arg4, arg5);
64   	}
65   	
66   	long __weak keyctl(int cmd, ...)
67   	{
68   		va_list va;
69   		unsigned long arg2, arg3, arg4, arg5;
70   	
71   		va_start(va, cmd);
72   		arg2 = va_arg(va, unsigned long);
73   		arg3 = va_arg(va, unsigned long);
74   		arg4 = va_arg(va, unsigned long);
75   		arg5 = va_arg(va, unsigned long);
76   		va_end(va);
77   	
78   		return __keyctl(cmd, arg2, arg3, arg4, arg5);
79   	}
80   	
81   	key_serial_t keyctl_get_keyring_ID(key_serial_t id, int create)
82   	{
83   		return keyctl(KEYCTL_GET_KEYRING_ID, id, create);
84   	}
85   	
86   	key_serial_t keyctl_join_session_keyring(const char *name)
87   	{
88   		return keyctl(KEYCTL_JOIN_SESSION_KEYRING, name);
89   	}
90   	
91   	long keyctl_update(key_serial_t id, const void *payload, size_t plen)
92   	{
93   		return keyctl(KEYCTL_UPDATE, id, payload, plen);
94   	}
95   	
96   	long keyctl_revoke(key_serial_t id)
97   	{
98   		return keyctl(KEYCTL_REVOKE, id);
99   	}
100  	
101  	long keyctl_chown(key_serial_t id, uid_t uid, gid_t gid)
102  	{
103  		return keyctl(KEYCTL_CHOWN, id, uid, gid);
104  	}
105  	
106  	long keyctl_setperm(key_serial_t id, key_perm_t perm)
107  	{
108  		return keyctl(KEYCTL_SETPERM, id, perm);
109  	}
110  	
111  	long keyctl_describe(key_serial_t id, char *buffer, size_t buflen)
112  	{
113  		return keyctl(KEYCTL_DESCRIBE, id, buffer, buflen);
114  	}
115  	
116  	long keyctl_clear(key_serial_t ringid)
117  	{
118  		return keyctl(KEYCTL_CLEAR, ringid);
119  	}
120  	
121  	long keyctl_link(key_serial_t id, key_serial_t ringid)
122  	{
123  		return keyctl(KEYCTL_LINK, id, ringid);
124  	}
125  	
126  	long keyctl_unlink(key_serial_t id, key_serial_t ringid)
127  	{
128  		return keyctl(KEYCTL_UNLINK, id, ringid);
129  	}
130  	
131  	long keyctl_search(key_serial_t ringid,
132  			   const char *type,
133  			   const char *description,
134  			   key_serial_t destringid)
135  	{
136  		return keyctl(KEYCTL_SEARCH, ringid, type, description, destringid);
137  	}
138  	
(1) Event noescape: "keyctl_read(key_serial_t, char *, size_t)" does not free or save its pointer parameter "buffer".
139  	long keyctl_read(key_serial_t id, char *buffer, size_t buflen)
140  	{
141  		return keyctl(KEYCTL_READ, id, buffer, buflen);
142  	}
143  	
144  	long keyctl_instantiate(key_serial_t id,
145  				const void *payload,
146  				size_t plen,
147  				key_serial_t ringid)
148  	{
149  		return keyctl(KEYCTL_INSTANTIATE, id, payload, plen, ringid);
150  	}
151  	
152  	long keyctl_negate(key_serial_t id, unsigned timeout, key_serial_t ringid)
153  	{
154  		return keyctl(KEYCTL_NEGATE, id, timeout, ringid);
155  	}
156  	
157  	long keyctl_set_reqkey_keyring(int reqkey_defl)
158  	{
159  		return keyctl(KEYCTL_SET_REQKEY_KEYRING, reqkey_defl);
160  	}
161  	
162  	long keyctl_set_timeout(key_serial_t id, unsigned timeout)
163  	{
164  		return keyctl(KEYCTL_SET_TIMEOUT, id, timeout);
165  	}
166  	
167  	long keyctl_assume_authority(key_serial_t id)
168  	{
169  		return keyctl(KEYCTL_ASSUME_AUTHORITY, id);
170  	}
171  	
172  	long keyctl_get_security(key_serial_t id, char *buffer, size_t buflen)
173  	{
174  		return keyctl(KEYCTL_GET_SECURITY, id, buffer, buflen);
175  	}
176  	
177  	long keyctl_session_to_parent(void)
178  	{
179  		return keyctl(KEYCTL_SESSION_TO_PARENT);
180  	}
181  	
182  	long keyctl_reject(key_serial_t id, unsigned timeout, unsigned error,
183  			   key_serial_t ringid)
184  	{
185  		long ret = keyctl(KEYCTL_REJECT, id, timeout, error, ringid);
186  	
187  		/* fall back to keyctl_negate() if this op is not supported by this
188  		 * kernel version */
189  		if (ret == -1 && errno == EOPNOTSUPP)
190  			return keyctl_negate(id, timeout, ringid);
191  		return ret;
192  	}
193  	
194  	long keyctl_instantiate_iov(key_serial_t id,
195  				    const struct iovec *payload_iov,
196  				    unsigned ioc,
197  				    key_serial_t ringid)
198  	{
199  		long ret = keyctl(KEYCTL_INSTANTIATE_IOV, id, payload_iov, ioc, ringid);
200  	
201  		/* fall back to keyctl_instantiate() if this op is not supported by
202  		 * this kernel version */
203  		if (ret == -1 && errno == EOPNOTSUPP) {
204  			unsigned loop;
205  			size_t bsize = 0, seg;
206  			void *buf, *p;
207  	
208  			if (!payload_iov || !ioc)
209  				return keyctl_instantiate(id, NULL, 0, ringid);
210  			for (loop = 0; loop < ioc; loop++)
211  				bsize += payload_iov[loop].iov_len;
212  			if (bsize == 0)
213  				return keyctl_instantiate(id, NULL, 0, ringid);
214  			p = buf = malloc(bsize);
215  			if (!buf)
216  				return -1;
217  			for (loop = 0; loop < ioc; loop++) {
218  				seg = payload_iov[loop].iov_len;
219  				p = memcpy(p, payload_iov[loop].iov_base, seg) + seg;
220  			}
221  			ret = keyctl_instantiate(id, buf, bsize, ringid);
222  			free(buf);
223  		}
224  		return ret;
225  	}
226  	
227  	long keyctl_invalidate(key_serial_t id)
228  	{
229  		return keyctl(KEYCTL_INVALIDATE, id);
230  	}
231  	
232  	long keyctl_get_persistent(uid_t uid, key_serial_t id)
233  	{
234  		return keyctl(KEYCTL_GET_PERSISTENT, uid, id);
235  	}
236  	
237  	/*****************************************************************************/
238  	/*
239  	 * fetch key description into an allocated buffer
240  	 * - resulting string is NUL terminated
241  	 * - returns count not including NUL
242  	 */
243  	int keyctl_describe_alloc(key_serial_t id, char **_buffer)
244  	{
245  		char *buf;
246  		long buflen, ret;
247  	
248  		ret = keyctl_describe(id, NULL, 0);
249  		if (ret < 0)
250  			return -1;
251  	
252  		buflen = ret;
253  		buf = malloc(buflen);
254  		if (!buf)
255  			return -1;
256  	
257  		for (;;) {
258  			ret = keyctl_describe(id, buf, buflen);
259  			if (ret < 0)
260  				return -1;
261  	
262  			if (buflen >= ret)
263  				break;
264  	
265  			buflen = ret;
266  			buf = realloc(buf, buflen);
267  			if (!buf)
268  				return -1;
269  		}
270  	
271  		*_buffer = buf;
272  		return buflen - 1;
273  	
274  	} /* end keyctl_describe_alloc() */
275  	
276  	/*****************************************************************************/
277  	/*
278  	 * fetch key contents into an allocated buffer
279  	 * - resulting buffer has an extra NUL added to the end
280  	 * - returns count (not including extraneous NUL)
281  	 */
282  	int keyctl_read_alloc(key_serial_t id, void **_buffer)
283  	{
284  		void *buf;
285  		long buflen, ret;
286  	
287  		ret = keyctl_read(id, NULL, 0);
(1) Event cond_false: Condition "ret < 0", taking false branch
288  		if (ret < 0)
(2) Event if_end: End of if statement
289  			return -1;
290  	
291  		buflen = ret;
(3) Event alloc_fn: Storage is returned from allocation function "malloc(size_t)".
(4) Event var_assign: Assigning: "buf" = "malloc(buflen + 1L)".
Also see events: [noescape][var_assign]
292  		buf = malloc(buflen + 1);
(5) Event cond_false: Condition "!buf", taking false branch
293  		if (!buf)
(6) Event if_end: End of if statement
294  			return -1;
295  	
(7) Event cond_true: Condition "true", taking true branch
296  		for (;;) {
(8) Event noescape: Resource "buf" is not freed or pointed-to in function "keyctl_read(key_serial_t, char *, size_t)". [details]
Also see events: [alloc_fn][var_assign][var_assign]
297  			ret = keyctl_read(id, buf, buflen);
(9) Event cond_false: Condition "ret < 0", taking false branch
298  			if (ret < 0)
(10) Event if_end: End of if statement
299  				return -1;
300  	
(11) Event cond_true: Condition "buflen >= ret", taking true branch
301  			if (buflen >= ret)
(12) Event break: Breaking from loop
302  				break;
303  	
304  			buflen = ret;
305  			buf = realloc(buf, buflen + 1);
306  			if (!buf)
307  				return -1;
(13) Event loop_end: Reached end of loop
308  		}
309  	
310  		((unsigned char *) buf)[buflen] = 0;
(14) Event var_assign: Assigning: "*_buffer" = "buf".
Also see events: [alloc_fn][var_assign][noescape]
311  		*_buffer = buf;
312  		return buflen;
313  	
314  	} /* end keyctl_read_alloc() */
315  	
316  	/*****************************************************************************/
317  	/*
318  	 * fetch key security label into an allocated buffer
319  	 * - resulting string is NUL terminated
320  	 * - returns count not including NUL
321  	 */
322  	int keyctl_get_security_alloc(key_serial_t id, char **_buffer)
323  	{
324  		char *buf;
325  		long buflen, ret;
326  	
327  		ret = keyctl_get_security(id, NULL, 0);
328  		if (ret < 0)
329  			return -1;
330  	
331  		buflen = ret;
332  		buf = malloc(buflen);
333  		if (!buf)
334  			return -1;
335  	
336  		for (;;) {
337  			ret = keyctl_get_security(id, buf, buflen);
338  			if (ret < 0)
339  				return -1;
340  	
341  			if (buflen >= ret)
342  				break;
343  	
344  			buflen = ret;
345  			buf = realloc(buf, buflen);
346  			if (!buf)
347  				return -1;
348  		}
349  	
350  		*_buffer = buf;
351  		return buflen - 1;
352  	}
353  	
354  	/*
355  	 * Depth-first recursively apply a function over a keyring tree
356  	 */
357  	static int recursive_key_scan_aux(key_serial_t parent, key_serial_t key,
358  					  int depth, recursive_key_scanner_t func,
359  					  void *data)
360  	{
361  		key_serial_t *pk;
362  		key_perm_t perm;
363  		size_t ringlen;
364  		void *ring;
365  		char *desc, type[255];
366  		int desc_len, uid, gid, ret, n, kcount = 0;
367  	
368  		if (depth > 800)
369  			return 0;
370  	
371  		/* read the key description */
372  		desc = NULL;
373  		desc_len = keyctl_describe_alloc(key, &desc);
374  		if (desc_len < 0)
375  			goto do_this_key;
376  	
377  		/* parse */
378  		type[0] = 0;
379  	
380  		n = sscanf(desc, "%[^;];%d;%d;%x;", type, &uid, &gid, &perm);
381  		if (n != 4) {
382  			free(desc);
383  			desc = NULL;
384  			errno = -EINVAL;
385  			desc_len = -1;
386  			goto do_this_key;
387  		}
388  	
389  		/* if it's a keyring then we're going to want to recursively search it
390  		 * if we can */
391  		if (strcmp(type, "keyring") == 0) {
392  			/* read the keyring's contents */
393  			ret = keyctl_read_alloc(key, &ring);
394  			if (ret < 0)
395  				goto do_this_key;
396  	
397  			ringlen = ret;
398  	
399  			/* walk the keyring */
400  			pk = ring;
401  			for (ringlen = ret;
402  			     ringlen >= sizeof(key_serial_t);
403  			     ringlen -= sizeof(key_serial_t)
404  			     )
405  				kcount += recursive_key_scan_aux(key, *pk++, depth + 1,
406  								 func, data);
407  	
408  			free(ring);
409  		}
410  	
411  	do_this_key:
412  		kcount += func(parent, key, desc, desc_len, data);
413  		free(desc);
414  		return kcount;
415  	}
416  	
417  	/*
418  	 * Depth-first apply a function over a keyring tree
419  	 */
420  	int recursive_key_scan(key_serial_t key, recursive_key_scanner_t func, void *data)
421  	{
422  		return recursive_key_scan_aux(0, key, 0, func, data);
423  	}
424  	
425  	/*
426  	 * Depth-first apply a function over session keyring tree
427  	 */
428  	int recursive_session_key_scan(recursive_key_scanner_t func, void *data)
429  	{
430  		key_serial_t session =
431  			keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 0);
432  		if (session > 0)
433  			return recursive_key_scan(session, func, data);
434  		return 0;
435  	}
436  	
437  	/*
438  	 * Find a key by type and description
439  	 */
440  	key_serial_t find_key_by_type_and_desc(const char *type, const char *desc,
441  					       key_serial_t destringid)
442  	{
443  		key_serial_t id, error;
444  		FILE *f;
445  		char buf[1024], typebuf[40], rdesc[1024], *kdesc, *cp;
446  		int n, ndesc, dlen;
447  	
448  		error = ENOKEY;
449  	
450  		id = request_key(type, desc, NULL, destringid);
451  		if (id >= 0 || errno == ENOMEM)
452  			return id;
453  		if (errno != ENOKEY)
454  			error = errno;
455  	
456  		dlen = strlen(desc);
457  	
458  		f = fopen("/proc/keys", "r");
459  		if (!f) {
460  			fprintf(stderr, "libkeyutils: Can't open /proc/keys: %m\n");
461  			return -1;
462  		}
463  	
464  		while (fgets(buf, sizeof(buf), f)) {
465  			cp = strchr(buf, '\n');
466  			if (*cp)
467  				*cp = '\0';
468  	
469  			n = sscanf(buf, "%x %*s %*u %*s %*x %*d %*d %s %n",
470  				   &id, typebuf, &ndesc);
471  			if (n == 2) {
472  				if (strcmp(typebuf, type) != 0)
473  					continue;
474  				kdesc = buf + ndesc;
475  				if (memcmp(kdesc, desc, dlen) != 0)
476  					continue;
477  				if (kdesc[dlen] != ':' &&
478  				    kdesc[dlen] != '\0' &&
479  				    kdesc[dlen] != ' ')
480  					continue;
481  				kdesc[dlen] = '\0';
482  	
483  				/* The key type appends extra stuff to the end of the
484  				 * description after a colon in /proc/keys.  Colons,
485  				 * however, are allowed in descriptions, so we need to
486  				 * make a further check. */
487  				n = keyctl_describe(id, rdesc, sizeof(rdesc) - 1);
488  				if (n == -1) {
489  					if (errno != ENOKEY)
490  						error = errno;
491  					if (errno == ENOMEM)
492  						break;
493  				}
494  				if (n >= sizeof(rdesc) - 1)
495  					continue;
496  				rdesc[n] = '\0';
497  	
498  				cp = strrchr(rdesc, ';');
499  				if (!cp)
500  					continue;
501  				cp++;
502  				if (strcmp(cp, desc) != 0)
503  					continue;
504  	
505  				fclose(f);
506  	
507  				if (destringid &&
508  				    keyctl_link(id, destringid) == -1)
509  					return -1;
510  	
511  				return id;
512  			}
513  		}
514  	
515  		fclose(f);
516  		errno = error;
517  		return -1;
518  	}
519  	
520  	#ifdef NO_GLIBC_KEYERR
521  	/*****************************************************************************/
522  	/*
523  	 * initialise error handling
524  	 */
525  	static void error_init(void)
526  	{
527  		char *err;
528  	
529  		error_inited = 1;
530  	
531  		dlerror();
532  	
533  		libc_perror = dlsym(RTLD_NEXT,"perror");
534  		if (!libc_perror) {
535  			fprintf(stderr, "Failed to look up next perror\n");
536  			err = dlerror();
537  			if (err)
538  				fprintf(stderr, "%s\n", err);
539  			abort();
540  		}
541  	
542  		//fprintf(stderr, "next perror at %p\n", libc_perror);
543  	
544  		libc_strerror_r = dlsym(RTLD_NEXT,"strerror_r");
545  		if (!libc_strerror_r) {
546  			fprintf(stderr, "Failed to look up next strerror_r\n");
547  			err = dlerror();
548  			if (err)
549  				fprintf(stderr, "%s\n", err);
550  			abort();
551  		}
552  	
553  		//fprintf(stderr, "next strerror_r at %p\n", libc_strerror_r);
554  	
555  	#if 0
556  		libc_xpg_strerror_r = dlsym(RTLD_NEXT,"xpg_strerror_r");
557  		if (!libc_xpg_strerror_r) {
558  			fprintf(stderr, "Failed to look up next xpg_strerror_r\n");
559  			err = dlerror();
560  			if (err)
561  				fprintf(stderr, "%s\n", err);
562  			abort();
563  		}
564  	
565  		//fprintf(stderr, "next xpg_strerror_r at %p\n", libc_xpg_strerror_r);
566  	#endif
567  	
568  	} /* end error_init() */
569  	
570  	/*****************************************************************************/
571  	/*
572  	 * overload glibc's strerror_r() with a version that knows about key errors
573  	 */
574  	char *strerror_r(int errnum, char *buf, size_t n)
575  	{
576  		const char *errstr;
577  		int len;
578  	
579  		printf("hello\n");
580  	
581  		if (!error_inited)
582  			error_init();
583  	
584  		switch (errnum) {
585  		case ENOKEY:
586  			errstr = "Requested key not available";
587  			break;
588  	
589  		case EKEYEXPIRED:
590  			errstr = "Key has expired";
591  			break;
592  	
593  		case EKEYREVOKED:
594  			errstr = "Key has been revoked";
595  			break;
596  	
597  		case EKEYREJECTED:
598  			errstr = "Key was rejected by service";
599  			break;
600  	
601  		default:
602  			return libc_strerror_r(errnum, buf, n);
603  		}
604  	
605  		len = strlen(errstr) + 1;
606  		if (n > len) {
607  			errno = ERANGE;
608  			if (n > 0) {
609  				memcpy(buf, errstr, n - 1);
610  				buf[n - 1] = 0;
611  			}
612  			return NULL;
613  		}
614  		else {
615  			memcpy(buf, errstr, len);
616  			return buf;
617  		}
618  	
619  	} /* end strerror_r() */
620  	
621  	#if 0
622  	/*****************************************************************************/
623  	/*
624  	 * overload glibc's strerror_r() with a version that knows about key errors
625  	 */
626  	int xpg_strerror_r(int errnum, char *buf, size_t n)
627  	{
628  		const char *errstr;
629  		int len;
630  	
631  		if (!error_inited)
632  			error_init();
633  	
634  		switch (errnum) {
635  		case ENOKEY:
636  			errstr = "Requested key not available";
637  			break;
638  	
639  		case EKEYEXPIRED:
640  			errstr = "Key has expired";
641  			break;
642  	
643  		case EKEYREVOKED:
644  			errstr = "Key has been revoked";
645  			break;
646  	
647  		case EKEYREJECTED:
648  			errstr = "Key was rejected by service";
649  			break;
650  	
651  		default:
652  			return libc_xpg_strerror_r(errnum, buf, n);
653  		}
654  	
655  		len = strlen(errstr) + 1;
656  		if (n > len) {
657  			errno = ERANGE;
658  			if (n > 0) {
659  				memcpy(buf, errstr, n - 1);
660  				buf[n - 1] = 0;
661  			}
662  			return -1;
663  		}
664  		else {
665  			memcpy(buf, errstr, len);
666  			return 0;
667  		}
668  	
669  	} /* end xpg_strerror_r() */
670  	#endif
671  	
672  	/*****************************************************************************/
673  	/*
674  	 *
675  	 */
676  	void perror(const char *msg)
677  	{
678  		if (!error_inited)
679  			error_init();
680  	
681  		switch (errno) {
682  		case ENOKEY:
683  			fprintf(stderr, "%s: Requested key not available\n", msg);
684  			return;
685  	
686  		case EKEYEXPIRED:
687  			fprintf(stderr, "%s: Key has expired\n", msg);
688  			return;
689  	
690  		case EKEYREVOKED:
691  			fprintf(stderr, "%s: Key has been revoked\n", msg);
692  			return;
693  	
694  		case EKEYREJECTED:
695  			fprintf(stderr, "%s: Key was rejected by service\n", msg);
696  			return;
697  	
698  		default:
699  			libc_perror(msg);
700  			return;
701  		}
702  	
703  	} /* end perror() */
704  	#endif
705