Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/libpkg/pkg_cpe.c
2645 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
*​ Copyright (c) 2025 The FreeBSD Foundation
5
*​
6
*​ Portions of this software were developed by
7
* Tuukka Pasanen <[email protected]> under sponsorship from
8
* the FreeBSD Foundation
9
*
10
* Common Platform Enumeration (CPE) is a standardized method of
11
* describing and identifying classes of applications, operating
12
* systems, and hardware devices present among an enterprise's
13
* computing assets
14
*
15
* CPE (current version 2.3) looks something like this:
16
* cpe:2.3:a:test:test_product:1.0:sp1:1:en-us:14.3:FreeBSD:x86_64:other_things
17
*
18
* Where parts are named like this:
19
* cpe:<cpe_version>:<part>:<vendor>:<product>:<version>:<update>:<edition>:<language>:<sw_edition>:<target_sw>:<target_hw>:<other>
20
*
21
* Whole spec can be found:
22
* https://csrc.nist.gov/pubs/ir/7695/final
23
*/
24
25
#include <xmalloc.h>
26
#include <ctype.h>
27
#include <stdlib.h>
28
#include <xstring.h>
29
30
#include "pkg.h"
31
#include "pkg/audit.h"
32
#include "private/pkg_cpe.h"
33
34
struct pkg_audit_cpe *
35
pkg_cpe_new()
36
{
37
return (struct pkg_audit_cpe *)xcalloc(1, sizeof(struct pkg_audit_cpe));
38
}
39
40
void
41
pkg_cpe_free(struct pkg_audit_cpe *cpe)
42
{
43
if(!cpe)
44
{
45
return;
46
}
47
48
if(cpe->vendor)
49
{
50
free(cpe->vendor);
51
cpe->vendor = NULL;
52
}
53
54
if(cpe->product)
55
{
56
free(cpe->product);
57
cpe->product = NULL;
58
}
59
60
if(cpe->version)
61
{
62
free(cpe->version);
63
cpe->version = NULL;
64
}
65
66
if(cpe->update)
67
{
68
free(cpe->update);
69
cpe->update = NULL;
70
}
71
72
if(cpe->edition)
73
{
74
free(cpe->edition);
75
cpe->edition = NULL;
76
}
77
78
if(cpe->language)
79
{
80
free(cpe->language);
81
cpe->language = NULL;
82
}
83
84
if(cpe->sw_edition)
85
{
86
free(cpe->sw_edition);
87
cpe->sw_edition = NULL;
88
}
89
90
if(cpe->target_sw)
91
{
92
free(cpe->target_sw);
93
cpe->target_sw = NULL;
94
}
95
96
if(cpe->target_hw)
97
{
98
free(cpe->target_hw);
99
cpe->target_hw = NULL;
100
}
101
102
if(cpe->other)
103
{
104
free(cpe->other);
105
cpe->other = NULL;
106
}
107
108
free(cpe);
109
}
110
111
char *
112
pkg_cpe_create(struct pkg_audit_cpe *cpe)
113
{
114
char *cpe_str = NULL;
115
/* To avoid (null) string in return string*/
116
char *cpe_parts[10] = {"", "", "", "", "", "", "", "", "", ""};
117
118
if(cpe->vendor)
119
{
120
cpe_parts[0] = cpe->vendor;
121
}
122
123
if(cpe->product)
124
{
125
cpe_parts[1] = cpe->product;
126
}
127
128
if(cpe->version)
129
{
130
cpe_parts[2] = cpe->version;
131
}
132
133
if(cpe->update)
134
{
135
cpe_parts[3] = cpe->update;
136
}
137
138
if(cpe->edition)
139
{
140
cpe_parts[4] = cpe->edition;
141
}
142
143
if(cpe->language)
144
{
145
cpe_parts[5] = cpe->language;
146
}
147
148
if(cpe->sw_edition)
149
{
150
cpe_parts[6] = cpe->sw_edition;
151
}
152
153
if(cpe->target_sw)
154
{
155
cpe_parts[7] = cpe->target_sw;
156
}
157
158
if(cpe->target_hw)
159
{
160
cpe_parts[8] = cpe->target_hw;
161
}
162
163
if(cpe->other)
164
{
165
cpe_parts[9] = cpe->other;
166
}
167
168
xasprintf(&cpe_str, "cpe:2.3:%c:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s", cpe->part, cpe_parts[0], cpe_parts[1], cpe_parts[2], cpe_parts[3], cpe_parts[4], cpe_parts[5], cpe_parts[6], cpe_parts[7], cpe_parts[8], cpe_parts[9]);
169
170
return cpe_str;
171
}
172
173
struct pkg_audit_cpe *
174
pkg_cpe_parse(const char *cpe_str)
175
{
176
char cpe_delimiter[] = ":";
177
char cpe_atoi[2] = {0x00, 0x00};
178
char *cpe_copy = NULL;
179
char *cpe_token = NULL;
180
struct pkg_audit_cpe *rtn_cpe = NULL;
181
unsigned int loc = 0;
182
bool is_error = false;
183
184
if(!cpe_str)
185
{
186
return NULL;
187
}
188
189
if(strnlen(cpe_str, 8) < 8)
190
{
191
return NULL;
192
}
193
194
cpe_copy = xstrdup(cpe_str);
195
cpe_token = strtok(cpe_copy, cpe_delimiter);
196
197
if(!cpe_token)
198
{
199
rtn_cpe = NULL;
200
goto cpe_return;
201
}
202
203
rtn_cpe = pkg_cpe_new();
204
205
while(cpe_token)
206
{
207
is_error = false;
208
switch(loc)
209
{
210
case 0:
211
if(strncmp(cpe_token,"cpe", 3))
212
{
213
is_error = true;
214
}
215
break;
216
217
case 1:
218
if(!isdigit(cpe_token[0]) || !isdigit(cpe_token[2]))
219
{
220
is_error = true;
221
break;
222
}
223
224
225
cpe_atoi[0] = cpe_token[0];
226
rtn_cpe->version_major = atoi(cpe_atoi);
227
228
cpe_atoi[0] = cpe_token[2];
229
rtn_cpe->version_minor = atoi(cpe_atoi);
230
231
if(rtn_cpe->version_major != 2 || rtn_cpe->version_minor != 3)
232
{
233
is_error = true;
234
}
235
break;
236
237
case 2:
238
if(cpe_token[0] != CPE_APPLICATIONS && cpe_token[0] != CPE_HARWARE && cpe_token[0] != CPE_OPERATING_SYSTEMS)
239
{
240
is_error = true;
241
}
242
243
rtn_cpe->part = cpe_token[0];
244
break;
245
246
case 3:
247
rtn_cpe->vendor = xstrdup(cpe_token);
248
break;
249
250
case 4:
251
rtn_cpe->product = xstrdup(cpe_token);
252
break;
253
254
case 5:
255
rtn_cpe->version = xstrdup(cpe_token);
256
break;
257
258
case 6:
259
rtn_cpe->update = xstrdup(cpe_token);
260
break;
261
262
case 7:
263
rtn_cpe->edition = xstrdup(cpe_token);
264
break;
265
266
case 8:
267
rtn_cpe->language = xstrdup(cpe_token);
268
break;
269
270
case 9:
271
rtn_cpe->sw_edition = xstrdup(cpe_token);
272
break;
273
274
case 10:
275
rtn_cpe->target_sw = xstrdup(cpe_token);
276
break;
277
278
case 11:
279
rtn_cpe->target_hw = xstrdup(cpe_token);
280
break;
281
282
case 12:
283
rtn_cpe->other = xstrdup(cpe_token);
284
break;
285
286
default:
287
break;
288
}
289
290
if(is_error)
291
{
292
pkg_cpe_free(rtn_cpe);
293
rtn_cpe = NULL;
294
goto cpe_return;
295
}
296
297
298
loc ++;
299
cpe_token = strtok(NULL, cpe_delimiter);
300
301
if(loc >= 13 && cpe_token)
302
{
303
break;
304
}
305
}
306
307
cpe_return:
308
if(loc <= 3)
309
{
310
pkg_cpe_free(rtn_cpe);
311
rtn_cpe = NULL;
312
}
313
314
free(cpe_copy);
315
cpe_copy = NULL;
316
return rtn_cpe;
317
}
318
319