1 /*++++++++++++++++++++
2 refdbda.c: refdb application server, administrative functions
3 markus@mhoenicka.de 6-5-00
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 +++++++++++++++++++++++++*/
20
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <limits.h>
25 #include <sys/types.h>
26 #include <sys/stat.h> /* for umask */
27 #include <unistd.h>
28 #include <syslog.h>
29 #include <fcntl.h>
30 #include <time.h> /* for strftime */
31 #include <math.h> /* for log10 */
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <dbi/dbi.h>
35
36 #include "backend.h"
37 #include "refdb.h"
38 #include "linklist.h"
39 #include "refdbd.h" /* depends on backend.h */
40 #include "tokenize.h"
41 #include "strfncs.h"
42 #include "connect.h"
43 #include "cgi.h"
44 #include "dbfncs.h"
45
46 /* these are defined in refdbd.c */
47 extern char server_ip[];
48 extern char log_file[];
49 extern char log_dest[];
50 extern char log_level[];
51 extern char port_address[];
52 extern char dbs_port_address[];
53 extern char refdb_timeout[];
54 extern char refdblib[];
55 extern char the_fifo[];
56 extern char pid_file[];
57 extern char cs_term[];
58 extern char main_db[];
59 extern char force_dbcheck[];
60 extern int n_log_level;
61 extern int n_log_dest;
62 extern int n_refdb_timeout;
63 extern int n_reopen_log;
64 extern int n_remote_admin;
65 extern int run;
66 extern int parent_pid;
67 extern int fd_fifo;
68
69 /* forward declarations of local functions */
70 static int is_reference_database(struct CLIENT_REQUEST* ptr_clrequest, dbi_conn conn, const char* dbname);
71 static int daemon_started_by_init(void);
72 static int daemon_started_by_inetd(void);
73 static long limit_open(void);
74
75 void log_dberror(dbi_conn Conn, void *user_argument);
76
77 /* declaration of the svn version function */
78 const char* svn_version(void);
79
80 /* additional types */
81 #ifndef HAVE_SOCKLEN_T
82 # define socklen_t int
83 #endif
84
85
86 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
87 child_confserv(): configures the application server (child process)
88 this fn sends the changes to the parent process
89 via a FIFO/named pipe (via a temp file in Cygwin).
90
91 int child_confserv returns 0 if ok, >0 if error
92
93 struct CLIENT_REQUEST* ptr_clrequest ptr to structure with client info
94
95 struct ADDRESULT* ptr_addresult ptr to struct with counters
96
97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
child_confserv(struct CLIENT_REQUEST * ptr_clrequest,struct ADDRESULT * ptr_addresult)98 int child_confserv(struct CLIENT_REQUEST* ptr_clrequest, struct ADDRESULT* ptr_addresult) {
99 char outbuffer[OUTBUF_LEN];
100 int fd_fifo = 0;
101 int retval;
102
103 if (!n_remote_admin) {
104 send_status(ptr_clrequest->fd, 0, TERM_NO);
105 tiwrite(ptr_clrequest->fd, "703\n", TERM_YES);
106 ptr_addresult->failure++;
107 return 2;
108 }
109
110 ptr_addresult->msg_len = 512;
111 ptr_addresult->msg = malloc(ptr_addresult->msg_len);
112 if (ptr_addresult->msg == NULL) {
113 send_status(ptr_clrequest->fd, 801, TERM_NO);
114 LOG_PRINT(LOG_CRIT, get_status_msg(801));
115 return 1;
116 }
117
118 *(ptr_addresult->msg) = '\0';
119
120 /* check our access rights */
121 retval = is_refdb_admin(ptr_clrequest, ptr_addresult);
122 if (!retval) { /* unauthorized attempt likely */
123 send_status(ptr_clrequest->fd, 0, TERM_NO);
124 tiwrite(ptr_clrequest->fd, ptr_addresult->msg, TERM_YES);
125 ptr_addresult->failure++;
126 return 2;
127 }
128 else if (retval == -1) { /* connection failed */
129 send_status(ptr_clrequest->fd, 202, TERM_NO);
130 LOG_PRINT(LOG_WARNING, get_status_msg(202));
131 return 1;
132 }
133
134 /* we have to treat ping separately as it should not
135 create a temp file or use the FIFO */
136 if (ptr_clrequest->inargc == *(ptr_clrequest->ptr_optind)+1 && strcmp(ptr_clrequest->inargv[*(ptr_clrequest->ptr_optind)], "ping") == 0) {
137 send_status(ptr_clrequest->fd, 0, TERM_NO);
138 sprintf(&(ptr_addresult->msg[strlen(ptr_addresult->msg)]), "707:parent %d:child %d\n", parent_pid, getpid());
139 tiwrite(ptr_clrequest->fd, ptr_addresult->msg, TERM_YES);
140 ptr_addresult->success++;
141 return 0;
142 }
143
144 #ifdef HAVE_MKFIFO
145 if (fd_fifo != -1) {
146 close(fd_fifo); /* this is still open for reading */
147 if ((fd_fifo = open(the_fifo, O_WRONLY)) == -1) {
148 LOG_PRINT(LOG_WARNING, get_status_msg(839));
149 send_status(ptr_clrequest->fd, 839, TERM_NO);
150 ptr_addresult->failure++;
151 return 1;
152 }
153 }
154 else {
155 LOG_PRINT(LOG_WARNING, get_status_msg(839));
156 send_status(ptr_clrequest->fd, 839, TERM_NO);
157 ptr_addresult->failure++;
158 return 1;
159 }
160 #else
161 if (access(the_fifo, F_OK) != -1) { /* old file still exists */
162 LOG_PRINT(LOG_WARNING, get_status_msg(839));
163 send_status(ptr_clrequest->fd, 839, TERM_NO);
164 ptr_addresult->failure++;
165 return 1;
166 }
167 else { /* create a temp file with exclusive rights */
168 if ((fd_fifo = open(the_fifo, O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) == -1) {
169 LOG_PRINT(LOG_WARNING, get_status_msg(839));
170 send_status(ptr_clrequest->fd, 839, TERM_NO);
171 ptr_addresult->failure++;
172 return 1;
173 }
174 }
175 #endif /* HAVE_MKFIFO */
176
177 /* the inargv array should have one or two entries: a command and
178 an optional argument */
179 if (ptr_clrequest->inargc == *(ptr_clrequest->ptr_optind)) { /* no argument given */
180 LOG_PRINT(LOG_WARNING, get_status_msg(301));
181 send_status(ptr_clrequest->fd, 301, TERM_NO);
182 ptr_addresult->failure++;
183 return 1;
184 }
185
186 if (ptr_clrequest->inargc == *(ptr_clrequest->ptr_optind)+1) { /* one argument */
187 if (strcmp(ptr_clrequest->inargv[*(ptr_clrequest->ptr_optind)], "stop") == 0) {
188 if (write(fd_fifo, "1stop", 6) == -1) {
189 LOG_PRINT(LOG_WARNING, get_status_msg(840));
190 send_status(ptr_clrequest->fd, 840, TERM_NO);
191 ptr_addresult->failure++;
192 return 1;
193 }
194 else {
195 sprintf(&(ptr_addresult->msg[strlen(ptr_addresult->msg)]), "708:%d:%d\n", parent_pid, getpid());
196 ptr_addresult->success++;
197 LOG_PRINT(LOG_INFO, get_status_msg(708));
198 }
199 }
200 else {
201 LOG_PRINT(LOG_WARNING, get_status_msg(301));
202 send_status(ptr_clrequest->fd, 301, TERM_NO);
203 ptr_addresult->failure++;
204 return 1;
205 }
206 }
207 else { /* more than one argument, use first two */
208 if (strcmp(ptr_clrequest->inargv[*(ptr_clrequest->ptr_optind)], "serverip") == 0) {
209 strcpy(ptr_clrequest->server_ip, ptr_clrequest->inargv[*(ptr_clrequest->ptr_optind)+1]);
210
211 sprintf(outbuffer, "2serverip %s", ptr_clrequest->server_ip);
212 if (write(fd_fifo, outbuffer, strlen(outbuffer) + 1) == -1) {
213 LOG_PRINT(LOG_WARNING, get_status_msg(840));
214 send_status(ptr_clrequest->fd, 840, TERM_NO);
215 ptr_addresult->failure++;
216 return 1;
217 }
218 else {
219 sprintf(outbuffer, "709:%s", ptr_clrequest->server_ip);
220 LOG_PRINT(LOG_INFO, outbuffer);
221 sprintf(&(ptr_addresult->msg[strlen(ptr_addresult->msg)]), "709:%s\n", ptr_clrequest->server_ip);
222 ptr_addresult->success++;
223 }
224 }
225 else if (strcmp(ptr_clrequest->inargv[*(ptr_clrequest->ptr_optind)], "timeout") == 0) {
226 strcpy(refdb_timeout, ptr_clrequest->inargv[*(ptr_clrequest->ptr_optind)+1]);
227 n_refdb_timeout = atoi(refdb_timeout);
228
229 sprintf(outbuffer, "2timeout %s", refdb_timeout);
230 if (write(fd_fifo, outbuffer, strlen(outbuffer) + 1) == -1) {
231 LOG_PRINT(LOG_WARNING, get_status_msg(840));
232 send_status(ptr_clrequest->fd, 840, TERM_NO);
233 ptr_addresult->failure++;
234 return 1;
235 }
236 else {
237 sprintf(outbuffer, "710:%d", n_refdb_timeout);
238 LOG_PRINT(LOG_INFO, outbuffer);
239 sprintf(&(ptr_addresult->msg[strlen(ptr_addresult->msg)]), "710:%d\n", n_refdb_timeout);
240 ptr_addresult->success++;
241 }
242 }
243 else if (strcmp(ptr_clrequest->inargv[*(ptr_clrequest->ptr_optind)], "logfile") == 0) {
244 strcpy(log_file, ptr_clrequest->inargv[*(ptr_clrequest->ptr_optind)+1]);
245
246 sprintf(outbuffer, "2logfile %s", log_file);
247 if (write(fd_fifo, outbuffer, strlen(outbuffer) + 1) == -1) {
248 LOG_PRINT(LOG_WARNING, get_status_msg(840));
249 send_status(ptr_clrequest->fd, 840, TERM_NO);
250 ptr_addresult->failure++;
251 return 1;
252 }
253 else {
254 sprintf(outbuffer, "711:%s", log_file);
255 LOG_PRINT(LOG_INFO, outbuffer);
256 sprintf(&(ptr_addresult->msg[strlen(ptr_addresult->msg)]), "711:%s\n", log_file);
257 ptr_addresult->success++;
258 }
259 }
260 else if (strcmp(ptr_clrequest->inargv[*(ptr_clrequest->ptr_optind)], "logdest") == 0) {
261 strcpy(log_dest, ptr_clrequest->inargv[*(ptr_clrequest->ptr_optind)+1]);
262 n_log_dest = atoi(log_dest);
263
264 sprintf(outbuffer, "2logdest %s", log_dest);
265 if (write(fd_fifo, outbuffer, strlen(outbuffer) + 1) == -1) {
266 LOG_PRINT(LOG_WARNING, get_status_msg(840));
267 send_status(ptr_clrequest->fd, 840, TERM_NO);
268 ptr_addresult->failure++;
269 return 1;
270 }
271 else {
272 sprintf(outbuffer, "712:%d", n_log_dest);
273 LOG_PRINT(LOG_INFO, outbuffer);
274 sprintf(&(ptr_addresult->msg[strlen(ptr_addresult->msg)]), "712:%d\n", n_log_dest);
275 ptr_addresult->success++;
276 }
277 }
278 else if (strcmp(ptr_clrequest->inargv[*(ptr_clrequest->ptr_optind)], "loglevel") == 0) {
279 strcpy(log_level, ptr_clrequest->inargv[*(ptr_clrequest->ptr_optind)+1]);
280 n_log_level = atoi(log_level);
281
282 sprintf(outbuffer, "2loglevel %s", log_level);
283 if (write(fd_fifo, outbuffer, strlen(outbuffer) + 1) == -1) {
284 LOG_PRINT(LOG_WARNING, get_status_msg(840));
285 send_status(ptr_clrequest->fd, 840, TERM_NO);
286 ptr_addresult->failure++;
287 return 1;
288 }
289 else {
290 sprintf(outbuffer, "713:%d", n_log_level);
291 LOG_PRINT(LOG_INFO, outbuffer);
292 sprintf(&(ptr_addresult->msg[strlen(ptr_addresult->msg)]), "713:%d\n", n_log_level);
293 ptr_addresult->success++;
294 }
295 }
296 else {
297 LOG_PRINT(LOG_WARNING, get_status_msg(301));
298 send_status(ptr_clrequest->fd, 301, TERM_NO);
299 ptr_addresult->failure++;
300 return 1;
301 }
302 }
303
304 close(fd_fifo);
305
306 /* send report to client */
307 send_status(ptr_clrequest->fd, 0, TERM_NO);
308 tiwrite(ptr_clrequest->fd, ptr_addresult->msg, TERM_YES);
309
310 return 0;
311 }
312
313 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
314 confserv(): configures the application server (parent process)
315
316 void confserv
317
318 char* command ptr to string with the command
319
320 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
confserv(char * command,char * server_ip)321 void confserv(char *command, char* server_ip) {
322 char outbuffer[OUTBUF_LEN];
323
324 /* the command buffer should have one or two entries: a command and
325 an optional argument */
326 if (*command == '1') { /* one argument */
327 if (strncmp(command + 1, "stop", 4) == 0) {
328 run = 0;
329 LOG_PRINT(LOG_INFO, "application server stopped");
330 }
331 }
332 else { /* more than one argument, use first two */
333 if (strncmp(command + 1, "serverip", 8) == 0) {
334 strcpy(server_ip, command + 10);
335 sprintf(outbuffer, "set serverip to %s", server_ip);
336 LOG_PRINT(LOG_INFO, outbuffer);
337 }
338 else if (strncmp(command + 1, "timeout", 7) == 0) {
339 strcpy(refdb_timeout, command + 9);
340 n_refdb_timeout = atoi(refdb_timeout);
341 sprintf(outbuffer, "set timeout to %d seconds", n_refdb_timeout);
342 LOG_PRINT(LOG_INFO, outbuffer);
343 }
344 else if (strncmp(command + 1, "logfile", 7) == 0) {
345 strcpy(log_file, command + 9);
346 sprintf(outbuffer, "set logfile to %s", log_file);
347 LOG_PRINT(LOG_INFO, outbuffer);
348 n_reopen_log = 1; /* signal the log fn to open new log file */
349 }
350 else if (strncmp(command + 1, "logdest", 7) == 0) {
351 strcpy(log_dest, command + 9);
352 n_log_dest = atoi(log_dest);
353 sprintf(outbuffer, "set logdest to %d", n_log_dest);
354 LOG_PRINT(LOG_INFO, outbuffer);
355 }
356 else if (strncmp(command + 1, "loglevel", 8) == 0) {
357 strcpy(log_level, command + 10);
358 n_log_level = atoi(log_level);
359 sprintf(outbuffer, "set loglevel to %d", n_log_level);
360 LOG_PRINT(LOG_INFO, outbuffer);
361 }
362 }
363 }
364
365 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
366 connect_to_db(): establishes a connection with the SQL database server
367
368 dbi_conn connect_to_db Returns connection ptr if successful,
369 NULL if failed
370
371 struct CLIENT_REQUEST* ptr_clrequest ptr to structure with connection info
372
373 const char* special_db ptr to string containing the name of a special
374 database to connect to if the latter is different from
375 the one in ptr_clrequest
376
377 int nocheck if 1, don't verify the database is a RefDB database
378
379 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
connect_to_db(struct CLIENT_REQUEST * ptr_clrequest,const char * special_db,int nocheck)380 dbi_conn connect_to_db(struct CLIENT_REQUEST* ptr_clrequest, const char* special_db, int nocheck) {
381 dbi_conn conn;
382 char *my_db;
383
384 LOG_PRINT(LOG_DEBUG, ptr_clrequest->server_ip);
385 LOG_PRINT(LOG_DEBUG, ptr_clrequest->username);
386 LOG_PRINT(LOG_DEBUG, ptr_clrequest->passwd);
387 LOG_PRINT(LOG_DEBUG, ptr_clrequest->current_db);
388 LOG_PRINT(LOG_DEBUG, ptr_clrequest->dbs_port_address);
389 LOG_PRINT(LOG_DEBUG, ptr_clrequest->dbserver);
390 LOG_PRINT(LOG_DEBUG, ptr_clrequest->db_path);
391 LOG_PRINT(LOG_DEBUG, ptr_clrequest->db_encoding);
392
393 conn = dbi_conn_new(ptr_clrequest->dbserver);
394
395 if (!conn) {
396 LOG_PRINT(LOG_WARNING, "creating database connection structure failed");
397 LOG_PRINT(LOG_WARNING, "check your libdbi installation");
398 return NULL;
399 }
400
401 my_db = (special_db && *special_db) ? (char*)special_db : ((*(ptr_clrequest->current_db)) ? ptr_clrequest->current_db : main_db);
402 LOG_PRINT(LOG_DEBUG, my_db);
403 /* common driver options */
404 dbi_conn_set_option(conn, "username", ptr_clrequest->username);
405 dbi_conn_set_option(conn, "password", (ptr_clrequest->passwd && *(ptr_clrequest->passwd)) ? ptr_clrequest->passwd : "");
406 /* connect to refdb unless a specific reference database is requested
407 special_db overrides ptr_clrequest->current_db */
408 dbi_conn_set_option(conn, "dbname", my_db);
409 dbi_conn_set_option(conn, "encoding", "auto");
410 dbi_conn_set_option_numeric(conn, "port", atoi(ptr_clrequest->dbs_port_address));
411
412 /* driver-specific options */
413 if (!strcmp(ptr_clrequest->dbserver, "mysql")) {
414 dbi_conn_set_option_numeric(conn, "compression", 1);
415 dbi_conn_set_option(conn, "host", ptr_clrequest->server_ip);
416 dbi_conn_set_option_numeric(conn, "mysql_include_trailing_null", 1);
417 }
418 else if (!strcmp(ptr_clrequest->dbserver, "pgsql")) {
419 /* don't set host if we want to connect locally */
420 if (strcmp(ptr_clrequest->server_ip, "localhost")) {
421 dbi_conn_set_option(conn, "host", ptr_clrequest->server_ip);
422 }
423 }
424 else if (!strcmp(ptr_clrequest->dbserver, "sqlite")) {
425 dbi_conn_set_option(conn, "sqlite_dbdir", ptr_clrequest->db_path);
426 dbi_conn_set_option_numeric(conn, "sqlite_timeout", ptr_clrequest->db_timeout);
427 }
428 else if (!strcmp(ptr_clrequest->dbserver, "sqlite3")) {
429 dbi_conn_set_option(conn, "sqlite3_dbdir", ptr_clrequest->db_path);
430 dbi_conn_set_option(conn, "encoding", "UTF-8");
431 dbi_conn_set_option_numeric(conn, "sqlite3_timeout", ptr_clrequest->db_timeout);
432 }
433
434 if (dbi_conn_connect(conn) < 0) { /* -1 and -2 indicate errors */
435 const char* errmsg = NULL;
436
437 LOG_PRINT(LOG_WARNING, "failed to connect to database server using database:");
438 LOG_PRINT(LOG_WARNING, my_db);
439 dbi_conn_error(conn, &errmsg);
440 if (errmsg) {
441 LOG_PRINT(LOG_WARNING, errmsg);
442 }
443 dbi_conn_close(conn);
444 return NULL;
445 }
446
447 if (!nocheck && strcmp(my_db, main_db) && !is_reference_database(NULL, conn, my_db)) {
448 /* if ((!strcmp(force_dbcheck, "t") || !nocheck) && strcmp(my_db, MAIN_DB) && !is_reference_database(NULL, conn, my_db)) { */
449 LOG_PRINT(LOG_WARNING, "does not appear to be a RefDB reference database:");
450 LOG_PRINT(LOG_WARNING, my_db);
451 dbi_conn_close(conn);
452 return NULL;
453 }
454
455 /* register dbi error handler */
456 dbi_conn_error_handler(conn, log_dberror, NULL);
457
458 LOG_PRINT(LOG_DEBUG, "connected to database server using database:");
459 LOG_PRINT(LOG_DEBUG, my_db);
460 return conn;
461 }
462
log_dberror(dbi_conn conn,void * user_argument)463 void log_dberror(dbi_conn conn, void *user_argument) {
464 const char *msg;
465
466 dbi_conn_error(conn, &msg);
467 LOG_PRINT(LOG_DEBUG, msg);
468 }
469
470 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
471 viewstat(): executes client command viewstat
472
473 int viewstat returns 0 if ok, 1 if memory error, 2 if other error
474
475 struct CLIENT_REQUEST* ptr_clrequest ptr to structure with client info
476
477 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
viewstat(struct CLIENT_REQUEST * ptr_clrequest)478 int viewstat(struct CLIENT_REQUEST* ptr_clrequest) {
479 dbi_conn conn; /* libdbi connection structure */
480 dbi_driver driver; /* libdbi driver structure */
481 dbi_result dbires; /* libdbi result structure */
482 char* outbuffer; /* ptr to a buffer for output */
483 short int dbversioninfo = 0;
484 char sql_command[64];
485 char db_version[VERSIONSTRING_LENGTH];
486
487 /* get a buffer to hold output data */
488 if ((outbuffer = malloc((size_t)OUTBUF_LEN)) == NULL) {
489 /* out of memory */
490 LOG_PRINT(LOG_CRIT, get_status_msg(801));
491 send_status(ptr_clrequest->fd, 801, TERM_NO);
492 return 1;
493 }
494
495 /* connect to the database */
496 if ((conn = connect_to_db(ptr_clrequest, NULL, 0)) != NULL) {
497 driver = dbi_conn_get_driver(conn);
498
499 sprintf(sql_command, "SELECT meta_dbversion FROM t_meta WHERE meta_type='refdb'");
500 dbires = dbi_conn_query(conn, sql_command);
501 LOG_PRINT(LOG_DEBUG, sql_command);
502 if (dbires) {
503 if (dbi_result_next_row(dbires)) {
504 dbversioninfo = dbi_result_get_short_idx(dbires, 1); /* 1-base index */
505 }
506
507 dbi_result_free(dbires);
508 }
509 else {
510 /* could not retrieve reference database metadata */
511 LOG_PRINT(LOG_ERR, get_status_msg(208));
512 send_status(ptr_clrequest->fd, 208, TERM_NO);
513 free(outbuffer);
514 return 2;
515 }
516
517 /* obtain database server version info */
518 dbi_conn_get_engine_version_string(conn, db_version);
519
520 sprintf(outbuffer, "You are served by: %s %s\nSVN revision: %s\nClient IP: %s\nConnected via %s driver (%s)\nto: %s\ndb version: %d\nserverip: %s\ntimeout: %s\ndbs_port: %s\nlogfile: %s\nlogdest: %s\nloglevel: %s\nremoteadmin: %s\npidfile: %s\n",
521 PACKAGE,
522 VERSION,
523 svn_version(),
524 ptr_clrequest->client_ip,
525 dbi_driver_get_name(driver),
526 dbi_driver_get_version(driver),
527 db_version,
528 dbversioninfo,
529 ptr_clrequest->server_ip,
530 refdb_timeout,
531 ptr_clrequest->dbs_port_address,
532 log_file,
533 log_dest,
534 log_level,
535 (n_remote_admin) ? "on" : "off",
536 pid_file);
537
538 /* all fine */
539 send_status(ptr_clrequest->fd, 0, TERM_NO);
540 tiwrite(ptr_clrequest->fd, outbuffer, TERM_YES);
541 dbi_conn_close(conn);
542 }
543 else {
544 /* access denied to reference database */
545 LOG_PRINT(LOG_WARNING, get_status_msg(204));
546 send_status(ptr_clrequest->fd, 204, TERM_NO);
547 free(outbuffer);
548 return 2;
549 }
550 free(outbuffer);
551
552 return 0;
553 }
554
555 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
556 listdb(): implements the client commands listdb and selectdb
557
558 int listdb returns 0 if ok, 1 if error
559
560 struct CLIENT_REQUEST* ptr_clrequest ptr to structure with client info
561
562 int select if 1, answers selectdb command, if 0, answers listdb command
563
564 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
listdb(struct CLIENT_REQUEST * ptr_clrequest,int select,struct ADDRESULT * ptr_addresult)565 int listdb(struct CLIENT_REQUEST* ptr_clrequest, int select, struct ADDRESULT* ptr_addresult) {
566 char* new_msg;
567 const char* dbname;
568 char message[128];
569
570 dbi_conn conn;
571 dbi_result dbires;
572
573 if ((ptr_addresult->msg = malloc((size_t)OUTBUF_LEN)) == NULL) {
574 /* out of memory */
575 LOG_PRINT(LOG_CRIT, get_status_msg(801));
576 send_status(ptr_clrequest->fd, 801, TERM_NO);
577 return 1;
578 }
579
580 *(ptr_addresult->msg) = '\0';
581
582 /* connect to the database */
583 if ((conn = connect_to_db(ptr_clrequest, NULL, 0)) != NULL) {
584 if (*(ptr_clrequest->argument)) {
585 /* this will list the databases that match the provided pattern */
586 dbires = dbi_conn_get_db_list(conn, ptr_clrequest->argument);
587 }
588 else {
589 /* this will list all databases */
590 dbires = dbi_conn_get_db_list(conn, NULL);
591 }
592
593 if (select) {
594 /* selectdb */
595
596 if (dbi_result_next_row(dbires)) {
597 /* this is just to prevent problems if the SQL server
598 allows longer database names than we expect */
599 dbname = dbi_result_get_string_idx(dbires, 1); /* 1-based index */
600 if (dbname) {
601 if (is_reference_database(ptr_clrequest, NULL, dbname)) {
602 snprintf(message, 128, "240:%s\n", dbname);
603
604 if ((new_msg = mstrcat(ptr_addresult->msg, message, &(ptr_addresult->msg_len), 0)) == NULL) {
605 send_status(ptr_clrequest->fd, 801, TERM_NO);
606 LOG_PRINT(LOG_INFO, get_status_msg(801));
607 dbi_result_free(dbires);
608 dbi_conn_close(conn);
609 return 1;
610 }
611 else {
612 ptr_addresult->msg = new_msg;
613 }
614 }
615 else { /* is not a reference database */
616 send_status(ptr_clrequest->fd, 225, TERM_NO);
617 LOG_PRINT(LOG_INFO, get_status_msg(225));
618 dbi_result_free(dbires);
619 dbi_conn_close(conn);
620 return 1;
621 }
622 }
623 else { /* database does not exist */
624 send_status(ptr_clrequest->fd, 226, TERM_NO);
625 LOG_PRINT(LOG_INFO, get_status_msg(226));
626 dbi_result_free(dbires);
627 dbi_conn_close(conn);
628 return 1;
629 }
630 }
631 else { /* database does not exist */
632 send_status(ptr_clrequest->fd, 226, TERM_NO);
633 LOG_PRINT(LOG_INFO, get_status_msg(226));
634 dbi_result_free(dbires);
635 dbi_conn_close(conn);
636 return 1;
637 }
638 }
639 else {
640 /* listdb */
641
642 while (dbi_result_next_row(dbires)) {
643 dbname = dbi_result_get_string_idx(dbires, 1);
644 if (dbname) {
645 if (is_reference_database(ptr_clrequest, NULL, dbname)) {
646 snprintf(message, 128, "%s\n", dbname);
647
648 if ((new_msg = mstrcat(ptr_addresult->msg, message, &(ptr_addresult->msg_len), 0)) == NULL) {
649 send_status(ptr_clrequest->fd, 801, TERM_NO);
650 LOG_PRINT(LOG_INFO, get_status_msg(801));
651 dbi_result_free(dbires);
652 dbi_conn_close(conn);
653 return 1;
654 }
655 else {
656 ptr_addresult->msg = new_msg;
657 }
658 ptr_addresult->success++;
659 }
660 }
661 }
662 }
663 dbi_result_free(dbires);
664 dbi_conn_close(conn);
665
666 send_status(ptr_clrequest->fd, 0, TERM_NO);
667 tiwrite(ptr_clrequest->fd, ptr_addresult->msg, TERM_YES);
668 }
669 else {
670 LOG_PRINT(LOG_WARNING, get_status_msg(202));
671 send_status(ptr_clrequest->fd, 202, TERM_NO);
672 return 1;
673 }
674
675 return 0;
676 }
677
678 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
679 is_reference_database(): checks whether a database is a RefDB
680 reference database
681
682 int is_reference_database returns 1 if the database is a RefDB database,
683 0 if not
684
685 struct CLIENT_REQUEST* ptr_clrequest ptr to structure with client info
686 set to NULL if using conn
687
688 dbi_conn conn optional existing connection to database. Overrides
689 ptr_clrequest. Set to NULL if not used
690
691 const char* dbname ptr to a string containing the database name
692
693 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
is_reference_database(struct CLIENT_REQUEST * ptr_clrequest,dbi_conn conn,const char * dbname)694 static int is_reference_database(struct CLIENT_REQUEST* ptr_clrequest, dbi_conn conn, const char* dbname) {
695 dbi_conn conn_ref;
696 dbi_result dbires;
697 char sql_command[128];
698 const char* app;
699 const char* type;
700 int retval = 0;
701 int close_conn_ref = 0;
702 short int dbversion;
703
704 if (conn) {
705 conn_ref = conn; /* legal as conn and conn_ref are pointers */
706 }
707 else {
708 if ((conn_ref = connect_to_db(ptr_clrequest, dbname, 1)) == NULL) {
709 /* can't access */
710 return 0;
711 }
712 close_conn_ref++;
713 }
714
715 sprintf(sql_command, "SELECT meta_app,meta_type,meta_dbversion FROM t_meta WHERE meta_type='risx'");
716
717 LOG_PRINT(LOG_DEBUG, sql_command);
718 dbires = dbi_conn_query(conn_ref, sql_command);
719
720 if (!dbires) {
721 goto Finish;
722 }
723
724 if (!dbi_result_next_row(dbires)) {
725 goto Finish;
726 }
727
728 app = dbi_result_get_string(dbires, "meta_app");
729 type = dbi_result_get_string(dbires, "meta_type");
730 dbversion = dbi_result_get_short(dbires, "meta_dbversion");
731
732 if (!strcmp(app, "refdb")
733 && (!strcmp(type, "ris") || !strcmp(type, "risx"))
734 && dbversion >= MIN_DB_VERSION) {
735 retval = 1;
736 }
737
738 Finish:
739 if (close_conn_ref) {
740 dbi_conn_close(conn_ref);
741 }
742
743 return retval;
744 }
745
746 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
747 listuser(): implements the client command listuser
748
749 int listuser returns 0 if ok, >0 if error
750
751 struct CLIENT_REQUEST* ptr_clrequest ptr to structure with client info
752
753 struct ADDRESULT* ptr_addresult ptr to struct with counters
754
755 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
listuser(struct CLIENT_REQUEST * ptr_clrequest,struct ADDRESULT * ptr_addresult)756 int listuser(struct CLIENT_REQUEST* ptr_clrequest, struct ADDRESULT* ptr_addresult) {
757 dbi_conn conn;
758 dbi_result dbires;
759 dbi_driver driver;
760 char sql_command[256];
761 const char* username;
762 char* myarg;
763 char* new_msg;
764
765 ptr_addresult->msg_len = 512;
766 if ((ptr_addresult->msg = malloc(ptr_addresult->msg_len)) == NULL) {
767 send_status(ptr_clrequest->fd, 801, TERM_NO);
768 LOG_PRINT(LOG_CRIT, get_status_msg(801));
769 return 1;
770 }
771
772 *(ptr_addresult->msg) = '\0';
773
774 /* connect to the database */
775 if ((conn = connect_to_db(ptr_clrequest, ptr_clrequest->current_db, 0)) != NULL) {
776 driver = dbi_conn_get_driver(conn);
777
778 if (ptr_clrequest->argument && *(ptr_clrequest->argument)) {
779 myarg = strdup(ptr_clrequest->argument);
780 }
781 else {
782 myarg = strdup(my_dbi_driver_get_cap(driver, "listall")); /* list all if no argument is specified */
783 }
784 if (!myarg) {
785 send_status(ptr_clrequest->fd, 801, TERM_NO);
786 LOG_PRINT(LOG_CRIT, get_status_msg(801));
787 dbi_conn_close(conn);
788 return 1;
789 }
790
791 /* escape any characters that the database server cannot digest */
792 if (dbi_conn_quote_string(conn, &myarg) == 0) {
793 dbi_conn_close(conn);
794 free(myarg);
795 send_status(ptr_clrequest->fd, 801, TERM_NO);
796 LOG_PRINT(LOG_CRIT, get_status_msg(801));
797 return 1;
798 }
799
800 snprintf(sql_command, 256, "SELECT DISTINCT user_name FROM t_user WHERE user_name %s %s", my_dbi_conn_get_cap(conn, "rlike"), myarg);
801 dbires = dbi_conn_query(conn, sql_command);
802 LOG_PRINT(LOG_DEBUG, sql_command);
803
804 if (dbires) {
805 while (dbi_result_next_row(dbires)) {
806 username = dbi_result_get_string(dbires, "user_name");
807 if (username) {
808 /* reuse sql_command */
809 sprintf(sql_command, "%s\n", username);
810 if ((new_msg = mstrcat(ptr_addresult->msg, sql_command, &(ptr_addresult->msg_len), 0)) == NULL) {
811 dbi_conn_close(conn);
812 free(myarg);
813 send_status(ptr_clrequest->fd, 801, TERM_NO);
814 LOG_PRINT(LOG_CRIT, get_status_msg(801));
815 return 1;
816 }
817 else {
818 ptr_addresult->msg = new_msg;
819 }
820 ptr_addresult->success++;
821 }
822 }
823 dbi_result_free(dbires);
824 }
825 else {
826 /* select failed */
827 dbi_conn_close(conn);
828 free(myarg);
829 send_status(ptr_clrequest->fd, 234, TERM_NO);
830 LOG_PRINT(LOG_DEBUG, get_status_msg(234));
831 return 1;
832 }
833 dbi_conn_close(conn);
834 free(myarg);
835
836 /* send back result to client */
837 send_status(ptr_clrequest->fd, 0, TERM_NO);
838 tiwrite(ptr_clrequest->fd, ptr_addresult->msg, TERM_YES);
839
840 return 0;
841 }
842 else {
843 send_status(ptr_clrequest->fd, 204, TERM_NO);
844 LOG_PRINT(LOG_WARNING, get_status_msg(204));
845 return 1;
846 }
847 }
848
849 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
850 listword(): implements the client command listword
851
852 int listword returns 0 if ok, >0 if error
853
854 struct CLIENT_REQUEST* ptr_clrequest ptr to structure with client info
855
856 struct ADDRESULT* ptr_addresult ptr to struct with counters
857
858 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
listword(struct CLIENT_REQUEST * ptr_clrequest,struct ADDRESULT * ptr_addresult)859 int listword(struct CLIENT_REQUEST* ptr_clrequest, struct ADDRESULT* ptr_addresult) {
860 dbi_conn conn;
861 dbi_result dbires;
862 dbi_driver driver;
863 char sql_command[512];
864 const char* wordname;
865 char* myarg;
866
867 /* connect to the database */
868 if ((conn = connect_to_db(ptr_clrequest, NULL, 0)) != NULL) {
869 driver = dbi_conn_get_driver(conn);
870
871 if (ptr_clrequest->argument && *(ptr_clrequest->argument)) {
872 myarg = strdup(ptr_clrequest->argument);
873 }
874 else {
875 myarg = strdup(my_dbi_driver_get_cap(driver, "listall")); /* list all if no argument is specified */
876 }
877
878 if (!myarg) {
879 dbi_conn_close(conn);
880 send_status(ptr_clrequest->fd, 801, TERM_NO);
881 LOG_PRINT(LOG_CRIT, get_status_msg(801));
882 return 1;
883 }
884
885 /* escape any characters that the database server cannot digest */
886 if (dbi_conn_quote_string(conn, &myarg) == 0) {
887 dbi_conn_close(conn);
888 free(myarg);
889 send_status(ptr_clrequest->fd, 801, TERM_NO);
890 LOG_PRINT(LOG_CRIT, get_status_msg(801));
891 return 1;
892 }
893
894 snprintf(sql_command, 512, "SELECT DISTINCT name FROM t_journal_words WHERE name %s %s", my_dbi_conn_get_cap(conn, "rlike"), myarg);
895 LOG_PRINT(LOG_DEBUG, sql_command);
896
897 dbires = dbi_conn_query(conn, sql_command);
898 if (dbires) {
899 send_status(ptr_clrequest->fd, 0, TERM_NO);
900
901 while (dbi_result_next_row(dbires)) {
902 wordname = dbi_result_get_string(dbires, "name");
903 if (wordname) {
904 tiwrite(ptr_clrequest->fd, wordname, TERM_NO);
905 tiwrite(ptr_clrequest->fd, "\n", TERM_NO);
906 ptr_addresult->success++;
907 }
908 else {
909 ptr_addresult->failure++;
910 }
911 }
912 dbi_result_free(dbires);
913
914 /* terminate message */
915 tiwrite(ptr_clrequest->fd, "", TERM_YES);
916 }
917 else {
918 /* select failed */
919 dbi_conn_close(conn);
920 free(myarg);
921 send_status(ptr_clrequest->fd, 234, TERM_NO);
922 LOG_PRINT(LOG_DEBUG, get_status_msg(234));
923 return 1;
924 }
925
926 dbi_conn_close(conn);
927 free(myarg);
928
929 return 0;
930 }
931 else {
932 send_status(ptr_clrequest->fd, 204, TERM_NO);
933 LOG_PRINT(LOG_WARNING, get_status_msg(204));
934 return 1;
935 }
936 }
937
938 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
939 createdb(): implements the client command createdb
940
941 int createdb returns 2 if error, 0 if successful
942
943 struct CLIENT_REQUEST* ptr_clrequest ptr to structure with client info
944
945 const char* db_encoding name of the character encoding to use
946
947 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
createdb(struct CLIENT_REQUEST * ptr_clrequest,struct ADDRESULT * ptr_addresult,int optind)948 int createdb(struct CLIENT_REQUEST* ptr_clrequest, struct ADDRESULT* ptr_addresult, int optind) {
949 int result;
950 char* new_msg;
951 char message[128];
952
953 if ((ptr_addresult->msg = malloc(512)) == NULL) {
954 send_status(ptr_clrequest->fd, 801, TERM_NO);
955 LOG_PRINT(LOG_CRIT, get_status_msg(801));
956 return 1;
957 }
958
959 *(ptr_addresult->msg) = '\0';
960
961 /* loop over all filename arguments */
962 for (; optind < ptr_clrequest->inargc; optind++) {
963 result = real_createdb(ptr_clrequest, ptr_clrequest->inargv[optind], ptr_addresult);
964 if (result == 1) {
965 ptr_addresult->failure++;
966 /* message is already in place */
967 send_status(ptr_clrequest->fd, 801, TERM_NO);
968 LOG_PRINT(LOG_CRIT, get_status_msg(801));
969 return 1;
970 }
971 else if (result) {
972 ptr_addresult->failure++;
973 /* message is already in place */
974 }
975 else {
976 ptr_addresult->success++;
977 snprintf(message, 128, "235:%s\n", ptr_clrequest->inargv[optind]);
978
979 if ((new_msg = mstrcat(ptr_addresult->msg, message, &(ptr_addresult->msg_len), 0)) == NULL) {
980 send_status(ptr_clrequest->fd, 801, TERM_NO);
981 LOG_PRINT(LOG_CRIT, get_status_msg(801));
982 return 1;
983 }
984 else {
985 ptr_addresult->msg = new_msg;
986 }
987 }
988 }
989
990 send_status(ptr_clrequest->fd, 0, TERM_NO);
991 tiwrite(ptr_clrequest->fd, ptr_addresult->msg, TERM_YES);
992
993 return 0;
994 }
995
996 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
997 real_createdb(): creates a database
998
999 int real_createdb returns 1 if mem error, 2 if other error, 0 if successful
1000
1001 struct CLIENT_REQUEST* ptr_clrequest ptr to structure with client info
1002
1003 const char* dbname ptr to string with the database name
1004
1005 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
real_createdb(struct CLIENT_REQUEST * ptr_clrequest,const char * dbname,struct ADDRESULT * ptr_addresult)1006 int real_createdb(struct CLIENT_REQUEST* ptr_clrequest, const char* dbname, struct ADDRESULT* ptr_addresult) {
1007 dbi_conn conn = NULL;
1008 dbi_result dbires;
1009 int error;
1010 int retval = 0;
1011 char date_buffer[24];
1012 char message[128] = "";
1013 char *sql_command = NULL;
1014 char *new_msg;
1015 const char *drivername;
1016 time_t the_time;
1017
1018 /* it is not necessary to quote database names */
1019
1020 /* connect to the main database */
1021 if ((conn = connect_to_db(ptr_clrequest, main_db, 0)) == NULL) {
1022 LOG_PRINT(LOG_WARNING, get_status_msg(202));
1023 snprintf(message, 128, "202:%s\n", dbname);
1024 retval = 2;
1025 goto finish;
1026 }
1027
1028 drivername = dbi_driver_get_name(dbi_conn_get_driver(conn));
1029
1030 /* allocate a buffer to assemble the sql command (give some extra byte
1031 for the command and encoding strings */
1032 sql_command = malloc((size_t)(strlen(dbname) + 256));
1033 if (sql_command == NULL) { /* malloc failed */
1034 LOG_PRINT(LOG_CRIT, get_status_msg(801));
1035 snprintf(message, 128, "801:%s\n", dbname);
1036 retval = 1;
1037 goto finish;
1038 }
1039
1040 /* create a new database. There is no such SQL command for sqlite.
1041 sqlite will create the database for us as soon as we try to access
1042 it */
1043
1044 if (strcmp(drivername, "sqlite")
1045 && strcmp(drivername, "sqlite3")) {
1046 const char* encoding_string;
1047
1048 encoding_string = my_dbi_conn_get_cap(conn, "encoding");
1049
1050 /* assemble sql command */
1051 if (*encoding_string) {
1052 if (ptr_clrequest->db_encoding && *(ptr_clrequest->db_encoding)) {
1053 sprintf(sql_command, "CREATE DATABASE %s %s '%s'", dbname, encoding_string, dbi_driver_encoding_from_iana(dbi_conn_get_driver(conn), ptr_clrequest->db_encoding));
1054 }
1055 else { /* use default encoding of db server */
1056 sprintf(sql_command, "CREATE DATABASE %s", dbname);
1057 }
1058 }
1059 else {
1060 if (ptr_clrequest->db_encoding && *(ptr_clrequest->db_encoding)) {
1061 LOG_PRINT(LOG_WARNING, "database engine does not support per-database character encodings, used default encoding instead");
1062 }
1063
1064 /* db engine does not support database-based encodings */
1065 sprintf(sql_command, "CREATE DATABASE %s", dbname);
1066 }
1067
1068 LOG_PRINT(LOG_DEBUG, sql_command);
1069
1070 dbires = dbi_conn_query(conn, sql_command);
1071
1072 if (dbires == NULL) {
1073 LOG_PRINT(LOG_ERR, get_status_msg(209));
1074 snprintf(message, 128, "209:%s\n", dbname);
1075 retval = 2;
1076 goto finish;
1077 }
1078
1079 dbi_result_free(dbires);
1080 }
1081 else if (ptr_clrequest->db_encoding && *(ptr_clrequest->db_encoding)) { /* if sqlite */
1082 LOG_PRINT(LOG_WARNING, "database engine does not support per-database character encodings, used default encoding instead");
1083 } /* end if not sqlite */
1084
1085 /* now we have to create the tables */
1086 if (!strcmp(my_dbi_conn_get_cap(conn, "multiple_db"), "t")) {
1087 /* we switch over to the new database */
1088 error = dbi_conn_select_db(conn, dbname);
1089 if (error) {
1090 LOG_PRINT(LOG_WARNING, get_status_msg(204));
1091 snprintf(message, 128, "204:%s\n", dbname);
1092 retval = 2;
1093 goto finish;
1094 }
1095 /* if (!strcmp(drivername, "mysql")) { */
1096 if ((error = create_tables_mysql(conn, ptr_clrequest, 0)) != 0) {
1097 /* function provides log message */
1098 snprintf(message, 128, "%d:%s\n", error, dbname);
1099 retval = 2;
1100 goto finish;
1101 }
1102 }
1103 else {
1104 /* we need a new connection to the fresh database */
1105 dbi_conn_close(conn);
1106
1107 /* do not check the database as it is brand new */
1108 if ((conn = connect_to_db(ptr_clrequest, dbname, 1)) == NULL) {
1109 LOG_PRINT(LOG_WARNING, get_status_msg(204));
1110 snprintf(message, 128, "204:%s\n", dbname);
1111 retval = 2;
1112 goto finish;
1113 }
1114
1115 if (!strcmp(drivername, "pgsql")) {
1116 if ((error = create_tables_pgsql(conn, ptr_clrequest, 0)) != 0) {
1117 /* function provides log message */
1118 snprintf(message, 128, "%d:%s\n", error, dbname);
1119 retval = 2;
1120 goto finish;
1121 }
1122 }
1123 else if (!strcmp(drivername, "sqlite")) {
1124 if ((error = create_tables_sqlite(conn, ptr_clrequest, 0)) != 0) {
1125 /* function provides log message */
1126 snprintf(message, 128, "%d:%s\n", error, dbname);
1127 retval = 2;
1128 goto finish;
1129 }
1130 }
1131 else if (!strcmp(drivername, "sqlite3")) {
1132 if ((error = create_tables_sqlite3(conn, ptr_clrequest, 0)) != 0) {
1133 /* function provides log message */
1134 snprintf(message, 128, "%d:%s\n", error, dbname);
1135 retval = 2;
1136 goto finish;
1137 }
1138 }
1139 /* else: should never happen */
1140 }
1141
1142 /* insert the meta data */
1143 time(&the_time);
1144 strftime(date_buffer, 24, "%Y-%m-%d %H:%M:%S", gmtime(&the_time));
1145 sprintf(sql_command, "INSERT INTO t_meta (meta_app,meta_type,meta_version,meta_dbversion,meta_create_date,meta_modify_date) VALUES (\'%s\', \'risx\', \'%s\', \'%d\', \'%s\', \'%s\')", PACKAGE, VERSION, DB_VERSION, date_buffer, date_buffer);
1146 LOG_PRINT(LOG_DEBUG, sql_command);
1147
1148 dbires = dbi_conn_query(conn, sql_command);
1149
1150 if (!dbires) {
1151 LOG_PRINT(LOG_ERR, get_status_msg(210));
1152 snprintf(message, 128, "210:%s\n", dbname);
1153 retval = 2;
1154 goto finish;
1155 }
1156
1157 dbi_result_free(dbires);
1158
1159 finish:
1160
1161 if (*message) {
1162 if ((new_msg = mstrcat(ptr_addresult->msg, message, &(ptr_addresult->msg_len), 0)) == NULL) {
1163 LOG_PRINT(LOG_CRIT, get_status_msg(801));
1164 retval = 1;
1165 }
1166 else {
1167 ptr_addresult->msg = new_msg;
1168 }
1169 }
1170
1171 /* cleanup */
1172 dbi_conn_close(conn);
1173 free(sql_command);
1174
1175 return retval;
1176 }
1177
1178 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1179 deletedb(): implements the client command deletedb
1180
1181 int deletedb returns 0 if failed, 1 if successful
1182
1183 struct CLIENT_REQUEST* ptr_clrequest ptr to structure with client info
1184
1185 int optind index for inargv
1186
1187 struct ADDRESULT* ptr_addresult ptr to struct with counters
1188
1189 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
deletedb(struct CLIENT_REQUEST * ptr_clrequest,int optind,struct ADDRESULT * ptr_addresult)1190 int deletedb(struct CLIENT_REQUEST* ptr_clrequest, int optind, struct ADDRESULT* ptr_addresult) {
1191 dbi_conn conn;
1192 dbi_result dbires;
1193 int error;
1194 char* sql_command;
1195 char* dbname;
1196 char* new_msg;
1197 const char* drivername;
1198
1199 /* it is not necessary to quote the database name */
1200
1201 /* allocate a buffer to assemble the sql command. We require
1202 _POSIX_PATH_MAX for the sqlite driver, but this will be more than
1203 enough for database names of other drivers */
1204 sql_command = malloc((size_t)_POSIX_PATH_MAX);
1205 if (sql_command == NULL) { /* malloc failed */
1206 send_status(ptr_clrequest->fd, 801, TERM_NO);
1207 LOG_PRINT(LOG_CRIT, get_status_msg(801));
1208 return 1;
1209 }
1210
1211 ptr_addresult->msg_len = 1024;
1212 ptr_addresult->msg = malloc(ptr_addresult->msg_len);
1213 if (ptr_addresult->msg == NULL) {
1214 free(sql_command);
1215 send_status(ptr_clrequest->fd, 801, TERM_NO);
1216 LOG_PRINT(LOG_CRIT, get_status_msg(801));
1217 return 1;
1218 }
1219
1220 *(ptr_addresult->msg) = '\0';
1221
1222 /* connect to main database */
1223 if ((conn = connect_to_db(ptr_clrequest, NULL, 0)) == NULL) {
1224 send_status(ptr_clrequest->fd, 202, TERM_NO);
1225 LOG_PRINT(LOG_WARNING, get_status_msg(202));
1226 return 1;
1227 }
1228
1229 drivername = dbi_driver_get_name(dbi_conn_get_driver(conn));
1230
1231 for (; optind < ptr_clrequest->inargc; optind++) {
1232 dbname = ptr_clrequest->inargv[optind];
1233
1234 error = 0;
1235
1236 if (!strcmp(drivername, "sqlite")
1237 || !strcmp(drivername, "sqlite3")) {
1238 /* sqlite has no SQL way to drop databases. Try to remove the
1239 database file from the file system manually */
1240 strcpy(sql_command, ptr_clrequest->db_path);
1241 if (sql_command[strlen(sql_command)-1] != '/') {
1242 strcat(sql_command, "/");
1243 }
1244 strcat(sql_command, dbname);
1245
1246 if (unlink(sql_command)) {
1247 /* todo: ERRNO contains reason of failure */
1248 sprintf(sql_command, "249:%s\n", dbname);
1249 if ((new_msg = mstrcat(ptr_addresult->msg, sql_command, &(ptr_addresult->msg_len), 0)) == NULL) {
1250 send_status(ptr_clrequest->fd, 801, TERM_NO);
1251 LOG_PRINT(LOG_CRIT, get_status_msg(801));
1252 free(sql_command);
1253 return 1;
1254 }
1255 else {
1256 ptr_addresult->msg = new_msg;
1257 }
1258 error++;
1259 }
1260 }
1261 else {
1262 /* other databases */
1263
1264 /* assemble sql command */
1265 strcpy(sql_command, "DROP DATABASE ");
1266 strcat(sql_command, dbname);
1267
1268 LOG_PRINT(LOG_DEBUG, sql_command);
1269
1270 dbires = dbi_conn_query(conn, sql_command);
1271
1272 /* Postgres does not set numrows_affected for DROP statements so
1273 we can't check easily whether the database was dropped */
1274 if (!dbires
1275 || (strcmp(drivername, "pgsql")
1276 && !dbi_result_get_numrows_affected(dbires))) {
1277 sprintf(sql_command, "249:%s\n", dbname);
1278 if ((new_msg = mstrcat(ptr_addresult->msg, sql_command, &(ptr_addresult->msg_len), 0)) == NULL) {
1279 send_status(ptr_clrequest->fd, 801, TERM_NO);
1280 LOG_PRINT(LOG_CRIT, get_status_msg(801));
1281 free(sql_command);
1282 return 1;
1283 }
1284 else {
1285 ptr_addresult->msg = new_msg;
1286 }
1287 error++;
1288 }
1289 else {
1290 dbi_result_free(dbires);
1291 }
1292
1293 if (!strcmp(drivername, "pgsql")) {
1294 /* With PostgreSQL we keep a group to manage access rights for each
1295 database. When dropping the database we drop the group too. This
1296 does not affect the existence of the users contained in this group */
1297 if (is_group_pgsql(conn, dbname, 0 /* read/write */) == 1) {
1298 sprintf(sql_command, "DROP GROUP %suser", ptr_clrequest->argument);
1299
1300 LOG_PRINT(LOG_DEBUG, sql_command);
1301
1302 dbires = dbi_conn_query(conn, sql_command);
1303 if (!dbires /*dbi_conn_error_flag(conn)*/) {
1304 sprintf(sql_command, "250:%s\n", dbname);
1305 if ((new_msg = mstrcat(ptr_addresult->msg, sql_command, &(ptr_addresult->msg_len), 0)) == NULL) {
1306 send_status(ptr_clrequest->fd, 801, TERM_NO);
1307 LOG_PRINT(LOG_CRIT, get_status_msg(801));
1308 free(sql_command);
1309 return 1;
1310 }
1311 else {
1312 ptr_addresult->msg = new_msg;
1313 }
1314 }
1315 else {
1316 dbi_result_free(dbires);
1317 }
1318 }
1319
1320 if (is_group_pgsql(conn, dbname, 1 /* read-only */) == 1) {
1321 sprintf(sql_command, "DROP GROUP %sruser", ptr_clrequest->argument);
1322
1323 LOG_PRINT(LOG_DEBUG, sql_command);
1324
1325 dbires = dbi_conn_query(conn, sql_command);
1326 if (!dbires /*dbi_conn_error_flag(conn)*/) {
1327 sprintf(sql_command, "250:%s\n", dbname);
1328 if ((new_msg = mstrcat(ptr_addresult->msg, sql_command, &(ptr_addresult->msg_len), 0)) == NULL) {
1329 send_status(ptr_clrequest->fd, 801, TERM_NO);
1330 LOG_PRINT(LOG_CRIT, get_status_msg(801));
1331 free(sql_command);
1332 return 1;
1333 }
1334 else {
1335 ptr_addresult->msg = new_msg;
1336 }
1337 }
1338 else {
1339 dbi_result_free(dbires);
1340 }
1341 }
1342 } /* end if pgsql */
1343 } /* end if other databases */
1344
1345 if (error) {
1346 ptr_addresult->failure++;
1347 }
1348 else {
1349 sprintf(sql_command, "251:%s\n", dbname);
1350 if ((new_msg = mstrcat(ptr_addresult->msg, sql_command, &(ptr_addresult->msg_len), 0)) == NULL) {
1351 send_status(ptr_clrequest->fd, 801, TERM_NO);
1352 LOG_PRINT(LOG_CRIT, get_status_msg(801));
1353 free(sql_command);
1354 return 1;
1355 }
1356 else {
1357 ptr_addresult->msg = new_msg;
1358 }
1359 ptr_addresult->success++;
1360 }
1361 } /* end for */
1362
1363 dbi_conn_close(conn);
1364
1365 send_status(ptr_clrequest->fd, 0, TERM_NO);
1366 tiwrite(ptr_clrequest->fd, ptr_addresult->msg, TERM_YES);
1367
1368 free(sql_command);
1369 return 0;
1370 }
1371
1372 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1373 adduser(): implements the client command adduser
1374
1375 int adduser returns 1 if mem error, 2 if other error, 0 if successful
1376
1377 struct CLIENT_REQUEST* ptr_clrequest ptr to structure with client info
1378
1379 char *user_host string containing the name of the host from which
1380 username will access the database. This is actually
1381 the host on which the refdbd runs that username
1382 will use to access the database. if user_host is
1383 NULL, it will be set to localhost
1384
1385 char *newuser_passwd string with the password for new users
1386
1387 int n_remove if 0, access will be granted. if 1, access will be revoked
1388
1389 int n_readonly if 0, user will have read/write access. If 1, user
1390 will have read-only access
1391
1392 struct ADDRESULT* ptr_addresult ptr to structure receiving the result
1393
1394 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
adduser(struct CLIENT_REQUEST * ptr_clrequest,char * user_host,char * newuser_passwd,int n_remove,int n_readonly,struct ADDRESULT * ptr_addresult)1395 int adduser(struct CLIENT_REQUEST* ptr_clrequest, char *user_host, char *newuser_passwd, int n_remove, int n_readonly, struct ADDRESULT* ptr_addresult) {
1396 dbi_conn conn;
1397 dbi_result dbires;
1398 int nread_done = 0;
1399 int inbuffer_len;
1400 int numbyte;
1401 int nhave_refdb;
1402 int n_host_regex = 0;
1403 int n_user_regex = 0;
1404 int n_client_status;
1405 size_t token_size;
1406 char *sql_command;
1407 char *inbuffer;
1408 char *new_inbuffer;
1409 char *token;
1410 char *userathost;
1411 char *new_msg;
1412 const char *item;
1413 const char *drivername;
1414 char localhost[] = "localhost";
1415 char message[128] = "";
1416 struct lilimem sentinel;
1417
1418 sentinel.ptr_mem = NULL;
1419 sentinel.ptr_next = NULL;
1420 sentinel.varname[0] = '\0';
1421
1422 sql_command = malloc(1024);
1423 if (sql_command == NULL || insert_lilimem(&sentinel, (void**)&sql_command, NULL)) {
1424 send_status(ptr_clrequest->fd, 801, TERM_NO);
1425 LOG_PRINT(LOG_CRIT, get_status_msg(801));
1426 return 1;
1427 }
1428
1429 inbuffer_len = (size_t)COMMAND_INBUF_LEN;
1430 inbuffer = malloc(inbuffer_len);
1431 if (inbuffer == NULL || insert_lilimem(&sentinel, (void**)&inbuffer, NULL)) {
1432 delete_all_lilimem(&sentinel);
1433 send_status(ptr_clrequest->fd, 801, TERM_NO);
1434 LOG_PRINT(LOG_CRIT, get_status_msg(801));
1435 return 1;
1436 }
1437
1438 ptr_addresult->msg_len = 1024;
1439 ptr_addresult->msg = malloc(ptr_addresult->msg_len);
1440 if (ptr_addresult->msg == NULL) {
1441 delete_all_lilimem(&sentinel);
1442 send_status(ptr_clrequest->fd, 801, TERM_NO);
1443 LOG_PRINT(LOG_CRIT, get_status_msg(801));
1444 return 1;
1445 }
1446
1447 *(ptr_addresult->msg) = '\0';
1448
1449 /* connect to the main database */
1450 if ((conn = connect_to_db(ptr_clrequest, NULL, 0)) != NULL) {
1451 /* see what driver we use */
1452 drivername = dbi_driver_get_name(dbi_conn_get_driver(conn));
1453
1454 if (!strcmp(drivername, "sqlite")
1455 || !strcmp(drivername, "sqlite3")) {
1456 /* driver does not support SQL-based access control */
1457 send_status(ptr_clrequest->fd, 224, TERM_NO);
1458 LOG_PRINT(LOG_WARNING, "999:access control not supported");
1459 dbi_conn_close(conn);
1460 delete_all_lilimem(&sentinel);
1461 return 1;
1462 }
1463
1464 /* send back confirmation to the client */
1465 send_status(ptr_clrequest->fd, 0, TERM_NO);
1466
1467 /* read from client and increase buffer size until we have all arguments */
1468 if ((n_client_status = read_status(ptr_clrequest->fd))) {
1469 delete_all_lilimem(&sentinel);
1470 LOG_PRINT(LOG_WARNING, get_status_msg(n_client_status));
1471 return 1;
1472 }
1473
1474 while (!nread_done) {
1475 numbyte = tread(ptr_clrequest->fd, inbuffer, COMMAND_INBUF_LEN-1);
1476 if (get_trailz(inbuffer, numbyte) == TERM_LEN) { /* if transmission complete */
1477 nread_done = 1;
1478 }
1479 else {
1480 inbuffer_len += (size_t)COMMAND_INBUF_LEN;
1481 if ((new_inbuffer = (char*)realloc(inbuffer, inbuffer_len)) == NULL) {
1482 delete_all_lilimem(&sentinel);
1483 send_status(ptr_clrequest->fd, 801, TERM_NO);
1484 LOG_PRINT(LOG_CRIT, get_status_msg(801));
1485 dbi_conn_close(conn);
1486 return 0;
1487 }
1488 else {
1489 inbuffer = new_inbuffer;
1490 }
1491 }
1492 }
1493
1494
1495 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++ */
1496 /* mysql */
1497
1498 /* mysqld keeps authentication information in the mysql
1499 database. These data are used for all user databases.
1500 Therefore we need only one entry to allow access to
1501 the database server, and entries per database to
1502 allow access to the databases themselves */
1503 if (!strcmp(drivername, "mysql")) {
1504 int create_new = 0;
1505 char lockstring[64];
1506 struct VERSIONINFO ver;
1507
1508 /* obtain database server version info */
1509 if (my_dbi_conn_get_versioninfo(conn, &ver)) {
1510 send_status(ptr_clrequest->fd, 205, TERM_NO);
1511 LOG_PRINT(LOG_ERR, get_status_msg(205));
1512 dbi_conn_close(conn);
1513 delete_all_lilimem(&sentinel);
1514 return 1;
1515 }
1516
1517 /* MySQL 4.0.2 introduced new privileges "LOCK TABLES" and
1518 "CREATE TEMPORARY TABLES". As older versions will barf at it,
1519 add them only if we use a newer version */
1520 if (!n_readonly
1521 && ((ver.major == 4 && ver.minor == 0 && ver.minuscule >=2)
1522 || (ver.major == 4 && ver.minor > 0)
1523 || ver.major > 4)) {
1524 strcpy(lockstring, ",LOCK TABLES, CREATE TEMPORARY TABLES");
1525 }
1526 else if (n_readonly
1527 && ((ver.major == 4 && ver.minor == 0 && ver.minuscule >=2)
1528 || (ver.major == 4 && ver.minor > 0)
1529 || ver.major > 4)){
1530 strcpy(lockstring, ",LOCK TABLES ");
1531 }
1532 else {
1533 strcpy(lockstring, " ");
1534 }
1535
1536 /* use localhost if no host was specified */
1537 if (!*user_host) {
1538 strcat(ptr_addresult->msg, "236\n");
1539 LOG_PRINT(LOG_INFO, get_status_msg(236));
1540 user_host = localhost;
1541 }
1542
1543 /* select mysql database */
1544 if (dbi_conn_select_db(conn, "mysql") == -1) {
1545 send_status(ptr_clrequest->fd, 205, TERM_NO);
1546 LOG_PRINT(LOG_ERR, get_status_msg(205));
1547 dbi_conn_close(conn);
1548 delete_all_lilimem(&sentinel);
1549 return 1;
1550 }
1551
1552 /* see whether the host info is a SQL regexp */
1553 if (strchr(user_host, (int)'%') || strchr(user_host, (int)'_')) {
1554 n_host_regex = 1;
1555 }
1556 else {
1557 n_host_regex = 0;
1558 }
1559
1560 token = inbuffer;
1561 token_size = -1;
1562
1563 userathost = malloc(USERNAME_LENGTH + HOSTNAME_LENGTH + 16);
1564 if (userathost == NULL || insert_lilimem(&sentinel, (void**)&userathost, NULL)) {
1565 send_status(ptr_clrequest->fd, 801, TERM_NO);
1566 LOG_PRINT(LOG_CRIT, get_status_msg(801));
1567 return 1;
1568 }
1569
1570 do {
1571 token = nstrtok(token + token_size + 1, &token_size, " ");
1572 if (token != NULL) {
1573 token[token_size] = '\0';
1574
1575 /* see whether the user info is a SQL regexp */
1576 if (strchr(token, (int)'%') || strchr(token, (int)'_')) {
1577 n_user_regex = 1;
1578 }
1579 else {
1580 n_user_regex = 0;
1581 }
1582
1583 if (n_remove) {
1584 if (n_user_regex || n_host_regex) {
1585 sprintf(sql_command, "REVOKE ALL ON %s.* FROM \'%s\'@\'%s\'", ptr_clrequest->current_db, token, user_host);
1586 }
1587 else {
1588 sprintf(sql_command, "REVOKE ALL ON %s.* FROM %s@%s", ptr_clrequest->current_db, token, user_host);
1589 }
1590 }
1591 else {
1592 /* check whether the given user/host combo exists in User table */
1593 sprintf(sql_command, "SELECT User FROM user WHERE User LIKE \'%s\' AND Host LIKE \'%s\'", token, user_host);
1594 LOG_PRINT(LOG_DEBUG, sql_command);
1595 dbires = dbi_conn_query(conn, sql_command);
1596 if (!dbires) {
1597 ptr_addresult->failure++;
1598 LOG_PRINT(LOG_WARNING, get_status_msg(234));
1599 snprintf(message, 128, "234:%s@%s:%s\n", token, user_host, ptr_clrequest->current_db);
1600 if ((new_msg = mstrcat(ptr_addresult->msg, message, &(ptr_addresult->msg_len), 0)) == NULL) {
1601 send_status(ptr_clrequest->fd, 801, TERM_NO);
1602 LOG_PRINT(LOG_CRIT, get_status_msg(801));
1603 return 1;
1604 }
1605 else {
1606 ptr_addresult->msg = new_msg;
1607 }
1608 continue;
1609 }
1610
1611 if (!dbi_result_get_numrows(dbires) && !n_user_regex) { /* user does not exist yet and does not contain regexp */
1612 create_new++;
1613 }
1614
1615 dbi_result_free(dbires);
1616
1617 /* check whether this host/user combo has access rights to
1618 refdb. If not, create as well */
1619 /* reset variables */
1620 nhave_refdb = 0;
1621 sprintf(sql_command, "SELECT User,Db FROM db WHERE User=\'%s\' AND Host=\'%s\' AND Db=\'%s\'", token, user_host, main_db);
1622 LOG_PRINT(LOG_DEBUG, sql_command);
1623 dbires = dbi_conn_query(conn, sql_command);
1624 if (!dbires) {
1625 ptr_addresult->failure++;
1626 LOG_PRINT(LOG_WARNING, get_status_msg(234));
1627 snprintf(message, 128, "234:%s@%s:%s\n", token, user_host, ptr_clrequest->current_db);
1628 if ((new_msg = mstrcat(ptr_addresult->msg, message, &(ptr_addresult->msg_len), 0)) == NULL) {
1629 send_status(ptr_clrequest->fd, 801, TERM_NO);
1630 LOG_PRINT(LOG_CRIT, get_status_msg(801));
1631 return 1;
1632 }
1633 else {
1634 ptr_addresult->msg = new_msg;
1635 }
1636 continue;
1637 }
1638
1639 while (dbi_result_next_row(dbires)) {
1640 item = dbi_result_get_string_idx(dbires, 2);
1641 if (!strcmp(item, main_db)) {
1642 nhave_refdb = 1;
1643 }
1644 }
1645
1646 dbi_result_free(dbires);
1647
1648 if (n_user_regex || n_host_regex) {
1649 sprintf(userathost, "\'%s\'@\'%s\'", token, user_host);
1650 }
1651 else {
1652 sprintf(userathost, "%s@%s", token, user_host);
1653 }
1654
1655 if (!nhave_refdb || (newuser_passwd && *newuser_passwd)) { /* user does not have access rights to refdb */
1656 if (newuser_passwd && *newuser_passwd) {
1657 /* if the user doesn't exist yet, this command will create
1658 a new user with the given password. If the user already
1659 exists, the password will be changed to the one given */
1660 if (!n_readonly) {
1661 sprintf(sql_command, "GRANT SELECT, INSERT, UPDATE, DELETE%s ON %s.* TO %s IDENTIFIED BY \'%s\'", lockstring, main_db, userathost, newuser_passwd);
1662 }
1663 else {
1664 sprintf(sql_command, "GRANT SELECT%s ON %s.* TO %s IDENTIFIED BY \'%s\'", lockstring, main_db, userathost, newuser_passwd);
1665 }
1666 }
1667 else if (create_new) {
1668 /* avoid possible security risk: we provide a default
1669 password to avoid creating users with no passwords */
1670 if (!n_readonly) {
1671 sprintf(sql_command, "GRANT SELECT, INSERT, UPDATE, DELETE%s ON %s.* TO %s IDENTIFIED BY \'refdb\'", lockstring, main_db, userathost);
1672 }
1673 else {
1674 sprintf(sql_command, "GRANT SELECT%s ON %s.* TO %s IDENTIFIED BY \'refdb\'", lockstring, main_db, userathost);
1675 }
1676 }
1677 else {
1678 /* the user already exists and we don't touch the password */
1679 if (!n_readonly) {
1680 sprintf(sql_command, "GRANT SELECT, INSERT, UPDATE, DELETE%s ON %s.* TO %s", lockstring, main_db, userathost);
1681 }
1682 else {
1683 sprintf(sql_command, "GRANT SELECT%s ON %s.* TO %s", lockstring, main_db, userathost);
1684 }
1685 }
1686 LOG_PRINT(LOG_DEBUG, sql_command);
1687 dbires = dbi_conn_query(conn, sql_command);
1688 if (!dbires) {
1689 ptr_addresult->failure++;
1690 LOG_PRINT(LOG_WARNING, get_status_msg(223));
1691 snprintf(message, 128, "223:%s@%s:%s\n", token, user_host, ptr_clrequest->current_db);
1692 if ((new_msg = mstrcat(ptr_addresult->msg, message, &(ptr_addresult->msg_len), 0)) == NULL) {
1693 send_status(ptr_clrequest->fd, 801, TERM_NO);
1694 LOG_PRINT(LOG_CRIT, get_status_msg(801));
1695 return 1;
1696 }
1697 else {
1698 ptr_addresult->msg = new_msg;
1699 }
1700 continue;
1701 }
1702 dbi_result_free(dbires);
1703 }
1704
1705
1706 /* now handle the requested database. Users need CREATE and
1707 DROP privileges for temp tables during bibliography creation*/
1708 if (n_user_regex || n_host_regex) {
1709 if (!n_readonly) {
1710 sprintf(sql_command, "GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP%s ON %s.* TO \'%s\'@\'%s\'", lockstring, ptr_clrequest->current_db, token, user_host);
1711 }
1712 else {
1713 sprintf(sql_command, "GRANT SELECT%s ON %s.* TO \'%s\'@\'%s\'", lockstring, ptr_clrequest->current_db, token, user_host);
1714 }
1715 }
1716 else {
1717 if (!n_readonly) {
1718 sprintf(sql_command, "GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP%s ON %s.* TO %s@%s", lockstring, ptr_clrequest->current_db, token, user_host);
1719 }
1720 else {
1721 sprintf(sql_command, "GRANT SELECT%s ON %s.* TO %s@%s", lockstring, ptr_clrequest->current_db, token, user_host);
1722 }
1723 }
1724 }
1725 LOG_PRINT(LOG_DEBUG, sql_command);
1726 dbires = dbi_conn_query(conn, sql_command);
1727 if (!dbires) {
1728 ptr_addresult->failure++;
1729 if (!n_remove) {
1730 LOG_PRINT(LOG_WARNING, get_status_msg(223));
1731 snprintf(message, 128, "223:%s@%s:%s\n", token, user_host, ptr_clrequest->current_db);
1732 }
1733 else {
1734 LOG_PRINT(LOG_WARNING, get_status_msg(239));
1735 snprintf(message, 128, "239:%s@%s:%s\n", token, user_host, ptr_clrequest->current_db);
1736 }
1737 }
1738 else {
1739 ptr_addresult->success++;
1740 dbi_result_free(dbires);
1741 if (!n_remove) {
1742 if (user_host && *user_host) {
1743 snprintf(message, 127, "237:%s@%s:%s", token, user_host, ptr_clrequest->current_db);
1744 }
1745 else {
1746 snprintf(message, 127, "237:%s:%s", token, ptr_clrequest->current_db);
1747 }
1748 LOG_PRINT(LOG_INFO, message);
1749 strcat(message, "\n");
1750 }
1751 else {
1752 if (user_host && *user_host) {
1753 snprintf(message, 127, "238:%s@%s:%s", token, user_host, ptr_clrequest->current_db);
1754 }
1755 else {
1756 snprintf(message, 127, "238:%s:%s", token, ptr_clrequest->current_db);
1757 }
1758 LOG_PRINT(LOG_INFO, message);
1759 strcat(message, "\n");
1760 }
1761 }
1762
1763 if ((new_msg = mstrcat(ptr_addresult->msg, message, &(ptr_addresult->msg_len), 0)) == NULL) {
1764 send_status(ptr_clrequest->fd, 801, TERM_NO);
1765 LOG_PRINT(LOG_CRIT, get_status_msg(801));
1766 return 1;
1767 }
1768 else {
1769 ptr_addresult->msg = new_msg;
1770 }
1771 }
1772 } while (token != NULL);
1773
1774 /* reloading permission tables is not necessary when using
1775 the GRANT/REVOKE syntax. Thus quoth the manual, but seeing
1776 is believing */
1777
1778 strcpy(sql_command, "FLUSH PRIVILEGES");
1779 LOG_PRINT(LOG_DEBUG, sql_command);
1780 dbires = dbi_conn_query(conn, sql_command);
1781 }
1782
1783 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++ */
1784 /* pgsql */
1785 else if (!strcmp(drivername, "pgsql")) {
1786 /* PostgreSQL knows users and groups. Access is granted to
1787 tables (and other stuff we don't use here). The system tables
1788 that hold the user and group information are accessible
1789 through connections to any existing database (at least for
1790 the superuser, that is). Each new refdb database creates a
1791 read/write group and a read-only group and grants access for
1792 these groups. We simply add users to or remove them from
1793 these groups. Same for the groups refdbuser/refdbruser which
1794 allow access to the common database refdb
1795 */
1796
1797 token = inbuffer;
1798 token_size = -1;
1799
1800 /* loop over all usernames */
1801 /* ToDo: this loop is inefficient. Better construct a comma-separated
1802 list of users and pass this as an argument to a single ALTER GROUP
1803 command */
1804 do {
1805 token = nstrtok(token + token_size + 1, &token_size, " ");
1806 if (token != NULL) {
1807 token[token_size] = '\0';
1808
1809 if (n_remove) {
1810 /* the current implementation removes only the group membership
1811 for the given database. Users will still have access to the
1812 refdb database. */
1813 /* ToDo: maybe a client command switch can be used to force
1814 removal from group refdbuser */
1815 if (!n_readonly) {
1816 sprintf(sql_command, "ALTER GROUP %suser DROP USER %s", ptr_clrequest->current_db, token);
1817 }
1818 else {
1819 sprintf(sql_command, "ALTER GROUP %sruser DROP USER %s", ptr_clrequest->current_db, token);
1820 }
1821 LOG_PRINT(LOG_DEBUG, sql_command);
1822 dbires = dbi_conn_query(conn, sql_command);
1823 if (!dbires) {
1824 ptr_addresult->failure++;
1825 LOG_PRINT(LOG_WARNING, get_status_msg(239));
1826 snprintf(message, 128, "239:%s@%s:%s\n", token, user_host, ptr_clrequest->current_db);
1827 }
1828 else {
1829 ptr_addresult->success++;
1830 dbi_result_free(dbires);
1831 LOG_PRINT(LOG_WARNING, get_status_msg(238));
1832 if (user_host && *user_host) {
1833 snprintf(message, 128, "238:%s@%s:%s\n", token, user_host, ptr_clrequest->current_db);
1834 }
1835 else {
1836 snprintf(message, 128, "238:%s:%s\n", token, ptr_clrequest->current_db);
1837 }
1838 }
1839 if ((new_msg = mstrcat(ptr_addresult->msg, message, &(ptr_addresult->msg_len), 0)) == NULL) {
1840 send_status(ptr_clrequest->fd, 801, TERM_NO);
1841 LOG_PRINT(LOG_CRIT, get_status_msg(801));
1842 return 1;
1843 }
1844 else {
1845 ptr_addresult->msg = new_msg;
1846 }
1847 }
1848 else { /* add new user */
1849 if (is_user_pgsql(conn, token) != 1) {
1850 sprintf(sql_command, "CREATE USER %s WITH PASSWORD \'%s\'", token, (*newuser_passwd) ? newuser_passwd : "refdb");
1851 LOG_PRINT(LOG_DEBUG, sql_command);
1852 dbires = dbi_conn_query(conn, sql_command);
1853 if (!dbires) {
1854 ptr_addresult->failure++;
1855 LOG_PRINT(LOG_WARNING, get_status_msg(223));
1856 snprintf(message, 128, "223:%s@%s:%s\n", token, user_host, ptr_clrequest->current_db);
1857 if ((new_msg = mstrcat(ptr_addresult->msg, message, &(ptr_addresult->msg_len), 0)) == NULL) {
1858 send_status(ptr_clrequest->fd, 801, TERM_NO);
1859 LOG_PRINT(LOG_CRIT, get_status_msg(801));
1860 return 1;
1861 }
1862 else {
1863 ptr_addresult->msg = new_msg;
1864 }
1865 continue;
1866 }
1867 dbi_result_free(dbires);
1868 }
1869
1870 /* Add user to the group refdbuser */
1871 /* Adding users that already are members will not cause
1872 an error. Checking membership would be extremely tedious as
1873 the user list is implemented as an array instead of
1874 using a separate table */
1875 if (!n_readonly) {
1876 sprintf(sql_command, "ALTER GROUP %suser ADD USER %s", main_db, token);
1877 }
1878 else {
1879 sprintf(sql_command, "ALTER GROUP %sruser ADD USER %s", main_db, token);
1880 }
1881 LOG_PRINT(LOG_DEBUG, sql_command);
1882 dbires = dbi_conn_query(conn, sql_command);
1883 if (!dbires) {
1884 ptr_addresult->failure++;
1885 LOG_PRINT(LOG_WARNING, get_status_msg(223));
1886 snprintf(message, 128, "223:%s@%s:%s\n", token, user_host, ptr_clrequest->current_db);
1887 if ((new_msg = mstrcat(ptr_addresult->msg, message, &(ptr_addresult->msg_len), 0)) == NULL) {
1888 send_status(ptr_clrequest->fd, 801, TERM_NO);
1889 LOG_PRINT(LOG_CRIT, get_status_msg(801));
1890 return 1;
1891 }
1892 else {
1893 ptr_addresult->msg = new_msg;
1894 }
1895 continue;
1896 }
1897 dbi_result_free(dbires);
1898
1899 /* now handle the requested database and add the user
1900 to the group <dbname>user */
1901 if (!n_readonly) {
1902 sprintf(sql_command, "ALTER GROUP %suser ADD USER %s", ptr_clrequest->current_db, token);
1903 }
1904 else {
1905 sprintf(sql_command, "ALTER GROUP %sruser ADD USER %s", ptr_clrequest->current_db, token);
1906 }
1907 LOG_PRINT(LOG_DEBUG, sql_command);
1908 dbires = dbi_conn_query(conn, sql_command);
1909 if (!dbires) {
1910 ptr_addresult->failure++;
1911 LOG_PRINT(LOG_WARNING, get_status_msg(239));
1912 snprintf(message, 128, "239:%s@%s:%s\n", token, user_host, ptr_clrequest->current_db);
1913 }
1914 else {
1915 ptr_addresult->success++;
1916 dbi_result_free(dbires);
1917 if (user_host && *user_host) {
1918 snprintf(message, 127, "238:%s@%s:%s", token, user_host, ptr_clrequest->current_db);
1919 }
1920 else {
1921 snprintf(message, 127, "238:%s:%s", token, ptr_clrequest->current_db);
1922 }
1923 LOG_PRINT(LOG_INFO, message);
1924 strcat(message, "\n");
1925 }
1926
1927 if ((new_msg = mstrcat(ptr_addresult->msg, message, &(ptr_addresult->msg_len), 0)) == NULL) {
1928 send_status(ptr_clrequest->fd, 801, TERM_NO);
1929 LOG_PRINT(LOG_CRIT, get_status_msg(801));
1930 return 1;
1931 }
1932 else {
1933 ptr_addresult->msg = new_msg;
1934 }
1935 } /* end if n_remove */
1936 } /* end if token != NULL */
1937 } while (token != NULL); /* end loop over all usernames */
1938 }
1939 dbi_conn_close(conn);
1940 }
1941 else {
1942 send_status(ptr_clrequest->fd, 202, TERM_NO);
1943 LOG_PRINT(LOG_WARNING, get_status_msg(202));
1944 return 1;
1945 }
1946
1947 send_status(ptr_clrequest->fd, 0, TERM_NO);
1948 tiwrite(ptr_clrequest->fd, ptr_addresult->msg, TERM_YES);
1949 delete_all_lilimem(&sentinel);
1950 return 0;
1951 }
1952
1953 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1954 addword(): implements the client command addword
1955
1956 int addword returns >0 if failed, 0 if successful
1957
1958 struct CLIENT_REQUEST* ptr_clrequest ptr to structure with client info
1959
1960 int n_remove if 0, access wil be granted. if 1, access will be revoked
1961
1962 struct ADDRESULT* ptr_addresult ptr to struct with counters
1963
1964 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
addword(struct CLIENT_REQUEST * ptr_clrequest,int n_remove,struct ADDRESULT * ptr_addresult)1965 int addword(struct CLIENT_REQUEST* ptr_clrequest, int n_remove, struct ADDRESULT* ptr_addresult) {
1966 dbi_conn conn;
1967 dbi_result dbires;
1968 dbi_driver driver;
1969 int nread_done = 0;
1970 int inbuffer_len;
1971 size_t token_size;
1972 int numbyte;
1973 int n_client_status;
1974 char message[512];
1975 char* new_msg;
1976 char* sql_command;
1977 char* inbuffer;
1978 char* new_inbuffer;
1979 char* token;
1980 char* mytoken;
1981 struct lilimem sentinel;
1982
1983 sentinel.ptr_mem = NULL;
1984 sentinel.ptr_next = NULL;
1985 sentinel.varname[0] = '\0';
1986
1987
1988 sql_command = malloc(1024);
1989 if (sql_command == NULL || insert_lilimem(&sentinel, (void**)&sql_command, NULL)) {
1990 send_status(ptr_clrequest->fd, 801, TERM_NO);
1991 LOG_PRINT(LOG_CRIT, get_status_msg(801));
1992 return 1;
1993 }
1994
1995 inbuffer_len = (size_t)COMMAND_INBUF_LEN;
1996 inbuffer = malloc(inbuffer_len);
1997 if (inbuffer == NULL || insert_lilimem(&sentinel, (void**)&inbuffer, NULL)) {
1998 delete_all_lilimem(&sentinel);
1999 send_status(ptr_clrequest->fd, 801, TERM_NO);
2000 LOG_PRINT(LOG_CRIT, get_status_msg(801));
2001 return 1;
2002 }
2003
2004 ptr_addresult->msg_len = 1024;
2005 ptr_addresult->msg = malloc(ptr_addresult->msg_len);
2006 if (ptr_addresult->msg == NULL) {
2007 delete_all_lilimem(&sentinel);
2008 send_status(ptr_clrequest->fd, 801, TERM_NO);
2009 LOG_PRINT(LOG_CRIT, get_status_msg(801));
2010 return 1;
2011 }
2012
2013 *(ptr_addresult->msg) = '\0';
2014
2015 /* connect to the database */
2016 if ((conn = connect_to_db(ptr_clrequest, NULL, 0)) != NULL) {
2017
2018 send_status(ptr_clrequest->fd, 0, TERM_NO);
2019
2020 /* read from client and increase buffer size until we have all arguments */
2021 if ((n_client_status = read_status(ptr_clrequest->fd))) {
2022 delete_all_lilimem(&sentinel);
2023 LOG_PRINT(LOG_WARNING, get_status_msg(n_client_status));
2024 return 1;
2025 }
2026
2027 while (!nread_done) {
2028 numbyte = tread(ptr_clrequest->fd, inbuffer, COMMAND_INBUF_LEN-1);
2029 if (get_trailz(inbuffer, numbyte) >= TERM_LEN) { /* if transmission complete */
2030 nread_done = 1;
2031 }
2032 else {
2033 inbuffer_len += (size_t)COMMAND_INBUF_LEN;
2034 if ((new_inbuffer = (char*)realloc(inbuffer, inbuffer_len)) == NULL) {
2035 delete_all_lilimem(&sentinel);
2036 dbi_conn_close(conn);
2037 send_status(ptr_clrequest->fd, 801, TERM_NO);
2038 LOG_PRINT(LOG_CRIT, get_status_msg(801));
2039 return 1;
2040 }
2041 else {
2042 inbuffer = new_inbuffer;
2043 }
2044 }
2045 } /* end while(!nread_done) */
2046
2047 /* printf("%s\n", inbuffer); */
2048
2049 token = inbuffer;
2050 token_size = -1;
2051
2052 do {
2053 token = nstrtok(token + token_size + 1, &token_size, " ");
2054 if (token != NULL) {
2055 token[token_size] = '\0';
2056
2057 /* make sure we have uppercase words only */
2058 mytoken = strdup(token);
2059 if (!mytoken) {
2060 ptr_addresult->failure++;
2061 send_status(ptr_clrequest->fd, 801, TERM_NO);
2062 LOG_PRINT(LOG_CRIT, get_status_msg(801));
2063 return 1;
2064 }
2065 strup(mytoken);
2066
2067 driver = dbi_conn_get_driver(conn);
2068
2069 /* escape any characters that the database server cannot digest */
2070 if (dbi_conn_quote_string(conn, &mytoken) == 0) {
2071 free(mytoken);
2072 ptr_addresult->failure++;
2073 send_status(ptr_clrequest->fd, 801, TERM_NO);
2074 LOG_PRINT(LOG_CRIT, get_status_msg(801));
2075 return 1;
2076 }
2077
2078 if (n_remove) {
2079 sprintf(sql_command, "DELETE FROM t_journal_words WHERE name %s %s", my_dbi_conn_get_cap(conn, "rlike"), mytoken);
2080 }
2081 else {
2082 sprintf(sql_command, "INSERT INTO t_journal_words (name) VALUES (%s)", mytoken);
2083 }
2084 LOG_PRINT(LOG_DEBUG, sql_command);
2085 free(mytoken);
2086
2087 dbires = dbi_conn_query(conn, sql_command);
2088 if (!dbires || !dbi_result_get_numrows_affected(dbires)) {
2089 if (n_remove) {
2090 sprintf(message, "420:%s\n", token);
2091 }
2092 else {
2093 sprintf(message, "414:%s\n", token);
2094 }
2095
2096 if ((new_msg = mstrcat(ptr_addresult->msg, message, &(ptr_addresult->msg_len), 0)) == NULL) {
2097 send_status(ptr_clrequest->fd, 801, TERM_NO);
2098 LOG_PRINT(LOG_CRIT, get_status_msg(801));
2099 return 1;
2100 }
2101 else {
2102 ptr_addresult->msg = new_msg;
2103 }
2104 ptr_addresult->failure++;
2105 }
2106 else {
2107 dbi_result_free(dbires);
2108 if (n_remove) {
2109 sprintf(message, "419:%s\n", token);
2110 }
2111 else {
2112 sprintf(message, "408:%s\n", token);
2113 }
2114
2115 if ((new_msg = mstrcat(ptr_addresult->msg, message, &(ptr_addresult->msg_len), 0)) == NULL) {
2116 send_status(ptr_clrequest->fd, 801, TERM_NO);
2117 LOG_PRINT(LOG_CRIT, get_status_msg(801));
2118 return 1;
2119 }
2120 else {
2121 ptr_addresult->msg = new_msg;
2122 }
2123 ptr_addresult->success++;
2124 }
2125 }
2126 } while (token != NULL);
2127 dbi_conn_close(conn);
2128 }
2129 else {
2130 /* send back error to the client */
2131 send_status(ptr_clrequest->fd, 202, TERM_NO);
2132 LOG_PRINT(LOG_WARNING, get_status_msg(202));
2133 delete_all_lilimem(&sentinel);
2134 return 1;
2135 }
2136
2137 /* send back report to client */
2138 send_status(ptr_clrequest->fd, 0, TERM_NO);
2139 tiwrite(ptr_clrequest->fd, ptr_addresult->msg, TERM_YES);
2140
2141 delete_all_lilimem(&sentinel);
2142 return 0;
2143 }
2144
2145 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2146 getfoo(): implements the client commands getau, getkw, and getjo
2147
2148 int getfoo returns 0 if ok, > 0 if error
2149
2150 struct CLIENT_REQUEST* ptr_clrequest ptr to structure with client info
2151
2152 int type the type of user command 0 = getau, 1 = getkw, 2 = getjo,
2153 3 = getjf, 4 = getj1, 5 = getj2
2154 6 = geted, 7 = getas, 8 = getax
2155
2156 int all if 1, return all synonyms of a journal name query
2157
2158 char* db_encoding output encoding
2159
2160 struct ADDRESULT* ptr_addresult ptr to struct that receives counts
2161
2162 char* format_string ptr to string containing formatting hints
2163
2164 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
getfoo(struct CLIENT_REQUEST * ptr_clrequest,int type,int all,char * db_encoding,struct ADDRESULT * ptr_addresult,char * format_string)2165 int getfoo(struct CLIENT_REQUEST* ptr_clrequest, int type, int all, char* db_encoding, struct ADDRESULT* ptr_addresult, char* format_string) {
2166 int n_sql_command_len;
2167 int rel_frequency;
2168 int n_leadingspaces;
2169 unsigned long long refcount;
2170 unsigned long long frequency;
2171 unsigned long long periodical_id;
2172 char buffer[512];
2173 char limitstring[128] = "";
2174 char *sql_command;
2175 char *myarg;
2176 char spaces[] = " "; /* ulonglong is 19 digits max */
2177 char* leadingspace;
2178 const char *foostring;
2179 dbi_conn conn;
2180 dbi_result dbires;
2181 dbi_result dbires1;
2182 dbi_driver driver;
2183
2184 /* connect to the database */
2185 if ((conn = connect_to_db(ptr_clrequest, NULL, 0)) != NULL) {
2186 driver = dbi_conn_get_driver(conn);
2187
2188 /* get reference count for later use */
2189 refcount = get_reference_count(conn, NULL, 0 /* istemp */);
2190
2191 if (ptr_clrequest->argument && *(ptr_clrequest->argument)) {
2192 myarg = malloc(strlen(ptr_clrequest->argument)+1);
2193 unescape_chars(myarg, ptr_clrequest->argument, strlen(ptr_clrequest->argument));
2194 }
2195 else {
2196 myarg = strdup(my_dbi_driver_get_cap(driver, "listall")); /* list all if no argument is specified */
2197 }
2198 if (!myarg) {
2199 send_status(ptr_clrequest->fd, 801, TERM_NO);
2200 LOG_PRINT(LOG_CRIT, get_status_msg(801));
2201 dbi_conn_close(conn);
2202 return 1;
2203 }
2204
2205 /* escape any characters that the database server cannot digest */
2206 if (dbi_conn_quote_string(conn, &myarg) == 0) {
2207 send_status(ptr_clrequest->fd, 801, TERM_NO);
2208 LOG_PRINT(LOG_CRIT, get_status_msg(801));
2209 dbi_conn_close(conn);
2210 free(myarg);
2211 return 1;
2212 }
2213
2214 n_sql_command_len = 512+strlen(myarg);
2215 sql_command = malloc(n_sql_command_len);
2216 if (sql_command == NULL) {
2217 send_status(ptr_clrequest->fd, 801, TERM_NO);
2218 LOG_PRINT(LOG_CRIT, get_status_msg(801));
2219 dbi_conn_close(conn);
2220 free(myarg);
2221 return 1;
2222 }
2223
2224 if (*(ptr_clrequest->limit)) {
2225 char *colon;
2226
2227 colon = strchr(ptr_clrequest->limit, (int)':');
2228
2229 if (!colon) {
2230 snprintf(limitstring, 128, " LIMIT %s ", ptr_clrequest->limit);
2231 }
2232 else {
2233 *colon = '\0';
2234 snprintf(limitstring, 128, " LIMIT %s OFFSET %s ", ptr_clrequest->limit, colon+1);
2235 }
2236 }
2237
2238 /* assemble query */
2239 if (type == GETAU) {
2240 sprintf(sql_command, "SELECT DISTINCT t_author.author_name, t_author.author_lastname, t_author.author_firstname, t_author.author_middlename, t_author.author_suffix, t_xauthor.xauthor_role, t_xauthor.author_id FROM t_author INNER JOIN t_xauthor ON t_author.author_id=t_xauthor.author_id WHERE t_xauthor.xauthor_type=%s AND t_author.author_name %s %s ORDER BY t_author.author_name%s", get_author_type_string(driver, 1), my_dbi_conn_get_cap(conn, "rlike"), myarg, limitstring);
2241 }
2242 else if (type == GETKW) {
2243 sprintf(sql_command, "SELECT DISTINCT keyword_name, keyword_id FROM t_keyword WHERE keyword_name %s %s ORDER BY keyword_name%s", my_dbi_conn_get_cap(conn, "rlike"), myarg, limitstring);
2244 }
2245 else if (type == GETJO) {
2246 sprintf(sql_command, "SELECT DISTINCT periodical_abbrev, periodical_id, periodical_name, periodical_custabbrev1, periodical_custabbrev2 FROM t_periodical WHERE periodical_abbrev %s %s ORDER BY periodical_abbrev,periodical_name,periodical_custabbrev1,periodical_custabbrev2%s", my_dbi_conn_get_cap(conn, "rlike"), myarg, limitstring);
2247 }
2248 else if (type == GETJF) {
2249 sprintf(sql_command, "SELECT DISTINCT periodical_name, periodical_id, periodical_abbrev, periodical_custabbrev1, periodical_custabbrev2 FROM t_periodical WHERE periodical_name %s %s ORDER BY periodical_abbrev,periodical_name,periodical_custabbrev1,periodical_custabbrev2%s", my_dbi_conn_get_cap(conn, "rlike"), myarg, limitstring);
2250 }
2251 else if (type == GETJ1) {
2252 sprintf(sql_command, "SELECT DISTINCT periodical_custabbrev1, periodical_id, periodical_name, periodical_abbrev, periodical_custabbrev2 FROM t_periodical WHERE periodical_custabbrev1 %s %s ORDER BY periodical_abbrev,periodical_name,periodical_custabbrev1,periodical_custabbrev2%s", my_dbi_conn_get_cap(conn, "rlike"), myarg, limitstring);
2253 }
2254 else if (type == GETJ2) {
2255 sprintf(sql_command, "SELECT DISTINCT periodical_custabbrev2, periodical_id, periodical_name, periodical_abbrev, periodical_custabbrev1 FROM t_periodical WHERE periodical_custabbrev2 %s %s ORDER BY periodical_abbrev,periodical_name,periodical_custabbrev1,periodical_custabbrev2%s", my_dbi_conn_get_cap(conn, "rlike"), myarg, limitstring);
2256 }
2257 else if (type == GETED) {
2258 sprintf(sql_command, "SELECT DISTINCT t_author.author_name, t_author.author_lastname, t_author.author_firstname, t_author.author_middlename, t_author.author_suffix, t_xauthor.xauthor_role, t_xauthor.author_id FROM t_author, t_xauthor WHERE t_author.author_id=t_xauthor.author_id AND t_xauthor.xauthor_type=%s AND t_author.author_name %s %s ORDER BY t_author.author_name%s", get_author_type_string(driver, 2), my_dbi_conn_get_cap(conn, "rlike"), myarg, limitstring);
2259 }
2260 else if (type == GETAS) {
2261 sprintf(sql_command, "SELECT DISTINCT t_author.author_name, t_author.author_lastname, t_author.author_firstname, t_author.author_middlename, t_author.author_suffix, t_xauthor.xauthor_role, t_xauthor.author_id FROM t_author, t_xauthor WHERE t_author.author_id=t_xauthor.author_id AND t_xauthor.xauthor_type=%s AND t_author.author_name %s %s ORDER BY t_author.author_name%s", get_author_type_string(driver, 3), my_dbi_conn_get_cap(conn, "rlike"), myarg, limitstring);
2262 }
2263 else if (type == GETAX) {
2264 sprintf(sql_command, "SELECT DISTINCT t_author.author_name, t_author.author_lastname, t_author.author_firstname, t_author.author_middlename, t_author.author_suffix, t_xauthor.xauthor_role, t_xauthor.author_id FROM t_author, t_xauthor WHERE t_author.author_id=t_xauthor.author_id AND t_author.author_name %s %s ORDER BY t_author.author_name%s", my_dbi_conn_get_cap(conn, "rlike"), myarg, limitstring);
2265 }
2266
2267 free(myarg);
2268
2269 /* send query */
2270 LOG_PRINT(LOG_DEBUG, sql_command);
2271 dbires = dbi_conn_query(conn, sql_command);
2272 if (!dbires) {
2273 send_status(ptr_clrequest->fd, 234, TERM_NO);
2274 LOG_PRINT(LOG_WARNING, get_status_msg(234));
2275 dbi_conn_close(conn);
2276 free(sql_command);
2277 return 1;
2278 }
2279
2280 free(sql_command);
2281
2282 /* send results to client */
2283 send_status(ptr_clrequest->fd, 0, TERM_NO);
2284
2285 /* see whether frequency data were requested */
2286 if (format_string
2287 && (!strcmp(format_string, "freq")
2288 || !strcmp(format_string, "relfreq"))) {
2289 if (type == GETAU
2290 || type == GETED
2291 || type == GETAS
2292 || type == GETAX) {
2293 while ((foostring = get_extended_author(dbires, 0 /* is_temp */, &frequency)) != NULL) {
2294 /* compute the leading space required to align the output */
2295 n_leadingspaces = (refcount) ? (int)log10(refcount):0;
2296 leadingspace = spaces+19-n_leadingspaces+((frequency) ? (int)log10(frequency):0);
2297
2298 ptr_addresult->success++;
2299 if (!strcmp(format_string,"relfreq")) {
2300 rel_frequency = calculate_relative_frequency(frequency, refcount);
2301 sprintf(buffer, "%d:%s\n", rel_frequency, foostring);
2302 }
2303 else {
2304 sprintf(buffer, "%s"ULLSPEC":%s\n", leadingspace, (unsigned long long)frequency, foostring);
2305 }
2306 tiwrite(ptr_clrequest->fd, buffer, TERM_NO);
2307 }
2308 }
2309 else if (type == GETKW) {
2310 while ((foostring = get_extended_keyword(dbires, 0 /* is_temp */, &frequency)) != NULL) {
2311 /* compute the leading space required to align the output */
2312 n_leadingspaces = (refcount) ? (int)log10(refcount):0;
2313 leadingspace = spaces+19-n_leadingspaces+((frequency) ? (int)log10(frequency):0);
2314
2315 ptr_addresult->success++;
2316 if (!strcmp(format_string,"relfreq")) {
2317 rel_frequency = calculate_relative_frequency(frequency, refcount);
2318 sprintf(buffer, "%d:%s\n", rel_frequency, foostring);
2319 }
2320 else {
2321 sprintf(buffer, "%s"ULLSPEC":%s\n", leadingspace, (unsigned long long)frequency, foostring);
2322 }
2323 tiwrite(ptr_clrequest->fd, buffer, TERM_NO);
2324 }
2325 }
2326 else /* if (type == GETJX) */ {
2327 while (dbi_result_next_row(dbires)) {
2328 ptr_addresult->success++;
2329
2330 periodical_id = my_dbi_result_get_idval_idx(dbires, 2);
2331
2332 sprintf(buffer, "SELECT count(*) FROM t_refdb WHERE t_refdb.refdb_periodical_id="ULLSPEC, (unsigned long long)periodical_id);
2333
2334 LOG_PRINT(LOG_DEBUG, buffer);
2335
2336 dbires1 = dbi_conn_query(dbi_result_get_conn(dbires), buffer);
2337 if (!dbires1) {
2338 continue;
2339 }
2340
2341 if (dbi_result_next_row(dbires1)) {
2342 frequency = my_dbi_result_get_idval_idx(dbires1, 1);
2343 if (dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
2344 dbi_result_free(dbires1);
2345 continue;
2346 }
2347 dbi_result_free(dbires1);
2348 }
2349 else {
2350 dbi_result_free(dbires1);
2351 frequency = 0;
2352 }
2353
2354
2355 /* compute the leading space required to align the output */
2356 n_leadingspaces = (refcount) ? (int)log10(refcount):0;
2357 leadingspace = spaces+19-n_leadingspaces+((frequency) ? (int)log10(frequency):0);
2358
2359 if (!all) {
2360 foostring = dbi_result_get_string_idx(dbires, 1); /* 1-base index */
2361 if (foostring) {
2362 if (!strcmp(format_string,"relfreq")) {
2363 rel_frequency = calculate_relative_frequency(frequency, refcount);
2364 sprintf(buffer, "%d:%s\n", rel_frequency, foostring);
2365 }
2366 else {
2367 sprintf(buffer, "%s"ULLSPEC":%s\n", leadingspace, (unsigned long long)frequency, foostring);
2368 }
2369 tiwrite(ptr_clrequest->fd, buffer, TERM_NO);
2370 }
2371 }
2372 else {
2373 /* display all synonyms. If one is missing, we still print
2374 the colon to indicate which one is missing */
2375 if (!strcmp(format_string,"relfreq")) {
2376 rel_frequency = calculate_relative_frequency(frequency, refcount);
2377 sprintf(buffer, "%d:\n", rel_frequency);
2378 }
2379 else {
2380 sprintf(buffer, ULLSPEC":\n", (unsigned long long)frequency);
2381 }
2382 tiwrite(ptr_clrequest->fd, buffer, TERM_NO);
2383
2384 foostring = dbi_result_get_string_idx(dbires, 1); /* 1-base index */
2385 if (foostring) {
2386 tiwrite(ptr_clrequest->fd, foostring, TERM_NO);
2387 }
2388
2389 tiwrite(ptr_clrequest->fd, ":", TERM_NO);
2390
2391 foostring = dbi_result_get_string_idx(dbires, 3); /* 1-base index */
2392 if (foostring) {
2393 tiwrite(ptr_clrequest->fd, foostring, TERM_NO);
2394 }
2395
2396 tiwrite(ptr_clrequest->fd, ":", TERM_NO);
2397
2398 foostring = dbi_result_get_string_idx(dbires, 4); /* 1-base index */
2399 if (foostring) {
2400 tiwrite(ptr_clrequest->fd, foostring, TERM_NO);
2401 }
2402
2403 tiwrite(ptr_clrequest->fd, ":", TERM_NO);
2404
2405 foostring = dbi_result_get_string_idx(dbires, 5); /* 1-base index */
2406 if (foostring) {
2407 tiwrite(ptr_clrequest->fd, foostring, TERM_NO);
2408 }
2409 }
2410 } /* end while */
2411 }
2412 }
2413 else { /* no frequency data requested */
2414 while (dbi_result_next_row(dbires)) {
2415 ptr_addresult->success++;
2416
2417 if (!all) {
2418 foostring = dbi_result_get_string_idx(dbires, 1); /* 1-base index */
2419 if (foostring) {
2420 tiwrite(ptr_clrequest->fd, foostring, TERM_NO);
2421 }
2422 }
2423 else {
2424 /* display all synonyms. If one is missing, we still print
2425 the colon to indicate which one is missing */
2426 foostring = dbi_result_get_string_idx(dbires, 1); /* 1-base index */
2427 if (foostring) {
2428 tiwrite(ptr_clrequest->fd, foostring, TERM_NO);
2429 }
2430
2431 tiwrite(ptr_clrequest->fd, ":", TERM_NO);
2432
2433 foostring = dbi_result_get_string_idx(dbires, 3); /* 1-base index */
2434 if (foostring) {
2435 tiwrite(ptr_clrequest->fd, foostring, TERM_NO);
2436 }
2437
2438 tiwrite(ptr_clrequest->fd, ":", TERM_NO);
2439
2440 foostring = dbi_result_get_string_idx(dbires, 4); /* 1-base index */
2441 if (foostring) {
2442 tiwrite(ptr_clrequest->fd, foostring, TERM_NO);
2443 }
2444
2445 tiwrite(ptr_clrequest->fd, ":", TERM_NO);
2446
2447 foostring = dbi_result_get_string_idx(dbires, 5); /* 1-base index */
2448 if (foostring) {
2449 tiwrite(ptr_clrequest->fd, foostring, TERM_NO);
2450 }
2451 tiwrite(ptr_clrequest->fd, "|", TERM_NO);
2452 }
2453 tiwrite(ptr_clrequest->fd, "\n", TERM_NO);
2454 } /* end while */
2455 } /* end if */
2456
2457 /* terminate output */
2458 iwrite(ptr_clrequest->fd, cs_term, TERM_LEN);
2459
2460 dbi_result_free(dbires);
2461 dbi_conn_close(conn);
2462 }
2463 else {
2464 /* connection failed */
2465 send_status(ptr_clrequest->fd, 204, TERM_NO);
2466 LOG_PRINT(LOG_WARNING, get_status_msg(204));
2467 return 1;
2468 }
2469
2470 return 0;
2471 }
2472
2473 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2474 is_refdb_admin(): tests whether a user is likely to be a refdbd
2475 administrator. We test whether the user has read
2476 access to a system table readable only for
2477 database administrators
2478
2479 int is_refdb_admin returns 0 if access is denied. returns 1 if
2480 access is allowed. If a database error occurs other
2481 than denial of access, it will also return 0.
2482 If the database engine does not support access control,
2483 this function always returns 1
2484 returns -1 if there was a connection problem
2485
2486 struct CLIENT_REQUEST* ptr_clrequest ptr to structure with client info
2487
2488 struct ADDRESULT* ptr_addresult ptr to struct with counters
2489
2490 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
is_refdb_admin(struct CLIENT_REQUEST * ptr_clrequest,struct ADDRESULT * ptr_addresult)2491 int is_refdb_admin(struct CLIENT_REQUEST* ptr_clrequest, struct ADDRESULT* ptr_addresult) {
2492 dbi_conn conn;
2493 dbi_result dbires;
2494 const char *drivername;
2495
2496 /* connect to database server */
2497 if ((conn = connect_to_db(ptr_clrequest, NULL, 0)) == NULL) {
2498 return -1;
2499 }
2500
2501 drivername = dbi_driver_get_name(dbi_conn_get_driver(conn));
2502
2503 /* try to access a system table that only db administrators
2504 may access */
2505 if (!strcmp(drivername, "mysql")) {
2506 dbires = dbi_conn_query(conn, "SELECT User FROM mysql.user");
2507 }
2508 else if (!strcmp(drivername, "pgsql")) {
2509 dbires = dbi_conn_query(conn, "SELECT * FROM pg_shadow");
2510 }
2511 else {
2512 /* no access control */
2513 sprintf(ptr_addresult->msg, "704\n");
2514 dbi_conn_close(conn);
2515 return 1;
2516 }
2517
2518 if (!dbires) {
2519 sprintf(ptr_addresult->msg, "705:%s", ptr_clrequest->username);
2520 LOG_PRINT(LOG_WARNING, ptr_addresult->msg);
2521 sprintf(ptr_addresult->msg, "705:%s\n", ptr_clrequest->username);
2522 dbi_conn_close(conn);
2523 return 0;
2524 }
2525
2526 dbi_result_free(dbires);
2527 dbi_conn_close(conn);
2528 sprintf(ptr_addresult->msg, "705:%s\n", ptr_clrequest->username);
2529
2530 return 1;
2531 }
2532
2533
2534 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2535 daemonize(): puts the process properly into the background
2536
2537 int daemonize returns 1 in case of an error, 0 if all went fine
2538
2539 char* progname optional string containing the name of the program
2540
2541 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
daemonize(char * progname)2542 int daemonize(char* progname) {
2543 /* this whole fn is more or less stolen from the libslack package */
2544 /* libslack - http://libslack.org/ */
2545 /* Copyright (C) 1999-2001 raf <raf@raf.org> (GPL) */
2546
2547
2548 pid_t pid;
2549 long nopen;
2550 int fd;
2551
2552 /*
2553 ** Don't setup a daemon-friendly process context
2554 ** if started by init(8) or inetd(8).
2555 */
2556
2557 if (!(daemon_started_by_init() || daemon_started_by_inetd())) {
2558 /*
2559 ** Background the process.
2560 ** Lose process group leadership.
2561 */
2562
2563 if ((pid = fork()) == -1) {
2564 return 1;
2565 }
2566
2567 if (pid) {
2568 exit(0);
2569 }
2570
2571 /* Become a process session leader. */
2572
2573 setsid();
2574
2575 #ifndef NO_EXTRA_SVR4_FORK
2576 #ifdef SVR4
2577 /*
2578 ** Lose process session leadership
2579 ** to prevent gaining a controlling
2580 ** terminal in SVR4.
2581 */
2582
2583 if ((pid = fork()) == -1) {
2584 return 1;
2585 }
2586
2587 if (pid) {
2588 exit(0);
2589 }
2590 #endif
2591 #endif
2592 }
2593
2594 /* Enter the root directory to prevent hampering umounts. */
2595
2596 if (chdir(ROOT_DIR) == -1) {
2597 return 1;
2598 }
2599
2600 /* Clear umask to enable explicit file modes. */
2601
2602 umask(0);
2603
2604 /*
2605 ** We need to close all open file descriptors. Check how
2606 ** many file descriptors we have (If indefinite, a usable
2607 ** number (1024) will be returned).
2608 */
2609
2610 if ((nopen = limit_open()) == -1) {
2611 return 1;
2612 }
2613
2614 /*
2615 ** Close all open file descriptors. If started by inetd,
2616 ** we don't close stdin, stdout and stderr.
2617 ** Don't forget to open any future tty devices with O_NOCTTY
2618 ** so as to prevent gaining a controlling terminal
2619 ** (not necessary with SVR4).
2620 */
2621
2622 if (daemon_started_by_inetd()) {
2623 for (fd = 0; fd < nopen; ++fd) {
2624 switch (fd) {
2625 case STDIN_FILENO:
2626 case STDOUT_FILENO:
2627 case STDERR_FILENO:
2628 break;
2629 default:
2630 close(fd);
2631 }
2632 }
2633 }
2634 else {
2635 for (fd = 0; fd < nopen; ++fd) {
2636 close(fd);
2637 }
2638
2639 /*
2640 ** Open stdin, stdout and stderr to /dev/null just in case some
2641 ** code buried in a library somewhere expects them to be open.
2642 */
2643
2644 if ((fd = open("/dev/null", O_RDWR)) == -1) {
2645 return 1;
2646 }
2647
2648 /*
2649 ** This is only needed for very strange (hypothetical)
2650 ** POSIX implementations where STDIN_FILENO != 0 or
2651 ** STDOUT_FILE != 1 or STERR_FILENO != 2 (yeah, right).
2652 */
2653
2654 if (fd != STDIN_FILENO) {
2655 if (dup2(fd, STDIN_FILENO) == -1) {
2656 return 1;
2657 }
2658
2659 close(fd);
2660 }
2661
2662 if (dup2(STDIN_FILENO, STDOUT_FILENO) == -1) {
2663 return 1;
2664 }
2665
2666 if (dup2(STDIN_FILENO, STDERR_FILENO) == -1) {
2667 return 1;
2668 }
2669 }
2670
2671 /* ToDo: deal with this later */
2672 /* Place our process id in the file system and lock it. */
2673
2674 /* if (name) */
2675 /* { */
2676 /* int rc; */
2677
2678 /* ptry(pthread_mutex_lock(&g.lock)) */
2679 /* rc = daemon_pidfile(name); */
2680 /* ptry(pthread_mutex_unlock(&g.lock)) */
2681
2682 /* return rc; */
2683 /* } */
2684
2685 return 0;
2686 }
2687
2688 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2689 daemon_started_by_init(): returns true if the daemon was started
2690 by init(8)
2691
2692 static int daemon_started_by_init returns 1 if the daemon was started by init
2693 returns 0 if the daemon was started by
2694 any other means
2695
2696 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
daemon_started_by_init(void)2697 static int daemon_started_by_init(void) {
2698 /* this code also taken from libslack */
2699 /* static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; */
2700 static int rc = -1;
2701
2702 if (rc == -1) {
2703 /* ptry(pthread_mutex_lock(&lock)) */
2704
2705 if (rc == -1) {
2706 rc = (getppid() == 1);
2707 }
2708
2709 /* ptry(pthread_mutex_unlock(&lock)) */
2710 }
2711
2712 return rc;
2713 }
2714
2715 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2716 daemon_started_by_inetd(): returns true if the daemon was started
2717 by inetd(8)
2718
2719 static int daemon_started_by_inetd returns 1 if the daemon was started by
2720 intetd. returns 0 otherwise.
2721
2722 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
daemon_started_by_inetd(void)2723 static int daemon_started_by_inetd(void) {
2724 /* this code also taken from libslack */
2725 /* static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; */
2726 static int rc = -1;
2727
2728 if (rc == -1) {
2729 /* socklen_t is not available on all platforms (OSX). We define it
2730 as 'int' at the top of this file if it is missing */
2731 socklen_t optlen = (socklen_t)sizeof(int);
2732 int optval;
2733
2734 /* ptry(pthread_mutex_lock(&lock)) */
2735
2736 if (rc == -1) {
2737 rc = (getsockopt(STDIN_FILENO, SOL_SOCKET, SO_TYPE, &optval, &optlen) == 0);
2738 }
2739
2740 /* ptry(pthread_mutex_unlock(&lock)) */
2741 }
2742
2743 return rc;
2744 }
2745
2746 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2747 limit_open(): Returns the maximum number of files that a process can
2748 have open at any time. If indeterminate, a usable
2749 guess (1024) is returned.
2750
2751 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
limit_open(void)2752 static long limit_open(void) {
2753 long value;
2754
2755 if ((value = sysconf(_SC_OPEN_MAX)) == -1) {
2756 return 1024L; /* educated guess */
2757 }
2758
2759 return value;
2760 }
2761
2762
2763