connman.cc

00001 /* 
00002    EyeDB Object Database Management System
00003    Copyright (C) 1994-2008 SYSRA
00004    
00005    EyeDB is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009    
00010    EyeDB is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014    
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with this library; if not, write to the Free Software
00017    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA 
00018 */
00019 
00020 /*
00021    Author: Eric Viara <viara@sysra.com>
00022 */
00023 
00024 #include "eyedbconfig.h"
00025 
00026 #include <stdio.h>
00027 #include <stdlib.h>
00028 #include <string.h>
00029 #include <sys/types.h>
00030 #include <sys/socket.h>
00031 #include <sys/stat.h>
00032 #ifdef HAVE_STROPTS_H
00033 #include <stropts.h>
00034 #endif
00035 #include <sys/uio.h>
00036 #include <sys/un.h>
00037 #include <netdb.h>
00038 #include <netinet/in.h>
00039 #include <unistd.h>
00040 #include <assert.h>
00041 #include <errno.h>
00042 #include <sys/select.h>
00043 #include <time.h>
00044 
00045 #include <eyedblib/connman.h>
00046 #include <eyedblib/log.h>
00047 #include <eyedblib/rpc_lib.h>
00048 #include <lib/rpc_lib_p.h>
00049 
00050 static const char *rpc_access_file;
00051 
00052 typedef struct {
00053   struct in_addr addr;
00054   rpc_TcpIp tcpip;
00055 } rpc_Access;
00056 
00057 #define TAKE_CHAR(S) \
00058  *p++ = 0; \
00059  words[nw++] = S; \
00060  empt = 1
00061 
00062 int
00063 line_parse(FILE *fd, char buf[], char **words, int *line)
00064 {
00065   for (;;) {
00066     char *p;
00067     char c;
00068     int empt = 1;
00069     int nw = 0;
00070     int isquote = 0;
00071 
00072     if (!fgets(buf, 256, fd))
00073       return -1;
00074 
00075     (*line)++;
00076     p = buf;
00077 
00078     while ((c = *p) == ' ' || c == '\t')
00079       p++;
00080 
00081     while (c = *p) {
00082       switch(c) {
00083       case '#':
00084         if (!empt)
00085           nw++;
00086         *p++ = 0;
00087         while (c = *++p)
00088           ;
00089         break;
00090 
00091       case '=':
00092         TAKE_CHAR("=");
00093         break;
00094 
00095       case '!':
00096         TAKE_CHAR("!");
00097         break;
00098 
00099       case '+':
00100         TAKE_CHAR("+");
00101         break;
00102 
00103       case ' ':
00104       case '\t':
00105       case '\n':
00106         empt = 1;
00107         *p++ = 0;
00108         break;
00109 
00110       default:
00111         if (empt) {
00112           empt = 0;
00113           words[nw++] = p;
00114         }
00115 
00116         p++;
00117         break;
00118       }
00119     }
00120 
00121     *p = 0;
00122     words[nw] = 0;
00123     return nw;
00124   }
00125 }
00126 
00127 static int access_cnt;
00128 static rpc_Access rpc_access[512];
00129 
00130 static void
00131 make_user(char *words[], int *n, rpc_User *user)
00132 {
00133   char *s = words[(*n)++];
00134 
00135   if (!strcmp(s, "!"))
00136     user->mode = rpc_User::NOT;
00137   else if (!strcmp(s, "="))
00138     user->mode = rpc_User::DEF;
00139   else if (!strcmp(s, "+")) {
00140     user->mode = rpc_User::ALL;
00141     user->user = strdup("");
00142     return;
00143   }
00144   else {
00145     user->mode = rpc_User::ON;
00146     user->user = strdup(s);
00147     return;
00148   }
00149 
00150   user->user = strdup(words[(*n)++]);
00151   return;
00152 }
00153 
00154 static const char *
00155 get_str(int mode)
00156 {
00157   if (mode == rpc_User::ON)
00158     return "";
00159   if (mode == rpc_User::NOT)
00160     return "not ";
00161   if (mode == rpc_User::DEF)
00162     return "default=";
00163   if (mode == rpc_User::ALL)
00164     return "+";
00165   return "<unknown>";
00166 }
00167 
00168 static void
00169 free_access()
00170 {
00171   int i, j;
00172   for (i = 0; i < access_cnt; i++) {
00173     for (j = 0; j < rpc_access[i].tcpip.user_cnt; j++)
00174       free(rpc_access[i].tcpip.users[j].user);
00175 
00176     free(rpc_access[i].tcpip.users);
00177   }
00178   access_cnt = 0;
00179 }
00180 
00181 void
00182 rpc_print_tcpip(FILE *fd, rpc_TcpIp *ci)
00183 {
00184   int j;
00185   for (j = 0; j < ci->user_cnt; j++)
00186     fprintf(fd, "%s%s%s", (j ? " " : ""),  get_str(ci->users[j].mode),
00187             ci->users[j].user);
00188 
00189   fprintf(fd, "\n");
00190 }
00191 
00192 static int
00193 read_access_file_realize()
00194 {
00195   FILE *fd;
00196   char *words[32];
00197   int nw, i, j, u;
00198   char buf[256];
00199   int line = 0;
00200 
00201   /*
00202   if (!(fd = fopen(rpc_access_file, "r"))) {
00203     fprintf(stderr, "cannot open access file '%s' for reading\n",
00204             rpc_access_file);
00205     return 1;
00206   }
00207   */
00208 
00209   free_access();
00210 
00211   if (!(fd = fopen(rpc_access_file, "r"))) {
00212     if (!hostname2addr("localhost", &rpc_access[access_cnt].addr)) {
00213       rpc_access[access_cnt].tcpip.users = (rpc_User *)calloc(sizeof(rpc_User), 1);
00214       rpc_access[access_cnt].tcpip.users[0].mode = rpc_User::ALL;
00215       rpc_access[access_cnt].tcpip.users[0].user = strdup("");
00216       rpc_access[access_cnt++].tcpip.user_cnt = 1;
00217       return 0;
00218     }
00219     return 1;
00220   }
00221 
00222   while ((nw = line_parse(fd, buf, words, &line)) >= 0) {
00223     if (!nw)
00224       continue;
00225 
00226     if (nw < 2) {
00227       fprintf(stderr, "access file %s: syntax error at line #%d\n",
00228               rpc_access_file, line);
00229       continue;
00230     }
00231 
00232     if (!strcmp(words[0], "+"))
00233       memset(&rpc_access[access_cnt].addr, 0, sizeof(struct in_addr));
00234     else if (hostname2addr(words[0], &rpc_access[access_cnt].addr)) {
00235       fprintf(stderr, "access file %s: invalid host name at line #%d: "
00236               "%s\n", rpc_access_file, line, words[0]);
00237       continue;
00238     }
00239 
00240     /* 2/09/05: already freed in free_access() */
00241     /*
00242     for (j = 0; j < rpc_access[access_cnt].tcpip.user_cnt; j++)
00243       free(rpc_access[access_cnt].tcpip.users[j].user);
00244     free(rpc_access[access_cnt].tcpip.users);
00245     */
00246 
00247     rpc_access[access_cnt].tcpip.users = (rpc_User *)calloc((nw-1)*sizeof(rpc_User), 1);
00248     for (j = 1, u = 0; j < nw; u++)
00249       make_user(words, &j, &rpc_access[access_cnt].tcpip.users[u]);
00250 
00251     rpc_access[access_cnt++].tcpip.user_cnt = u;
00252   }
00253 
00254   fclose(fd);
00255 
00256   /*
00257   for (i = 0; i < access_cnt; i++) {
00258     print_addr(stderr, &rpc_access[i].addr);
00259     fprintf(stderr, ": ");
00260     rpc_print_tcpip(stderr, &rpc_access[i].tcpip);
00261   }
00262   */
00263 
00264   return 0;
00265 }
00266 
00267 static int
00268 read_access_file()
00269 {
00270   static time_t last_read;
00271   //struct stat st;
00272   int r;
00273 
00274   if (!rpc_access_file)
00275     return 0;
00276 
00277   /*
00278   if (stat(rpc_access_file, &st) < 0) {
00279     fprintf(stderr, "cannot stat access file '%s'\n", rpc_access_file);
00280     return 1;
00281   }
00282 
00283   if (st.st_mtime <= last_read)
00284     return 0;
00285   */
00286 
00287   r = read_access_file_realize();
00288   time(&last_read);
00289   return r;
00290 }
00291 
00292 int
00293 rpc_connman_init(const char *access_file)
00294 {
00295   rpc_access_file = access_file;
00296   return read_access_file();
00297 }
00298 
00299 static bool
00300 rpc_is_localhost(const struct in_addr *peer_addr)
00301 {
00302   struct in_addr addr;
00303   if (hostname2addr("localhost", &addr))
00304     return false;
00305 
00306   return cmp_addr(peer_addr, &addr);
00307 }
00308 
00309 rpc_ConnInfo *
00310 rpc_check_addr(struct in_addr *addr)
00311 {
00312   int i;
00313   if (read_access_file())
00314     return 0;
00315 
00316   for (i = 0; i < access_cnt; i++) {
00317     if (cmp_addr(&rpc_access[i].addr, addr)) {
00318       rpc_ConnInfo *ci = (rpc_ConnInfo *)calloc(sizeof(rpc_ConnInfo), 1);
00319       ci->tcpip = rpc_access[i].tcpip;
00320       ci->peer_addr = *addr;
00321       ci->is_localhost = rpc_is_localhost(&ci->peer_addr);;
00322       return ci;
00323     }
00324   }
00325 
00326   IDB_LOG(IDB_LOG_CONN,
00327           ("connection refused to %d.%d.%d.%d\n", RPC_BYTE1(addr), RPC_BYTE2(addr), RPC_BYTE3(addr), RPC_BYTE4(addr)));
00328 
00329   return 0;
00330 }
00331 
00332 rpc_ConnInfo *
00333 rpc_make_tcpip_conninfo(int fd)
00334 {
00335   struct sockaddr_in addr;
00336   socklen_t len = sizeof(addr);
00337 
00338   memset(&addr, 0, sizeof(addr));
00339 
00340   if (getpeername(fd, (struct sockaddr *)&addr, &len)) {
00341     perror("getpeername");
00342     return (rpc_ConnInfo *)0;
00343   }
00344 
00345   rpc_ConnInfo *ci = rpc_check_addr(&addr.sin_addr);
00346   if (ci)
00347     ci->mode = rpc_ConnInfo::TCPIP;
00348   return ci;
00349 }
00350 
00351 static rpc_ConnInfo *
00352 rpc_check_localhost(struct in_addr *addr)
00353 {
00354   if (hostname2addr("localhost", addr))
00355     return 0;
00356 
00357   return rpc_check_addr(addr);
00358 }
00359 
00360 #ifdef HAVE_FATTACH
00361 rpc_ConnInfo *
00362 rpc_make_stream_conninfo(int fd, struct strrecvfd *info)
00363 {
00364   struct in_addr addr;
00365   rpc_ConnInfo *ci = rpc_check_localhost(&addr);
00366 
00367   if (ci) {
00368     ci->mode = rpc_ConnInfo::STREAM;
00369     ci->auth.uid = info->uid;
00370     ci->auth.gid = info->gid;
00371     ci->peer_addr = addr;
00372     ci->is_localhost = rpc_is_localhost(&ci->peer_addr);;
00373   }
00374 
00375   return ci;
00376 }
00377 
00378 #else
00379 
00380 rpc_ConnInfo *
00381 rpc_make_unix_conninfo(int fd)
00382 {
00383   struct in_addr addr;
00384   rpc_ConnInfo *ci = rpc_check_localhost(&addr);
00385 
00386   if (ci) {
00387     ci->mode = rpc_ConnInfo::UNIX;
00388     ci->peer_addr = addr;
00389     ci->is_localhost = rpc_is_localhost(&ci->peer_addr);;
00390   }
00391 
00392   return ci;
00393 }
00394 
00395 #endif
00396 

Generated on Mon Dec 22 18:15:53 2008 for eyedb by  doxygen 1.5.3