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