1 /*
2  * Copyright (c) 1997-8 Andrew G Morgan <morgan@kernel.org>
3  *
4  * This file deals with exchanging internal and external
5  * representations of capability sets.
6  */
7 
8 #include "libcap.h"
9 
10 /*
11  * External representation for capabilities. (exported as a fixed
12  * length)
13  */
14 #define CAP_EXT_MAGIC "\220\302\001\121"
15 #define CAP_EXT_MAGIC_SIZE 4
16 const static __u8 external_magic[CAP_EXT_MAGIC_SIZE+1] = CAP_EXT_MAGIC;
17 
18 struct cap_ext_struct {
19     __u8 magic[CAP_EXT_MAGIC_SIZE];
20     __u8 length_of_capset;
21     /*
22      * note, we arrange these so the caps are stacked with byte-size
23      * resolution
24      */
25     __u8 bytes[CAP_SET_SIZE][NUMBER_OF_CAP_SETS];
26 };
27 
28 /*
29  * return size of external capability set
30  */
31 
cap_size(cap_t caps)32 ssize_t cap_size(cap_t caps)
33 {
34     return ssizeof(struct cap_ext_struct);
35 }
36 
37 /*
38  * Copy the internal (cap_d) capability set into an external
39  * representation.  The external representation is portable to other
40  * Linux architectures.
41  */
42 
cap_copy_ext(void * cap_ext,cap_t cap_d,ssize_t length)43 ssize_t cap_copy_ext(void *cap_ext, cap_t cap_d, ssize_t length)
44 {
45     struct cap_ext_struct *result = (struct cap_ext_struct *) cap_ext;
46     int i;
47 
48     /* valid arguments? */
49     if (!good_cap_t(cap_d) || length < ssizeof(struct cap_ext_struct)
50 	|| cap_ext == NULL) {
51 	errno = EINVAL;
52 	return -1;
53     }
54 
55     /* fill external capability set */
56     memcpy(&result->magic, external_magic, CAP_EXT_MAGIC_SIZE);
57     result->length_of_capset = CAP_SET_SIZE;
58 
59     for (i=0; i<NUMBER_OF_CAP_SETS; ++i) {
60 	size_t j;
61 	for (j=0; j<CAP_SET_SIZE; ) {
62 	    __u32 val;
63 
64 	    val = cap_d->u[j/sizeof(__u32)].flat[i];
65 
66 	    result->bytes[j++][i] =  val        & 0xFF;
67 	    result->bytes[j++][i] = (val >>= 8) & 0xFF;
68 	    result->bytes[j++][i] = (val >>= 8) & 0xFF;
69 	    result->bytes[j++][i] = (val >> 8)  & 0xFF;
70 	}
71     }
72 
73     /* All done: return length of external representation */
74     return (ssizeof(struct cap_ext_struct));
75 }
76 
77 /*
78  * Import an external representation to produce an internal rep.
79  * the internal rep should be liberated with cap_free().
80  */
81 
cap_copy_int(const void * cap_ext)82 cap_t cap_copy_int(const void *cap_ext)
83 {
84     const struct cap_ext_struct *export =
85 	(const struct cap_ext_struct *) cap_ext;
86     cap_t cap_d;
87     int set, blen;
88 
89     /* Does the external representation make sense? */
90     if ((export == NULL)
91 	|| memcmp(export->magic, external_magic, CAP_EXT_MAGIC_SIZE)) {
92 	errno = EINVAL;
93 	return NULL;
94     }
95 
96     /* Obtain a new internal capability set */
97     if (!(cap_d = cap_init()))
98        return NULL;
99 
100     blen = export->length_of_capset;
101     for (set=0; set<NUMBER_OF_CAP_SETS; ++set) {
102 	unsigned blk;
103 	int bno = 0;
104 	for (blk=0; blk<(CAP_SET_SIZE/sizeof(__u32)); ++blk) {
105 	    __u32 val = 0;
106 
107 	    if (bno != blen)
108 		val  = export->bytes[bno++][set];
109 	    if (bno != blen)
110 		val |= export->bytes[bno++][set] << 8;
111 	    if (bno != blen)
112 		val |= export->bytes[bno++][set] << 16;
113 	    if (bno != blen)
114 		val |= export->bytes[bno++][set] << 24;
115 
116 	    cap_d->u[blk].flat[set] = val;
117 	}
118     }
119 
120     /* all done */
121     return cap_d;
122 }
123 
124