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>
38 # define F_SEND_SIGNATURE \
39 netsnmp_transport *t, const void *buf, int size, void **opaque, int *olength
40 # define F_FMTADDR_SIGNATURE netsnmp_transport *t, const void *data, int len
41 # define F_FROM_OSTRING_SIGNATURE const void *o, size_t o_len, int local
43 # define F_SEND_SIGNATURE \
44 netsnmp_transport *t, void *buf, int size, void **opaque, int *olength
45 # define F_FMTADDR_SIGNATURE netsnmp_transport *t, void *data, int len
46 # define F_FROM_OSTRING_SIGNATURE const u_char *o, size_t o_len, int local
49 static oid netsnmp_unix
[] = { TRANSPORT_DOMAIN_LOCAL
};
50 static netsnmp_tdomain unixDomain
;
53 agent_priv_unix_fmtaddr(F_FMTADDR_SIGNATURE
)
55 /* We don't bother to implement the full function */
56 return strdup("Local Unix socket with privilege separation: unknown");
60 agent_priv_unix_recv(netsnmp_transport
*t
, void *buf
, int size
, void **opaque
,
64 socklen_t tolen
= sizeof(struct sockaddr_un
);
65 struct sockaddr
*to
= NULL
;
67 if (t
== NULL
|| t
->sock
< 0) goto recv_error
;
68 to
= (struct sockaddr
*)calloc(1, sizeof(struct sockaddr_un
));
69 if (to
== NULL
) goto recv_error
;
70 if (getsockname(t
->sock
, to
, &tolen
) != 0) goto recv_error
;
72 rc
= recv(t
->sock
, buf
, size
, 0);
73 /* TODO: handle the (unlikely) case where we get EAGAIN or EWOULDBLOCK
75 if (rc
< 0 && errno
!= EINTR
) {
76 log_warn("snmp", "unable to receive from fd %d", t
->sock
);
81 *olength
= sizeof(struct sockaddr_un
);
91 # define AGENT_WRITE_TIMEOUT 2000
93 agent_priv_unix_send(F_SEND_SIGNATURE
)
97 if (t
!= NULL
&& t
->sock
>= 0) {
98 struct pollfd sagentx
= { .fd
= t
->sock
,
99 .events
= POLLOUT
| POLLERR
| POLLHUP
};
101 rc
= poll(&sagentx
, 1, AGENT_WRITE_TIMEOUT
);
104 "timeout while communicating with the master agent");
109 /* We can either write or have an error somewhere */
110 rc
= send(t
->sock
, buf
, size
, 0);
112 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
||
117 "error while sending to master agent");
121 if (errno
!= EINTR
) {
123 "error while attempting to send to master agent");
134 agent_priv_unix_close(netsnmp_transport
*t
)
147 agent_priv_unix_accept(netsnmp_transport
*t
)
149 log_warnx("snmp", "should not have been called");
153 static netsnmp_transport
*
154 agent_priv_unix_transport(const char *string
, int len
, int local
)
156 struct sockaddr_un addr
= { .sun_family
= AF_UNIX
};
157 netsnmp_transport
*t
= NULL
;
160 log_warnx("snmp", "should not have been called for local transport");
163 if (!string
) return NULL
;
164 if (len
>= sizeof(addr
.sun_path
) ||
165 strlcpy(addr
.sun_path
, string
, sizeof(addr
.sun_path
)) >=
166 sizeof(addr
.sun_path
)) {
167 log_warnx("snmp", "path too long for Unix domain transport");
171 if ((t
= (netsnmp_transport
*)calloc(1, sizeof(netsnmp_transport
))) == NULL
)
174 t
->domain
= netsnmp_unix
;
175 t
->domain_length
= sizeof(netsnmp_unix
) / sizeof(netsnmp_unix
[0]);
177 if ((t
->sock
= priv_snmp_socket(&addr
)) < 0) {
178 netsnmp_transport_free(t
);
182 t
->flags
= NETSNMP_TRANSPORT_FLAG_STREAM
;
184 if ((t
->remote
= (u_char
*)calloc(1, strlen(addr
.sun_path
) + 1)) == NULL
) {
185 agent_priv_unix_close(t
);
186 netsnmp_transport_free(t
);
189 memcpy(t
->remote
, addr
.sun_path
, strlen(addr
.sun_path
));
190 t
->remote_length
= strlen(addr
.sun_path
);
192 t
->msgMaxSize
= 0x7fffffff;
193 t
->f_recv
= agent_priv_unix_recv
;
194 t
->f_send
= agent_priv_unix_send
;
195 t
->f_close
= agent_priv_unix_close
;
196 t
->f_accept
= agent_priv_unix_accept
;
197 t
->f_fmtaddr
= agent_priv_unix_fmtaddr
;
202 # if HAVE_NETSNMP_TDOMAIN_F_CREATE_FROM_TSTRING_NEW
203 static netsnmp_transport
*
204 agent_priv_unix_create_tstring_new(const char *string
, int local
,
205 const char *default_target
)
207 if ((!string
|| *string
== '\0') && default_target
&& *default_target
!= '\0') {
208 string
= default_target
;
210 if (!string
) return NULL
;
211 return agent_priv_unix_transport(string
, strlen(string
), local
);
214 static netsnmp_transport
*
215 agent_priv_unix_create_tstring(const char *string
, int local
)
217 if (!string
) return NULL
;
218 return agent_priv_unix_transport(string
, strlen(string
), local
);
222 static netsnmp_transport
*
223 agent_priv_unix_create_ostring(F_FROM_OSTRING_SIGNATURE
)
225 return agent_priv_unix_transport((char *)o
, o_len
, local
);
229 agent_priv_register_domain()
231 unixDomain
.name
= netsnmp_unix
;
232 unixDomain
.name_length
= sizeof(netsnmp_unix
) / sizeof(oid
);
233 unixDomain
.prefix
= (const char **)calloc(2, sizeof(char *));
234 unixDomain
.prefix
[0] = "unix";
235 # if HAVE_NETSNMP_TDOMAIN_F_CREATE_FROM_TSTRING_NEW
236 unixDomain
.f_create_from_tstring_new
= agent_priv_unix_create_tstring_new
;
238 unixDomain
.f_create_from_tstring
= agent_priv_unix_create_tstring
;
240 unixDomain
.f_create_from_ostring
= agent_priv_unix_create_ostring
;
241 netsnmp_tdomain_register(&unixDomain
);