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=%p\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
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=%p\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=%p\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
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=%p\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
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=%p\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 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
00171
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
00183
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];
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
00203
00204
00205
00206 if (childpid) {
00207 netsnmp_std_data *data;
00208
00209
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: malloc 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=%p\n", t->data));
00226 } else {
00227
00228
00229
00230 close(0);
00231
00232 dup(infd[0]);
00233
00234
00235 close(1);
00236
00237 dup(outfd[1]);
00238
00239
00240 close(infd[0]);
00241 close(infd[1]);
00242 close(outfd[0]);
00243 close(outfd[1]);
00244
00245
00246 system(instring);
00247
00248
00249 exit(0);
00250
00251
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 }