net-snmp
5.4.1
|
00001 #include <net-snmp/net-snmp-config.h> 00002 00003 #include <stdio.h> 00004 #include <sys/types.h> 00005 #include <signal.h> 00006 #include <errno.h> 00007 00008 #if HAVE_STRING_H 00009 #include <string.h> 00010 #else 00011 #include <strings.h> 00012 #endif 00013 #if HAVE_STDLIB_H 00014 #include <stdlib.h> 00015 #endif 00016 #if HAVE_UNISTD_H 00017 #include <unistd.h> 00018 #endif 00019 00020 #if HAVE_DMALLOC_H 00021 #include <dmalloc.h> 00022 #endif 00023 00024 #include <net-snmp/types.h> 00025 #include <net-snmp/output_api.h> 00026 00027 #include <net-snmp/library/snmp_transport.h> 00028 #include <net-snmp/library/snmpSTDDomain.h> 00029 #include <net-snmp/library/tools.h> 00030 00031 oid netsnmp_snmpSTDDomain[] = { TRANSPORT_DOMAIN_STD_IP }; 00032 static netsnmp_tdomain stdDomain; 00033 00034 /* 00035 * Return a string representing the address in data, or else the "far end" 00036 * address if data is NULL. 00037 */ 00038 00039 static char * 00040 netsnmp_std_fmtaddr(netsnmp_transport *t, void *data, int len) 00041 { 00042 char *buf; 00043 DEBUGMSGTL(("domain:std","formatting addr. data=%x\n",t->data)); 00044 if (t->data) { 00045 netsnmp_std_data *data = (netsnmp_std_data*)t->data; 00046 buf = (char*)malloc(SNMP_MAXBUF_MEDIUM); 00047 if (!buf) 00048 return strdup("STDInOut"); 00049 snprintf(buf, SNMP_MAXBUF_MEDIUM, "STD:%s", data->prog); 00050 DEBUGMSGTL(("domain:std"," formatted:=%s\n",buf)); 00051 return buf; 00052 } 00053 return strdup("STDInOut"); 00054 } 00055 00056 00057 00058 /* 00059 * You can write something into opaque that will subsequently get passed back 00060 * to your send function if you like. For instance, you might want to 00061 * remember where a PDU came from, so that you can send a reply there... 00062 */ 00063 00064 static int 00065 netsnmp_std_recv(netsnmp_transport *t, void *buf, int size, 00066 void **opaque, int *olength) 00067 { 00068 int rc = -1; 00069 00070 DEBUGMSGTL(("domain:std","recv on sock %d. data=%x\n",t->sock, t->data)); 00071 while (rc < 0) { 00072 rc = read(t->sock, buf, size); 00073 DEBUGMSGTL(("domain:std"," bytes: %d.\n", rc)); 00074 if (rc < 0 && errno != EINTR) { 00075 DEBUGMSGTL(("netsnmp_std", " read on fd %d failed: %d (\"%s\")\n", 00076 t->sock, errno, strerror(errno))); 00077 break; 00078 } 00079 if (rc == 0) { 00080 /* 0 input is probably bad since we selected on it */ 00081 return -1; 00082 } 00083 DEBUGMSGTL(("netsnmp_std", "read on stdin got %d bytes\n", rc)); 00084 } 00085 00086 return rc; 00087 } 00088 00089 00090 00091 static int 00092 netsnmp_std_send(netsnmp_transport *t, void *buf, int size, 00093 void **opaque, int *olength) 00094 { 00095 int rc = -1; 00096 00097 DEBUGMSGTL(("domain:std","send on sock. data=%x\n", t->data)); 00098 while (rc < 0) { 00099 if (t->data) { 00100 netsnmp_std_data *data = (netsnmp_std_data*)t->data; 00101 rc = write(data->outfd, buf, size); 00102 } else { 00103 /* straight to stdout */ 00104 rc = write(1, buf, size); 00105 } 00106 if (rc < 0 && errno != EINTR) { 00107 break; 00108 } 00109 } 00110 return rc; 00111 } 00112 00113 static int 00114 netsnmp_std_close(netsnmp_transport *t) 00115 { 00116 DEBUGMSGTL(("domain:std","close. data=%x\n", t->data)); 00117 if (t->data) { 00118 netsnmp_std_data *data = (netsnmp_std_data*)t->data; 00119 close(data->outfd); 00120 close(t->sock); 00121 00122 /* kill the child too */ 00123 DEBUGMSGTL(("domain:std"," killing %d\n", data->childpid)); 00124 kill(data->childpid, SIGTERM); 00125 sleep(1); 00126 kill(data->childpid, SIGKILL); 00127 /* XXX: set an alarm to kill harder the child */ 00128 } else { 00129 /* close stdout/in */ 00130 close(1); 00131 close(0); 00132 } 00133 return 0; 00134 } 00135 00136 00137 00138 static int 00139 netsnmp_std_accept(netsnmp_transport *t) 00140 { 00141 DEBUGMSGTL(("domain:std"," accept data=%x\n", t->data)); 00142 /* nothing to do here */ 00143 return 0; 00144 } 00145 00146 /* 00147 * Open a STDIN/STDOUT -based transport for SNMP. 00148 */ 00149 00150 netsnmp_transport * 00151 netsnmp_std_transport(const char *instring, size_t instring_len, 00152 const char *default_target) 00153 { 00154 netsnmp_transport *t; 00155 00156 t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport)); 00157 if (t == NULL) { 00158 return NULL; 00159 } 00160 memset(t, 0, sizeof(netsnmp_transport)); 00161 00162 t->domain = netsnmp_snmpSTDDomain; 00163 t->domain_length = 00164 sizeof(netsnmp_snmpSTDDomain) / sizeof(netsnmp_snmpSTDDomain[0]); 00165 00166 t->sock = 0; 00167 t->flags = NETSNMP_TRANSPORT_FLAG_STREAM | NETSNMP_TRANSPORT_FLAG_TUNNELED; 00168 00169 /* 00170 * Message size is not limited by this transport (hence msgMaxSize 00171 * is equal to the maximum legal size of an SNMP message). 00172 */ 00173 00174 t->msgMaxSize = 0x7fffffff; 00175 t->f_recv = netsnmp_std_recv; 00176 t->f_send = netsnmp_std_send; 00177 t->f_close = netsnmp_std_close; 00178 t->f_accept = netsnmp_std_accept; 00179 t->f_fmtaddr = netsnmp_std_fmtaddr; 00180 00181 /* 00182 * if instring is not null length, it specifies a path to a prog 00183 * XXX: plus args 00184 */ 00185 if (instring_len == 0 && default_target != NULL) { 00186 instring = default_target; 00187 instring_len = strlen(default_target); 00188 } 00189 00190 if (instring_len != 0) { 00191 int infd[2], outfd[2]; /* sockets to and from the client */ 00192 int childpid; 00193 00194 if (pipe(infd) || pipe(outfd)) { 00195 snmp_log(LOG_ERR, 00196 "Failed to create needed pipes for a STD transport"); 00197 netsnmp_transport_free(t); 00198 return NULL; 00199 } 00200 00201 childpid = fork(); 00202 /* parentpid => childpid */ 00203 /* infd[1] => infd[0] */ 00204 /* outfd[0] <= outfd[1] */ 00205 00206 if (childpid) { 00207 netsnmp_std_data *data; 00208 00209 /* we're in the parent */ 00210 close(infd[0]); 00211 close(outfd[1]); 00212 00213 data = SNMP_MALLOC_TYPEDEF(netsnmp_std_data); 00214 if (!data) { 00215 snmp_log(LOG_ERR, "snmpSTDDomain: memdup failed"); 00216 netsnmp_transport_free(t); 00217 return NULL; 00218 } 00219 t->data = data; 00220 t->data_length = sizeof(netsnmp_std_data); 00221 t->sock = outfd[0]; 00222 data->prog = strdup(instring); 00223 data->outfd = infd[1]; 00224 data->childpid = childpid; 00225 DEBUGMSGTL(("domain:std","parent. data=%x\n", t->data)); 00226 } else { 00227 /* we're in the child */ 00228 00229 /* close stdin */ 00230 close(0); 00231 /* copy pipe output to stdout */ 00232 dup(infd[0]); 00233 00234 /* close stdout */ 00235 close(1); 00236 /* copy pipe output to stdin */ 00237 dup(outfd[1]); 00238 00239 /* close all the pipes themselves */ 00240 close(infd[0]); 00241 close(infd[1]); 00242 close(outfd[0]); 00243 close(outfd[1]); 00244 00245 /* call exec */ 00246 system(instring); 00247 /* XXX: TODO: use exec form instead; needs args */ 00248 /* execv(instring, NULL); */ 00249 exit(0); 00250 00251 /* ack... we should never ever get here */ 00252 snmp_log(LOG_ERR, "STD transport returned after execv()\n"); 00253 } 00254 } 00255 00256 return t; 00257 } 00258 00259 netsnmp_transport * 00260 netsnmp_std_create_tstring(const char *instring, int local, 00261 const char *default_target) 00262 { 00263 return netsnmp_std_transport(instring, strlen(instring), default_target); 00264 } 00265 00266 netsnmp_transport * 00267 netsnmp_std_create_ostring(const u_char * o, size_t o_len, int local) 00268 { 00269 return netsnmp_std_transport((const char*)o, o_len, NULL); 00270 } 00271 00272 void 00273 netsnmp_std_ctor(void) 00274 { 00275 stdDomain.name = netsnmp_snmpSTDDomain; 00276 stdDomain.name_length = sizeof(netsnmp_snmpSTDDomain) / sizeof(oid); 00277 stdDomain.prefix = (const char **)calloc(2, sizeof(char *)); 00278 stdDomain.prefix[0] = "std"; 00279 00280 stdDomain.f_create_from_tstring_new = netsnmp_std_create_tstring; 00281 stdDomain.f_create_from_ostring = netsnmp_std_create_ostring; 00282 00283 netsnmp_tdomain_register(&stdDomain); 00284 }