use OS type on IMV side
[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 typedef struct private_imv_os_database_t private_imv_os_database_t;
21
22 /**
23 * Private data of a imv_os_database_t object.
24 *
25 */
26 struct private_imv_os_database_t {
27
28 /**
29 * Public imv_os_database_t interface.
30 */
31 imv_os_database_t public;
32
33 /**
34 * database instance
35 */
36 database_t *db;
37
38 };
39
40 METHOD(imv_os_database_t, check_packages, status_t,
41 private_imv_os_database_t *this, imv_os_state_t *state,
42 enumerator_t *package_enumerator)
43 {
44 char *product, *package, *release, *cur_release;
45 u_char *pos;
46 chunk_t os_name, os_version, name, version;
47 os_type_t os_type;
48 size_t os_version_len;
49 int pid, gid, security;
50 int count = 0, count_ok = 0, count_no_match = 0, count_not_found = 0;
51 enumerator_t *e;
52 status_t status = SUCCESS;
53 bool found, match;
54
55 state->get_info(state, &os_type, &os_name, &os_version);
56
57 if (os_type == OS_TYPE_ANDROID)
58 {
59 /*no package dependency on Android version */
60 os_version_len = 0;
61 }
62 else
63 {
64 /* remove appended platform info */
65 pos = memchr(os_version.ptr, ' ', os_version.len);
66 os_version_len = pos ? (pos - os_version.ptr) : os_version.len;
67 }
68
69 product = malloc(os_name.len + 1 + os_version_len + 1);
70 sprintf(product, "%.*s %.*s", os_name.len, os_name.ptr,
71 os_version_len, os_version.ptr);
72
73 /* Get primary key of product */
74 e = this->db->query(this->db,
75 "SELECT id FROM products WHERE name = ?",
76 DB_TEXT, product, DB_INT);
77 if (!e)
78 {
79 free(product);
80 return FAILED;
81 }
82 if (!e->enumerate(e, &pid))
83 {
84 e->destroy(e);
85 free(product);
86 return NOT_FOUND;
87 }
88 e->destroy(e);
89
90 while (package_enumerator->enumerate(package_enumerator, &name, &version))
91 {
92 /* Convert package name chunk to a string */
93 package = malloc(name.len + 1);
94 memcpy(package, name.ptr, name.len);
95 package[name.len] = '\0';
96 count++;
97
98 /* Get primary key of package */
99 e = this->db->query(this->db,
100 "SELECT id FROM packages WHERE name = ?",
101 DB_TEXT, package, DB_INT);
102 if (!e)
103 {
104 free(product);
105 free(package);
106 return FAILED;
107 }
108 if (!e->enumerate(e, &gid))
109 {
110 /* package not present in database for any product - skip */
111 if (os_type == OS_TYPE_ANDROID)
112 {
113 DBG2(DBG_IMV, "package '%s' (%.*s) not found",
114 package, version.len, version.ptr);
115 }
116 count_not_found++;
117 e->destroy(e);
118 continue;
119 }
120 e->destroy(e);
121
122 /* Convert package version chunk to a string */
123 release = malloc(version.len + 1);
124 memcpy(release, version.ptr, version.len);
125 release[version.len] = '\0';
126
127 /* Enumerate over all acceptable versions */
128 e = this->db->query(this->db,
129 "SELECT release, security FROM versions "
130 "WHERE product = ? AND package = ?",
131 DB_INT, pid, DB_INT, gid, DB_TEXT, DB_INT);
132 if (!e)
133 {
134 free(product);
135 free(package);
136 free(release);
137 return FAILED;
138 }
139 found = FALSE;
140 match = FALSE;
141
142 while (e->enumerate(e, &cur_release, &security))
143 {
144 found = TRUE;
145 if (streq(release, cur_release))
146 {
147 match = TRUE;
148 break;
149 }
150 }
151 e->destroy(e);
152
153 if (found)
154 {
155 if (match)
156 {
157 DBG2(DBG_IMV, "package '%s' (%s)%s is ok", package, release,
158 security ? " [s]" : "");
159 count_ok++;
160 }
161 else
162 {
163 DBG1(DBG_IMV, "package '%s' (%s) no match", package, release);
164 count_no_match++;
165 status = VERIFY_ERROR;
166 }
167 }
168 else
169 {
170 /* package not present in database for this product - skip */
171 count_not_found++;
172 }
173 free(package);
174 free(release);
175 }
176 free(product);
177
178 DBG1(DBG_IMV, "processed %d packages: %d no match, %d ok, %d not found",
179 count, count_no_match, count_ok, count_not_found);
180
181 return status;
182 }
183
184 METHOD(imv_os_database_t, destroy, void,
185 private_imv_os_database_t *this)
186 {
187 this->db->destroy(this->db);
188 free(this);
189 }
190
191 /**
192 * See header
193 */
194 imv_os_database_t *imv_os_database_create(char *uri)
195 {
196 private_imv_os_database_t *this;
197
198 INIT(this,
199 .public = {
200 .check_packages = _check_packages,
201 .destroy = _destroy,
202 },
203 .db = lib->db->create(lib->db, uri),
204 );
205
206 if (!this->db)
207 {
208 DBG1(DBG_IMV,
209 "failed to connect to OS database '%s'", uri);
210 free(this);
211 return NULL;
212 }
213
214 return &this->public;
215 }
216