00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
00094
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
00139
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
00167
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
00206 buffer[buflen - 1] = '\0';
00207 ret = readlink(filename, buffer, buflen);
00208
00209
00210 if (ret < 0)
00211 return 0;
00212
00213
00214 if (buffer[buflen - 1] != '\0')
00215 return 0;
00216
00217
00218 if (((int) buflen - 1) < ret)
00219 return 0;
00220
00221
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
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
00253
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
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
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
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
00300 if (!secure_snprintf
00301 (path_process, sizeof(path_process), "/proc/%s",
00302 file->d_name))
00303 continue;
00304
00305
00306 if (!secure_snprintf
00307 (path_fd, sizeof(path_fd), "%s/fd", path_process))
00308 continue;
00309
00310
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