1 /*
2  * $Id: query.c 45 2010-07-27 07:30:50Z jimklimov $
3  */
4 
5 #ifdef HAVE_CONFIG_H
6 #include <config.h>
7 #endif
8 
9 #include <ctype.h>
10 #include <errno.h>
11 #include <netdb.h>
12 #include <stdio.h>
13 #include <stdarg.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <arpa/inet.h>
18 #include <netinet/in.h>
19 #include <sys/socket.h>
20 #include <sys/wait.h>
21 #include <sysexits.h>
22 
23 #include "sdig.h"
24 #include "common.h"
25 #include "snmpget.h"
26 
27 char
findmac_at_rtr_ip(const char * ip,const char * rtr_ip,rtype * rtr)28 *findmac_at_rtr_ip(const char *ip, const char *rtr_ip, rtype *rtr)
29 {
30 	char	query[256], *ret;
31 	int	ifnum, eqcheck;
32 
33 	debug(2, "\n\nfindmac_at_rtr_ip: [%s] [%s] [%s] [%s]\n", ip, rtr_ip, rtr->ip, rtr->pw);
34 
35 	/* find the router's internal interface number */
36 
37 	snprintf(query, sizeof(query),
38 		"IP-MIB::ipAdEntIfIndex.%s", rtr_ip);
39 
40 	ifnum = snmpget_int(rtr->ip, rtr->pw, query);
41 
42 	if (ifnum == -1)
43 		return NULL;
44 
45 	debug(6, "router interface number for %s is %d\n",
46 		rtr_ip, ifnum);
47 
48 	/* now look it up in the net to media table relative to the ifnum */
49 
50 	/* if digging the router itself, use a different OID */
51 
52 	eqcheck = strcmp(ip, rtr_ip);
53 	if (!eqcheck)
54 		snprintf(query, sizeof(query),
55 			"interfaces.ifTable.ifEntry.ifPhysAddress.%d",
56 			ifnum);
57 	else
58 		snprintf(query, sizeof(query),
59 		"ip.ipNetToMediaTable.ipNetToMediaEntry.ipNetToMediaPhysAddress.%d.%s",
60 		ifnum, ip);
61 
62 	ret = snmpget_mac(rtr->ip, rtr->pw, query);
63 
64 	if (!ret && eqcheck) {
65 // Avaya's have offset OIDs by 1 (maybe VLAN ID reservation?), i.e.
66 // RFC1213-MIB::atPhysAddress.1.1.192.168.42.4 = Hex-STRING: 00 1B 4F 0C 79 E1
67 		snprintf(query, sizeof(query),
68 		"ip.ipNetToMediaTable.ipNetToMediaEntry.ipNetToMediaPhysAddress.%d.1.%s",
69 		ifnum, ip);
70 
71 		ret = snmpget_mac(rtr->ip, rtr->pw, query);
72 	}
73 
74         return ret;
75 }
76 
77 char
findmac(const char * ip,rtype * rtr)78 *findmac(const char *ip, rtype *rtr)
79 {
80 	char	query[256], *ret;
81 	int	ifnum;
82 
83 	debug(2, "\n\nfindmac: [%s] [%s] [%s]\n", ip, rtr->ip, rtr->pw);
84 
85 	/* find the router's internal interface number */
86 	ifnum = -1;
87 	ret = NULL;
88 
89 	if (rtr->rtrip) {
90 		/* we have a user-configured rtr_ip */
91 
92 		debug(2, "\n\nfindmac: an rtr->rtrip is known as [%s]\n", rtr->rtrip);
93 
94 		ret = findmac_at_rtr_ip(ip, rtr->rtrip, rtr);
95 		if ( ret ) {
96 			return ret;
97 		}
98 	}
99 
100 	if ( (!ret) ) {
101 		/* an rtr_ip is not previously known, or the known one
102 		   doesn't work */
103 
104 		/* for backward compatibility (sdig-0.43 and before),
105 		   try rtr->ip address (now intended for SNMP contacts) */
106 		ret = findmac_at_rtr_ip(ip, rtr->ip, rtr);
107 		if ( ret ) {
108 			/* Match on first sight! */
109 			if (rtr->rtrip == NULL) {
110 				rtr->rtrip = xstrdup(rtr->ip);
111 			}
112 
113 	    		return ret;
114 		};
115 
116 		if ( !ret ) {
117 		    /* router's contact IP maybe not in the seeked subnet */
118 		    /* User may have configured an explicit rtr->rtrip address
119 		    in the desired subnet; otherwise we'll try to find it
120 		    and set rtrip value */
121 
122 		    /* This snmpwalking is a TODO for sdig-0.46 */
123 
124 			ret = NULL;
125 		}
126 	}
127 
128 	if ( (!ret) ) {
129 		debug(2, "\n\nfindmac: failed to find a router IP\n");
130 		return NULL;
131 	}
132 
133 	return ret;
134 }
135 
136 
137 int
findport(unsigned const char * mac,stype * sw)138 findport(unsigned const char *mac, stype *sw)
139 {
140 	char	query[64];
141 
142 	if (sw->ip == NULL) {
143 		printf("No switch defined for that network\n");
144 		exit(1);
145 	}
146 
147 	/* build the OID for the mapping of MAC addresses to port numbers */
148 
149 	snprintf(query, sizeof(query), "SNMPv2-SMI::mib-2.17.4.3.1.2.%u.%u.%u.%u.%u.%u",
150 		mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
151 
152 	debug(4, "findport: snmpget_int(%s, %s, %s)\n",
153 		sw->ip, sw->pw, query);
154 
155 	return snmpget_int(sw->ip, sw->pw, query);
156 }
157 
158 char
getlink(const char * ip,long port)159 *getlink(const char *ip, long port)
160 {
161 	litype	*tmp;
162 
163 	tmp = firstli;
164 
165 	while (tmp) {
166 		if ((!strcmp(tmp->ip, ip)) && (tmp->port == port))
167 			return tmp->desc;
168 
169 		tmp = tmp->next;
170 	}
171 
172 	return NULL;
173 }
174 
175 char
getdesc(const char * ip,long port)176 *getdesc(const char *ip, long port)
177 {
178 	pdtype	*tmp;
179 
180 	tmp = firstpd;
181 
182 	while (tmp) {
183 		if ((!strcmp(tmp->ip, ip)) && (tmp->port == port))
184 			return tmp->desc;
185 
186 		tmp = tmp->next;
187 	}
188 
189 	return NULL;
190 }
191 
192 const char
macmfr(unsigned char * inmac)193 *macmfr(unsigned char *inmac)
194 {
195 	FILE	*macdb;
196 	char	buf[256], *tmp, macfind[16];
197 	int	i;
198 
199 	macdb = fopen(mactable, "r");
200 	if (!macdb)
201 		return "MAC table file not available";
202 
203 	/* rewrite the MAC address into something that'll match the table */
204 
205 	snprintf(macfind, sizeof(macfind), "%02x %02x %02x",
206 		inmac[0], inmac[1], inmac[2]);
207 
208 	while (fgets(buf, sizeof(buf), macdb)) {
209 		buf[strlen(buf) - 1] = '\0';
210 
211 		if (!strncasecmp(buf, macfind, 8)) {
212 			tmp = xstrdup(&buf[9]);
213 			for (i = strlen(tmp) - 1; i >= 0; i--) {
214 				if (!isspace(tmp[i])) {
215 					tmp[i+1] = '\0';
216 					return tmp;
217 				}
218 			}
219 			return tmp;
220 		}
221 	}
222 
223 	fclose(macdb);
224 	return "Not available";
225 }
226 
227 char
wins_resolve(const char * host)228 *wins_resolve(const char *host)
229 {
230 	char	exec[256], buf[256];
231 	FILE	*wq;
232 
233 	if (!wins) {
234 		fprintf(stderr, "WINS not defined in config file!\n");
235 		return NULL;
236 	}
237 
238 	if (!nmblookup) {
239 		fprintf(stderr, "NMBLOOKUP not defined in config file!\n");
240 		return NULL;
241 	}
242 
243 	snprintf(exec, sizeof(exec), "%s -U %s -R %s | tail -1 | cut -f 1 -d \" \"",
244 		nmblookup, wins, host);
245 
246 	debug(5, "popen: %s\n", exec);
247 	wq = popen(exec, "r");
248 
249 	fgets(buf, sizeof(buf), wq);
250 	pclose(wq);
251 
252 	buf[strlen(buf) - 1] = '\0';
253 	debug(7, "read [%s]\n", buf);
254 	if (!strcmp(buf, "name_query")) {
255 		fprintf(stderr, "WINS lookup failed\n");
256 		exit(1);
257 	}
258 
259 	printf("  Address: %s (WINS)\n", buf);
260 
261 	return(xstrdup(buf));
262 }
263 
264 char
dns_resolve(const char * host,int verbose)265 *dns_resolve(const char *host, int verbose)
266 {
267 	struct	hostent	*dns;
268 	struct	in_addr	addr;
269 
270 	if ((dns = gethostbyname(host)) == (struct hostent *) NULL)
271 		return NULL;
272 
273 	memcpy(&addr, dns->h_addr, dns->h_length);
274 
275 	if ( verbose )
276 	   printf("  Address: %s (DNS)\n", inet_ntoa(addr));
277 
278 	return(xstrdup(inet_ntoa(addr)));
279 }
280 
281 void
do_ifdescr(stype * sw,long port)282 do_ifdescr(stype *sw, long port)
283 {
284 	char	query[256], *ifdescr, *ifname, *ifalias;
285 	long	ifnum;
286 
287 	/* first get the switch's ifnum for the port */
288 
289 	snprintf(query, sizeof(query), "SNMPv2-SMI::mib-2.17.1.4.1.2.%ld", port);
290 	ifnum = snmpget_int(sw->ip, sw->pw, query);
291 
292 	if (ifnum == -1)
293 		return;
294 
295 	snprintf(query, sizeof(query), "IF-MIB::ifName.%ld",
296 		ifnum);
297 
298 	ifname = snmpget_str(sw->ip, sw->pw, query);
299 
300 	/* Unlike previous versions of sdig, we always want an ifAlias:
301 	   "name" and "desc" fields are nearly the same and almost useless
302 	   on Cisco Catalyst and HP switches (ifDesc doesn't reflect the
303 	   switch manager's decription in the switch config, but is just
304 	   the Switch OS's long version of interface name. */
305 	snprintf(query, sizeof(query), "IF-MIB::ifAlias.%ld",
306 		ifnum);
307 
308 	ifalias = snmpget_str(sw->ip, sw->pw, query);
309 
310 	snprintf(query, sizeof(query), "IF-MIB::ifDescr.%ld",
311 		ifnum);
312 
313 	ifdescr = snmpget_str(sw->ip, sw->pw, query);
314 
315 	if (ifname) {
316 		printf(" (%s)", ifname);
317 		free(ifname);
318 	}
319 
320 	if (ifdescr) {
321 		printf(" [%s]", ifdescr);
322 		free(ifdescr);
323 	}
324 
325 	if (ifalias) {
326 		printf(" {%s}", ifalias);
327 		free(ifalias);
328 	}
329 }
330 
331 int
isip(const char * buf)332 isip(const char *buf)
333 {
334 	int	i;
335 
336 	for (i = 0; i < strlen(buf); i++)
337 		if ((!isdigit(buf[i])) && (buf[i] != '.'))
338 			return 0;
339 
340 	return 1;
341 }
342 
343 void
dnsreverse(const char * ip)344 dnsreverse(const char *ip)
345 {
346 	struct	hostent	*dns;
347 	struct	in_addr	addr;
348 
349 #if HAVE_INET_ATON
350 	inet_aton(ip, &addr);
351 #elif HAVE_INET_PTON
352 	inet_pton(AF_INET, ip, &addr);
353 #else
354 #error	Cannot convert address
355 #endif
356 
357 	dns = gethostbyaddr((char *)&addr, sizeof(struct in_addr), AF_INET);
358 
359 	if (dns)
360 		printf(" Hostname: %s (DNS)\n", dns->h_name);
361 }
362 
363 stype
find_switch(const char * ipaddr,stype * last)364 *find_switch(const char *ipaddr, stype *last)
365 {
366 	stype	*tmp, *tmpuniq;
367 	int	addrchk, swchk;
368 
369 	if (last)
370 		tmp = last->next;
371 	else
372 		tmp = firstsw;
373 
374 	if ( ipaddr ) {
375 		while (tmp) {
376 			/* User requested a specific host/ip */
377 			addrchk = ntohl(inet_addr(ipaddr)) & tmp->mask;
378 			swchk = tmp->addr & tmp->mask;
379 
380 			if (swchk == addrchk)
381 				return tmp;
382 
383 			tmp = tmp->next;
384 		}
385 	} else {
386 		/* ipaddr==NULL, check all configured switches */
387 		/* NOTE: may check same switch many times, i.e.
388 		    for Cisco Catalysts - different VLANs require
389 		    different community strings. */
390 
391 		/* Check uniquity for same switch IP x COMMUNITY */
392 
393 		tmpuniq = firstsw;
394 		while (tmpuniq != tmp && tmp && tmpuniq) {
395 			if (
396 			    strcmp(tmpuniq->pw, tmp->pw) == 0 &&
397 			    strcmp(tmpuniq->ip, tmp->ip) == 0
398 			) {
399 			    /* an earlier switch (tmpuniq) IP x COMMUNITY
400 			       are the same as our current candidate (tmp)
401 			       Try next candidate */
402 				debug (6, "\nfind_switch: Any_IP mode: switch IP x COMMUNITY already checked: [%s] [%s]\n", tmp->ip, tmp->pw);
403 				tmp = tmp->next;
404 			}
405 			tmpuniq = tmpuniq->next;
406 		}
407 
408 		/* Here we are. TMPUNIQ==TMP (no matches => tmp is unique)
409 		   or either one is null (end of list) */
410 
411 		/* The caller will return soon with "tmp"
412 		   as next starting point */
413 		return tmp;
414 	} //if
415 
416 	return NULL;
417 }
418 
419 int fork_wrapper(unsigned const char *macaddr, stype *sw);
420 
421 /* ask the switch about where the MAC address is */
422 void
switchscan(const char * ipaddr,unsigned const char * macaddr)423 switchscan(const char *ipaddr, unsigned const char *macaddr)
424 {
425 	stype	*sw;
426 	int	ret, status;
427 
428 	printf("\n");
429 
430 	if (get_debuglevel() >= 2) {
431 		debug(2, "switchscan: seeking (%s, ", (ipaddr?ipaddr:"Any_IP"));
432 		printmac(macaddr);
433 		printf(")\n");
434 	}
435 
436 	sw = find_switch(ipaddr, NULL);
437 
438 	while (sw) {
439 		debug(3, "switchscan: matched %s\n", sw->ip);
440 
441 #ifdef SDIG_USE_SEMS
442 		if ( dofork ) {
443 			/* fflush is needed to correctly pass output
444 			 * from children when parent's stdout is piped
445 			 * to elsewhere (file, sdig.cgi wrapper, etc.)
446 			 * Must be done BOTH before fork and after child labor
447 			 */
448 			fflush(stdout);
449 			fflush(stderr);
450 			ret = fork();
451 
452 			switch (ret) {
453 			case 0: /* child process */
454 
455 				ret = fork_wrapper(macaddr, sw);
456 				// _exit(EX_OK);
457 				debug(3, "child %d done (%d)\n", getpid(), ret);
458 
459 				fflush(stdout);
460 				fflush(stderr);
461 				_exit(ret);
462 				break;
463 
464 			case -1:
465 				perror("fork");
466 				exit(EX_SOFTWARE);
467 				break;
468 
469 			default: /* parent process */
470 				debug(3, "child %d started (%s, %s)\n", ret, sw->ip, sw->pw);
471 				break;
472 			}
473 		} else {
474 #endif
475 			fork_wrapper(macaddr, sw);
476 #ifdef SDIG_USE_SEMS
477 		}
478 #endif
479 
480 		sw = find_switch(ipaddr, sw);
481 	}
482 
483 #ifdef SDIG_USE_SEMS
484 	if ( dofork ) {
485 		while ((ret = wait(&status)) != -1)
486 			debug(3, "child %d exited (%d)\n", ret, WEXITSTATUS(status));
487 
488 		output_sem_cleanup();
489 	}
490 #endif
491 
492 	exit(EX_OK);
493 }
494 
495 int
fork_wrapper(unsigned const char * macaddr,stype * sw)496 fork_wrapper(unsigned const char *macaddr, stype *sw)
497 {
498 	int port;
499 
500 	port = findport(macaddr, sw);
501 
502 	if (port != -1)
503 		printport(sw, port);
504 
505 	debug(3, "findport got port %d\n", port);
506 	return port;
507 }
508 
509 rtype
find_router(const char * ipaddr,rtype * last)510 *find_router(const char *ipaddr, rtype *last)
511 {
512 	rtype	*tmp;
513 	int	addrchk, rtchk;
514 
515 	if (last)
516 		tmp = last->next;
517 	else
518 		tmp = firstrt;
519 
520 	while (tmp) {
521 		addrchk = ntohl(inet_addr(ipaddr)) & tmp->mask;
522 		rtchk = tmp->addr & tmp->mask;
523 
524 		if (rtchk == addrchk)
525 			return tmp;
526 
527 		tmp = tmp->next;
528 	}
529 
530 	return NULL;
531 }
532 
533 /* run the user's script for extra details about a host */
534 void
do_hostinfo(const char * ipaddr)535 do_hostinfo(const char *ipaddr)
536 {
537 	char	exec[256];
538 
539 	fflush(stdout);
540 
541 	snprintf(exec, sizeof(exec), "%s %s", hostinfo, ipaddr);
542 	system(exec);
543 }
544 
545 /* walk the list of routers checking for the IP address */
546 void
routerscan(const char * ipaddr)547 routerscan(const char *ipaddr)
548 {
549 	unsigned char	*macaddr;
550 	rtype	*rtr;
551 
552 	/* spew out some additional info about the IP address */
553 	if (fastmode == 0) {
554 		dnsreverse(ipaddr);
555 
556 		if (hostinfo)
557 			do_hostinfo(ipaddr);
558 	}
559 
560 	printf("\n");
561 
562 	debug(2, "routerscan: looking for a router for host %s\n", ipaddr);
563 
564 	/* XXX: ping code for waking up sleeping/inactive hosts */
565 
566 	/* find the first one that covers this network */
567 	rtr = find_router(ipaddr, NULL);
568 
569 	while (rtr) {
570 		debug(3, "routerscan: matched %s\n", rtr->ip);
571 
572 		/* try to find the target IP address on this router */
573 		macaddr = findmac(ipaddr, rtr);
574 
575 		if (macaddr) {
576 			printf("   Router: %s - %s\n", rtr->desc, (rtr->rtrip?rtr->rtrip:rtr->ip) );
577 
578 			printf("   TgtMAC: ");
579 			printmac(macaddr);
580 			printf(" (%s)\n", macmfr(macaddr));
581 
582 			switchscan(ipaddr, macaddr);
583 		}
584 
585 		rtr = find_router(ipaddr, rtr);
586 	}
587 
588 	fprintf(stderr, "Error: no routers found for %s\n", ipaddr);
589 	exit(1);
590 }
591 
592 /* turn <name> into an IP address and pass it to the router scanner */
593 void
resolvename(const char * name)594 resolvename(const char *name)
595 {
596 	char	*ipaddr;
597 
598 	/* first try DNS */
599 	ipaddr = dns_resolve(name, 1);
600 
601 	if (ipaddr)
602 		routerscan(ipaddr);
603 
604 	/* now try WINS */
605 	ipaddr = wins_resolve(name);
606 
607 	if (ipaddr)
608 		routerscan(ipaddr);
609 
610 	fprintf(stderr, "Can't resolve %s with DNS or WINS!\n", name);
611 	exit(1);
612 }
613 
614 /* Different OSes and switches have several ways to write a MAC address.
615    Convert some of these formats to "XX:XX:XX:XX:XX:XX" standard */
616 char
standardize_mac(char * buf)617 *standardize_mac(char *buf)
618 {
619 	static	char	mac[256];
620 	char *ptr;
621 	char cc, cd, cp, macfmt;
622 	int i, j, k;
623 
624 	/* First pass: count separators, determine known format */
625 	cc = 0;
626 	cd = 0;
627 	cp = 0;
628 	for (i = 0; i < strlen(buf); i++) {
629 		switch (buf[i]) {
630 		    case '-':
631 			/* Possibly a Windows-format MAC XX-XX-XX-XX-XX-XX */
632 			/* or a Hewlett-Packard format XXXXXX-XXXXXX */
633 			buf[i] = ':';
634 			cd++;
635 			break;
636 		    case ':':
637 			cc++;
638 			break;
639 		    case '.':
640 			/* Possibly a Cisco format XXXX.XXXX.XXXX */
641 			cp++;
642 			buf[i] = ':';
643 			break;
644 		}
645 
646 		if ((!isxdigit(buf[i])) && (buf[i] != ':')) {
647 			fprintf(stderr, "Invalid MAC address specified: %s\n", buf);
648 			fprintf(stderr, "Valid characters are hex digits and [:-.]\n");
649 			exit(1);
650 		}
651 	}
652 
653 	if ( (cd+cc) == 5 ) {
654 		/* 6x(0 to 2 hex digits) separated by 5x(dash or doublecolon) */
655 		// strncpy (mac, buf, 18);
656 		k = 0;
657 		for (i = 0, j = 0; i < strlen(buf); i++) {
658 			if (
659 				( (i>0 && buf[i-1]==':') || (i==0) ) &&
660 				(buf[i] == ':' || buf[i] == '\0' || i==strlen(buf))
661 		        ) {
662 				/* We have a 0-digit long component */
663 				mac[j++] = '0'; k++;
664 				mac[j++] = '0'; k++;
665 		        } else {
666 				/* We have a 1-digit long component */
667 			        if (
668 					( (i>0 && buf[i-1]==':') || (i==0) ) &&
669 					(buf[i+1] == ':' || buf[i+1] == '\0' || (i+1)==strlen(buf))
670 				) {
671 					mac[j++] = '0';
672 					k++;
673 				}
674 			}
675 
676 			//printf ("%d=%c ",k, buf[i]);
677 
678 		        if ( k>3 ) {
679     			        mac[j]='\0';
680 				fprintf(stderr, "Invalid MAC address specified: %s (%s)\n", buf, mac);
681 			        fprintf(stderr, "A double-hex component is longer than two characters!\n");
682 				exit(1);
683 			}
684 
685 			if ( buf[i] == ':' || buf[i] == '\0' || i==strlen(buf) ) {
686 			        k=0;
687 		        }
688 
689 		        if ( j>=17 ) {
690 				mac[j]='\0';
691 				fprintf(stderr, "Invalid MAC address specified: %s (%s)\n", buf, mac);
692 				fprintf(stderr, "String length exceeded!\n");
693 				exit(1);
694 			}
695 
696 		        mac[j++] = tolower(buf[i]); k++;
697 		}
698 
699 		debug (1, "standardize_mac: got a Windows/Linux/Solaris MAC: [%s]\n", mac);
700 		return mac;
701 	}
702 
703 	if ( ((cc+cd+cp) == 0) && (strlen(buf)==12) ) {
704 		/* xxxxxxxxxxxx */
705 		for (i = 0, j = 0, k = 0; i < strlen(buf); i++) {
706 			mac[j++] = tolower(buf[i]); k++;
707 			if ( k==2 ) {
708 				if ( i < (strlen(buf)-1) ) {
709 					k=0;
710 					mac[j++] = ':';
711 				} else {
712 					mac[j++] = '\0';
713 				}
714 			}
715 		}
716 
717 		debug (1, "standardize_mac: got an unseparated MAC: [%s]\n", mac);
718 		return mac;
719 	}
720 
721 	if ( (cd+cc)==1 && (strlen(buf)==13) && buf[6]==':' ) {
722 		/* originally Hewlett-Packard: XXXXXX-XXXXXX */
723 		for (i = 0, j = 0, k = 0; i < strlen(buf); i++) {
724 			if ( i!= 6 ) {
725 				mac[j++] = tolower(buf[i]);
726 				k++;
727 			}
728 
729 			if ( k==2 ) {
730 				if ( i < (strlen(buf)-1) ) {
731 					k=0;
732 					mac[j++] = ':';
733 				} else {
734 					mac[j++] = '\0';
735 				}
736 			}
737 		}
738 
739 		debug (1, "standardize_mac: got a HP MAC: [%s]\n", mac);
740 		return mac;
741 	}
742 
743 	if ( (cp+cd+cc)==2 && (strlen(buf)==14) &&
744 		buf[4]==':' && buf[9]==':' ) {
745 		/* originally Cisco: XXXX.XXXX.XXXX */
746 		for (i = 0, j = 0, k = 0; i < strlen(buf); i++) {
747 			if ( i!= 4 && i!=9 ) {
748 				mac[j++] = tolower(buf[i]);
749 				k++;
750 			}
751 
752 			if ( k==2 ) {
753 				if ( i < (strlen(buf)-1) ) {
754 					k=0;
755 					mac[j++] = ':';
756 				} else {
757 					mac[j++] = '\0';
758 				}
759 			}
760 		}
761 
762 		debug (1, "standardize_mac: got a Cisco MAC: [%s]\n", mac);
763 		return mac;
764 	}
765 
766 
767 	strncpy (mac, buf, 18);
768 	debug (1, "standardize_mac: unrecognized format, passed on as is: [%s]\n", mac);
769 	return mac;
770 }
771 
772 /* see if the specified mac address is sane, and make it machine-readable */
773 char
pack_mac(char * buf)774 *pack_mac(char *buf)
775 {
776 	int	i, cc, sl, v, mp;
777 	char	*ptr, *cp;
778 	static	char	mac[16];
779 
780 	cc = 0;
781 	for (i = 0; i < strlen(buf); i++) {
782 
783 		if (buf[i] == '-')
784 			/* Possibly a Windows-format MAC XX-XX-XX-XX-XX-XX */
785 			buf[i] = ':';
786 
787 		if (buf[i] == ':')
788 			cc++;
789 
790 		if ((!isxdigit(buf[i])) && (buf[i] != ':')) {
791 			fprintf(stderr, "Invalid MAC address specified: %s\n", buf);
792 			fprintf(stderr, "Valid characters are hex digits and :\n");
793 			exit(1);
794 		}
795 	}
796 
797 	if (cc != 5) {
798 		fprintf(stderr, "Invalid MAC address specified: %s\n", buf);
799 		fprintf(stderr, "It must contain exactly 5 : separators.\n");
800 		exit(1);
801 	}
802 
803 	strcpy(mac, "");
804 	ptr = buf;
805 	sl = strlen(buf);
806 	mp = 0;
807 
808 	for (i = 0; i < sl; i++) {
809 		cp = strchr(ptr, ':');
810 
811 		if (!cp) {
812 			v = strtol(ptr, (char **) NULL, 16);
813 
814 			mac[mp++] = v;
815 			break;
816 		}
817 
818 		*cp++ = '\0';
819 
820 		v = strtol(ptr, (char **) NULL, 16);
821 		mac[mp++] = v;
822 
823 		ptr = cp;
824 	}
825 
826 	return mac;
827 }
828