Coverage Report

Created: 2025-11-11 06:56

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
3.98k
{
521
3.98k
    unixDomain.name = netsnmp_UnixDomain;
522
3.98k
    unixDomain.name_length = OID_LENGTH(netsnmp_UnixDomain);
523
3.98k
    unixDomain.prefix = calloc(2, sizeof(char *));
524
3.98k
    if (!unixDomain.prefix) {
525
0
        snmp_log(LOG_ERR, "calloc() failed - out of memory\n");
526
0
        return;
527
0
    }
528
3.98k
    unixDomain.prefix[0] = "unix";
529
530
3.98k
    unixDomain.f_create_from_tstring_new = netsnmp_unix_create_tstring;
531
3.98k
    unixDomain.f_create_from_ostring     = netsnmp_unix_create_ostring;
532
533
3.98k
    netsnmp_tdomain_register(&unixDomain);
534
3.98k
}
535
536
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
537
/* support for SNMPv1 and SNMPv2c on unix domain*/
538
539
153
#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
210
{
626
210
    char   secName[VACMSTRINGLEN + 1];
627
210
    size_t secNameLen;
628
210
    char   contextName[VACMSTRINGLEN + 1];
629
210
    size_t contextNameLen;
630
210
    char   community[COMMUNITY_MAX_LEN + 1];
631
210
    size_t communityLen;
632
210
    char   sockpath[sizeof(((struct sockaddr_un*)0)->sun_path) + 1];
633
210
    size_t sockpathLen;
634
635
210
    param = copy_nword( param, secName, sizeof(secName));
636
210
    if (strcmp(secName, "-Cn") == 0) {
637
11
        if (!param) {
638
1
            config_perror("missing CONTEXT_NAME parameter");
639
1
            return;
640
1
        }
641
10
        param = copy_nword( param, contextName, sizeof(contextName));
642
10
        contextNameLen = strlen(contextName) + 1;
643
10
        if (contextNameLen > VACMSTRINGLEN) {
644
1
            config_perror("context name too long");
645
1
            return;
646
1
        }
647
9
        if (!param) {
648
1
            config_perror("missing NAME parameter");
649
1
            return;
650
1
        }
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
34
        config_perror("empty NAME parameter");
659
34
        return;
660
173
    } else if (secNameLen > VACMSTRINGLEN) {
661
15
        config_perror("security name too long");
662
15
        return;
663
15
    }
664
665
158
    if (!param) {
666
33
        config_perror("missing SOCKPATH parameter");
667
33
        return;
668
33
    }
669
125
    param = copy_nword( param, sockpath, sizeof(sockpath));
670
125
    if (sockpath[0] == '\0') {
671
1
        config_perror("empty SOCKPATH parameter");
672
1
        return;
673
1
    }
674
124
    sockpathLen = strlen(sockpath) + 1;
675
124
    if (sockpathLen > sizeof(((struct sockaddr_un*)0)->sun_path)) {
676
0
        config_perror("sockpath too long");
677
0
        return;
678
0
    }
679
680
124
    if (!param) {
681
22
        config_perror("missing COMMUNITY parameter");
682
22
        return;
683
22
    }
684
102
    param = copy_nword( param, community, sizeof(community));
685
102
    if (community[0] == '\0') {
686
1
        config_perror("empty COMMUNITY parameter");
687
1
        return;
688
1
    }
689
101
    communityLen = strlen(community) + 1;
690
101
    if (communityLen >= COMMUNITY_MAX_LEN) {
691
0
        config_perror("community name too long");
692
0
        return;
693
0
    }
694
101
    if (communityLen == sizeof(EXAMPLE_COMMUNITY) &&
695
26
        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
100
    if(strcmp(sockpath, "default") == 0) {
702
1
        sockpathLen = 0;
703
1
    }
704
705
100
    {
706
100
        char *last;
707
100
        com2SecUnixEntry* e = malloc(offsetof(com2SecUnixEntry, community) +
708
100
                                     communityLen + sockpathLen + secNameLen +
709
100
                                     contextNameLen);
710
100
        if (!e) {
711
0
            config_perror("memory allocation failed");
712
0
            return;
713
0
        }
714
715
100
        last = (char *)e + offsetof(com2SecUnixEntry, community);
716
717
100
        DEBUGMSGTL(("netsnmp_unix_parse_security",
718
100
                    "<\"%s\", \"%.*s\"> => \"%s\"\n",
719
100
                    community, (int)sockpathLen, sockpath, secName));
720
721
100
        memcpy(last, community, communityLen);
722
100
        last += communityLen;
723
724
100
        if (sockpathLen) {
725
99
            e->sockpath = last;
726
99
            memcpy(last, sockpath, sockpathLen);
727
99
            last += sockpathLen;
728
99
            e->pathlen = sockpathLen - 1;
729
99
        } else {
730
1
            e->sockpath = last - 1;
731
1
            e->pathlen = 0;
732
1
        }
733
734
100
        e->secName = last;
735
100
        memcpy(last, secName, secNameLen);
736
100
        last += secNameLen;
737
738
100
        if (contextNameLen) {
739
8
            e->contextName = last;
740
8
            memcpy(last, contextName, contextNameLen);
741
8
            last += contextNameLen;
742
8
        } else
743
92
            e->contextName = last - 1;
744
745
100
        e->next = NULL;
746
747
100
        if (com2SecUnixListLast != NULL) {
748
99
            com2SecUnixListLast->next = e;
749
99
            com2SecUnixListLast = e;
750
99
        } else {
751
1
            com2SecUnixListLast = com2SecUnixList = e;
752
1
        }
753
100
    }
754
100
}
755
756
void
757
netsnmp_unix_com2SecList_free(void)
758
6.48k
{
759
6.48k
    com2SecUnixEntry   *e = com2SecUnixList;
760
6.48k
    while (e != NULL) {
761
0
        com2SecUnixEntry   *tmp = e;
762
0
        e = e->next;
763
0
        free(tmp);
764
0
    }
765
6.48k
    com2SecUnixList = com2SecUnixListLast = NULL;
766
6.48k
}
767
#endif /* support for community based SNMP */
768
769
void
770
netsnmp_unix_agent_config_tokens_register(void)
771
3.24k
{
772
3.24k
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
773
3.24k
    register_app_config_handler("com2secunix", netsnmp_unix_parse_security,
774
3.24k
                                netsnmp_unix_com2SecList_free,
775
3.24k
                                "[-Cn CONTEXT] secName sockpath community");
776
3.24k
#endif /* support for community based SNMP */
777
3.24k
}