implemented reason string and remediation instructions for OS IMV
[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;
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 product = strdup(enum_to_name(os_type_names, os_type));
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 product = malloc(os_name.len + 1 + os_version_len + 1);
68 sprintf(product, "%.*s %.*s", os_name.len, os_name.ptr,
69 os_version_len, os_version.ptr);
70 }
71 DBG1(DBG_IMV, "processing installed '%s' packages", product);
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 e->destroy(e);
117 continue;
118 }
119 e->destroy(e);
120
121 /* Convert package version chunk to a string */
122 release = malloc(version.len + 1);
123 memcpy(release, version.ptr, version.len);
124 release[version.len] = '\0';
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, &security))
142 {
143 found = TRUE;
144 if (streq(release, cur_release))
145 {
146 match = TRUE;
147 break;
148 }
149 }
150 e->destroy(e);
151
152 if (found)
153 {
154 if (match)
155 {
156 DBG2(DBG_IMV, "package '%s' (%s)%s is ok", package, release,
157 security ? " [s]" : "");
158 count_ok++;
159 }
160 else
161 {
162 DBG1(DBG_IMV, "package '%s' (%s) no match", package, release);
163 count_no_match++;
164 state->add_bad_package(state, package);
165 }
166 }
167 else
168 {
169 /* package not present in database for this product - skip */
170 }
171 free(package);
172 free(release);
173 }
174 free(product);
175 state->set_count(state, count, count_no_match, count_ok);
176
177 return status;
178 }
179
180 METHOD(imv_os_database_t, destroy, void,
181 private_imv_os_database_t *this)
182 {
183 this->db->destroy(this->db);
184 free(this);
185 }
186
187 /**
188 * See header
189 */
190 imv_os_database_t *imv_os_database_create(char *uri)
191 {
192 private_imv_os_database_t *this;
193
194 INIT(this,
195 .public = {
196 .check_packages = _check_packages,
197 .destroy = _destroy,
198 },
199 .db = lib->db->create(lib->db, uri),
200 );
201
202 if (!this->db)
203 {
204 DBG1(DBG_IMV,
205 "failed to connect to OS database '%s'", uri);
206 free(this);
207 return NULL;
208 }
209
210 return &this->public;
211 }
212