]>
Commit | Line | Data |
---|---|---|
da2d50d1 | 1 | |
2 | ||
627f6d02 | 3 | /*********************************************************** |
4 | Copyright 1989 by Carnegie Mellon University | |
5 | ||
6 | All Rights Reserved | |
7 | ||
8 | Permission to use, copy, modify, and distribute this software and its | |
9 | documentation for any purpose and without fee is hereby granted, | |
10 | provided that the above copyright notice appear in all copies and that | |
11 | both that copyright notice and this permission notice appear in | |
12 | supporting documentation, and that the name of CMU not be | |
13 | used in advertising or publicity pertaining to distribution of the | |
14 | software without specific, written prior permission. | |
15 | ||
da2d50d1 | 16 | CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING |
17 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL | |
18 | CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR | |
19 | ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |
20 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
21 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
22 | SOFTWARE. | |
23 | ******************************************************************/ | |
24 | /* | |
25 | * snmp_api.c - API for access to snmp. | |
26 | */ | |
27 | #define DEBUG_SNMPTRACE 0 /* set to 1 to print all SNMP actions */ | |
28 | #define DEBUG_SNMPFULLDUMP 0 /* set to 1 to dump all SNMP packets */ | |
29 | ||
30 | #include <stdio.h> | |
31 | #include <sys/types.h> | |
32 | #include <sys/param.h> | |
33 | #include <sys/time.h> | |
34 | #include <netinet/in.h> | |
35 | #include <sys/socket.h> | |
36 | #include <netdb.h> | |
37 | #ifdef linux | |
38 | #include <arpa/inet.h> | |
39 | #include <stdlib.h> | |
40 | #include <string.h> | |
41 | #include <unistd.h> | |
42 | #endif | |
43 | ||
44 | ||
45 | #include "asn1.h" | |
46 | #include "snmp.h" | |
47 | #include "snmp_impl.h" | |
48 | #include "snmp_api.h" | |
49 | #include "snmp_client.h" | |
50 | ||
51 | #define PACKET_LENGTH 4500 | |
52 | ||
53 | #ifndef BSD4_3 | |
54 | #define BSD4_2 | |
55 | #endif | |
56 | ||
57 | #if !defined(BSD4_3) && !defined(linux) && !defined(sun) | |
58 | ||
59 | typedef long fd_mask; | |
60 | #define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */ | |
61 | ||
62 | #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) | |
63 | #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) | |
64 | #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) | |
65 | #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) | |
66 | #endif | |
67 | ||
68 | oid default_enterprise[] = | |
69 | {1, 3, 6, 1, 4, 1, 3, 1, 1}; /* enterprises.cmu.systems.cmuSNMP */ | |
70 | ||
71 | #define DEFAULT_COMMUNITY "public" | |
72 | #define DEFAULT_REMPORT SNMP_PORT | |
73 | #define DEFAULT_ENTERPRISE default_enterprise | |
74 | #define DEFAULT_TIME 0 | |
75 | #define DEFAULT_MMS 1389 /* large, randomly picked for testing purposes */ | |
76 | ||
77 | /* | |
78 | * Internal information about the state of the snmp session. | |
79 | */ | |
80 | struct snmp_internal_session { | |
81 | int sd; /* socket descriptor for this connection */ | |
82 | ipaddr addr; /* address of connected peer */ | |
83 | struct request_list *requests; /* Info about outstanding requests */ | |
84 | }; | |
85 | ||
86 | /* | |
87 | * A list of all the outstanding requests for a particular session. | |
88 | */ | |
89 | struct request_list { | |
90 | struct request_list *next_request; | |
91 | u_long request_id; /* request id */ | |
92 | int retries; /* Number of retries */ | |
93 | u_long timeout; /* length to wait for timeout */ | |
94 | struct timeval time; /* Time this request was made */ | |
95 | struct timeval expire; /* time this request is due to expire */ | |
96 | struct snmp_pdu *pdu; /* The pdu for this request (saved so it can be retransmitted */ | |
97 | }; | |
98 | ||
99 | /* | |
100 | * The list of active/open sessions. | |
101 | */ | |
102 | struct session_list { | |
103 | struct session_list *next; | |
104 | struct snmp_session *session; | |
105 | struct snmp_internal_session *internal; | |
106 | }; | |
107 | ||
108 | struct session_list *Sessions = NULL; | |
109 | ||
110 | u_long Reqid = 0; | |
111 | int snmp_errno = 0; | |
112 | ||
113 | char *api_errors[4] = | |
114 | { | |
115 | "Unknown session", | |
116 | "Unknown host", | |
117 | "Invalid local port", | |
118 | "Unknown Error" | |
119 | }; | |
120 | ||
121 | ||
122 | void sync_with_agent(); | |
123 | int parse_app_community_string(); | |
124 | void snmp_synch_setup(); | |
125 | int snmp_synch_response(); | |
126 | void md5Digest(); | |
127 | ||
128 | ||
129 | static char * | |
130 | api_errstring(snmp_errnumber) | |
131 | int snmp_errnumber; | |
132 | { | |
133 | if (snmp_errnumber <= SNMPERR_BAD_SESSION && snmp_errnumber >= SNMPERR_GENERR) { | |
134 | return api_errors[snmp_errnumber + 4]; | |
135 | } else { | |
136 | return "Unknown Error"; | |
137 | } | |
138 | } | |
139 | ||
140 | #if 0 | |
141 | /* | |
142 | * Gets initial request ID for all transactions. | |
143 | */ | |
144 | static void | |
145 | init_snmp() | |
146 | { | |
147 | struct timeval tv; | |
148 | ||
149 | gettimeofday(&tv, (struct timezone *) 0); | |
150 | srandom(tv.tv_sec ^ tv.tv_usec); | |
151 | Reqid = random(); | |
152 | } | |
153 | ||
154 | #endif | |
155 | ||
156 | ||
157 | /* | |
158 | * Dump snmp packet to stdout: | |
159 | */ | |
160 | static void | |
161 | snmp_print_packet(packet, length, addr, code) | |
162 | char *packet; | |
163 | int length; | |
164 | ipaddr addr; | |
165 | int code; | |
166 | { | |
167 | if (length < 0) { | |
168 | return; | |
169 | } | |
170 | if (code <= 0) { /* received */ | |
171 | printf("\nReceived %4d bytes from ", length); | |
172 | } else { /* sending */ | |
173 | printf("\nSending %4d bytes to ", length); | |
174 | } | |
175 | printf("%s:", inet_ntoa(addr.sin_addr)); | |
176 | #if DEBUG_SNMPFULLDUMP | |
177 | for (count = 0; count < length; count++) { | |
178 | if ((count & 15) == 0) { | |
179 | printf("\n "); | |
180 | } | |
181 | printf("%02X ", (int) (packet[count] & 255)); | |
182 | } | |
183 | #endif | |
184 | fflush(stdout); | |
185 | } | |
186 | ||
187 | #if DEBUG_SNMPTRACE | |
188 | /* | |
189 | * Print request | |
190 | */ | |
191 | #define TRACE_SEND (0) | |
192 | #define TRACE_RECV (1) | |
193 | #define TRACE_TIMEOUT (2) | |
194 | static void | |
195 | snmp_print_trace(slp, rp, code) | |
196 | struct session_list *slp; | |
197 | struct request_list *rp; | |
198 | int code; | |
199 | { | |
200 | int reqid = 0, retries = 1; | |
201 | if (rp) { | |
202 | reqid = rp->request_id; | |
203 | retries = rp->retries; | |
204 | } | |
205 | printf("\n Session %2d ReqId %4d ", slp->internal->sd, reqid); | |
206 | switch (code) { | |
207 | case TRACE_SEND: | |
208 | printf("send pdu (%d)", retries); | |
209 | break; | |
210 | case TRACE_RECV: | |
211 | printf("recv pdu"); | |
212 | break; | |
213 | case TRACE_TIMEOUT: | |
214 | printf("time out"); | |
215 | break; | |
216 | } | |
217 | fflush(stdout); | |
218 | } | |
219 | #endif /* DEBUG_SNMPTRACE */ | |
220 | ||
221 | ||
222 | ||
223 | ||
224 | /* | |
225 | * Sets up the session with the snmp_session information provided | |
226 | * by the user. Then opens and binds the necessary UDP port. | |
227 | * A handle to the created session is returned (this is different than | |
228 | * the pointer passed to snmp_open()). On any error, NULL is returned | |
229 | * and snmp_errno is set to the appropriate error code. | |
230 | */ | |
231 | struct snmp_session * | |
232 | snmp_open(session) | |
233 | struct snmp_session *session; | |
234 | { | |
235 | struct session_list *slp; | |
236 | struct snmp_internal_session *isp; | |
237 | u_char *cp; | |
238 | int sd; | |
239 | u_long addr; | |
240 | struct sockaddr_in me; | |
241 | struct hostent *hp; | |
242 | struct servent *servp; | |
243 | extern int check_received_pkt(); | |
244 | ||
245 | /* Copy session structure and link into list */ | |
246 | slp = (struct session_list *) calloc(1, sizeof(struct session_list)); | |
247 | slp->internal = isp = (struct snmp_internal_session *) calloc(1, sizeof(struct snmp_internal_session)); | |
248 | bzero((char *) isp, sizeof(struct snmp_internal_session)); | |
249 | slp->internal->sd = -1; /* mark it not set */ | |
250 | slp->session = (struct snmp_session *) calloc(1, sizeof(struct snmp_session)); | |
251 | bcopy((char *) session, (char *) slp->session, sizeof(struct snmp_session)); | |
252 | session = slp->session; | |
253 | /* now link it in. */ | |
254 | slp->next = Sessions; | |
255 | Sessions = slp; | |
256 | ||
257 | /* | |
258 | * session now points to the new structure that still contains pointers to | |
259 | * data allocated elsewhere. Some of this data is copied to space malloc'd | |
260 | * here, and the pointer replaced with the new one. | |
261 | */ | |
262 | ||
263 | if (session->peername != NULL) { | |
264 | cp = (u_char *) calloc(1, (unsigned) strlen(session->peername) + 1); | |
265 | strcpy((char *) cp, session->peername); | |
266 | session->peername = (char *) cp; | |
267 | } | |
268 | if (session->retries == SNMP_DEFAULT_RETRIES) | |
269 | session->retries = SNMP_API_DEFAULT_RETRIES; | |
270 | if (session->timeout == SNMP_DEFAULT_TIMEOUT) | |
271 | session->timeout = SNMP_API_DEFAULT_TIMEOUT; | |
272 | if (session->MMS == 0) | |
273 | session->MMS = DEFAULT_MMS; | |
274 | isp->requests = NULL; | |
275 | ||
276 | ||
277 | /* Fill in defaults if necessary */ | |
278 | if (session->community_len != SNMP_DEFAULT_COMMUNITY_LEN) { | |
279 | if (*session->community == '+') { | |
280 | session->community_len--; | |
281 | cp = (u_char *) calloc(1, (unsigned) session->community_len); | |
282 | bcopy((char *) session->community + 1, (char *) cp, | |
283 | session->community_len); | |
284 | session->version = SNMP_VERSION_2C; | |
285 | } else { | |
286 | cp = (u_char *) calloc(1, (unsigned) session->community_len); | |
287 | bcopy((char *) session->community, (char *) cp, | |
288 | session->community_len); | |
289 | } | |
290 | ||
291 | } else { | |
292 | session->community_len = strlen(DEFAULT_COMMUNITY); | |
293 | cp = (u_char *) calloc(1, (unsigned) session->community_len); | |
294 | bcopy((char *) DEFAULT_COMMUNITY, (char *) cp, session->community_len); | |
295 | } | |
296 | ||
297 | /* Set up connections */ | |
298 | sd = socket(AF_INET, SOCK_DGRAM, 0); | |
299 | if (sd < 0) { | |
300 | perror("socket"); | |
301 | snmp_errno = SNMPERR_GENERR; | |
302 | if (!snmp_close(session)) { | |
303 | fprintf(stderr, "Couldn't abort session: %s. Exiting\n", api_errstring(snmp_errno)); | |
304 | exit(1); | |
305 | } | |
306 | return 0; | |
307 | } | |
308 | isp->sd = sd; | |
309 | ||
310 | if (session->peername != SNMP_DEFAULT_PEERNAME) { | |
311 | if ((addr = inet_addr(session->peername)) != -1) { | |
312 | bcopy((char *) &addr, (char *) &isp->addr.sin_addr, sizeof(isp->addr.sin_addr)); | |
313 | } else { | |
314 | hp = gethostbyname(session->peername); | |
315 | if (hp == NULL) { | |
316 | fprintf(stderr, "unknown host: %s\n", session->peername); | |
317 | snmp_errno = SNMPERR_BAD_ADDRESS; | |
318 | if (!snmp_close(session)) { | |
319 | fprintf(stderr, "Couldn't abort session: %s. Exiting\n", api_errstring(snmp_errno)); | |
320 | exit(2); | |
321 | } | |
322 | return 0; | |
323 | } else { | |
324 | bcopy((char *) hp->h_addr, (char *) &isp->addr.sin_addr, hp->h_length); | |
325 | } | |
326 | } | |
327 | isp->addr.sin_family = AF_INET; | |
328 | if (session->remote_port == SNMP_DEFAULT_REMPORT) { | |
329 | /*servp = getservbyname("snmp", "udp"); */ | |
330 | servp = NULL; | |
331 | if (servp != NULL) { | |
332 | isp->addr.sin_port = servp->s_port; | |
333 | } else { | |
334 | isp->addr.sin_port = htons(SNMP_PORT); | |
335 | } | |
336 | } else { | |
337 | isp->addr.sin_port = htons(session->remote_port); | |
338 | } | |
339 | } else { | |
340 | isp->addr.sin_addr.s_addr = SNMP_DEFAULT_ADDRESS; | |
341 | } | |
342 | ||
343 | me.sin_family = AF_INET; | |
344 | me.sin_addr.s_addr = INADDR_ANY; | |
345 | me.sin_port = htons(session->local_port); | |
346 | if (bind(sd, (struct sockaddr *) &me, sizeof(me)) != 0) { | |
347 | perror("bind"); | |
348 | snmp_errno = SNMPERR_BAD_LOCPORT; | |
349 | if (!snmp_close(session)) { | |
350 | fprintf(stderr, "Couldn't abort session: %s. Exiting\n", | |
351 | api_errstring(snmp_errno)); | |
352 | exit(3); | |
353 | } | |
354 | return 0; | |
355 | } | |
356 | if (*cp == '/') { | |
357 | session->authenticator = check_received_pkt; | |
358 | sync_with_agent(session); | |
359 | parse_app_community_string(session); | |
360 | session->qoS |= USEC_QOS_GENREPORT; | |
361 | } | |
362 | /* replace comm pointer with pointer to new data: */ | |
363 | session->community = cp; | |
364 | ||
365 | return session; | |
366 | } | |
367 | ||
368 | void | |
369 | sync_with_agent(session) | |
370 | struct snmp_session *session; | |
371 | { | |
372 | struct snmp_pdu *pdu, *response = 0; | |
373 | int status; | |
374 | ||
375 | session->qoS = USEC_QOS_GENREPORT; | |
376 | session->userLen = 6; | |
377 | session->version = SNMP_VERSION_2; | |
378 | strcpy(session->userName, "public"); | |
379 | ||
380 | snmp_synch_setup(session); | |
381 | pdu = snmp_pdu_create(GET_REQ_MSG); | |
382 | status = snmp_synch_response(session, pdu, &response); | |
383 | ||
384 | if (status == STAT_SUCCESS) { | |
385 | memcpy(session->agentID, response->params.agentID, 12); | |
386 | ||
387 | /* save the clocks -- even though they are not authentic */ | |
388 | session->agentBoots = response->params.agentBoots; | |
389 | session->agentTime = response->params.agentTime; | |
390 | session->agentClock = response->params.agentTime - time(NULL); | |
391 | ||
392 | } else { | |
393 | if (status == STAT_TIMEOUT) { | |
394 | printf("No Response from %s\n", session->peername); | |
395 | } else { /* status == STAT_ERROR */ | |
396 | printf("An error occurred, Quitting\n"); | |
397 | } | |
398 | exit(-1); | |
399 | } | |
400 | ||
401 | /** freed to early: | |
402 | snmp_free_pdu(pdu); | |
403 | if (response) snmp_free_pdu(response); | |
404 | **/ | |
405 | } | |
406 | #if 1/***/ BUG_SNMPTRACE */cked for testing purposes */e key! replace... | |
407 | */ | |
408 | Content-type: text/html ]>