]> git.decadent.org.uk Git - ap-utils.git/blob - lib/snmp.c
Imported Upstream version 1.5~pre3~a
[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 sigjmp_buf position;
34
35 extern char *community;
36 extern short ap_type;
37 extern int sockfd;
38 extern struct in_addr ap_ip;
39
40 int snmp_retries = 5, retries;
41 char *buf = NULL;
42
43 static void alarm_handler()
44 {
45     retries--;
46     siglongjmp(position, 1);
47 }
48
49 /*
50 unsigned int ber_decode_uint(unsigned char *bevp, int len)
51 {
52     unsigned int out = 0;
53
54     while (len--) {
55         out = (out << 7) | (*bevp & (*bevp & 0x80 ? 0x7f : 0xff));
56         bevp++;
57     }
58
59     return out;
60 }
61 */
62
63 int ber(char *message, varbind * varbindlist, int num, int type)
64 {
65
66     char pdu1[1024], pdu[1024], *list = pdu1;
67     int len_var = 0, lenp, len_tmp, len = 0, community_len =
68         strlen(community), i;
69     char snmp_ver[] = { 0x02, 0x01, 0x00 };
70     const char req_id[] = { 0x02, 0x01 }, err[] = {
71     0x02, 0x01, 0x00};
72
73     for (i = 0; i < num; i++) {
74         *(pdu1 + len++) = ASN_HEADER;
75         len_tmp =
76             (varbindlist + i)->len_oid + (varbindlist + i)->len_val + 4;
77         if (!(ap_type == NWN && type == SET)) {
78             *(pdu1 + len++) = 0x82;
79             *(pdu1 + len++) = (len_tmp - (len_tmp % 256)) / 256;
80         }
81         *(pdu1 + len++) = len_tmp % 256;
82         *(pdu1 + len++) = OID_VALUE;
83         *(pdu1 + len++) = (varbindlist + i)->len_oid;
84         memcpy(pdu1 + len, (varbindlist + i)->oid,
85                (varbindlist + i)->len_oid);
86         len += (varbindlist + i)->len_oid;
87         *(pdu1 + len++) = (varbindlist + i)->type;
88         *(pdu1 + len++) = (varbindlist + i)->len_val;
89         memcpy(pdu1 + len, (varbindlist + i)->value,
90                (varbindlist + i)->len_val);
91         len += (varbindlist + i)->len_val;
92     }
93
94     len_var = len;
95
96     lenp = 0;
97     len_tmp = len_var + ((ap_type == NWN && type == SET) ? 11 : 13);
98     *(pdu + lenp++) = type;
99     if (!(ap_type == NWN && type == SET)) {
100         *(pdu + lenp++) = 0x82;
101         *(pdu + lenp++) = (len_tmp - (len_tmp % 256)) / 256;
102     }
103     *(pdu + lenp++) = len_tmp % 256;
104
105     memcpy(pdu + lenp, req_id, sizeof(req_id));
106     lenp += sizeof(req_id);
107     *(pdu + lenp++) =
108         (1 + (int) (255.0 * rand() / (RAND_MAX + 1.0))) & 0xFF;
109     memcpy(pdu + lenp, err, sizeof(err));
110     lenp += sizeof(err);
111     memcpy(pdu + lenp, err, sizeof(err));
112     lenp += sizeof(err);
113     *(pdu + lenp++) = ASN_HEADER;
114     len_tmp = len_var;
115     if (!(ap_type == NWN && type == SET)) {
116         *(pdu + lenp++) = 0x82;
117         *(pdu + lenp++) = (len_tmp - (len_tmp % 256)) / 256;
118     }
119     *(pdu + lenp++) = len_tmp % 256;
120     memcpy(pdu + lenp, list, len_var);
121     lenp += len_var;
122
123     *message = ASN_HEADER;
124     len = 1;
125
126     i = lenp + community_len + 5;
127     if (!(ap_type == NWN && type == SET)) {
128         *(message + len++) = 0x82;
129         *(message + len++) = (i - (i % 256)) / 256;
130     }
131     *(message + len++) = i % 256;
132
133     memcpy(message + len, snmp_ver, 3);
134     len += 3;
135     *(message + len++) = STRING_VALUE;
136     *(message + len++) = community_len & 0xFF;
137     memcpy(message + len, community, community_len);
138     len += community_len;
139     memcpy(message + len, pdu, lenp);
140     len += lenp;
141
142     return len;
143 }
144
145 int snmp(varbind * varbindlist, int num, int type)
146 {
147     unsigned char message[1024], *start;
148     unsigned int num_reply;
149     int len;
150     struct sockaddr_in server;
151
152     if (num == 0)
153         return 1;
154
155     memset(&server, 0, sizeof server);
156     server.sin_family = AF_INET;
157     server.sin_port = htons(161);
158     server.sin_addr.s_addr = ap_ip.s_addr;
159
160     signal(SIGALRM, alarm_handler);
161     retries = snmp_retries;
162     sigsetjmp(position, 1);
163     if (!retries) {
164         return 0;
165     }
166
167     alarm(1);
168     len = ber(message, varbindlist, num, type);
169     if (sendto(sockfd, message, len, 0, (struct sockaddr *) &server, SIZE)
170         == -1) {
171         alarm(0);
172         return 0;
173     }
174     if ((len = recv(sockfd, message, 1024, 0)) == -1) {
175         alarm(0);
176         return 0;
177     }
178     alarm(0);
179
180     if (buf)
181         free(buf);
182     buf = (char *) malloc(len);
183     memcpy(buf, message, len);
184
185     start = buf;
186     num_reply = 0;
187     if (*start != ASN_HEADER) {
188         return 0;
189     }
190
191     if (start[1] & 0x80) {
192         start += (start[1] & 0x7F) + 2;
193         len -= ((start[1] & 0x7F) + 2);
194     } else {
195         start += 2;
196         len -= 2;
197     }
198
199     len -= *(start + 4) + 5;
200     start += *(start + 4) + 5;
201
202     if (*(start) != RESPONSE) {
203         return 0;
204     }
205
206
207
208     if (start[1] & 0x80) {
209         start += (start[1] & 0x7F) + 2;
210         len -= ((start[1] & 0x7F) + 2);
211     } else {
212         start += 2;
213         len -= 2;
214     }
215
216     if (*(start + 5))
217         return -*(start + 8);
218
219     start += 9;
220     len -= 9;
221     if (*(start) != ASN_HEADER) {
222         return 0;
223     }
224
225
226     if (start[1] & 0x80) {
227         start += (start[1] & 0x7F) + 2;
228         len -= ((start[1] & 0x7F) + 2);
229     } else {
230         start += 2;
231         len -= 2;
232     }
233     while (len) {
234         if (*(start) != ASN_HEADER) {
235             return num_reply;
236         }
237         if (start[1] & 0x80) {
238             start += (start[1] & 0x7F) + 2;
239             len -= ((start[1] & 0x7F) + 2);
240         } else {
241             start += 2;
242             len -= 2;
243         }
244
245
246         varbindlist[num_reply].len_oid = start[1];
247 /*      if(varbindlist[num_reply].oid)
248             free(varbindlist[num_reply].oid);
249         varbindlist[num_reply].oid =
250             (char *) malloc(varbindlist[num_reply].len_oid);
251         memcpy(varbindlist[num_reply].oid, start + 2,
252                varbindlist[num_reply].len_oid);
253 */
254         varbindlist[num_reply].oid = start + 2;
255         len -= *(start + 1) + 2;
256         start += *(start + 1) + 2;
257         varbindlist[num_reply].type = *(start);
258
259         if (start[1] & 0x80) {
260             varbindlist[num_reply].len_val = start[2];
261             start += (start[1] & 0x7F) + 2;
262             len -= ((start[1] & 0x7F) + 2);
263         } else {
264             varbindlist[num_reply].len_val = start[1];
265             start += 2;
266             len -= 2;
267         }
268
269 /*      if(varbindlist[num_reply].value)
270             free(varbindlist[num_reply].value);
271         varbindlist[num_reply].value =
272             (char *) malloc(varbindlist[num_reply].len_val);
273         memcpy(varbindlist[num_reply].value, start,
274                varbindlist[num_reply].len_val);
275 */
276         varbindlist[num_reply].value = start;
277         len -= varbindlist[num_reply].len_val;
278         start += varbindlist[num_reply].len_val;
279         num_reply++;
280     }
281
282     return num_reply;
283 }