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