Coverage Report

Created: 2023-09-25 06:12

/src/net-snmp/snmplib/transports/snmpSTDDomain.c
Line
Count
Source (jump to first uncovered line)
1
#include <net-snmp/net-snmp-config.h>
2
3
#include <net-snmp/library/snmpSTDDomain.h>
4
5
#include <stdio.h>
6
#include <sys/types.h>
7
#include <signal.h>
8
#include <errno.h>
9
10
#ifdef HAVE_STRING_H
11
#include <string.h>
12
#else
13
#include <strings.h>
14
#endif
15
#ifdef HAVE_STDLIB_H
16
#include <stdlib.h>
17
#endif
18
#ifdef HAVE_UNISTD_H
19
#include <unistd.h>
20
#endif
21
22
#include <net-snmp/types.h>
23
#include <net-snmp/output_api.h>
24
#include <net-snmp/library/snmp.h>
25
#include <net-snmp/library/snmp_transport.h>
26
#include <net-snmp/library/tools.h>
27
28
const oid netsnmp_snmpSTDDomain[] = { TRANSPORT_DOMAIN_STD_IP };
29
static netsnmp_tdomain stdDomain;
30
31
/*
32
 * Return a string representing the address in data, or else the "far end"
33
 * address if data is NULL.  
34
 */
35
36
static char *
37
netsnmp_std_fmtaddr(netsnmp_transport *t, const void *data, int len)
38
0
{
39
0
    DEBUGMSGTL(("domain:std","formatting addr.  data=%p\n",t->data));
40
0
    if (t->data) {
41
0
        netsnmp_std_data *data = (netsnmp_std_data*)t->data;
42
0
  char *buf;
43
44
0
        if (asprintf(&buf, "STD:%s", data->prog) < 0)
45
0
            buf = NULL;
46
0
        DEBUGMSGTL(("domain:std","  formatted:=%s\n",buf));
47
0
        return buf;
48
0
    }
49
0
    return strdup("STDInOut");
50
0
}
51
52
static void
53
netsnmp_std_get_taddr(netsnmp_transport *t, void **addr, size_t *addr_len)
54
0
{
55
0
    *addr_len = t->remote_length;
56
0
    *addr = netsnmp_memdup(t->remote, *addr_len);
57
0
}
58
59
/*
60
 * You can write something into opaque that will subsequently get passed back 
61
 * to your send function if you like.  For instance, you might want to
62
 * remember where a PDU came from, so that you can send a reply there...  
63
 */
64
65
static int
66
netsnmp_std_recv(netsnmp_transport *t, void *buf, int size,
67
     void **opaque, int *olength)
68
0
{
69
0
    int rc = -1;
70
71
0
    DEBUGMSGTL(("domain:std","recv on sock %d.  data=%p\n",t->sock, t->data));
72
0
    while (rc < 0) {
73
0
        rc = read(t->sock, buf, size);
74
0
        DEBUGMSGTL(("domain:std","  bytes: %d.\n", rc));
75
0
        if (rc < 0 && errno != EINTR) {
76
0
            DEBUGMSGTL(("netsnmp_std", " read on fd %d failed: %d (\"%s\")\n",
77
0
                        t->sock, errno, strerror(errno)));
78
0
            break;
79
0
        }
80
0
        if (rc == 0) {
81
            /* 0 input is probably bad since we selected on it */
82
0
            return -1;
83
0
        }
84
0
        DEBUGMSGTL(("netsnmp_std", "read on stdin got %d bytes\n", rc));
85
0
    }
86
87
0
    return rc;
88
0
}
89
90
91
92
static int
93
netsnmp_std_send(netsnmp_transport *t, const void *buf, int size,
94
     void **opaque, int *olength)
95
0
{
96
0
    int rc = -1;
97
98
0
    DEBUGMSGTL(("domain:std","send on sock.  data=%p\n", t->data));
99
0
    while (rc < 0) {
100
0
        if (t->data) {
101
0
            netsnmp_std_data *data = (netsnmp_std_data*)t->data;
102
0
            rc = write(data->outfd, buf, size);
103
0
        } else {
104
            /* straight to stdout */
105
0
            rc = write(1, buf, size);
106
0
        }
107
0
        if (rc < 0 && errno != EINTR) {
108
0
            break;
109
0
        }
110
0
    }
111
0
    return rc;
112
0
}
113
114
static int
115
netsnmp_std_close(netsnmp_transport *t)
116
0
{
117
0
    DEBUGMSGTL(("domain:std","close.  data=%p\n", t->data));
118
0
    if (t->data) {
119
0
        netsnmp_std_data *data = (netsnmp_std_data*)t->data;
120
0
        close(data->outfd);
121
0
        close(t->sock);
122
123
        /* kill the child too */
124
0
        DEBUGMSGTL(("domain:std"," killing %d\n", data->childpid));
125
0
        kill(data->childpid, SIGTERM);
126
0
        sleep(1);
127
0
        kill(data->childpid, SIGKILL);
128
        /* XXX: set an alarm to kill harder the child */
129
0
    } else {
130
        /* close stdout/in */
131
0
        close(STDOUT_FILENO);
132
0
        close(STDIN_FILENO);
133
0
    }
134
0
    return 0;
135
0
}
136
137
138
139
static int
140
netsnmp_std_accept(netsnmp_transport *t)
141
0
{
142
0
    DEBUGMSGTL(("domain:std"," accept data=%p\n", t->data));
143
    /* nothing to do here */
144
0
    return 0;
145
0
}
146
147
/*
148
 * Open a STDIN/STDOUT -based transport for SNMP.
149
 */
150
151
netsnmp_transport *
152
netsnmp_std_transport(const char *instring, size_t instring_len,
153
          const char *default_target)
154
0
{
155
0
    netsnmp_transport *t;
156
157
0
    t = SNMP_MALLOC_TYPEDEF(netsnmp_transport);
158
0
    if (t == NULL) {
159
0
        return NULL;
160
0
    }
161
162
0
    t->domain = netsnmp_snmpSTDDomain;
163
0
    t->domain_length =
164
0
        sizeof(netsnmp_snmpSTDDomain) / sizeof(netsnmp_snmpSTDDomain[0]);
165
166
0
    t->sock = -1;
167
0
    t->flags = NETSNMP_TRANSPORT_FLAG_STREAM | NETSNMP_TRANSPORT_FLAG_TUNNELED;
168
169
    /*
170
     * Message size is not limited by this transport (hence msgMaxSize
171
     * is equal to the maximum legal size of an SNMP message).  
172
     */
173
174
0
    t->msgMaxSize = SNMP_MAX_PACKET_LEN;
175
0
    t->f_recv     = netsnmp_std_recv;
176
0
    t->f_send     = netsnmp_std_send;
177
0
    t->f_close    = netsnmp_std_close;
178
0
    t->f_accept   = netsnmp_std_accept;
179
0
    t->f_fmtaddr  = netsnmp_std_fmtaddr;
180
0
    t->f_get_taddr = netsnmp_std_get_taddr;
181
182
    /*
183
     * if instring is not null length, it specifies a path to a prog
184
     * XXX: plus args
185
     */
186
0
    if (instring_len == 0 && default_target != NULL) {
187
0
  instring = default_target;
188
0
  instring_len = strlen(default_target);
189
0
    }
190
191
0
    if (instring_len != 0) {
192
0
        int infd[2], outfd[2];  /* sockets to and from the client */
193
0
        int childpid;
194
195
0
        if (pipe(infd) || pipe(outfd)) {
196
0
            snmp_log(LOG_ERR,
197
0
                     "Failed to create needed pipes for a STD transport");
198
0
            netsnmp_transport_free(t);
199
0
            return NULL;
200
0
        }
201
202
0
        childpid = fork();
203
        /* parentpid => childpid */
204
        /* infd[1]   => infd[0] */
205
        /* outfd[0]  <= outfd[1] */
206
207
0
        if (childpid) {
208
0
            netsnmp_std_data *data;
209
            
210
            /* we're in the parent */
211
0
            close(infd[0]);
212
0
            close(outfd[1]);
213
214
0
            data = SNMP_MALLOC_TYPEDEF(netsnmp_std_data);
215
0
            if (!data) {
216
0
                snmp_log(LOG_ERR, "snmpSTDDomain: malloc failed");
217
0
                netsnmp_transport_free(t);
218
0
                return NULL;
219
0
            }
220
0
            t->data = data;
221
0
            t->data_length = sizeof(netsnmp_std_data);
222
0
            t->sock = outfd[0];
223
0
            data->prog = strdup(instring);
224
0
            data->outfd = infd[1];
225
0
            data->childpid = childpid;
226
0
            DEBUGMSGTL(("domain:std","parent.  data=%p\n", t->data));
227
0
        } else {
228
            /* we're in the child */
229
230
0
            dup2(infd[0], STDIN_FILENO);
231
0
            dup2(outfd[1], STDOUT_FILENO);
232
233
            /* close all the pipes themselves */
234
0
            close(infd[0]);
235
0
            close(infd[1]);
236
0
            close(outfd[0]);
237
0
            close(outfd[1]);
238
239
            /* call exec */
240
0
            NETSNMP_IGNORE_RESULT(system(instring));
241
            /* XXX: TODO: use exec form instead; needs args */
242
            /* execv(instring, NULL); */
243
0
            exit(0);
244
245
            /* ack...  we should never ever get here */
246
0
            snmp_log(LOG_ERR, "STD transport returned after execv()\n");
247
0
        }
248
0
    }            
249
250
0
    return t;
251
0
}
252
253
netsnmp_transport *
254
netsnmp_std_create_tstring(const char *instring, int local,
255
         const char *default_target)
256
0
{
257
0
    return netsnmp_std_transport(instring, strlen(instring), default_target);
258
0
}
259
260
netsnmp_transport *
261
netsnmp_std_create_ostring(const void *o, size_t o_len, int local)
262
0
{
263
0
    return netsnmp_std_transport(o, o_len, NULL);
264
0
}
265
266
void
267
netsnmp_std_ctor(void)
268
3.39k
{
269
3.39k
    stdDomain.name = netsnmp_snmpSTDDomain;
270
3.39k
    stdDomain.name_length = OID_LENGTH(netsnmp_snmpSTDDomain);
271
3.39k
    stdDomain.prefix = calloc(2, sizeof(char *));
272
3.39k
    if (!stdDomain.prefix) {
273
0
        snmp_log(LOG_ERR, "calloc() failed - out of memory\n");
274
0
        return;
275
0
    }
276
3.39k
    stdDomain.prefix[0] = "std";
277
278
3.39k
    stdDomain.f_create_from_tstring_new = netsnmp_std_create_tstring;
279
3.39k
    stdDomain.f_create_from_ostring     = netsnmp_std_create_ostring;
280
281
3.39k
    netsnmp_tdomain_register(&stdDomain);
282
3.39k
}