Coverage Report

Created: 2026-01-10 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/net-snmp/snmplib/transports/snmpUnixDomain.c
Line
Count
Source
1
#include <net-snmp/net-snmp-config.h>
2
#include <net-snmp/net-snmp-features.h>
3
4
#include <sys/types.h>
5
#include <net-snmp/library/snmpUnixDomain.h>
6
7
#include <stddef.h>
8
#include <stdio.h>
9
#include <ctype.h>
10
#include <errno.h>
11
12
#ifdef HAVE_STRING_H
13
#include <string.h>
14
#else
15
#include <strings.h>
16
#endif
17
#ifdef HAVE_STDLIB_H
18
#include <stdlib.h>
19
#endif
20
#ifdef HAVE_UNISTD_H
21
#include <unistd.h>
22
#endif
23
#ifdef HAVE_SYS_SOCKET_H
24
#include <sys/socket.h>
25
#endif
26
27
#include <net-snmp/types.h>
28
#include <net-snmp/output_api.h>
29
#include <net-snmp/config_api.h>
30
31
#include <net-snmp/library/snmp.h>
32
#include <net-snmp/library/snmp_impl.h>
33
#include <net-snmp/library/snmp_transport.h>
34
#include <net-snmp/library/snmpSocketBaseDomain.h>
35
#include <net-snmp/library/system.h> /* mkdirhier */
36
#include <net-snmp/library/tools.h>
37
38
#ifndef NETSNMP_NO_SYSTEMD
39
#include <net-snmp/library/sd-daemon.h>
40
#endif
41
42
netsnmp_feature_child_of(transport_unix_socket_all, transport_all);
43
netsnmp_feature_child_of(unix_socket_paths, transport_unix_socket_all);
44
45
#ifndef NETSNMP_STREAM_QUEUE_LEN
46
#define NETSNMP_STREAM_QUEUE_LEN  5
47
#endif
48
49
#undef SUN_LEN
50
/*
51
 * Evaluate to actual length of the `sockaddr_un' structure.
52
 */
53
0
#define SUN_LEN(ptr) ((size_t)&(((struct sockaddr_un *)NULL)->sun_path)      \
54
0
                      + strlen ((ptr)->sun_path))
55
56
const oid netsnmp_UnixDomain[] = { TRANSPORT_DOMAIN_LOCAL };
57
static netsnmp_tdomain unixDomain;
58
59
60
/*
61
 * This is the structure we use to hold transport-specific data.
62
 */
63
64
typedef struct _sockaddr_un_pair {
65
    int             local;
66
    struct sockaddr_un server;
67
    struct sockaddr_un client;
68
} sockaddr_un_pair;
69
70
71
/*
72
 * Return a string representing the address in data, or else the "far end"
73
 * address if data is NULL.
74
 */
75
76
static char *
77
netsnmp_unix_fmtaddr(netsnmp_transport *t, const void *data, int len)
78
0
{
79
0
    const struct sockaddr_un *to = NULL;
80
81
0
    if (data != NULL)
82
0
        to = (const struct sockaddr_un *) data;
83
0
    else if (t != NULL && t->data != NULL)
84
0
        to = &(((const sockaddr_un_pair *) t->data)->server);
85
0
    if (to == NULL) {
86
        /*
87
         * "Local IPC" is the Posix.1g term for Unix domain protocols,
88
         * according to W. R. Stevens, ``Unix Network Programming Volume I
89
         * Second Edition'', p. 374.
90
         */
91
0
        return strdup("Local IPC: unknown");
92
0
    } else if (to->sun_path[0] == 0) {
93
        /*
94
         * This is an abstract name.  We could render it as hex or something
95
         * but let's not worry about that for now.
96
         */
97
0
        return strdup("Local IPC: abstract");
98
0
    } else {
99
0
        char *tmp;
100
101
0
        if (asprintf(&tmp, "Local IPC: %s", to->sun_path) < 0)
102
0
            tmp = NULL;
103
0
        return tmp;
104
0
    }
105
0
}
106
107
static void
108
netsnmp_unix_get_taddr(netsnmp_transport *t, void **addr, size_t *addr_len)
109
0
{
110
0
    *addr_len = t->remote_length;
111
0
    *addr = netsnmp_memdup(t->remote, *addr_len);
112
0
}
113
114
/*
115
 * You can write something into opaque that will subsequently get passed back
116
 * to your send function if you like.  For instance, you might want to
117
 * remember where a PDU came from, so that you can send a reply there...
118
 */
119
120
static int
121
netsnmp_unix_recv(netsnmp_transport *t, void *buf, int size,
122
                  void **opaque, int *olength)
123
0
{
124
0
    int rc = -1;
125
0
    socklen_t       tolen = sizeof(struct sockaddr_un);
126
0
    struct sockaddr *to;
127
128
129
0
    if (t != NULL && t->sock >= 0) {
130
0
        to = (struct sockaddr *) malloc(sizeof(struct sockaddr_un));
131
0
        if (to == NULL) {
132
0
            *opaque = NULL;
133
0
            *olength = 0;
134
0
            return -1;
135
0
        } else {
136
0
            memset(to, 0, tolen);
137
0
        }
138
0
        if(getsockname(t->sock, to, &tolen) != 0){
139
0
            free(to);
140
0
            *opaque = NULL;
141
0
            *olength = 0;
142
0
            return -1;
143
0
        };
144
0
        while (rc < 0) {
145
0
#ifdef MSG_DONTWAIT
146
0
            rc = recvfrom(t->sock, buf, size, MSG_DONTWAIT, NULL, NULL);
147
#else
148
            rc = recvfrom(t->sock, buf, size, 0, NULL, NULL);
149
#endif
150
0
            if (rc < 0 && errno != EINTR) {
151
0
                DEBUGMSGTL(("netsnmp_unix", "recv fd %d err %d (\"%s\")\n",
152
0
                            t->sock, errno, strerror(errno)));
153
0
                free(to);
154
0
                return rc;
155
0
            }
156
0
            *opaque = (void*)to;
157
0
            *olength = sizeof(struct sockaddr_un);
158
0
        }
159
0
        DEBUGMSGTL(("netsnmp_unix", "recv fd %d got %d bytes\n", t->sock, rc));
160
0
    }
161
0
    return rc;
162
0
}
163
164
165
166
static int
167
netsnmp_unix_send(netsnmp_transport *t, const void *buf, int size,
168
                  void **opaque, int *olength)
169
0
{
170
0
    int rc = -1;
171
172
0
    if (t != NULL && t->sock >= 0) {
173
0
        DEBUGMSGTL(("netsnmp_unix", "send %d bytes to %p on fd %d\n",
174
0
                    size, buf, t->sock));
175
0
        while (rc < 0) {
176
0
            rc = sendto(t->sock, buf, size, 0, NULL, 0);
177
0
            if (rc < 0 && errno != EINTR) {
178
0
                break;
179
0
            }
180
0
        }
181
0
    }
182
0
    return rc;
183
0
}
184
185
186
187
static int
188
netsnmp_unix_close(netsnmp_transport *t)
189
0
{
190
0
    int rc = 0;
191
0
    sockaddr_un_pair *sup = (sockaddr_un_pair *) t->data;
192
193
0
    if (t->sock >= 0) {
194
0
#ifndef HAVE_CLOSESOCKET
195
0
        rc = close(t->sock);
196
#else
197
        rc = closesocket(t->sock);
198
#endif
199
0
        t->sock = -1;
200
0
        if (sup != NULL) {
201
0
            if (sup->local) {
202
0
                if (sup->server.sun_path[0] != 0) {
203
0
                  DEBUGMSGTL(("netsnmp_unix", "close: server unlink(\"%s\")\n",
204
0
                              sup->server.sun_path));
205
0
                  unlink(sup->server.sun_path);
206
0
                }
207
0
            } else {
208
0
                if (sup->client.sun_path[0] != 0) {
209
0
                  DEBUGMSGTL(("netsnmp_unix", "close: client unlink(\"%s\")\n",
210
0
                              sup->client.sun_path));
211
0
                  unlink(sup->client.sun_path);
212
0
                }
213
0
            }
214
0
        }
215
0
        return rc;
216
0
    } else {
217
0
        return -1;
218
0
    }
219
0
}
220
221
222
223
static int
224
netsnmp_unix_accept(netsnmp_transport *t)
225
0
{
226
0
    struct sockaddr *farend = NULL;
227
0
    int             newsock = -1;
228
0
    socklen_t       farendlen = sizeof(struct sockaddr_un);
229
230
0
    farend = (struct sockaddr *) malloc(farendlen);
231
232
0
    if (farend == NULL) {
233
        /*
234
         * Indicate that the acceptance of this socket failed.
235
         */
236
0
        DEBUGMSGTL(("netsnmp_unix", "accept: malloc failed\n"));
237
0
        return -1;
238
0
    }
239
0
    memset(farend, 0, farendlen);
240
241
0
    if (t != NULL && t->sock >= 0) {
242
0
        newsock = accept(t->sock, farend, &farendlen);
243
244
0
        if (newsock < 0) {
245
0
            DEBUGMSGTL(("netsnmp_unix","accept failed rc %d errno %d \"%s\"\n",
246
0
                        newsock, errno, strerror(errno)));
247
0
            free(farend);
248
0
            return newsock;
249
0
        }
250
251
0
        if (t->data != NULL) {
252
0
            free(t->data);
253
0
        }
254
255
0
        DEBUGMSGTL(("netsnmp_unix", "accept succeeded (farend %p len %d)\n",
256
0
                    farend, (int) farendlen));
257
0
        t->data = farend;
258
0
        t->data_length = sizeof(struct sockaddr_un);
259
0
       netsnmp_sock_buffer_set(newsock, SO_SNDBUF, 1, 0);
260
0
       netsnmp_sock_buffer_set(newsock, SO_RCVBUF, 1, 0);
261
0
        return newsock;
262
0
    } else {
263
0
        free(farend);
264
0
        return -1;
265
0
    }
266
0
}
267
268
static int create_path = 0;
269
static mode_t create_mode;
270
271
#ifndef NETSNMP_FEATURE_REMOVE_UNIX_SOCKET_PATHS
272
/** If trying to create unix sockets in non-existing directories then
273
 *  try to create the directory with mask mode.
274
 */
275
void netsnmp_unix_create_path_with_mode(int mode)
276
0
{
277
0
    create_path = 1;
278
0
    create_mode = mode;
279
0
}
280
281
/** If trying to create unix sockets in non-existing directories then
282
 *  fail.
283
 */
284
void netsnmp_unix_dont_create_path(void)
285
0
{
286
0
    create_path = 0;
287
0
}
288
#endif /* NETSNMP_FEATURE_REMOVE_UNIX_SOCKET_PATHS */
289
290
/*
291
 * Open a Unix-domain transport for SNMP.  Local is TRUE if addr is the local
292
 * address to bind to (i.e. this is a server-type session); otherwise addr is
293
 * the remote address to send things to (and we make up a temporary name for
294
 * the local end of the connection).
295
 */
296
297
netsnmp_transport *
298
netsnmp_unix_transport(const struct sockaddr_un *addr, int local)
299
0
{
300
0
    netsnmp_transport *t = NULL;
301
0
    sockaddr_un_pair *sup = NULL;
302
0
    int             rc = 0;
303
0
    int             socket_initialized = 0;
304
305
#ifdef NETSNMP_NO_LISTEN_SUPPORT
306
    /* SPECIAL CIRCUMSTANCE: We still want AgentX to be able to operate,
307
       so we allow for unix domain sockets to still listen when everything
308
       else isn't allowed to.  Thus, we ignore this define in this file.
309
    */
310
#endif /* NETSNMP_NO_LISTEN_SUPPORT */
311
312
0
    if (addr == NULL || addr->sun_family != AF_UNIX) {
313
0
        return NULL;
314
0
    }
315
316
0
    t = SNMP_MALLOC_TYPEDEF(netsnmp_transport);
317
0
    if (t == NULL) {
318
0
        return NULL;
319
0
    }
320
321
0
    DEBUGIF("netsnmp_unix") {
322
0
        char *str = netsnmp_unix_fmtaddr(NULL, addr,
323
0
                                         sizeof(struct sockaddr_un));
324
0
        DEBUGMSGTL(("netsnmp_unix", "open %s %s\n", local ? "local" : "remote",
325
0
                    str));
326
0
        free(str);
327
0
    }
328
329
0
    t->domain = netsnmp_UnixDomain;
330
0
    t->domain_length =
331
0
        sizeof(netsnmp_UnixDomain) / sizeof(netsnmp_UnixDomain[0]);
332
333
0
    t->data = malloc(sizeof(sockaddr_un_pair));
334
0
    if (t->data == NULL) {
335
0
        netsnmp_transport_free(t);
336
0
        return NULL;
337
0
    }
338
0
    memset(t->data, 0, sizeof(sockaddr_un_pair));
339
0
    t->data_length = sizeof(sockaddr_un_pair);
340
0
    sup = (sockaddr_un_pair *) t->data;
341
342
0
#ifndef NETSNMP_NO_SYSTEMD
343
    /*
344
     * Maybe the socket was already provided by systemd...
345
     */
346
0
    if (local) {
347
0
        t->sock = netsnmp_sd_find_unix_socket(SOCK_STREAM, 1, addr->sun_path);
348
0
        if (t->sock >= 0)
349
0
            socket_initialized = 1;
350
0
    }
351
0
#endif
352
0
    if (!socket_initialized)
353
0
        t->sock = socket(PF_UNIX, SOCK_STREAM, 0);
354
0
    if (t->sock < 0) {
355
0
        netsnmp_transport_free(t);
356
0
        return NULL;
357
0
    }
358
359
0
    t->flags = NETSNMP_TRANSPORT_FLAG_STREAM;
360
361
0
    if (local) {
362
0
        t->local_length = strlen(addr->sun_path);
363
0
        t->local = strdup(addr->sun_path);
364
0
        if (t->local == NULL) {
365
0
            netsnmp_unix_close(t);
366
0
            netsnmp_transport_free(t);
367
0
            return NULL;
368
0
        }
369
370
        /*
371
         * This session is intended as a server, so we must bind to the given
372
         * path (unlinking it first, to avoid errors).
373
         */
374
375
0
        t->flags |= NETSNMP_TRANSPORT_FLAG_LISTEN;
376
377
0
        if (!socket_initialized) {
378
0
            unlink(addr->sun_path);
379
0
            rc = bind(t->sock, (const struct sockaddr *)addr, SUN_LEN(addr));
380
0
            if (rc != 0 && errno == ENOENT && create_path) {
381
0
                rc = mkdirhier(addr->sun_path, create_mode, 1);
382
0
                if (rc != 0) {
383
0
                    netsnmp_unix_close(t);
384
0
                    netsnmp_transport_free(t);
385
0
                    return NULL;
386
0
                }
387
0
                rc = bind(t->sock, (const struct sockaddr *)addr,
388
0
        SUN_LEN(addr));
389
0
            }
390
0
            if (rc != 0) {
391
0
                DEBUGMSGTL(("netsnmp_unix_transport",
392
0
                        "couldn't bind \"%s\", errno %d (%s)\n",
393
0
                        addr->sun_path, errno, strerror(errno)));
394
0
                netsnmp_unix_close(t);
395
0
                netsnmp_transport_free(t);
396
0
                return NULL;
397
0
            }
398
0
        }
399
400
        /*
401
         * Save the address in the transport-specific data pointer for later
402
         * use by netsnmp_unix_close.
403
         */
404
405
0
        sup->server.sun_family = AF_UNIX;
406
0
        strcpy(sup->server.sun_path, addr->sun_path);
407
0
        sup->local = 1;
408
409
        /*
410
         * Now sit here and listen for connections to arrive.
411
         */
412
413
0
        if (!socket_initialized) {
414
0
            rc = listen(t->sock, NETSNMP_STREAM_QUEUE_LEN);
415
0
            if (rc != 0) {
416
0
                DEBUGMSGTL(("netsnmp_unix_transport",
417
0
                            "couldn't listen to \"%s\", errno %d (%s)\n",
418
0
                            addr->sun_path, errno, strerror(errno)));
419
0
                netsnmp_unix_close(t);
420
0
                netsnmp_transport_free(t);
421
0
                return NULL;
422
0
            }
423
0
        }
424
0
    } else {
425
0
        t->remote_length = strlen(addr->sun_path);
426
0
        t->remote = strdup(addr->sun_path);
427
0
        if (t->remote == NULL) {
428
0
            netsnmp_transport_free(t);
429
0
            return NULL;
430
0
        }
431
432
0
        rc = connect(t->sock, (const struct sockaddr *)addr,
433
0
         sizeof(struct sockaddr_un));
434
0
        if (rc != 0) {
435
0
            DEBUGMSGTL(("netsnmp_unix_transport",
436
0
                        "couldn't connect to \"%s\", errno %d (%s)\n",
437
0
                        addr->sun_path, errno, strerror(errno)));
438
0
            netsnmp_unix_close(t);
439
0
            netsnmp_transport_free(t);
440
0
            return NULL;
441
0
        }
442
443
        /*
444
         * Save the remote address in the transport-specific data pointer for
445
         * later use by netsnmp_unix_send.
446
         */
447
448
0
        sup->server.sun_family = AF_UNIX;
449
0
        strcpy(sup->server.sun_path, addr->sun_path);
450
0
        sup->local = 0;
451
0
        netsnmp_sock_buffer_set(t->sock, SO_SNDBUF, local, 0);
452
0
        netsnmp_sock_buffer_set(t->sock, SO_RCVBUF, local, 0);
453
0
    }
454
455
    /*
456
     * Message size is not limited by this transport (hence msgMaxSize
457
     * is equal to the maximum legal size of an SNMP message).
458
     */
459
460
0
    t->msgMaxSize = SNMP_MAX_PACKET_LEN;
461
0
    t->f_recv     = netsnmp_unix_recv;
462
0
    t->f_send     = netsnmp_unix_send;
463
0
    t->f_close    = netsnmp_unix_close;
464
0
    t->f_accept   = netsnmp_unix_accept;
465
0
    t->f_fmtaddr  = netsnmp_unix_fmtaddr;
466
0
    t->f_get_taddr = netsnmp_unix_get_taddr;
467
468
0
    return t;
469
0
}
470
471
netsnmp_transport *
472
netsnmp_unix_create_tstring(const char *string, int local,
473
          const char *default_target)
474
0
{
475
0
    struct sockaddr_un addr;
476
477
0
    if (string && *string != '\0') {
478
0
    } else if (default_target && *default_target != '\0') {
479
0
      string = default_target;
480
0
    }
481
482
0
    if ((string != NULL && *string != '\0') &&
483
0
  (strlen(string) < sizeof(addr.sun_path))) {
484
0
        addr.sun_family = AF_UNIX;
485
0
        memset(addr.sun_path, 0, sizeof(addr.sun_path));
486
0
        strlcpy(addr.sun_path, string, sizeof(addr.sun_path));
487
0
        return netsnmp_unix_transport(&addr, local);
488
0
    } else {
489
0
        if (string != NULL && *string != '\0') {
490
0
            snmp_log(LOG_ERR, "Path too long for Unix domain transport\n");
491
0
        }
492
0
        return NULL;
493
0
    }
494
0
}
495
496
497
498
netsnmp_transport *
499
netsnmp_unix_create_ostring(const void *ostring, size_t o_len, int local)
500
0
{
501
0
    struct sockaddr_un addr;
502
503
0
    if (o_len > 0 && o_len < (sizeof(addr.sun_path) - 1)) {
504
0
        addr.sun_family = AF_UNIX;
505
0
        memset(addr.sun_path, 0, sizeof(addr.sun_path));
506
0
        strlcpy(addr.sun_path, ostring, sizeof(addr.sun_path));
507
0
        return netsnmp_unix_transport(&addr, local);
508
0
    } else {
509
0
        if (o_len > 0) {
510
0
            snmp_log(LOG_ERR, "Path too long for Unix domain transport\n");
511
0
        }
512
0
    }
513
0
    return NULL;
514
0
}
515
516
517
518
void
519
netsnmp_unix_ctor(void)
520
4.25k
{
521
4.25k
    unixDomain.name = netsnmp_UnixDomain;
522
4.25k
    unixDomain.name_length = OID_LENGTH(netsnmp_UnixDomain);
523
4.25k
    unixDomain.prefix = calloc(2, sizeof(char *));
524
4.25k
    if (!unixDomain.prefix) {
525
0
        snmp_log(LOG_ERR, "calloc() failed - out of memory\n");
526
0
        return;
527
0
    }
528
4.25k
    unixDomain.prefix[0] = "unix";
529
530
4.25k
    unixDomain.f_create_from_tstring_new = netsnmp_unix_create_tstring;
531
4.25k
    unixDomain.f_create_from_ostring     = netsnmp_unix_create_ostring;
532
533
4.25k
    netsnmp_tdomain_register(&unixDomain);
534
4.25k
}
535
536
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
537
/* support for SNMPv1 and SNMPv2c on unix domain*/
538
539
149
#define EXAMPLE_COMMUNITY "COMMUNITY"
540
typedef struct com2SecUnixEntry_s {
541
    const char*     sockpath;
542
    const char*     secName;
543
    const char*     contextName;
544
    struct com2SecUnixEntry_s *next;
545
    unsigned short  pathlen;
546
    const char      community[1];
547
} com2SecUnixEntry;
548
549
static com2SecUnixEntry   *com2SecUnixList = NULL, *com2SecUnixListLast = NULL;
550
551
552
int
553
netsnmp_unix_getSecName(void *opaque, int olength,
554
                        const char *community,
555
                        size_t community_len,
556
                        const char **secName, const char **contextName)
557
0
{
558
0
    const com2SecUnixEntry   *c;
559
0
    struct sockaddr_un *to = (struct sockaddr_un *) opaque;
560
0
    char           *ztcommunity = NULL;
561
562
0
    if (secName != NULL) {
563
0
        *secName = NULL;  /* Haven't found anything yet */
564
0
    }
565
566
    /*
567
     * Special case if there are NO entries (as opposed to no MATCHING
568
     * entries).
569
     */
570
571
0
    if (com2SecUnixList == NULL) {
572
0
        DEBUGMSGTL(("netsnmp_unix_getSecName", "no com2sec entries\n"));
573
0
        return 0;
574
0
    }
575
576
    /*
577
     * If there is no unix socket path, then there can be no valid security
578
     * name.
579
     */
580
581
0
    if (opaque == NULL || olength != sizeof(struct sockaddr_un) ||
582
0
        to->sun_family != AF_UNIX) {
583
0
        DEBUGMSGTL(("netsnmp_unix_getSecName",
584
0
                    "no unix destine address in PDU?\n"));
585
0
        return 1;
586
0
    }
587
588
0
    DEBUGIF("netsnmp_unix_getSecName") {
589
0
        ztcommunity = (char *)malloc(community_len + 1);
590
0
        if (ztcommunity != NULL) {
591
0
            memcpy(ztcommunity, community, community_len);
592
0
            ztcommunity[community_len] = '\0';
593
0
        }
594
595
0
        DEBUGMSGTL(("netsnmp_unix_getSecName", "resolve <\"%s\">\n",
596
0
                    ztcommunity ? ztcommunity : "<malloc error>"));
597
0
    }
598
599
0
    for (c = com2SecUnixList; c != NULL; c = c->next) {
600
0
        DEBUGMSGTL(("netsnmp_unix_getSecName","compare <\"%s\",to socket %s>",
601
0
                    c->community, c->sockpath ));
602
0
        if ((community_len == strlen(c->community)) &&
603
0
            (memcmp(community, c->community, community_len) == 0) &&
604
            /* compare sockpath, if pathlen == 0, always match */
605
0
            (strlen(to->sun_path) == c->pathlen || c->pathlen == 0) &&
606
0
            (memcmp(to->sun_path, c->sockpath, c->pathlen) == 0)
607
0
            ) {
608
0
            DEBUGMSG(("netsnmp_unix_getSecName", "... SUCCESS\n"));
609
0
            if (secName != NULL) {
610
0
                *secName = c->secName;
611
0
                *contextName = c->contextName;
612
0
            }
613
0
            break;
614
0
        }
615
0
        DEBUGMSG(("netsnmp_unix_getSecName", "... nope\n"));
616
0
    }
617
0
    if (ztcommunity != NULL) {
618
0
        free(ztcommunity);
619
0
    }
620
0
    return 1;
621
0
}
622
623
void
624
netsnmp_unix_parse_security(const char *token, char *param)
625
211
{
626
211
    char   secName[VACMSTRINGLEN + 1];
627
211
    size_t secNameLen;
628
211
    char   contextName[VACMSTRINGLEN + 1];
629
211
    size_t contextNameLen;
630
211
    char   community[COMMUNITY_MAX_LEN + 1];
631
211
    size_t communityLen;
632
211
    char   sockpath[sizeof(((struct sockaddr_un*)0)->sun_path) + 1];
633
211
    size_t sockpathLen;
634
635
211
    param = copy_nword( param, secName, sizeof(secName));
636
211
    if (strcmp(secName, "-Cn") == 0) {
637
12
        if (!param) {
638
1
            config_perror("missing CONTEXT_NAME parameter");
639
1
            return;
640
1
        }
641
11
        param = copy_nword( param, contextName, sizeof(contextName));
642
11
        contextNameLen = strlen(contextName) + 1;
643
11
        if (contextNameLen > VACMSTRINGLEN) {
644
1
            config_perror("context name too long");
645
1
            return;
646
1
        }
647
10
        if (!param) {
648
2
            config_perror("missing NAME parameter");
649
2
            return;
650
2
        }
651
8
        param = copy_nword( param, secName, sizeof(secName));
652
199
    } else {
653
199
        contextNameLen = 0;
654
199
    }
655
656
207
    secNameLen = strlen(secName) + 1;
657
207
    if (secNameLen == 1) {
658
32
        config_perror("empty NAME parameter");
659
32
        return;
660
175
    } else if (secNameLen > VACMSTRINGLEN) {
661
13
        config_perror("security name too long");
662
13
        return;
663
13
    }
664
665
162
    if (!param) {
666
41
        config_perror("missing SOCKPATH parameter");
667
41
        return;
668
41
    }
669
121
    param = copy_nword( param, sockpath, sizeof(sockpath));
670
121
    if (sockpath[0] == '\0') {
671
1
        config_perror("empty SOCKPATH parameter");
672
1
        return;
673
1
    }
674
120
    sockpathLen = strlen(sockpath) + 1;
675
120
    if (sockpathLen > sizeof(((struct sockaddr_un*)0)->sun_path)) {
676
0
        config_perror("sockpath too long");
677
0
        return;
678
0
    }
679
680
120
    if (!param) {
681
19
        config_perror("missing COMMUNITY parameter");
682
19
        return;
683
19
    }
684
101
    param = copy_nword( param, community, sizeof(community));
685
101
    if (community[0] == '\0') {
686
2
        config_perror("empty COMMUNITY parameter");
687
2
        return;
688
2
    }
689
99
    communityLen = strlen(community) + 1;
690
99
    if (communityLen >= COMMUNITY_MAX_LEN) {
691
0
        config_perror("community name too long");
692
0
        return;
693
0
    }
694
99
    if (communityLen == sizeof(EXAMPLE_COMMUNITY) &&
695
25
        memcmp(community, EXAMPLE_COMMUNITY, sizeof(EXAMPLE_COMMUNITY)) == 0) {
696
1
        config_perror("example config COMMUNITY not properly configured");
697
1
        return;
698
1
    }
699
700
    /* Deal with the "default" case */
701
98
    if(strcmp(sockpath, "default") == 0) {
702
1
        sockpathLen = 0;
703
1
    }
704
705
98
    {
706
98
        char *last;
707
98
        com2SecUnixEntry* e = malloc(offsetof(com2SecUnixEntry, community) +
708
98
                                     communityLen + sockpathLen + secNameLen +
709
98
                                     contextNameLen);
710
98
        if (!e) {
711
0
            config_perror("memory allocation failed");
712
0
            return;
713
0
        }
714
715
98
        last = (char *)e + offsetof(com2SecUnixEntry, community);
716
717
98
        DEBUGMSGTL(("netsnmp_unix_parse_security",
718
98
                    "<\"%s\", \"%.*s\"> => \"%s\"\n",
719
98
                    community, (int)sockpathLen, sockpath, secName));
720
721
98
        memcpy(last, community, communityLen);
722
98
        last += communityLen;
723
724
98
        if (sockpathLen) {
725
97
            e->sockpath = last;
726
97
            memcpy(last, sockpath, sockpathLen);
727
97
            last += sockpathLen;
728
97
            e->pathlen = sockpathLen - 1;
729
97
        } else {
730
1
            e->sockpath = last - 1;
731
1
            e->pathlen = 0;
732
1
        }
733
734
98
        e->secName = last;
735
98
        memcpy(last, secName, secNameLen);
736
98
        last += secNameLen;
737
738
98
        if (contextNameLen) {
739
6
            e->contextName = last;
740
6
            memcpy(last, contextName, contextNameLen);
741
6
            last += contextNameLen;
742
6
        } else
743
92
            e->contextName = last - 1;
744
745
98
        e->next = NULL;
746
747
98
        if (com2SecUnixListLast != NULL) {
748
97
            com2SecUnixListLast->next = e;
749
97
            com2SecUnixListLast = e;
750
97
        } else {
751
1
            com2SecUnixListLast = com2SecUnixList = e;
752
1
        }
753
98
    }
754
98
}
755
756
void
757
netsnmp_unix_com2SecList_free(void)
758
6.85k
{
759
6.85k
    com2SecUnixEntry   *e = com2SecUnixList;
760
6.85k
    while (e != NULL) {
761
0
        com2SecUnixEntry   *tmp = e;
762
0
        e = e->next;
763
0
        free(tmp);
764
0
    }
765
6.85k
    com2SecUnixList = com2SecUnixListLast = NULL;
766
6.85k
}
767
#endif /* support for community based SNMP */
768
769
void
770
netsnmp_unix_agent_config_tokens_register(void)
771
3.42k
{
772
3.42k
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
773
3.42k
    register_app_config_handler("com2secunix", netsnmp_unix_parse_security,
774
3.42k
                                netsnmp_unix_com2SecList_free,
775
3.42k
                                "[-Cn CONTEXT] secName sockpath community");
776
3.42k
#endif /* support for community based SNMP */
777
3.42k
}