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 
main(int argc,char ** argv)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 }
319