]> git.decadent.org.uk Git - ap-utils.git/blob - lib/snmp.c
Imported Upstream version 1.5~pre1
[ap-utils.git] / lib / snmp.c
1 /*
2  *      snmp.c from Access Point SNMP Utils for Linux
3  *      basic snmp packets assembly/disassembly and send/receive functions
4  *
5  * Copyright (c) Roman Festchook <roma at polesye dot net>
6  *               Jan Rafaj <jr-aputils at cedric dot unob dot cz>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License Version 2 from
10  * June 1991 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  *
21  */
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <signal.h>
26 #include <setjmp.h>
27 #include <sys/types.h>
28 #include <netinet/in.h>
29 #include <sys/socket.h>
30 #include <arpa/inet.h>
31 #include "ap-utils.h"
32
33 #define RETRIES 5
34
35 sigjmp_buf position;
36
37 extern char *community;
38 extern short ap_type;
39 extern int sockfd;
40 extern struct in_addr ap_ip;
41 int retries;
42 char *buf = NULL;
43
44 static void alarm_handler()
45 {
46     retries--;
47     siglongjmp(position, 1);
48 }
49
50 /*
51 unsigned int ber_decode_uint(unsigned char *bevp, int len)
52 {
53     unsigned int out = 0;
54
55     while (len--) {
56         out = (out << 7) | (*bevp & (*bevp & 0x80 ? 0x7f : 0xff));
57         bevp++;
58     }
59
60     return out;
61 }
62 */
63
64 int ber(char *message, varbind * varbindlist, int num, int type)
65 {
66
67     char pdu1[1024], pdu[1024], *list = pdu1;
68     int len_var = 0, lenp, len_tmp, len = 0, community_len =
69         strlen(community), i;
70     char snmp_ver[] = { 0x02, 0x01, 0x00 };
71     const char req_id[] = { 0x02, 0x01 }, err[] = {
72     0x02, 0x01, 0x00};
73
74     for (i = 0; i < num; i++) {
75         *(pdu1 + len++) = ASN_HEADER;
76         len_tmp =
77             (varbindlist + i)->len_oid + (varbindlist + i)->len_val + 4;
78         if (!(ap_type == NWN && type == SET)) {
79             *(pdu1 + len++) = 0x82;
80             *(pdu1 + len++) = (len_tmp - (len_tmp % 256)) / 256;
81         }
82         *(pdu1 + len++) = len_tmp % 256;
83         *(pdu1 + len++) = OID_VALUE;
84         *(pdu1 + len++) = (varbindlist + i)->len_oid;
85         memcpy(pdu1 + len, (varbindlist + i)->oid,
86                (varbindlist + i)->len_oid);
87         len += (varbindlist + i)->len_oid;
88         *(pdu1 + len++) = (varbindlist + i)->type;
89         *(pdu1 + len++) = (varbindlist + i)->len_val;
90         memcpy(pdu1 + len, (varbindlist + i)->value,
91                (varbindlist + i)->len_val);
92         len += (varbindlist + i)->len_val;
93     }
94
95     len_var = len;
96
97     lenp = 0;
98     len_tmp = len_var + ((ap_type == NWN && type == SET) ? 11 : 13);
99     *(pdu + lenp++) = type;
100     if (!(ap_type == NWN && type == SET)) {
101         *(pdu + lenp++) = 0x82;
102         *(pdu + lenp++) = (len_tmp - (len_tmp % 256)) / 256;
103     }
104     *(pdu + lenp++) = len_tmp % 256;
105
106     memcpy(pdu + lenp, req_id, sizeof(req_id));
107     lenp += sizeof(req_id);
108     *(pdu + lenp++) =
109         (1 + (int) (255.0 * rand() / (RAND_MAX + 1.0))) & 0xFF;
110     memcpy(pdu + lenp, err, sizeof(err));
111     lenp += sizeof(err);
112     memcpy(pdu + lenp, err, sizeof(err));
113     lenp += sizeof(err);
114     *(pdu + lenp++) = ASN_HEADER;
115     len_tmp = len_var;
116     if (!(ap_type == NWN && type == SET)) {
117         *(pdu + lenp++) = 0x82;
118         *(pdu + lenp++) = (len_tmp - (len_tmp % 256)) / 256;
119     }
120     *(pdu + lenp++) = len_tmp % 256;
121     memcpy(pdu + lenp, list, len_var);
122     lenp += len_var;
123
124     *message = ASN_HEADER;
125     len = 1;
126
127     i = lenp + community_len + 5;
128     if (!(ap_type == NWN && type == SET)) {
129         *(message + len++) = 0x82;
130         *(message + len++) = (i - (i % 256)) / 256;
131     }
132     *(message + len++) = i % 256;
133
134     memcpy(message + len, snmp_ver, 3);
135     len += 3;
136     *(message + len++) = STRING_VALUE;
137     *(message + len++) = community_len & 0xFF;
138     memcpy(message + len, community, community_len);
139     len += community_len;
140     memcpy(message + len, pdu, lenp);
141     len += lenp;
142
143     return len;
144 }
145
146 int snmp(varbind * varbindlist, int num, int type)
147 {
148     unsigned char message[1024], *start;
149     unsigned int num_reply;
150     int len;
151     struct sockaddr_in server;
152
153     if (num == 0)
154         return 1;
155
156     memset(&server, 0, sizeof server);
157     server.sin_family = AF_INET;
158     server.sin_port = htons(161);
159     server.sin_addr.s_addr = ap_ip.s_addr;
160
161     signal(SIGALRM, alarm_handler);
162     retries = RETRIES;
163     sigsetjmp(position, 1);
164     if (!retries) {
165         return 0;
166     }
167
168     alarm(1);
169     len = ber(message, varbindlist, num, type);
170     if (sendto(sockfd, message, len, 0, (struct sockaddr *) &server, SIZE)
171         == -1) {
172         alarm(0);
173         return 0;
174     }
175     if ((len = recv(sockfd, message, 1024, 0)) == -1) {
176         alarm(0);
177         return 0;
178     }
179     alarm(0);
180
181     if (buf)
182         free(buf);
183     buf = (char *) malloc(len);
184     memcpy(buf, message, len);
185
186     start = buf;
187     num_reply = 0;
188     if (*start != ASN_HEADER) {
189         return 0;
190     }
191
192     if (start[1] & 0x80) {
193         start += (start[1] & 0x7F) + 2;
194         len -= ((start[1] & 0x7F) + 2);
195     } else {
196         start += 2;
197         len -= 2;
198     }
199
200     len -= *(start + 4) + 5;
201     start += *(start + 4) + 5;
202
203     if (*(start) != RESPONSE) {
204         return 0;
205     }
206
207
208
209     if (start[1] & 0x80) {
210         start += (start[1] & 0x7F) + 2;
211         len -= ((start[1] & 0x7F) + 2);
212     } else {
213         start += 2;
214         len -= 2;
215     }
216
217     if (*(start + 5))
218         return -*(start + 8);
219
220     start += 9;
221     len -= 9;
222     if (*(start) != ASN_HEADER) {
223         return 0;
224     }
225
226
227     if (start[1] & 0x80) {
228         start += (start[1] & 0x7F) + 2;
229         len -= ((start[1] & 0x7F) + 2);
230     } else {
231         start += 2;
232         len -= 2;
233     }
234     while (len) {
235         if (*(start) != ASN_HEADER) {
236             return num_reply;
237         }
238         if (start[1] & 0x80) {
239             start += (start[1] & 0x7F) + 2;
240             len -= ((start[1] & 0x7F) + 2);
241         } else {
242             start += 2;
243             len -= 2;
244         }
245
246
247         varbindlist[num_reply].len_oid = start[1];
248 /*      if(varbindlist[num_reply].oid)
249             free(varbindlist[num_reply].oid);
250         varbindlist[num_reply].oid =
251             (char *) malloc(varbindlist[num_reply].len_oid);
252         memcpy(varbindlist[num_reply].oid, start + 2,
253                varbindlist[num_reply].len_oid);
254 */
255         varbindlist[num_reply].oid = start + 2;
256         len -= *(start + 1) + 2;
257         start += *(start + 1) + 2;
258         varbindlist[num_reply].type = *(start);
259
260         if (start[1] & 0x80) {
261             varbindlist[num_reply].len_val = start[2];
262             start += (start[1] & 0x7F) + 2;
263             len -= ((start[1] & 0x7F) + 2);
264         } else {
265             varbindlist[num_reply].len_val = start[1];
266             start += 2;
267             len -= 2;
268         }
269
270 /*      if(varbindlist[num_reply].value)
271             free(varbindlist[num_reply].value);
272         varbindlist[num_reply].value =
273             (char *) malloc(varbindlist[num_reply].len_val);
274         memcpy(varbindlist[num_reply].value, start,
275                varbindlist[num_reply].len_val);
276 */
277         varbindlist[num_reply].value = start;
278         len -= varbindlist[num_reply].len_val;
279         start += varbindlist[num_reply].len_val;
280         num_reply++;
281     }
282
283     return num_reply;
284 }