721bf619de6dc43bf210718f625a4e939ccad4a6
[strongswan.git] / src / libimcv / plugins / imv_os / imv_os_database.c
1 /*
2 * Copyright (C) 2012 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "imv_os_database.h"
17
18 #include <utils/debug.h>
19
20 #include <string.h>
21
22 typedef struct private_imv_os_database_t private_imv_os_database_t;
23
24 /**
25 * Private data of a imv_os_database_t object.
26 *
27 */
28 struct private_imv_os_database_t {
29
30 /**
31 * Public imv_os_database_t interface.
32 */
33 imv_os_database_t public;
34
35 /**
36 * database instance
37 */
38 database_t *db;
39
40 };
41
42 METHOD(imv_os_database_t, check_packages, status_t,
43 private_imv_os_database_t *this, imv_os_state_t *state,
44 enumerator_t *package_enumerator)
45 {
46 char *product, *package, *release, *cur_release;
47 u_char *pos;
48 chunk_t os_name, os_version, name, version;
49 os_type_t os_type;
50 size_t os_version_len;
51 os_package_state_t package_state;
52 int pid, gid;
53 int count = 0, count_ok = 0, count_no_match = 0, count_blacklist = 0;
54 enumerator_t *e;
55 status_t status = SUCCESS;
56 bool found, match;
57
58 state->get_info(state, &os_type, &os_name, &os_version);
59
60 if (os_type == OS_TYPE_ANDROID)
61 {
62 /*no package dependency on Android version */
63 product = strdup(enum_to_name(os_type_names, os_type));
64 }
65 else
66 {
67 /* remove appended platform info */
68 pos = memchr(os_version.ptr, ' ', os_version.len);
69 os_version_len = pos ? (pos - os_version.ptr) : os_version.len;
70 product = malloc(os_name.len + 1 + os_version_len + 1);
71 sprintf(product, "%.*s %.*s", os_name.len, os_name.ptr,
72 os_version_len, os_version.ptr);
73 }
74 DBG1(DBG_IMV, "processing installed '%s' packages", product);
75
76 /* Get primary key of product */
77 e = this->db->query(this->db,
78 "SELECT id FROM products WHERE name = ?",
79 DB_TEXT, product, DB_INT);
80 if (!e)
81 {
82 free(product);
83 return FAILED;
84 }
85 if (!e->enumerate(e, &pid))
86 {
87 e->destroy(e);
88 free(product);
89 return NOT_FOUND;
90 }
91 e->destroy(e);
92
93 while (package_enumerator->enumerate(package_enumerator, &name, &version))
94 {
95 /* Convert package name chunk to a string */
96 package = strndup(name.ptr, name.len);
97 count++;
98
99 /* Get primary key of package */
100 e = this->db->query(this->db,
101 "SELECT id FROM packages WHERE name = ?",
102 DB_TEXT, package, DB_INT);
103 if (!e)
104 {
105 free(product);
106 free(package);
107 return FAILED;
108 }
109 if (!e->enumerate(e, &gid))
110 {
111 /* package not present in database for any product - skip */
112 if (os_type == OS_TYPE_ANDROID)
113 {
114 DBG2(DBG_IMV, "package '%s' (%.*s) not found",
115 package, version.len, version.ptr);
116 }
117 free(package);
118 e->destroy(e);
119 continue;
120 }
121 e->destroy(e);
122
123 /* Convert package version chunk to a string */
124 release = strndup(version.ptr, version.len);
125
126 /* Enumerate over all acceptable versions */
127 e = this->db->query(this->db,
128 "SELECT release, security FROM versions "
129 "WHERE product = ? AND package = ?",
130 DB_INT, pid, DB_INT, gid, DB_TEXT, DB_INT);
131 if (!e)
132 {
133 free(product);
134 free(package);
135 free(release);
136 return FAILED;
137 }
138 found = FALSE;
139 match = FALSE;
140
141 while (e->enumerate(e, &cur_release, &package_state))
142 {
143 found = TRUE;
144 if (streq(release, cur_release) || streq("*", cur_release))
145 {
146 match = TRUE;
147 break;
148 }
149 }
150 e->destroy(e);
151
152 if (found)
153 {
154 if (match)
155 {
156 if (package_state == OS_PACKAGE_STATE_BLACKLIST)
157 {
158 DBG2(DBG_IMV, "package '%s' (%s) is blacklisted",
159 package, release);
160 count_blacklist++;
161 state->add_bad_package(state, package, package_state);
162 }
163 else
164 {
165 DBG2(DBG_IMV, "package '%s' (%s)%N is ok", package, release,
166 os_package_state_names, package_state);
167 count_ok++;
168 }
169 }
170 else
171 {
172 DBG1(DBG_IMV, "package '%s' (%s) no match", package, release);
173 count_no_match++;
174 state->add_bad_package(state, package, package_state);
175 }
176 }
177 else
178 {
179 /* package not present in database for this product - skip */
180 }
181 free(package);
182 free(release);
183 }
184 free(product);
185 state->set_count(state, count, count_no_match, count_blacklist, count_ok);
186
187 return status;
188 }
189
190 METHOD(imv_os_database_t, get_device_id, int,
191 private_imv_os_database_t *this, chunk_t value)
192 {
193 enumerator_t *e;
194 int id;
195
196 /* get primary key of device ID */
197 e = this->db->query(this->db, "SELECT id FROM devices WHERE value = ?",
198 DB_BLOB, value, DB_INT);
199 if (!e)
200 {
201 return 0;
202 }
203 if (e->enumerate(e, &id))
204 {
205 /* device ID already exists in database - return primary key */
206 e->destroy(e);
207 return id;
208 }
209
210 /* register new device ID in database and return primary key */
211 return (this->db->execute(this->db, &id,
212 "INSERT INTO devices (value) VALUES (?)", DB_BLOB, value) == 1) ?
213 id : 0;
214 }
215
216 METHOD(imv_os_database_t, destroy, void,
217 private_imv_os_database_t *this)
218 {
219 this->db->destroy(this->db);
220 free(this);
221 }
222
223 /**
224 * See header
225 */
226 imv_os_database_t *imv_os_database_create(char *uri)
227 {
228 private_imv_os_database_t *this;
229
230 INIT(this,
231 .public = {
232 .check_packages = _check_packages,
233 .get_device_id = _get_device_id,
234 .destroy = _destroy,
235 },
236 .db = lib->db->create(lib->db, uri),
237 );
238
239 if (!this->db)
240 {
241 DBG1(DBG_IMV,
242 "failed to connect to OS database '%s'", uri);
243 free(this);
244 return NULL;
245 }
246
247 return &this->public;
248 }
249