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
00036
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 = t->data;
00046 buf = 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
00060
00061
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
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 = t->data;
00101 rc = write(data->outfd, buf, size);
00102 } else {
00103
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 = t->data;
00119 close(data->outfd);
00120 close(t->sock);
00121
00122
00123 DEBUGMSGTL(("domain:std"," killing %d\n", data->childpid));
00124 kill(data->childpid, SIGTERM);
00125 sleep(1);
00126 kill(data->childpid, SIGKILL);
00127
00128 } else {
00129
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
00143 return 0;
00144 }
00145
00146
00147
00148
00149
00150 netsnmp_transport *
00151 netsnmp_std_transport(const char *instring, size_t instring_len)
00152 {
00153 netsnmp_transport *t;
00154
00155 t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport));
00156 if (t == NULL) {
00157 return NULL;
00158 }
00159 memset(t, 0, sizeof(netsnmp_transport));
00160
00161 t->domain = netsnmp_snmpSTDDomain;
00162 t->domain_length =
00163 sizeof(netsnmp_snmpSTDDomain) / sizeof(netsnmp_snmpSTDDomain[0]);
00164
00165 t->sock = 0;
00166 t->flags = NETSNMP_TRANSPORT_FLAG_STREAM | NETSNMP_TRANSPORT_FLAG_TUNNELED;
00167
00168
00169
00170
00171
00172
00173 t->msgMaxSize = 0x7fffffff;
00174 t->f_recv = netsnmp_std_recv;
00175 t->f_send = netsnmp_std_send;
00176 t->f_close = netsnmp_std_close;
00177 t->f_accept = netsnmp_std_accept;
00178 t->f_fmtaddr = netsnmp_std_fmtaddr;
00179
00180
00181
00182
00183
00184 if (instring_len != 0) {
00185 int infd[2], outfd[2];
00186 int childpid;
00187
00188 if (pipe(infd) || pipe(outfd)) {
00189 snmp_log(LOG_ERR,
00190 "Failed to create needed pipes for a STD transport");
00191 netsnmp_transport_free(t);
00192 return NULL;
00193 }
00194
00195 childpid = fork();
00196
00197
00198
00199
00200 if (childpid) {
00201 netsnmp_std_data *data;
00202
00203
00204 close(infd[0]);
00205 close(outfd[1]);
00206
00207 data = SNMP_MALLOC_TYPEDEF(netsnmp_std_data);
00208 if (!data) {
00209 snmp_log(LOG_ERR, "snmpSTDDomain: memdup failed");
00210 netsnmp_transport_free(t);
00211 return NULL;
00212 }
00213 t->data = data;
00214 t->data_length = sizeof(netsnmp_transport_free);
00215 t->sock = outfd[0];
00216 data->prog = strdup(instring);
00217 data->outfd = infd[1];
00218 data->childpid = childpid;
00219 DEBUGMSGTL(("domain:std","parent. data=%x\n", t->data));
00220 } else {
00221
00222
00223
00224 close(0);
00225
00226 dup(infd[0]);
00227
00228
00229 close(1);
00230
00231 dup(outfd[1]);
00232
00233
00234 close(infd[0]);
00235 close(infd[1]);
00236 close(outfd[0]);
00237 close(outfd[1]);
00238
00239
00240 system(instring);
00241
00242
00243 exit(0);
00244
00245
00246 snmp_log(LOG_ERR, "STD transport returned after execv()\n");
00247 }
00248 }
00249
00250 return t;
00251 }
00252
00253 netsnmp_transport *
00254 netsnmp_std_create_tstring(const char *instring, int local)
00255 {
00256 return netsnmp_std_transport(instring, strlen(instring));
00257 }
00258
00259 netsnmp_transport *
00260 netsnmp_std_create_ostring(const u_char * o, size_t o_len, int local)
00261 {
00262 return netsnmp_std_transport(o, o_len);
00263 }
00264
00265 void
00266 netsnmp_std_ctor(void)
00267 {
00268 stdDomain.name = netsnmp_snmpSTDDomain;
00269 stdDomain.name_length = sizeof(netsnmp_snmpSTDDomain) / sizeof(oid);
00270 stdDomain.prefix = calloc(2, sizeof(char *));
00271 stdDomain.prefix[0] = "std";
00272
00273 stdDomain.f_create_from_tstring = netsnmp_std_create_tstring;
00274 stdDomain.f_create_from_ostring = netsnmp_std_create_ostring;
00275
00276 netsnmp_tdomain_register(&stdDomain);
00277 }