]> git.decadent.org.uk Git - ap-utils.git/blob - src/ap-trapd.c
cd864a1d84c10cd6f5a6fdc1986dbe6194bdd4c9
[ap-utils.git] / src / ap-trapd.c
1 /*
2  *      ap-trapd.c from Access Point SNMP Utils for Linux
3  *      SNMP traps processing daemon code
4  *
5  * Copyright (c) 2002 Roman Festchook <roma at polesye dot net>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License Version 2 from
9  * June 1991 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  */
21
22 #include <sys/types.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <pwd.h>
27 #include <syslog.h>
28 #include <stdio.h>
29 #include "ap-utils.h"
30
31 #define TRAPD_USER "nobody"
32
33 int main(int argc, char **argv)
34 {
35     extern char *optarg;
36     extern int optind;
37     extern int opterr;
38     extern int optopt;
39     int opt = 0;
40
41     char *user=NULL, *device=NULL;
42     
43
44     pid_t pid;
45     struct passwd *pwd;
46     struct sockaddr_in server;
47     struct sockaddr_in client;
48     int sockfd, len;
49     unsigned int client_len = SIZE, hand, sec, min;
50     unsigned char buf[512], *start, snmp_version,
51         *community = NULL, generic_trap, specific_trap;
52     unsigned int i, atmel_ap_type = 0;
53     size_t time_stamp;
54     char mac[6], *enterprise_oid = NULL, c, mac_info[31], mac_flag = 0;
55     struct in_addr agent_addr;
56     char enterprise[] = { 0x2b, 0x06, 1, 4, 1, 0x83, 0x1a, 1, 1 };
57     char *generic_traps[8] = { "ColdStart",
58         "WarmStart",
59         "LinkDown",
60         "LinkUp",
61         "AuthenticationFailure",
62         "EgpNeighborLoss",
63         "EnterpriseSpecific",
64         "unknown"
65     };
66     char *specific_traps[22] = {
67         "Reassociation",
68         "RoamOut",
69         "Association",
70         "Disassociation",
71         "AssociationExpire",
72         "Reset",
73         "SettingPingIPAddress",
74         "StartUp",
75         "FailedToEraseFlash",
76         "APClientScanning",
77         "APClientAuthenticating",
78         "APClientAssociating",
79         "APClientReAssociating",
80         "APClientAuthenticationFailed",
81         "APClientAssociationFailed",
82         "APClientConnected",
83         "APClientDisconnected",
84         "APClientScanFailed",
85         "APClientJoinFailed",
86         "APClientJoining",
87         "unknown",
88         "APClientScanFinished" /* I think:) /roma */
89     };
90
91     char *specific_traps_sb[22] = {
92         "Reassociation",
93         "RoamOut",
94         "Association",
95         "Disassociation",
96         "AssociationExpire",
97         "Reset",
98         "SettingPingIPAddress",
99         "StartUp",
100         "FailedToEraseFlash",
101         "APClientAssociating",
102         "APClientScanning",
103         "MultiAttachedStation",
104         "unknown",
105         "unknown",
106         "unknown",
107         "unknown",
108         "unknown",
109         "unknown",
110         "unknown",
111         "unknown",
112         "unknown",
113         "unknown"
114 };
115
116     memset(&server, 0, sizeof server);
117     server.sin_family = AF_INET;
118     server.sin_port = htons(162);
119     server.sin_addr.s_addr = INADDR_ANY;
120
121 #ifdef HAVE_GETTEXT
122     /* locale support init */
123     setlocale(LC_ALL, "");
124     bindtextdomain("ap-utils", LOCALEDIR);
125     textdomain("ap-utils");
126 #endif
127
128     if (argc > 1)
129      do {
130         opterr = 0;
131         switch (opt = getopt(argc, argv, "u:i:s")) {
132         case 'i':
133             device = malloc(strlen(optarg) + 1);
134             strncpy(device, optarg, strlen(optarg) + 1);
135             break;
136         case 'u':
137             user = malloc(strlen(optarg) + 1);
138             strncpy(user, optarg, strlen(optarg) + 1);
139             break;
140         case 's':
141             atmel_ap_type = 1;
142             break;
143         }
144     } while (opt != -1);
145
146
147     openlog("ap-trapd", LOG_PID, LOG_LOCAL0);
148     syslog(LOG_INFO, _("ap-trapd %s started%s%s."), VERSION,
149            (device) ? _(" on ") : "", (device) ? device : "");
150
151     pid = fork();
152     if (pid > 0) {              /* parent */
153         return 0;
154     } else if (pid < 0) {       /* failed */
155         syslog(LOG_ERR, _("Unable to fork. Exiting."));
156         return 1;
157     }
158     if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
159         syslog(LOG_ERR, _("Can't create socket. Exiting."));
160         return 1;
161     }
162
163
164     if (bind(sockfd, (struct sockaddr *) &server, SIZE) == -1) {
165         syslog(LOG_ERR, _("Can't bind socket. Exiting."));
166         return 1;
167     }
168 #ifdef OS_LINUX
169     if (device) {
170         if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, device,
171                        strlen(device) + 1) == -1) {
172             syslog(LOG_ERR, _("Can't bind to device %s. Exiting."),
173                    device);
174             return 1;
175         }
176     }
177 #endif
178
179     if (user == NULL)
180         user = TRAPD_USER;
181     /* after opening socket change userid  */
182     if ((pwd = getpwnam(user)) == NULL) {
183         syslog(LOG_ERR, _("Unable to process username %s. Error: %m."),
184                user);
185         return 1;
186     }
187     if (setgid(pwd->pw_gid) == -1 || setuid(pwd->pw_uid) == -1) {
188         syslog(LOG_ERR, _("Unable to change to uid %d."), pwd->pw_uid);
189         return 1;
190     }
191
192     while (1) {
193         if ((len =
194              recvfrom(sockfd, buf, 512, 0, (struct sockaddr *) &client,
195                       &client_len)) == -1)
196             continue;
197         if (buf[0] != ASN_HEADER) {
198             continue;
199         }
200         start = buf;
201         if (buf[1] & 0x80) {
202             start += (buf[1] & 0x7F) + 2;
203         } else {
204             start += 2;
205         }
206         snmp_version = start[2];
207
208         if (community)
209             free(community);
210         community = malloc(start[4] + 1);
211         memcpy(community, start + 5, start[4]);
212         community[start[4]] = '\0';
213         start += *(start + 4) + 5;
214
215         if (start[0] != TRAP) {
216             continue;
217         }
218
219         if (start[1] & 0x80) {
220             start += (start[1] & 0x7F) + 2;
221         } else {
222             start += 2;
223         }
224
225         if (enterprise_oid)
226             free(enterprise_oid);
227         enterprise_oid = malloc(start[1] + 1);
228         memcpy(enterprise_oid, start + 2, start[1]);
229         enterprise_oid[start[1]] = '\0';
230         start += start[1] + 2;
231         memcpy(&agent_addr.s_addr, start + 2, 4);
232         if (memcmp(enterprise_oid, enterprise, sizeof(enterprise))) {
233             syslog(LOG_INFO,
234                    _
235                    ("Received unknown SNMP ver %d trap. From %s:%d. Agent: %s. Community: %s."),
236                    snmp_version + 1, inet_ntoa(client.sin_addr),
237                    ntohs(client.sin_port), inet_ntoa(agent_addr),
238                    community);
239             continue;
240         }
241
242         start += 6;
243         generic_trap = start[2];
244         if (generic_trap > 6)
245             generic_trap = 7;
246         specific_trap = start[5];
247         if (specific_trap > 22)
248             specific_trap = 21;
249
250         time_stamp = 0;
251         c = 0;
252         i = 1;
253         while (c < start[7]) {
254             time_stamp += (unsigned char) *(start + 7 + start[7] - c) * i;
255             i *= 256;
256             c++;
257         }
258         hand = time_stamp % 100;
259         time_stamp = time_stamp / 100;
260         sec = time_stamp % 60;
261         time_stamp = time_stamp / 60;
262         min = time_stamp % 60;
263         time_stamp = time_stamp / 60;
264
265         start += start[7] + 8;
266
267
268         mac_flag = 0;
269         if ((start - buf < len) && *(start) == ASN_HEADER) {
270
271             if (start[1] & 0x80) {
272                 start += (start[1] & 0x7F) + 2;
273                 len -= ((start[1] & 0x7F) + 2);
274             } else {
275                 start += 2;
276                 len -= 2;
277             }
278
279             if (*(start) == ASN_HEADER) {
280                 if (start[1] & 0x80) {
281                     start += (start[1] & 0x7F) + 2;
282                     len -= ((start[1] & 0x7F) + 2);
283                 } else {
284                     start += 2;
285                     len -= 2;
286                 }
287                 start += start[1] + 4;
288                 memcpy(mac, start, 6);
289                 if (generic_trap == 6 && specific_trap >= 1
290                     && (specific_trap <= 5 || specific_trap >= 9)) {
291                     sprintf(mac_info, "%02X%02X%02X%02X%02X%02X",
292                             mac[0] & 0xFF, mac[1] & 0xFF, mac[2] & 0xFF,
293                             mac[3] & 0xFF, mac[4] & 0xFF, mac[5] & 0xFF);
294                     mac_flag = 1;
295                 }
296                 if (generic_trap == 6 && specific_trap == 7) {
297                     sprintf(mac_info,
298                             "%d.%d.%d.%d",
299                             mac[0] & 0xFF, mac[1] & 0xFF, mac[2] & 0xFF,
300                             mac[3] & 0xFF);
301                     mac_flag = 1;
302                 }
303             }
304         }
305         syslog(LOG_INFO,
306                _
307                ("Agent:v%d %s (%s@%s:%d) %s%s%s. SysUptime %d:%02d:%02d.%02d"),
308                snmp_version + 1,  inet_ntoa(agent_addr),
309                community, inet_ntoa(client.sin_addr), ntohs(client.sin_port),
310                (generic_trap ==
311                 6) ? (atmel_ap_type == 1) ? specific_traps[specific_trap-1] : specific_traps_sb[specific_trap-1] :
312                generic_traps[generic_trap], (mac_flag) ? " " : "",
313                (mac_flag) ? mac_info : "", time_stamp, min, sec, hand);
314     }
315
316     /* not reachable */
317     return 0;
318 }