1 /* -*- mode: c; c-file-style: "openbsd" -*- */
3 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 /* Some of the code here (agent_priv_unix_*) has been adapted from code from
19 * Net-SNMP project (snmplib/snmpUnixDomain.c). Net-SNMP project is licensed
20 * using BSD and BSD-like licenses. I don't know the exact license of the file
21 * snmplib/snmpUnixDomain.c. */
30 #include <net-snmp/net-snmp-config.h>
31 #include <net-snmp/net-snmp-includes.h>
32 #include <net-snmp/agent/net-snmp-agent-includes.h>
33 #include <net-snmp/agent/snmp_vars.h>
34 #include <net-snmp/library/snmpUnixDomain.h>
36 static oid netsnmp_unix
[] = { TRANSPORT_DOMAIN_LOCAL
};
37 static netsnmp_tdomain unixDomain
;
40 agent_priv_unix_fmtaddr(netsnmp_transport
*t
, void *data
, int len
)
42 /* We don't bother to implement the full function */
43 return strdup("Local Unix socket with privilege separation: unknown");
47 agent_priv_unix_recv(netsnmp_transport
*t
, void *buf
, int size
,
48 void **opaque
, int *olength
)
51 socklen_t tolen
= sizeof(struct sockaddr_un
);
52 struct sockaddr
*to
= NULL
;
54 if (t
== NULL
|| t
->sock
< 0)
56 to
= (struct sockaddr
*)calloc(1, sizeof(struct sockaddr_un
));
59 if (getsockname(t
->sock
, to
, &tolen
) != 0)
62 rc
= recv(t
->sock
, buf
, size
, 0);
63 /* TODO: handle the (unlikely) case where we get EAGAIN or EWOULDBLOCK */
64 if (rc
< 0 && errno
!= EINTR
) {
65 log_warn("snmp", "unable to receive from fd %d",
71 *olength
= sizeof(struct sockaddr_un
);
81 #define AGENT_WRITE_TIMEOUT 2000
83 agent_priv_unix_send(netsnmp_transport
*t
, void *buf
, int size
,
84 void **opaque
, int *olength
)
88 if (t
!= NULL
&& t
->sock
>= 0) {
89 struct pollfd sagentx
= {
91 .events
= POLLOUT
| POLLERR
| POLLHUP
94 rc
= poll(&sagentx
, 1, AGENT_WRITE_TIMEOUT
);
97 "timeout while communicating with the master agent");
102 /* We can either write or have an error somewhere */
103 rc
= send(t
->sock
, buf
, size
, 0);
105 if (errno
== EAGAIN
||
106 errno
== EWOULDBLOCK
||
111 "error while sending to master agent");
115 if (errno
!= EINTR
) {
117 "error while attempting to send to master agent");
128 agent_priv_unix_close(netsnmp_transport
*t
)
141 agent_priv_unix_accept(netsnmp_transport
*t
)
143 log_warnx("snmp", "should not have been called");
147 static netsnmp_transport
*
148 agent_priv_unix_transport(const char *string
, int len
, int local
)
150 struct sockaddr_un addr
= {
151 .sun_family
= AF_UNIX
153 netsnmp_transport
*t
= NULL
;
156 log_warnx("snmp", "should not have been called for local transport");
161 if (len
>= sizeof(addr
.sun_path
) ||
162 strlcpy(addr
.sun_path
, string
, sizeof(addr
.sun_path
)) >= sizeof(addr
.sun_path
)) {
163 log_warnx("snmp", "path too long for Unix domain transport");
167 if ((t
= (netsnmp_transport
*)
168 calloc(1, sizeof(netsnmp_transport
))) == NULL
)
171 t
->domain
= netsnmp_unix
;
173 sizeof(netsnmp_unix
) / sizeof(netsnmp_unix
[0]);
175 if ((t
->sock
= priv_snmp_socket(&addr
)) < 0) {
176 netsnmp_transport_free(t
);
180 t
->flags
= NETSNMP_TRANSPORT_FLAG_STREAM
;
182 if ((t
->remote
= (u_char
*)
183 calloc(1, strlen(addr
.sun_path
) + 1)) == NULL
) {
184 agent_priv_unix_close(t
);
185 netsnmp_transport_free(t
);
188 memcpy(t
->remote
, addr
.sun_path
, strlen(addr
.sun_path
));
189 t
->remote_length
= strlen(addr
.sun_path
);
191 t
->msgMaxSize
= 0x7fffffff;
192 t
->f_recv
= agent_priv_unix_recv
;
193 t
->f_send
= agent_priv_unix_send
;
194 t
->f_close
= agent_priv_unix_close
;
195 t
->f_accept
= agent_priv_unix_accept
;
196 t
->f_fmtaddr
= agent_priv_unix_fmtaddr
;
202 #if !HAVE_NETSNMP_TDOMAIN_F_CREATE_FROM_TSTRING_NEW
203 agent_priv_unix_create_tstring(const char *string
, int local
)
205 agent_priv_unix_create_tstring(const char *string
, int local
, const char *default_target
)
208 #if HAVE_NETSNMP_TDOMAIN_F_CREATE_FROM_TSTRING_NEW
209 if ((!string
|| *string
== '\0') && default_target
&&
210 *default_target
!= '\0') {
211 string
= default_target
;
216 return agent_priv_unix_transport(string
, strlen(string
), local
);
219 static netsnmp_transport
*
220 agent_priv_unix_create_ostring(const u_char
* o
, size_t o_len
, int local
)
222 return agent_priv_unix_transport((char *)o
, o_len
, local
);
226 agent_priv_register_domain()
228 unixDomain
.name
= netsnmp_unix
;
229 unixDomain
.name_length
= sizeof(netsnmp_unix
) / sizeof(oid
);
230 unixDomain
.prefix
= (const char**)calloc(2, sizeof(char *));
231 unixDomain
.prefix
[0] = "unix";
232 #if !HAVE_NETSNMP_TDOMAIN_F_CREATE_FROM_TSTRING_NEW
233 unixDomain
.f_create_from_tstring
= agent_priv_unix_create_tstring
;
235 unixDomain
.f_create_from_tstring_new
= agent_priv_unix_create_tstring
;
237 unixDomain
.f_create_from_ostring
= agent_priv_unix_create_ostring
;
238 netsnmp_tdomain_register(&unixDomain
);