Separated IMV session management from IMV policy 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 #define _GNU_SOURCE /* for stdndup() */
17 #include <string.h>
18
19 #include "imv_os_database.h"
20
21 #include <utils/debug.h>
22
23 typedef struct private_imv_os_database_t private_imv_os_database_t;
24
25 /**
26 * Private data of a imv_os_database_t object.
27 *
28 */
29 struct private_imv_os_database_t {
30
31 /**
32 * Public imv_os_database_t interface.
33 */
34 imv_os_database_t public;
35
36 /**
37 * database instance
38 */
39 database_t *db;
40
41 };
42
43 METHOD(imv_os_database_t, check_packages, status_t,
44 private_imv_os_database_t *this, imv_os_state_t *os_state,
45 enumerator_t *package_enumerator)
46 {
47 imv_state_t *state;
48 imv_session_t *session;
49 imv_os_info_t *os_info;
50 os_type_t os_type;
51 char *product, *package, *release, *cur_release;
52 chunk_t name, version;
53 int pid, gid, security, blacklist;
54 int count = 0, count_ok = 0, count_no_match = 0, count_blacklist = 0;
55 enumerator_t *e;
56 status_t status = SUCCESS;
57 bool found, match;
58
59 state = &os_state->interface;
60 session = state->get_session(state);
61 os_info = session->get_os_info(session);
62 os_type = os_info->get_type(os_info);
63 product = os_info->get_info(os_info);
64
65 if (os_type == OS_TYPE_ANDROID)
66 {
67 /*no package dependency on Android version */
68 product = enum_to_name(os_type_names, os_type);
69 }
70 DBG1(DBG_IMV, "processing installed '%s' packages", product);
71
72 /* Get primary key of product */
73 e = this->db->query(this->db,
74 "SELECT id FROM products WHERE name = ?",
75 DB_TEXT, product, DB_INT);
76 if (!e)
77 {
78 return FAILED;
79 }
80 if (!e->enumerate(e, &pid))
81 {
82 e->destroy(e);
83 return NOT_FOUND;
84 }
85 e->destroy(e);
86
87 while (package_enumerator->enumerate(package_enumerator, &name, &version))
88 {
89 /* Convert package name chunk to a string */
90 package = strndup(name.ptr, name.len);
91 count++;
92
93 /* Get primary key of package */
94 e = this->db->query(this->db,
95 "SELECT id FROM packages WHERE name = ?",
96 DB_TEXT, package, DB_INT);
97 if (!e)
98 {
99 free(package);
100 return FAILED;
101 }
102 if (!e->enumerate(e, &gid))
103 {
104 /* package not present in database for any product - skip */
105 if (os_type == OS_TYPE_ANDROID)
106 {
107 DBG2(DBG_IMV, "package '%s' (%.*s) not found",
108 package, version.len, version.ptr);
109 }
110 free(package);
111 e->destroy(e);
112 continue;
113 }
114 e->destroy(e);
115
116 /* Convert package version chunk to a string */
117 release = strndup(version.ptr, version.len);
118
119 /* Enumerate over all acceptable versions */
120 e = this->db->query(this->db,
121 "SELECT release, security, blacklist FROM versions "
122 "WHERE product = ? AND package = ?",
123 DB_INT, pid, DB_INT, gid, DB_TEXT, DB_INT, DB_INT);
124 if (!e)
125 {
126 free(package);
127 free(release);
128 return FAILED;
129 }
130 found = FALSE;
131 match = FALSE;
132
133 while (e->enumerate(e, &cur_release, &security, &blacklist))
134 {
135 found = TRUE;
136 if (streq(release, cur_release) || streq("*", cur_release))
137 {
138 match = TRUE;
139 break;
140 }
141 }
142 e->destroy(e);
143
144 if (found)
145 {
146 if (match)
147 {
148 if (blacklist)
149 {
150 DBG2(DBG_IMV, "package '%s' (%s) is blacklisted",
151 package, release);
152 count_blacklist++;
153 os_state->add_bad_package(os_state, package,
154 OS_PACKAGE_STATE_BLACKLIST);
155 }
156 else
157 {
158 DBG2(DBG_IMV, "package '%s' (%s)%s is ok", package, release,
159 security ? " [s]" : "");
160 count_ok++;
161 }
162 }
163 else
164 {
165 DBG1(DBG_IMV, "package '%s' (%s) no match", package, release);
166 count_no_match++;
167 os_state->add_bad_package(os_state, package,
168 OS_PACKAGE_STATE_SECURITY);
169 }
170 }
171 else
172 {
173 /* package not present in database for this product - skip */
174 }
175 free(package);
176 free(release);
177 }
178 os_state->set_count(os_state, count, count_no_match,
179 count_blacklist, count_ok);
180
181 return status;
182 }
183
184 METHOD(imv_os_database_t, set_device_info, void,
185 private_imv_os_database_t *this, int session_id, int count,
186 int count_update, int count_blacklist, u_int flags)
187 {
188 this->db->execute(this->db, NULL,
189 "INSERT INTO device_infos (session, count, count_update, "
190 "count_blacklist, flags) VALUES (?, ?, ?, ?, ?)",
191 DB_INT, session_id, DB_INT, count, DB_INT, count_update,
192 DB_INT, count_blacklist, DB_UINT, flags);
193 }
194
195 METHOD(imv_os_database_t, destroy, void,
196 private_imv_os_database_t *this)
197 {
198 free(this);
199 }
200
201 /**
202 * See header
203 */
204 imv_os_database_t *imv_os_database_create(imv_database_t *imv_db)
205 {
206 private_imv_os_database_t *this;
207
208 if (!imv_db)
209 {
210 return NULL;
211 }
212
213 INIT(this,
214 .public = {
215 .check_packages = _check_packages,
216 .set_device_info = _set_device_info,
217 .destroy = _destroy,
218 },
219 .db = imv_db->get_database(imv_db),
220 );
221
222 return &this->public;
223 }
224