1 /*
2  * $Id$
3  *
4  * Copyright (C) 2001-2003 FhG Fokus
5  *
6  * This file is part of Kamailio, a free SIP server.
7  *
8  * Kamailio is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * Kamailio is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22  /*
23   * History:
24   * --------
25   *  2004-06-06  updated to the new DB api (andrei)
26   */
27 
28 #include "../../core/mem/shm_mem.h"
29 #include "../../lib/srdb1/db.h"
30 #include "../../core/dprint.h"
31 #include "../../core/str.h"
32 #include "cpl_db.h"
33 
34 #define TABLE_VERSION 1
35 
36 static db1_con_t* db_hdl=0;
37 static db_func_t cpl_dbf;
38 
39 str cpl_username_col = str_init("username");
40 str cpl_domain_col = str_init("domain");
41 str cpl_xml_col  = str_init("cpl_xml");
42 str cpl_bin_col  = str_init("cpl_bin");
43 
44 
cpl_db_bind(const str * db_url,const str * db_table)45 int cpl_db_bind(const str* db_url, const str *db_table)
46 {
47 	if (db_bind_mod(db_url, &cpl_dbf )) {
48 		LM_CRIT("cannot bind to database module! "
49 		    "Did you forget to load a database module ?\n");
50 		return -1;
51 	}
52 
53 	/* CPL module uses all database functions */
54 	if (!DB_CAPABILITY(cpl_dbf, DB_CAP_ALL)) {
55 		LM_CRIT("Database modules does not "
56 		    "provide all functions needed by cpl-c module\n");
57 		return -1;
58 	}
59 
60 	if ( cpl_db_init( db_url, db_table) )
61 		return -1;
62 
63 	if(db_check_table_version(&cpl_dbf, db_hdl, db_table, TABLE_VERSION) < 0) {
64 		str tmp = *db_table;
65 		DB_TABLE_VERSION_ERROR(tmp);
66 		cpl_db_close();
67 		return -1;
68 	}
69 
70 	cpl_db_close();
71 	return 0;
72 }
73 
74 
75 
cpl_db_init(const str * db_url,const str * db_table)76 int cpl_db_init(const str* db_url, const str* db_table)
77 {
78 	if (cpl_dbf.init==0){
79 		LM_CRIT("BUG - unbound database module\n");
80 		return -1;
81 	}
82 
83 	db_hdl=cpl_dbf.init(db_url);
84 
85 	if (db_hdl==0){
86 		LM_CRIT("cannot initialize database connection\n");
87 		return -1;
88 	}
89 
90 	if (cpl_dbf.use_table(db_hdl, db_table)<0) {
91 		LM_CRIT("cannot select table \"%.*s\"\n",db_table->len, db_table->s);
92 		cpl_db_close();
93 		return -1;
94 	}
95 
96 	return 0;
97 }
98 
99 
cpl_db_close(void)100 void cpl_db_close(void)
101 {
102 	if (db_hdl && cpl_dbf.close){
103 		cpl_dbf.close(db_hdl);
104 		db_hdl=0;
105 	}
106 }
107 
108 
109 /* gets from database the cpl script in binary format; the returned script is
110  * allocated in shared memory
111  * Returns:  1 - success
112  *          -1 - error
113  */
get_user_script(str * username,str * domain,str * script,str * key)114 int get_user_script(str *username, str *domain, str *script, str* key)
115 {
116 	db_key_t   keys_cmp[2];
117 	db_key_t   keys_ret[1];
118 	db_val_t   vals[2];
119 	db1_res_t   *res = NULL;
120 	int n;
121 
122 	keys_cmp[0] = &cpl_username_col;
123 	keys_cmp[1] = &cpl_domain_col;
124 	keys_ret[0] = key;
125 
126 	LM_DBG("fetching script for user <%.*s>\n",
127 		username->len,username->s);
128 	vals[0].type = DB1_STR;
129 	vals[0].nul  = 0;
130 	vals[0].val.str_val = *username;
131 	n = 1;
132 	if (domain) {
133 		vals[1].type = DB1_STR;
134 		vals[1].nul  = 0;
135 		vals[1].val.str_val = *domain;
136 		n++;
137 	}
138 
139 	if (cpl_dbf.query(db_hdl, keys_cmp, 0, vals, keys_ret, n, 1, NULL, &res)
140 			< 0){
141 		LM_ERR("db_query failed\n");
142 		goto error;
143 	}
144 
145 	if (res->n==0) {
146 		LM_DBG("user <%.*s> not found in db -> probably "
147 			"he has no script\n",username->len, username->s);
148 		script->s = 0;
149 		script->len = 0;
150 	} else {
151 		if (res->rows[0].values[0].nul) {
152 			LM_DBG("user <%.*s> has a NULL script\n",
153 				username->len, username->s);
154 			script->s = 0;
155 			script->len = 0;
156 		} else {
157 			LM_DBG("we got the script len=%d\n",
158 				res->rows[0].values[0].val.blob_val.len);
159 			script->len = res->rows[0].values[0].val.blob_val.len;
160 			script->s = shm_malloc( script->len );
161 			if (!script->s) {
162 				LM_ERR("no free sh_mem\n");
163 				goto error;
164 			}
165 			memcpy( script->s, res->rows[0].values[0].val.blob_val.s,
166 				script->len);
167 		}
168 	}
169 
170 	cpl_dbf.free_result( db_hdl, res);
171 	return 1;
172 error:
173 	if (res)
174 		cpl_dbf.free_result( db_hdl, res);
175 	script->s = 0;
176 	script->len = 0;
177 	return -1;
178 }
179 
180 
181 
182 /* inserts into database a cpl script in XML format(xml) along with its binary
183  * format (bin)
184  * Returns:  1 - success
185  *          -1 - error
186  */
write_to_db(str * username,str * domain,str * xml,str * bin)187 int write_to_db(str *username, str *domain, str *xml, str *bin)
188 {
189 	db_key_t   keys[4];
190 	db_val_t   vals[4];
191 	db1_res_t   *res = NULL;
192 	int n;
193 
194 	/* lets see if the user is already in database */
195 	keys[2] = &cpl_username_col;
196 	vals[2].type = DB1_STR;
197 	vals[2].nul  = 0;
198 	vals[2].val.str_val = *username;
199 	n = 1;
200 	if (domain) {
201 		keys[3] = &cpl_domain_col;
202 		vals[3].type = DB1_STR;
203 		vals[3].nul  = 0;
204 		vals[3].val.str_val = *domain;
205 		n++;
206 	}
207 	if (cpl_dbf.query(db_hdl, keys+2, 0, vals+2, keys+2, n, 1, NULL, &res)<0) {
208 		LM_ERR("db_query failed\n");
209 		goto error;
210 	}
211 	if (res->n>1) {
212 		LM_ERR("Inconsistent CPL database:"
213 			" %d records for user %.*s\n",res->n,username->len,username->s);
214 		goto error;
215 	}
216 
217 	/* cpl text */
218 	keys[0] = &cpl_xml_col;
219 	vals[0].type = DB1_BLOB;
220 	vals[0].nul  = 0;
221 	vals[0].val.blob_val.s = xml->s;
222 	vals[0].val.blob_val.len = xml->len;
223 	n++;
224 	/* cpl bin */
225 	keys[1] = &cpl_bin_col;
226 	vals[1].type = DB1_BLOB;
227 	vals[1].nul  = 0;
228 	vals[1].val.blob_val.s = bin->s;
229 	vals[1].val.blob_val.len = bin->len;
230 	n++;
231 	/* insert or update ? */
232 	if (res->n==0) {
233 		LM_DBG("no user %.*s in CPL database->insert\n",
234 			username->len,username->s);
235 		if (cpl_dbf.insert(db_hdl, keys, vals, n) < 0) {
236 			LM_ERR("insert failed !\n");
237 			goto error;
238 		}
239 	} else {
240 		LM_DBG("user %.*s already in CPL database ->"
241 			" update\n",username->len,username->s);
242 		if (cpl_dbf.update(db_hdl, keys+2, 0, vals+2, keys, vals, n-2, 2) < 0) {
243 			LM_ERR("update failed !\n");
244 			goto error;
245 		}
246 	}
247 
248 	return 1;
249 error:
250 	return -1;
251 }
252 
253 
254 
255 /* delete from database the entity record for a given user - if a user has no
256  * script, he will be removed completely from db; users without script are not
257  * allowed into db ;-)
258  * Returns:  1 - success
259  *          -1 - error
260  */
rmv_from_db(str * username,str * domain)261 int rmv_from_db(str *username, str *domain)
262 {
263 	db_key_t   keys[2];
264 	db_val_t   vals[2];
265 	int n;
266 
267 	/* username */
268 	keys[0] = &cpl_username_col;
269 	vals[0].type = DB1_STR;
270 	vals[0].nul  = 0;
271 	vals[0].val.str_val = *username;
272 	n = 1;
273 	if (domain) {
274 		keys[1] = &cpl_domain_col;
275 		vals[1].type = DB1_STR;
276 		vals[1].nul  = 0;
277 		vals[1].val.str_val = *domain;
278 		n++;
279 	}
280 
281 	if (cpl_dbf.delete(db_hdl, keys, NULL, vals, n) < 0) {
282 		LM_ERR("failed to delete script for "
283 			"user \"%.*s\"\n",username->len,username->s);
284 		return -1;
285 	}
286 
287 	return 1;
288 }
289 
290