proc.c

Go to the documentation of this file.
00001 /*
00002  ** Copyright 2005-2007 - INL
00003  ** Written by Eric Leblond <regit@inl.fr>
00004  **            Victor Stinner <haypo@inl.fr>
00005  ** INL http://www.inl.fr/
00006  **
00007  ** $Id: proc.c 4847 2008-06-13 14:48:31Z regit $
00008  **
00009  ** This program is free software; you can redistribute it and/or modify
00010  ** it under the terms of the GNU General Public License as published by
00011  ** the Free Software Foundation, version 3 of the License.
00012  **
00013  ** This program is distributed in the hope that it will be useful,
00014  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  ** GNU General Public License for more details.
00017  **
00018  ** You should have received a copy of the GNU General Public License
00019  ** along with this program; if not, write to the Free Software
00020  ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00021  */
00022 
00023 
00024 #include <config.h>
00025 
00026 #include "libnuclient.h"
00027 #include "proc.h"
00028 
00029 #ifdef LINUX
00030 
00031 #include <errno.h>
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <strings.h>
00036 #include <unistd.h>
00037 #include <ctype.h>
00038 #include <fcntl.h>
00039 #include <netdb.h>
00040 #include <paths.h>
00041 #include <pwd.h>
00042 #include <getopt.h>
00043 #include <sys/param.h>
00044 #include <sys/socket.h>
00045 #include <arpa/inet.h>
00046 #include <netinet/in.h>
00047 #include <sys/ioctl.h>
00048 #include <net/if.h>
00049 #include <dirent.h>
00050 
00051 #include "security.h"
00052 
00053 #include <nubase.h>
00054 
00055 
00061 static struct prg_node {
00062         struct prg_node *next; 
00063         unsigned long inode;   
00064         char name[PROGNAME_WIDTH];
00066 } *prg_hash[PRG_HASH_SIZE];
00067 
00068 #define PROGNAME_WIDTHs PROGNAME_WIDTH1(PROGNAME_WIDTH)
00069 #define PROGNAME_WIDTH1(s) PROGNAME_WIDTH2(s)
00070 #define PROGNAME_WIDTH2(s) #s
00071 
00072 #define PRG_HASHIT(x) ((x) % PRG_HASH_SIZE)
00073 
00074 #define PRG_LOCAL_ADDRESS "local_address"
00075 #define PRG_INODE        "inode"
00076 #define PRG_SOCKET_PFX    "socket:["
00077 #define PRG_SOCKET_PFXl (strlen(PRG_SOCKET_PFX))
00078 #define PRG_SOCKET_PFX2   "[0000]:"
00079 #define PRG_SOCKET_PFX2l  (strlen(PRG_SOCKET_PFX2))
00080 
00081 #ifndef PATH_MAX
00082 #  define PATH_MAX 4096
00083 #endif
00084 
00085 static void prg_cache_add(unsigned long inode, char *name)
00086 {
00087         unsigned hi = PRG_HASHIT(inode);
00088         struct prg_node **pnp, *pn;
00089 
00090         prg_cache_loaded = 2;
00091         for (pnp = prg_hash + hi; (pn = *pnp); pnp = &pn->next) {
00092                 if (pn->inode == inode) {
00093                         /* Some warning should be appropriate here
00094                            as we got multiple processes for one i-node */
00095                         return;
00096                 }
00097         }
00098         *pnp = malloc(sizeof(**pnp));
00099         if (*pnp == NULL)
00100                 return;
00101         pn = *pnp;
00102         pn->next = NULL;
00103         pn->inode = inode;
00104         SECURE_STRNCPY(pn->name, name, sizeof(pn->name));
00105 }
00106 
00107 const char *prg_cache_get(unsigned long inode)
00108 {
00109         unsigned hi = PRG_HASHIT(inode);
00110         struct prg_node *pn;
00111 
00112         for (pn = prg_hash[hi]; pn; pn = pn->next)
00113                 if (pn->inode == inode)
00114                         return (pn->name);
00115         return ("-");
00116 }
00117 
00118 void prg_cache_clear(void)
00119 {
00120         struct prg_node **pnp, *pn;
00121 
00122         if (prg_cache_loaded == 2)
00123                 for (pnp = prg_hash; pnp < prg_hash + PRG_HASH_SIZE; pnp++)
00124                         while ((pn = *pnp)) {
00125                                 *pnp = pn->next;
00126                                 free(pn);
00127                         }
00128         prg_cache_loaded = 0;
00129 }
00130 
00131 static int extract_type_1_socket_inode(char lname[],
00132                                        unsigned long *inode_p)
00133 {
00134         char *inode_str;
00135         char *serr;
00136         size_t len = strlen(lname);
00137 
00138         /* If lname is of the form "socket:[12345]", extract the "12345"
00139            as *inode_p.  Otherwise, return -1 as *inode_p.
00140          */
00141         if (len < PRG_SOCKET_PFXl + 3)
00142                 return (-1);
00143         if (memcmp(lname, PRG_SOCKET_PFX, PRG_SOCKET_PFXl))
00144                 return (-1);
00145         if (lname[len - 1] != ']')
00146                 return (-1);
00147 
00148         inode_str = lname + PRG_SOCKET_PFXl;
00149         lname[len - 1] = '\0';
00150         *inode_p = strtol(inode_str, &serr, 0);
00151         if (serr == NULL || *serr != '\0' || *inode_p >= INT_MAX) {
00152                 lname[len - 1] = ']';
00153                 printf("no %s\n", lname);
00154                 return (-1);
00155         }
00156         lname[len - 1] = ']';
00157         return (0);
00158 }
00159 
00160 static int extract_type_2_socket_inode(const char lname[],
00161                                        unsigned long *inode_p)
00162 {
00163 
00164         char *serr;
00165 
00166         /* If lname is of the form "[0000]:12345", extract the "12345"
00167            as *inode_p.  Otherwise, return -1 as *inode_p.
00168          */
00169 
00170         if (strlen(lname) < PRG_SOCKET_PFX2l + 1)
00171                 return (-1);
00172         if (memcmp(lname, PRG_SOCKET_PFX2, PRG_SOCKET_PFX2l))
00173                 return (-1);
00174 
00175         *inode_p = strtol(lname + PRG_SOCKET_PFX2l, &serr, 0);
00176         if (serr == NULL || *serr != '\0' || *inode_p >= INT_MAX)
00177                 return (-1);
00178         return (0);
00179 }
00180 
00186 int str_is_integer(const char *str)
00187 {
00188         for (; *str != '\0'; ++str) {
00189                 if (!isdigit(*str))
00190                         return 0;
00191         }
00192         return 1;
00193 }
00194 
00200 int secure_readlink(const char *filename, char *buffer,
00201                     unsigned int buflen)
00202 {
00203         int ret;
00204 
00205         /* call readlink (add 'canary' to check "buffer overflow") */
00206         buffer[buflen - 1] = '\0';
00207         ret = readlink(filename, buffer, buflen);
00208 
00209         /* error if readlink fails */
00210         if (ret < 0)
00211                 return 0;
00212 
00213         /* error if buffer is too small ("buffer overflow") */
00214         if (buffer[buflen - 1] != '\0')
00215                 return 0;
00216 
00217         /* that should never happens, but ... */
00218         if (((int) buflen - 1) < ret)
00219                 return 0;
00220 
00221         /* write nul byte at the end */
00222         buffer[ret] = '\0';
00223         return 1;
00224 }
00225 
00229 void prg_cache_load_sub(DIR * dir, const char *path_process,
00230                         const char *path_fd)
00231 {
00232         char path[PATH_MAX];
00233         char lname[30];
00234         char finbuf[PROGNAME_WIDTH];
00235         unsigned long inode;
00236         struct dirent *file;
00237 
00238         while ((file = readdir(dir)) != NULL) {
00239 #ifdef HAVE_STRUCT_DIRENT_D_TYPE
00240                 if (file->d_type != DT_LNK)
00241                         continue;
00242 #endif
00243 
00244                 /* read link of "/proc/123/fd/FILENAME" */
00245                 if (!secure_snprintf
00246                     (path, sizeof(path), "%s/%s", path_fd, file->d_name))
00247                         continue;
00248                 if (!secure_readlink(path, lname, sizeof(lname)))
00249                         continue;
00250 
00251                 /*
00252                  * extract inode number from name like "socket:[12345]"
00253                  * or "[0000]:12345"
00254                  */
00255                 if (extract_type_1_socket_inode(lname, &inode) < 0)
00256                         if (extract_type_2_socket_inode(lname, &inode) < 0)
00257                                 continue;
00258 
00259                 /* get exec fullpath */
00260                 if (!secure_snprintf
00261                     (path, sizeof(path), "%s/exe", path_process))
00262                         continue;
00263                 if (!secure_readlink(path, finbuf, sizeof(finbuf)))
00264                         continue;
00265 
00266                 /* add item to the cache */
00267                 prg_cache_add(inode, finbuf);
00268         }
00269 }
00270 
00274 void prg_cache_load()
00275 {
00276         char path_process[PATH_MAX];
00277         char path_fd[PATH_MAX];
00278         DIR *dirproc = NULL;
00279         DIR *dirfd = NULL;
00280         struct dirent *file;
00281 
00282         if (prg_cache_loaded)
00283                 return;
00284         prg_cache_loaded = 1;
00285 
00286         /* open directory "/proc" */
00287         dirproc = opendir("/proc");
00288         if (dirproc == NULL)
00289                 panic("Fail to open /proc directory!");
00290 
00291         while ((file = readdir(dirproc)) != NULL) {
00292 #ifdef HAVE_STRUCT_DIRENT_D_TYPE
00293                 if (file->d_type != DT_DIR)
00294                         continue;
00295 #endif
00296                 if (!str_is_integer(file->d_name))
00297                         continue;
00298 
00299                 /* create path like "/proc/123" */
00300                 if (!secure_snprintf
00301                     (path_process, sizeof(path_process), "/proc/%s",
00302                      file->d_name))
00303                         continue;
00304 
00305                 /* create path like "/proc/123/fd" */
00306                 if (!secure_snprintf
00307                     (path_fd, sizeof(path_fd), "%s/fd", path_process))
00308                         continue;
00309 
00310                 /* open directory like "/proc/123/fd" */
00311                 dirfd = opendir(path_fd);
00312                 if (dirfd != NULL) {
00313                         prg_cache_load_sub(dirfd, path_process, path_fd);
00314                         closedir(dirfd);
00315                 }
00316         }
00317         closedir(dirproc);
00318 }
00319 
00322 #endif                          /* of #ifdef LINUX */

Generated on Sat Nov 22 04:00:37 2008 for NuFW by  doxygen 1.4.7