mactelnet-0.4.2/0000774000175100017630000000000012622313406012134 5ustar haakoncymactelnet-0.4.2/macping.c0000664000175100017630000002107212622313406013721 0ustar haakoncy/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #if defined(__FreeBSD__) #include #include #include #include #define ETH_FRAME_LEN ETHER_MAX_LEN #define ETH_ALEN ETHER_ADDR_LEN #else #include #endif #include #include #include #include #include #include #include "protocol.h" #include "interfaces.h" #include "config.h" #include "utlist.h" #define MAX_DEVICES 128 #define MT_INTERFACE_LEN 128 #define PROGRAM_NAME "MAC-Ping" #define _(String) gettext (String) static int sockfd, insockfd; static unsigned short ping_size = 38; struct net_interface *interfaces; static struct in_addr sourceip; static struct in_addr destip; static unsigned char dstmac[ETH_ALEN]; static int ping_sent = 0; static int pong_received = 0; static float min_ms = FLT_MAX; static float avg_ms = 0; static float max_ms = 0; /* Protocol data direction, not used here, but obligatory for protocol.c */ unsigned char mt_direction_fromserver = 0; static void print_version() { fprintf(stderr, PROGRAM_NAME " " PROGRAM_VERSION "\n"); } static long long int toddiff(struct timeval *tod1, struct timeval *tod2) { long long t1, t2; t1 = tod1->tv_sec * 1000000 + tod1->tv_usec; t2 = tod2->tv_sec * 1000000 + tod2->tv_usec; return t1 - t2; } static void display_results() { int percent = (int)((100.f/ping_sent) * pong_received); if (percent > 100) { percent = 0; } if (percent < 0) { percent = 0; } if (min_ms == FLT_MAX) { min_ms = 0; } printf("\n"); printf(_("%d packets transmitted, %d packets received, %d%% packet loss\n"), ping_sent, pong_received, 100 - percent); printf(_("round-trip min/avg/max = %.2f/%.2f/%.2f ms\n"), min_ms, avg_ms/pong_received, max_ms); /* For bash scripting */ if (pong_received == 0) { exit(1); } exit(0); } int main(int argc, char **argv) { int optval = 1; int print_help = 0; int send_packets = 5; int fastmode = 0; int c; struct sockaddr_in si_me; struct mt_packet packet; int i; setlocale(LC_ALL, ""); bindtextdomain("mactelnet","/usr/share/locale"); textdomain("mactelnet"); while (1) { c = getopt(argc, argv, "fs:c:hv?"); if (c == -1) { break; } switch (c) { case 'f': fastmode = 1; break; case 's': ping_size = atoi(optarg) - 18; break; case 'v': print_version(); exit(0); break; case 'c': send_packets = atoi(optarg); break; case 'h': case '?': print_help = 1; break; } } /* We don't want people to use this for the wrong reasons */ if (fastmode && (send_packets == 0 || send_packets > 100)) { fprintf(stderr, _("Number of packets to send must be more than 0 and less than 100 in fast mode.\n")); return 1; } if (argc - optind < 1 || print_help) { print_version(); fprintf(stderr, _("Usage: %s [-h] [-f] [-c ] [-s ]\n"), argv[0]); if (print_help) { fprintf(stderr, _("\nParameters:\n" " MAC MAC-Address of the RouterOS/mactelnetd device.\n" " -f Fast mode, do not wait before sending next ping request.\n" " -s Specify size of ping packet.\n" " -c Number of packets to send. (0 = unlimited)\n" " -h This help.\n" "\n")); } return 1; } if (ping_size > ETH_FRAME_LEN - 42) { fprintf(stderr, _("Packet size must be between 18 and %d\n"), ETH_FRAME_LEN - 42 + 18); exit(1); } /* Mikrotik RouterOS does not answer unless the packet has the correct recipient mac-address in * the ethernet frame. Unlike real MacTelnet connections where the OS is ok with it being a * broadcast mac address. */ if (geteuid() != 0) { fprintf(stderr, _("You need to have root privileges to use %s.\n"), argv[0]); return 1; } /* Get mac-address from string, or check for hostname via mndp */ if (!query_mndp_or_mac(argv[optind], dstmac, 1)) { /* No valid mac address found, abort */ return 1; } sockfd = net_init_raw_socket(); insockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (insockfd < 0) { perror("insockfd"); return 1; } /* Set initialize address/port */ memset((char *) &si_me, 0, sizeof(si_me)); si_me.sin_family = AF_INET; si_me.sin_port = htons(MT_MACTELNET_PORT); si_me.sin_addr.s_addr = htonl(INADDR_ANY); setsockopt(insockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (optval)); /* Bind to specified address/port */ if (bind(insockfd, (struct sockaddr *)&si_me, sizeof(si_me))==-1) { fprintf(stderr, _("Error binding to %s:%d\n"), inet_ntoa(si_me.sin_addr), MT_MNDP_PORT); return 1; } /* Listen address*/ inet_pton(AF_INET, (char *)"0.0.0.0", &sourceip); /* Set up global info about the connection */ inet_pton(AF_INET, (char *)"255.255.255.255", &destip); srand(time(NULL)); /* Enumerate available interfaces */ net_get_interfaces(&interfaces); if (ping_size < sizeof(struct timeval)) { ping_size = sizeof(struct timeval); } signal(SIGINT, display_results); for (i = 0; i < send_packets || send_packets == 0; ++i) { fd_set read_fds; static struct timeval lasttimestamp; int reads, result; struct timeval timeout; int ii; int sent = 0; int waitforpacket; struct timeval timestamp; unsigned char pingdata[1500]; struct net_interface *interface; gettimeofday(×tamp, NULL); memcpy(pingdata, ×tamp, sizeof(timestamp)); for (ii = sizeof(timestamp); ii < ping_size; ++ii) { pingdata[ii] = rand() % 256; } LL_FOREACH(interfaces, interface) { if (!interface->has_mac) { continue; } init_pingpacket(&packet, interface->mac_addr, dstmac); add_packetdata(&packet, pingdata, ping_size); result = net_send_udp(sockfd, interface, interface->mac_addr, dstmac, &sourceip, MT_MACTELNET_PORT, &destip, MT_MACTELNET_PORT, packet.data, packet.size); if (result > 0) { sent++; } } if (sent == 0) { fprintf(stderr, _("Error sending packet.\n")); continue; } ping_sent++; FD_ZERO(&read_fds); FD_SET(insockfd, &read_fds); timeout.tv_sec = 1; timeout.tv_usec = 0; waitforpacket = 1; while (waitforpacket) { /* Wait for data or timeout */ reads = select(insockfd+1, &read_fds, NULL, NULL, &timeout); if (reads <= 0) { waitforpacket = 0; fprintf(stderr, _("%s ping timeout\n"), ether_ntoa((struct ether_addr *)&dstmac)); break; } unsigned char buff[1500]; struct sockaddr_in saddress; unsigned int slen = sizeof(saddress); struct mt_mactelnet_hdr pkthdr; result = recvfrom(insockfd, buff, 1500, 0, (struct sockaddr *)&saddress, &slen); parse_packet(buff, &pkthdr); /* TODO: Check that we are the receiving host */ if (pkthdr.ptype != MT_PTYPE_PONG) { /* Wait for the correct packet */ continue; } struct timeval pongtimestamp; struct timeval nowtimestamp; waitforpacket = 0; gettimeofday(&nowtimestamp, NULL); memcpy(&pongtimestamp, pkthdr.data - 4, sizeof(pongtimestamp)); if (memcmp(pkthdr.data - 4, pingdata, ping_size) == 0) { float diff = toddiff(&nowtimestamp, &pongtimestamp) / 1000.0f; if (diff < min_ms) { min_ms = diff; } if (diff > max_ms) { max_ms = diff; } avg_ms += diff; printf(_("%s %d byte, ping time %.2f ms%s\n"), ether_ntoa((struct ether_addr *)&(pkthdr.srcaddr)), result, diff, (char *)(memcmp(&pongtimestamp,&lasttimestamp,sizeof(lasttimestamp)) == 0 ? " DUP" : "")); } else { printf(_("%s Reply of %d bytes of unequal data\n"), ether_ntoa((struct ether_addr *)&(pkthdr.srcaddr)), result); } pong_received++; memcpy(&lasttimestamp, &pongtimestamp, sizeof(pongtimestamp)); if (!fastmode) { sleep(1); } } } /* Display statistics and exit */ display_results(); return 0; } mactelnet-0.4.2/console.h0000664000175100017630000000207312622313406013752 0ustar haakoncy/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ extern int get_terminal_size(unsigned short *width, unsigned short *height); extern int raw_term(); extern int reset_term(); extern int set_terminal_size(int fd, unsigned short width, unsigned short height); mactelnet-0.4.2/mactelnet.h0000664000175100017630000000160612622313406014265 0ustar haakoncy/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define CONNECT_TIMEOUT 2 mactelnet-0.4.2/md5.h0000664000175100017630000000650012622313406012774 0ustar haakoncy/* Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.h is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Removed support for non-ANSI compilers; removed references to Ghostscript; clarified derivation from RFC 1321; now handles byte order either statically or dynamically. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); added conditionalization for C++ compilation from Martin Purschke . 1999-05-03 lpd Original version. */ #ifndef md5_INCLUDED # define md5_INCLUDED /* * This package supports both compile-time and run-time determination of CPU * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is * defined as non-zero, the code will be compiled to run only on big-endian * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to * run on either big- or little-endian CPUs, but will run slightly less * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. */ typedef unsigned char md5_byte_t; /* 8-bit byte */ typedef unsigned int md5_word_t; /* 32-bit word */ /* Define the state of the MD5 Algorithm. */ typedef struct md5_state_s { md5_word_t count[2]; /* message length in bits, lsw first */ md5_word_t abcd[4]; /* digest buffer */ md5_byte_t buf[64]; /* accumulate block */ } md5_state_t; #ifdef __cplusplus extern "C" { #endif /* Initialize the algorithm. */ void md5_init(md5_state_t *pms); /* Append a string to the message. */ void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); /* Finish the message and return the digest. */ void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); #ifdef __cplusplus } /* end extern "C" */ #endif #endif /* md5_INCLUDED */ mactelnet-0.4.2/users.h0000664000175100017630000000232712622313406013453 0ustar haakoncy/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _USERS_H #define _USERS_H 1 #define MT_CRED_LEN 100 #define MT_CRED_MAXNUM 128 struct mt_credentials { char username[MT_CRED_LEN]; char password[MT_CRED_LEN]; struct mt_credentials *prev; struct mt_credentials *next; }; extern struct mt_credentials *mt_users; extern void read_userfile(); struct mt_credentials* find_user(char *username); #endif mactelnet-0.4.2/Makefile0000664000175100017630000000365412622313406013605 0ustar haakoncy CC?=gcc all: macping mndp mactelnet mactelnetd clean: distclean distclean: rm -f mactelnet macping mactelnetd mndp rm -f *.o potclean: rm -f po/*.pot dist: distclean potclean pot install: all install-docs install -d $(DESTDIR)/usr/bin install mndp $(DESTDIR)/usr/bin/ install macping $(DESTDIR)/usr/bin/ install mactelnet $(DESTDIR)/usr/bin/ install -d $(DESTDIR)/usr/sbin install -o root mactelnetd $(DESTDIR)/usr/sbin/ install -d $(DESTDIR)/etc install -m 600 -o root config/mactelnetd.users $(DESTDIR)/etc/ install-docs: install -d $(DESTDIR)/usr/share/man/man1/ install docs/*.1 $(DESTDIR)/usr/share/man/man1/ pot: po/mactelnet.pot po/mactelnet.pot: *.c xgettext --package-name=mactelnet --msgid-bugs-address=haakon.nessjoen@gmail.com -d mactelnet -C -c_ -k_ -kgettext_noop *.c -o po/mactelnet.pot autologin.o: autologin.c autologin.h ${CC} -Wall ${CFLAGS} -c autologin.c users.o: users.c users.h ${CC} -Wall ${CFLAGS} -DUSERSFILE='"/etc/mactelnetd.users"' -c users.c protocol.o: protocol.c protocol.h ${CC} -Wall ${CFLAGS} -c protocol.c interfaces.o: interfaces.c interfaces.h ${CC} -Wall ${CFLAGS} -c interfaces.c md5.o: md5.c md5.h ${CC} -Wall ${CFLAGS} -c md5.c console.o: console.c ${CC} -Wall ${CFLAGS} -c console.c mactelnet: config.h mactelnet.c mactelnet.h protocol.o console.o interfaces.o md5.o mndp.c autologin.o ${CC} -Wall ${CFLAGS} ${LDFLAGS} -o mactelnet mactelnet.c protocol.o console.o interfaces.o md5.o autologin.o -DFROM_MACTELNET mndp.c ${LIBS} mactelnetd: config.h mactelnetd.c protocol.o interfaces.o console.o users.o users.h md5.o ${CC} -Wall ${CFLAGS} ${LDFLAGS} -o mactelnetd mactelnetd.c protocol.o console.o interfaces.o users.o md5.o -lrt ${LIBS} mndp: config.h mndp.c protocol.o ${CC} -Wall ${CFLAGS} ${LDFLAGS} -o mndp mndp.c protocol.o ${LIBS} macping: config.h macping.c interfaces.o protocol.o ${CC} -Wall ${CFLAGS} ${LDFLAGS} -o macping macping.c interfaces.o protocol.o ${LIBS} mactelnet-0.4.2/users.c0000664000175100017630000000423512622313406013446 0ustar haakoncy/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include "users.h" #include "config.h" #include "utlist.h" #define _(String) gettext (String) struct mt_credentials *mt_users = NULL; void read_userfile() { struct mt_credentials *cred, *tmp; FILE *file = fopen(USERSFILE, "r"); char line [BUFSIZ]; if (file == NULL) { perror(USERSFILE); exit(1); } DL_FOREACH_SAFE(mt_users, cred, tmp) { DL_DELETE(mt_users, cred); free(cred); } while ( fgets(line, sizeof line, file) ) { char *user; char *password; user = strtok(line, ":"); password = strtok(NULL, "\n"); if (user == NULL || password == NULL || user[0] == '#') { continue; } cred = (struct mt_credentials *)calloc(1, sizeof(struct mt_credentials)); if (cred == NULL) { fprintf(stderr, _("Error allocating memory for user information\n")); exit(1); } memcpy(cred->username, user, strlen(user) < MT_CRED_LEN - 1? strlen(user) : MT_CRED_LEN); memcpy(cred->password, password, strlen(password) < MT_CRED_LEN - 1? strlen(password) : MT_CRED_LEN); DL_APPEND(mt_users, cred); } fclose(file); } struct mt_credentials* find_user(char *username) { struct mt_credentials *cred; DL_FOREACH(mt_users, cred) { if (strcmp(username, cred->username) == 0) { return cred; } } return NULL; } mactelnet-0.4.2/LICENSE0000664000175100017630000004325412622313406013152 0ustar haakoncy GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. mactelnet-0.4.2/md5.c0000664000175100017630000003022212622313406012765 0ustar haakoncy/* Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.c is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order either statically or dynamically; added missing #include in library. 2002-03-11 lpd Corrected argument list for main(), and added int return type, in test program and T value program. 2002-02-21 lpd Added missing #include in test program. 2000-07-03 lpd Patched to eliminate warnings about "constant is unsigned in ANSI C, signed in traditional"; made test program self-checking. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). 1999-05-03 lpd Original version. */ #include "md5.h" #include #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ #ifdef ARCH_IS_BIG_ENDIAN # define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) #else # define BYTE_ORDER 0 #endif #define T_MASK ((md5_word_t)~0) #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) #define T3 0x242070db #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) #define T6 0x4787c62a #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) #define T9 0x698098d8 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) #define T13 0x6b901122 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) #define T16 0x49b40821 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) #define T19 0x265e5a51 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) #define T22 0x02441453 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) #define T25 0x21e1cde6 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) #define T28 0x455a14ed #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) #define T31 0x676f02d9 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) #define T35 0x6d9d6122 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) #define T38 0x4bdecfa9 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) #define T41 0x289b7ec6 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) #define T44 0x04881d05 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) #define T47 0x1fa27cf8 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) #define T50 0x432aff97 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) #define T53 0x655b59c3 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) #define T57 0x6fa87e4f #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) #define T60 0x4e0811a1 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) #define T63 0x2ad7d2bb #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) static void md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) { md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d = pms->abcd[3]; md5_word_t t; #if BYTE_ORDER > 0 /* Define storage only for big-endian CPUs. */ md5_word_t X[16]; #else /* Define storage for little-endian or both types of CPUs. */ md5_word_t xbuf[16]; const md5_word_t *X; #endif { #if BYTE_ORDER == 0 /* * Determine dynamically whether this is a big-endian or * little-endian machine, since we can use a more efficient * algorithm on the latter. */ static const int w = 1; if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ #endif #if BYTE_ORDER <= 0 /* little-endian */ { /* * On little-endian machines, we can process properly aligned * data without copying it. */ if (!((data - (const md5_byte_t *)0) & 3)) { /* data are properly aligned */ X = (const md5_word_t *)data; } else { /* not aligned */ memcpy(xbuf, data, 64); X = xbuf; } } #endif #if BYTE_ORDER == 0 else /* dynamic big-endian */ #endif #if BYTE_ORDER >= 0 /* big-endian */ { /* * On big-endian machines, we must arrange the bytes in the * right order. */ const md5_byte_t *xp = data; int i; # if BYTE_ORDER == 0 X = xbuf; /* (dynamic only) */ # else # define xbuf X /* (static only) */ # endif for (i = 0; i < 16; ++i, xp += 4) xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); } #endif } #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) /* Round 1. */ /* Let [abcd k s i] denote the operation a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + F(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 7, T1); SET(d, a, b, c, 1, 12, T2); SET(c, d, a, b, 2, 17, T3); SET(b, c, d, a, 3, 22, T4); SET(a, b, c, d, 4, 7, T5); SET(d, a, b, c, 5, 12, T6); SET(c, d, a, b, 6, 17, T7); SET(b, c, d, a, 7, 22, T8); SET(a, b, c, d, 8, 7, T9); SET(d, a, b, c, 9, 12, T10); SET(c, d, a, b, 10, 17, T11); SET(b, c, d, a, 11, 22, T12); SET(a, b, c, d, 12, 7, T13); SET(d, a, b, c, 13, 12, T14); SET(c, d, a, b, 14, 17, T15); SET(b, c, d, a, 15, 22, T16); #undef SET /* Round 2. */ /* Let [abcd k s i] denote the operation a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + G(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 1, 5, T17); SET(d, a, b, c, 6, 9, T18); SET(c, d, a, b, 11, 14, T19); SET(b, c, d, a, 0, 20, T20); SET(a, b, c, d, 5, 5, T21); SET(d, a, b, c, 10, 9, T22); SET(c, d, a, b, 15, 14, T23); SET(b, c, d, a, 4, 20, T24); SET(a, b, c, d, 9, 5, T25); SET(d, a, b, c, 14, 9, T26); SET(c, d, a, b, 3, 14, T27); SET(b, c, d, a, 8, 20, T28); SET(a, b, c, d, 13, 5, T29); SET(d, a, b, c, 2, 9, T30); SET(c, d, a, b, 7, 14, T31); SET(b, c, d, a, 12, 20, T32); #undef SET /* Round 3. */ /* Let [abcd k s t] denote the operation a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ #define H(x, y, z) ((x) ^ (y) ^ (z)) #define SET(a, b, c, d, k, s, Ti)\ t = a + H(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 5, 4, T33); SET(d, a, b, c, 8, 11, T34); SET(c, d, a, b, 11, 16, T35); SET(b, c, d, a, 14, 23, T36); SET(a, b, c, d, 1, 4, T37); SET(d, a, b, c, 4, 11, T38); SET(c, d, a, b, 7, 16, T39); SET(b, c, d, a, 10, 23, T40); SET(a, b, c, d, 13, 4, T41); SET(d, a, b, c, 0, 11, T42); SET(c, d, a, b, 3, 16, T43); SET(b, c, d, a, 6, 23, T44); SET(a, b, c, d, 9, 4, T45); SET(d, a, b, c, 12, 11, T46); SET(c, d, a, b, 15, 16, T47); SET(b, c, d, a, 2, 23, T48); #undef SET /* Round 4. */ /* Let [abcd k s t] denote the operation a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ #define I(x, y, z) ((y) ^ ((x) | ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + I(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 6, T49); SET(d, a, b, c, 7, 10, T50); SET(c, d, a, b, 14, 15, T51); SET(b, c, d, a, 5, 21, T52); SET(a, b, c, d, 12, 6, T53); SET(d, a, b, c, 3, 10, T54); SET(c, d, a, b, 10, 15, T55); SET(b, c, d, a, 1, 21, T56); SET(a, b, c, d, 8, 6, T57); SET(d, a, b, c, 15, 10, T58); SET(c, d, a, b, 6, 15, T59); SET(b, c, d, a, 13, 21, T60); SET(a, b, c, d, 4, 6, T61); SET(d, a, b, c, 11, 10, T62); SET(c, d, a, b, 2, 15, T63); SET(b, c, d, a, 9, 21, T64); #undef SET /* Then perform the following additions. (That is increment each of the four registers by the value it had before this block was started.) */ pms->abcd[0] += a; pms->abcd[1] += b; pms->abcd[2] += c; pms->abcd[3] += d; } void md5_init(md5_state_t *pms) { pms->count[0] = pms->count[1] = 0; pms->abcd[0] = 0x67452301; pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; pms->abcd[3] = 0x10325476; } void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) { const md5_byte_t *p = data; int left = nbytes; int offset = (pms->count[0] >> 3) & 63; md5_word_t nbits = (md5_word_t)(nbytes << 3); if (nbytes <= 0) return; /* Update the message length. */ pms->count[1] += nbytes >> 29; pms->count[0] += nbits; if (pms->count[0] < nbits) pms->count[1]++; /* Process an initial partial block. */ if (offset) { int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); memcpy(pms->buf + offset, p, copy); if (offset + copy < 64) return; p += copy; left -= copy; md5_process(pms, pms->buf); } /* Process full blocks. */ for (; left >= 64; p += 64, left -= 64) md5_process(pms, p); /* Process a final partial block. */ if (left) memcpy(pms->buf, p, left); } void md5_finish(md5_state_t *pms, md5_byte_t digest[16]) { static const md5_byte_t pad[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; md5_byte_t data[8]; int i; /* Save the length before padding. */ for (i = 0; i < 8; ++i) data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); /* Pad to 56 bytes mod 64. */ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); /* Append the length. */ md5_append(pms, data, 8); for (i = 0; i < 16; ++i) digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); } mactelnet-0.4.2/config/0000774000175100017630000000000012622313406013401 5ustar haakoncymactelnet-0.4.2/config/mactelnetd.init0000664000175100017630000000063512622313406016413 0ustar haakoncy# mactelnetd - MAC-Telnet server # # The MAC-Telnet server provides telnet access via MAC addresses. # # Ubuntu upstart config: description "MAC-Telnet server" start on filesystem stop on runlevel [!2345] respawn respawn limit 10 5 umask 022 pre-start script test -O /etc/mactelnetd.users || { stop; exit 0; } test -x /usr/sbin/mactelnetd || { stop; exit 0; } end script exec /usr/sbin/mactelnetd -f mactelnet-0.4.2/config/mactelnetd.users0000664000175100017630000000070612622313406016610 0ustar haakoncy# Users file for MAC-Telnetd # #################################################################### # WARNING: This file has passwords written in plain-text. # # Make sure this file is owned and only readable by root. # #################################################################### # # Each line consists of a username and a password seperated by :. # Usernames must be existing users from passwd. # # Format: #username:password mactelnet-0.4.2/protocol.h0000664000175100017630000001243612622313406014155 0ustar haakoncy/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _MACTELNET_H #define _MACTELNET_H 1 #define MT_HEADER_LEN 22 #define MT_CPHEADER_LEN 9 #define MT_PACKET_LEN 1500 #define MT_MACTELNET_PORT 20561 #define MT_MNDP_PORT 5678 #define MT_MNDP_MAX_STRING_LENGTH 128 #define MT_MNDP_BROADCAST_INTERVAL 30 #define MT_MNDP_TIMEOUT 5 #define MT_MNDP_LONGTIMEOUT 120 #define MT_SOFTID_MACTELNET "MAC-Telnet" #ifndef ETH_ALEN #define ETH_ALEN 6 #endif #ifndef IPV4_ALEN #define IPV4_ALEN 4 #endif /* Packet type */ enum mt_ptype { MT_PTYPE_SESSIONSTART, MT_PTYPE_DATA, MT_PTYPE_ACK, MT_PTYPE_PING = 4, MT_PTYPE_PONG, MT_PTYPE_END = 255 }; /* Control packet type */ enum mt_cptype { MT_CPTYPE_BEGINAUTH, MT_CPTYPE_ENCRYPTIONKEY, MT_CPTYPE_PASSWORD, MT_CPTYPE_USERNAME, MT_CPTYPE_TERM_TYPE, MT_CPTYPE_TERM_WIDTH, MT_CPTYPE_TERM_HEIGHT, MT_CPTYPE_PACKET_ERROR, MT_CPTYPE_END_AUTH = 9, /* Internal CPTYPE, not part of protocol */ MT_CPTYPE_PLAINDATA = -1 }; /* MNDP attribute type */ enum mt_mndp_attrtype { MT_MNDPTYPE_ADDRESS = 0x0001, MT_MNDPTYPE_IDENTITY = 0x0005, MT_MNDPTYPE_VERSION = 0x0007, MT_MNDPTYPE_PLATFORM = 0x0008, MT_MNDPTYPE_TIMESTAMP = 0x000a, MT_MNDPTYPE_SOFTID = 0x000b, MT_MNDPTYPE_HARDWARE = 0x000c, MT_MNDPTYPE_IFNAME = 0x0010 }; /* MNDP packet header */ struct mt_mndp_hdr { unsigned char version; unsigned char ttl; unsigned short cksum; }; struct mt_mactelnet_hdr { unsigned char ver; enum mt_ptype ptype; unsigned char clienttype[2]; unsigned char srcaddr[6]; unsigned char dstaddr[6]; unsigned short seskey; unsigned int counter; unsigned char *data; }; struct mt_mactelnet_control_hdr { enum mt_cptype cptype; unsigned int length; unsigned char *data; }; /* TODO: Add all the other information obtainable from mndp */ struct mt_mndp_info { struct mt_mndp_hdr header; unsigned char address[ETH_ALEN]; char identity[MT_MNDP_MAX_STRING_LENGTH]; char version[MT_MNDP_MAX_STRING_LENGTH]; char platform[MT_MNDP_MAX_STRING_LENGTH]; char hardware[MT_MNDP_MAX_STRING_LENGTH]; char softid[MT_MNDP_MAX_STRING_LENGTH]; char ifname[MT_MNDP_MAX_STRING_LENGTH]; unsigned int uptime; }; struct mt_packet { int size; unsigned char data[MT_PACKET_LEN]; }; /* MacTelnet/Winbox packets */ extern int init_packet(struct mt_packet *packet, enum mt_ptype ptype, unsigned char *srcmac, unsigned char *dstmac, unsigned short sessionkey, unsigned int counter); extern int add_control_packet(struct mt_packet *packet, enum mt_cptype cptype, void *cpdata, int data_len); extern void parse_packet(unsigned char *data, struct mt_mactelnet_hdr *pkthdr); extern int parse_control_packet(unsigned char *data, int data_len, struct mt_mactelnet_control_hdr *cpkthdr); /* MAC-Ping packets */ int init_pingpacket(struct mt_packet *packet, unsigned char *srcmac, unsigned char *dstmac); int init_pongpacket(struct mt_packet *packet, unsigned char *srcmac, unsigned char *dstmac); int add_packetdata(struct mt_packet *packet, unsigned char *data, unsigned short length); /* MNDP packets */ extern int mndp_init_packet(struct mt_packet *packet, unsigned char version, unsigned char ttl); extern int mndp_add_attribute(struct mt_packet *packet, enum mt_mndp_attrtype attrtype, void *attrdata, unsigned short data_len); extern struct mt_mndp_info *parse_mndp(const unsigned char *data, const int packet_len); int query_mndp(const char *identity, unsigned char *mac); int query_mndp_or_mac(char *address, unsigned char *dstmac, int verbose); /* Number of milliseconds between each retransmission */ #define MAX_RETRANSMIT_INTERVALS 9 static const int retransmit_intervals[MAX_RETRANSMIT_INTERVALS] = { 15, 20, 30, 50, 90, 170, 330, 660, 1000 }; /* Control packet magic header */ static const unsigned char mt_mactelnet_cpmagic[4] = { 0x56, 0x34, 0x12, 0xff }; static const unsigned char mt_mactelnet_clienttype[2] = { 0x00, 0x15 }; /* Must be initialized by application */ extern unsigned char mt_direction_fromserver; /* Debugging stuff */ #if defined(DEBUG_PROTO) #ifndef hexdump_defined void hexdump(const char *title, const void *buf, int len) { int i; unsigned char *data = (unsigned char *)buf; fprintf(stderr, "%s:\n", title); for (i = 0; i < len; i++) { if (!(i & 0xf)) fprintf(stderr, "%04x:", i); fprintf(stderr, " %02x", data[i]); if (!(~i & 0xf) || i == len - 1) fprintf(stderr, "\n"); } } #define HEXDUMP(title, buf, len) hexdump(title, buf, len) #define hexdump_defined #else #define HEXDUMP(title, buf, len) #endif #endif #endif mactelnet-0.4.2/interfaces.c0000664000175100017630000002572012622313406014432 0ustar haakoncy/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #if defined(__FreeBSD__) #define __USE_BSD #define __FAVOR_BSD #endif #include #include #include #include #include #include #include #include #include #if defined(__FreeBSD__) #include #endif #include #include #if defined(__FreeBSD__) #include #define ETH_FRAME_LEN (ETHER_MAX_LEN - ETHER_CRC_LEN) #define ETH_ALEN ETHER_ADDR_LEN #else #include #endif #include #include #include #ifndef __linux__ #include #include #include #include #include #else #include #endif #include "protocol.h" #include "interfaces.h" #include "utlist.h" #define _(String) gettext (String) struct net_interface *net_get_interface_ptr(struct net_interface **interfaces, char *name, int create) { struct net_interface *interface; DL_FOREACH(*interfaces, interface) { if (strncmp(interface->name, name, 254) == 0) { return interface; } } if (create) { interface = (struct net_interface *)calloc(1, sizeof(struct net_interface)); if (interface == NULL) { fprintf(stderr, "Unable to allocate memory for interface\n"); exit(1); } strncpy(interface->name, name, 254); interface->name[254] = '\0'; DL_APPEND(*interfaces, interface); return interface; } return NULL; } #ifdef __linux__ static void net_update_mac(struct net_interface *interfaces) { unsigned char emptymac[] = {0, 0, 0, 0, 0, 0}; struct ifreq ifr; int tmpsock; struct net_interface *interface; tmpsock = socket(PF_INET, SOCK_DGRAM, 0); if (tmpsock < 0) { perror("net_update_mac"); exit(1); } DL_FOREACH(interfaces, interface) { /* Find interface hardware address from device_name */ strncpy(ifr.ifr_name, interface->name, 16); if (ioctl(tmpsock, SIOCGIFHWADDR, &ifr) == 0) { /* Fetch mac address */ memcpy(interface->mac_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); if (memcmp(interface->mac_addr, &emptymac, ETH_ALEN) != 0) { interface->has_mac = 1; } } } close(tmpsock); } static int get_device_index(char *device_name) { struct ifreq ifr; int tmpsock; tmpsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); /* Find interface index from device_name */ strncpy(ifr.ifr_name, device_name, 16); if (ioctl(tmpsock, SIOCGIFINDEX, &ifr) != 0) { return -1; } /* Return interface index */ return ifr.ifr_ifindex; } #endif int net_get_interfaces(struct net_interface **interfaces) { static struct ifaddrs *int_addrs; static const struct ifaddrs *ifaddrsp; const struct sockaddr_in *dl_addr; int found = 0; if (getifaddrs(&int_addrs) < 0) { perror("getifaddrs"); exit(1); } for (ifaddrsp = int_addrs; ifaddrsp; ifaddrsp = ifaddrsp->ifa_next) { dl_addr = (const struct sockaddr_in *) ifaddrsp->ifa_addr; if (ifaddrsp->ifa_addr == NULL) continue; if (ifaddrsp->ifa_addr->sa_family == AF_INET) { struct net_interface *interface = net_get_interface_ptr(interfaces, ifaddrsp->ifa_name, 1); if (interface != NULL) { found++; memcpy(interface->ipv4_addr, &dl_addr->sin_addr, IPV4_ALEN); } #ifdef __linux__ interface->ifindex = get_device_index(interface->name); #endif } #ifndef __linux__ { unsigned char emptymac[] = {0, 0, 0, 0, 0, 0}; struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifaddrsp->ifa_addr; if (sdl->sdl_alen == ETH_ALEN) { struct net_interface *interface = net_get_interface_ptr(interfaces, ifaddrsp->ifa_name, 1); memcpy(interface->mac_addr, LLADDR(sdl), ETH_ALEN); if (interface != NULL && memcmp(interface->mac_addr, &emptymac, ETH_ALEN) != 0) { interface->has_mac = 1; } } } #endif } freeifaddrs(int_addrs); #ifdef __linux__ net_update_mac(*interfaces); #endif #if 0 { struct net_interface *interface; DL_FOREACH(*interfaces, interface) { struct in_addr *addr = (struct in_addr *)interface->ipv4_addr; printf("Interface %s:\n", interface->name); printf("\tIP: %s\n", inet_ntoa(*addr)); printf("\tMAC: %s\n", ether_ntoa((struct ether_addr *)interface->mac_addr)); #ifdef __linux__ printf("\tIfIndex: %d\n", interface->ifindex); #endif printf("\n"); } } #endif return found; } unsigned short in_cksum(unsigned short *addr, int len) { int nleft = len; int sum = 0; unsigned short *w = addr; unsigned short answer = 0; while (nleft > 1) { sum += *w++; nleft -= 2; } if (nleft == 1) { *(unsigned char *) (&answer) = *(unsigned char *) w; sum += answer; } sum = (sum >> 16) + (sum & 0xFFFF); sum += (sum >> 16); answer = ~sum; return (answer); } unsigned short udp_sum_calc(unsigned char *src_addr,unsigned char *dst_addr, unsigned char *data, unsigned short len) { unsigned short prot_udp=17; unsigned short padd=0; unsigned short word16; unsigned int sum = 0; int i; /* Padding ? */ padd = (len % 2); if (padd) { data[len] = 0; } /* header+data */ for (i = 0; i < len + padd; i += 2){ word16 = ((data[i] << 8) & 0xFF00) + (data[i + 1] & 0xFF); sum += word16; } /* source ip */ for (i = 0; i < IPV4_ALEN; i += 2){ word16 = ((src_addr[i] << 8) & 0xFF00) + (src_addr[i + 1] & 0xFF); sum += word16; } /* dest ip */ for (i = 0; i < IPV4_ALEN; i += 2){ word16 = ((dst_addr[i] << 8) & 0xFF00) + (dst_addr[i + 1] & 0xFF); sum += word16; } sum += prot_udp + len; while (sum>>16) sum = (sum & 0xFFFF) + (sum >> 16); sum = ~sum; if (sum == 0) sum = 0xFFFF; return (unsigned short) sum; } int net_init_raw_socket() { int fd; #ifdef __linux__ /* Transmit raw packets with this socket */ fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (fd < 0) { perror("raw_socket"); exit(1); } #else /* Transmit raw packets with bpf */ fd = open("/dev/bpf0", O_RDWR); if (fd <= 0) { perror("open_bpf"); exit(1); } #endif return fd; } int net_send_udp(const int fd, struct net_interface *interface, const unsigned char *sourcemac, const unsigned char *destmac, const struct in_addr *sourceip, const int sourceport, const struct in_addr *destip, const int destport, const unsigned char *data, const int datalen) { #ifdef __linux__ struct sockaddr_ll socket_address; #endif /* * Create a buffer for the full ethernet frame * and align header pointers to the correct positions. */ static unsigned char stackbuf[ETH_FRAME_LEN]; void* buffer = (void*)&stackbuf; #if defined(__FreeBSD__) struct ether_header *eh = (struct ether_header *)buffer; struct ip *ip = (struct ip *)(buffer + 14); #else struct ethhdr *eh = (struct ethhdr *)buffer; struct iphdr *ip = (struct iphdr *)(buffer + 14); #endif struct udphdr *udp = (struct udphdr *)(buffer + 14 + 20); unsigned char *rest = (unsigned char *)(buffer + 20 + 14 + sizeof(struct udphdr)); if (((void *)rest - (void*)buffer) + datalen > ETH_FRAME_LEN) { fprintf(stderr, _("packet size too large\n")); return 0; } static unsigned int id = 1; int send_result = 0; /* Abort if we couldn't allocate enough memory */ if (buffer == NULL) { perror("malloc"); exit(1); } /* Init ethernet header */ #if defined(__FreeBSD__) memcpy(eh->ether_shost, sourcemac, ETH_ALEN); memcpy(eh->ether_dhost, destmac, ETH_ALEN); eh->ether_type = htons(ETHERTYPE_IP); #else memcpy(eh->h_source, sourcemac, ETH_ALEN); memcpy(eh->h_dest, destmac, ETH_ALEN); eh->h_proto = htons(ETH_P_IP); #endif #ifdef __linux__ /* Init SendTo struct */ socket_address.sll_family = AF_PACKET; socket_address.sll_protocol = htons(ETH_P_IP); socket_address.sll_ifindex = interface->ifindex; socket_address.sll_hatype = ARPHRD_ETHER; socket_address.sll_pkttype = PACKET_OTHERHOST; socket_address.sll_halen = ETH_ALEN; memcpy(socket_address.sll_addr, eh->h_source, ETH_ALEN); socket_address.sll_addr[6] = 0x00;/*not used*/ socket_address.sll_addr[7] = 0x00;/*not used*/ #endif /* Init IP Header */ #if defined(__FreeBSD__) ip->ip_v = 4; ip->ip_hl = 5; ip->ip_tos = 0x10; ip->ip_len = htons(datalen + 8 + 20); ip->ip_id = htons(id++); ip->ip_off = htons(0x4000); ip->ip_ttl = 64; ip->ip_p = 17; /* UDP */ ip->ip_sum = 0; ip->ip_src.s_addr = sourceip->s_addr; ip->ip_dst.s_addr = destip->s_addr; #else ip->version = 4; ip->ihl = 5; ip->tos = 0x10; ip->tot_len = htons(datalen + 8 + 20); ip->id = htons(id++); ip->frag_off = htons(0x4000); ip->ttl = 64; ip->protocol = 17; /* UDP */ ip->check = 0x0000; ip->saddr = sourceip->s_addr; ip->daddr = destip->s_addr; #endif /* Calculate checksum for IP header */ #if defined(__FreeBSD__) ip->ip_sum = in_cksum((unsigned short *)ip, sizeof(struct ip)); #else ip->check = in_cksum((unsigned short *)ip, sizeof(struct iphdr)); #endif /* Init UDP Header */ #if defined(__FreeBSD__) udp->uh_sport = htons(sourceport); udp->uh_dport = htons(destport); udp->uh_ulen = htons(sizeof(struct udphdr) + datalen); udp->uh_sum = 0; #else udp->source = htons(sourceport); udp->dest = htons(destport); udp->len = htons(sizeof(struct udphdr) + datalen); udp->check = 0; #endif /* Insert actual data */ memcpy(rest, data, datalen); /* Add UDP checksum */ #if defined(__FreeBSD__) udp->uh_sum = udp_sum_calc((unsigned char *)&(ip->ip_src.s_addr), (unsigned char *)&(ip->ip_dst.s_addr), (unsigned char *)udp, sizeof(struct udphdr) + datalen); udp->uh_sum = htons(udp->uh_sum); #else udp->check = udp_sum_calc((unsigned char *)&(ip->saddr), (unsigned char *)&(ip->daddr), (unsigned char *)udp, sizeof(struct udphdr) + datalen); udp->check = htons(udp->check); #endif #ifdef __linux__ /* Send the packet */ send_result = sendto(fd, buffer, datalen + 8 + 14 + 20, 0, (struct sockaddr*)&socket_address, sizeof(socket_address)); if (send_result == -1) perror("sendto"); #else { struct ifreq req_if; /* Pick device to send through */ strcpy(req_if.ifr_name, interface->name); if (ioctl(fd, BIOCSETIF, &req_if) > 0) { perror("ioctl_BIOCSETIF"); exit(1); } } send_result = write(fd, buffer, datalen + 8 + 14 + 20); if (send_result == -1) perror("bpf_write"); #endif /* Return amount of _data_ bytes sent */ if (send_result - 8 - 14 - 20 < 0) { return 0; } return send_result - 8 - 14 - 20; } mactelnet-0.4.2/mactelnet.c0000664000175100017630000005067212622313406014267 0ustar haakoncy/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define _BSD_SOURCE #include #include #include #include #include #include #include #include #include #if defined(__FreeBSD__) #include #include #include #else #include #include #endif #include #include #include #include #include #include #include #ifdef __linux__ #include #include #endif #include "md5.h" #include "protocol.h" #include "console.h" #include "interfaces.h" #include "config.h" #include "mactelnet.h" #include "mndp.h" #include "autologin.h" #include "utlist.h" #define PROGRAM_NAME "MAC-Telnet" #define _(String) gettext (String) static int sockfd = 0; static int insockfd; static unsigned int outcounter = 0; static long incounter = -1; static int sessionkey = 0; static int running = 1; static unsigned char use_raw_socket = 0; static unsigned char terminal_mode = 0; static unsigned char srcmac[ETH_ALEN]; static unsigned char dstmac[ETH_ALEN]; static struct in_addr sourceip; static struct in_addr destip; static int sourceport; static int connect_timeout = CONNECT_TIMEOUT; static char run_mndp = 0; static int mndp_timeout = 0; static int is_a_tty = 1; static int quiet_mode = 0; static int batch_mode = 0; static int no_autologin = 0; static char autologin_path[255]; static int keepalive_counter = 0; static unsigned char encryptionkey[128]; static char username[255]; static char password[255]; static char nonpriv_username[255]; struct net_interface *interfaces=NULL; struct net_interface *active_interface; /* Protocol data direction */ unsigned char mt_direction_fromserver = 0; static unsigned int send_socket; static int handle_packet(unsigned char *data, int data_len); static void print_version() { fprintf(stderr, PROGRAM_NAME " " PROGRAM_VERSION "\n"); } void drop_privileges(char *username) { struct passwd *user = (struct passwd *) getpwnam(username); if (user == NULL) { fprintf(stderr, _("Failed dropping privileges. The user %s is not a valid username on local system.\n"), username); exit(1); } if (getuid() == 0) { /* process is running as root, drop privileges */ if (setgid(user->pw_gid) != 0) { fprintf(stderr, _("setgid: Error dropping group privileges\n")); exit(1); } if (setuid(user->pw_uid) != 0) { fprintf(stderr, _("setuid: Error dropping user privileges\n")); exit(1); } /* Verify if the privileges were developed. */ if (setuid(0) != -1) { fprintf(stderr, _("Failed to drop privileges\n")); exit(1); } } } static int send_udp(struct mt_packet *packet, int retransmit) { int sent_bytes; /* Clear keepalive counter */ keepalive_counter = 0; if (!use_raw_socket) { /* Init SendTo struct */ struct sockaddr_in socket_address; socket_address.sin_family = AF_INET; socket_address.sin_port = htons(MT_MACTELNET_PORT); socket_address.sin_addr.s_addr = htonl(INADDR_BROADCAST); sent_bytes = sendto(send_socket, packet->data, packet->size, 0, (struct sockaddr*)&socket_address, sizeof(socket_address)); } else { sent_bytes = net_send_udp(sockfd, active_interface, srcmac, dstmac, &sourceip, sourceport, &destip, MT_MACTELNET_PORT, packet->data, packet->size); } /* * Retransmit packet if no data is received within * retransmit_intervals milliseconds. */ if (retransmit) { int i; for (i = 0; i < MAX_RETRANSMIT_INTERVALS; ++i) { fd_set read_fds; int reads; struct timeval timeout; int interval = retransmit_intervals[i] * 1000; /* Init select */ FD_ZERO(&read_fds); FD_SET(insockfd, &read_fds); timeout.tv_sec = 0; timeout.tv_usec = interval; /* Wait for data or timeout */ reads = select(insockfd + 1, &read_fds, NULL, NULL, &timeout); if (reads && FD_ISSET(insockfd, &read_fds)) { unsigned char buff[1500]; int result; bzero(buff, 1500); result = recvfrom(insockfd, buff, 1500, 0, 0, 0); /* Handle incoming packets, waiting for an ack */ if (result > 0 && handle_packet(buff, result) == MT_PTYPE_ACK) { return sent_bytes; } } /* Retransmit */ send_udp(packet, 0); } if (is_a_tty && terminal_mode) { reset_term(); } fprintf(stderr, _("\nConnection timed out\n")); exit(1); } return sent_bytes; } static void send_auth(char *username, char *password) { struct mt_packet data; unsigned short width = 0; unsigned short height = 0; char *terminal = getenv("TERM"); char md5data[100]; unsigned char md5sum[17]; int plen; md5_state_t state; #if defined(__linux__) && defined(_POSIX_MEMLOCK_RANGE) mlock(md5data, sizeof(md5data)); mlock(md5sum, sizeof(md5data)); #endif /* Concat string of 0 + password + encryptionkey */ md5data[0] = 0; strncpy(md5data + 1, password, 82); md5data[83] = '\0'; memcpy(md5data + 1 + strlen(password), encryptionkey, 16); /* Generate md5 sum of md5data with a leading 0 */ md5_init(&state); md5_append(&state, (const md5_byte_t *)md5data, strlen(password) + 17); md5_finish(&state, (md5_byte_t *)md5sum + 1); md5sum[0] = 0; /* Send combined packet to server */ init_packet(&data, MT_PTYPE_DATA, srcmac, dstmac, sessionkey, outcounter); plen = add_control_packet(&data, MT_CPTYPE_PASSWORD, md5sum, 17); plen += add_control_packet(&data, MT_CPTYPE_USERNAME, username, strlen(username)); plen += add_control_packet(&data, MT_CPTYPE_TERM_TYPE, terminal, strlen(terminal)); if (is_a_tty && get_terminal_size(&width, &height) != -1) { width = htole16(width); height = htole16(height); plen += add_control_packet(&data, MT_CPTYPE_TERM_WIDTH, &width, 2); plen += add_control_packet(&data, MT_CPTYPE_TERM_HEIGHT, &height, 2); } outcounter += plen; /* TODO: handle result */ send_udp(&data, 1); } static void sig_winch(int sig) { unsigned short width,height; struct mt_packet data; int plen; /* terminal height/width has changed, inform server */ if (get_terminal_size(&width, &height) != -1) { init_packet(&data, MT_PTYPE_DATA, srcmac, dstmac, sessionkey, outcounter); width = htole16(width); height = htole16(height); plen = add_control_packet(&data, MT_CPTYPE_TERM_WIDTH, &width, 2); plen += add_control_packet(&data, MT_CPTYPE_TERM_HEIGHT, &height, 2); outcounter += plen; send_udp(&data, 1); } /* reinstate signal handler */ signal(SIGWINCH, sig_winch); } static int handle_packet(unsigned char *data, int data_len) { struct mt_mactelnet_hdr pkthdr; parse_packet(data, &pkthdr); /* We only care about packets with correct sessionkey */ if (pkthdr.seskey != sessionkey) { return -1; } /* Handle data packets */ if (pkthdr.ptype == MT_PTYPE_DATA) { struct mt_packet odata; struct mt_mactelnet_control_hdr cpkt; int success = 0; /* Always transmit ACKNOWLEDGE packets in response to DATA packets */ init_packet(&odata, MT_PTYPE_ACK, srcmac, dstmac, sessionkey, pkthdr.counter + (data_len - MT_HEADER_LEN)); send_udp(&odata, 0); /* Accept first packet, and all packets greater than incounter, and if counter has wrapped around. */ if (pkthdr.counter > incounter || (incounter - pkthdr.counter) > 65535) { incounter = pkthdr.counter; } else { /* Ignore double or old packets */ return -1; } /* Parse controlpacket data */ success = parse_control_packet(data + MT_HEADER_LEN, data_len - MT_HEADER_LEN, &cpkt); while (success) { /* If we receive encryptionkey, transmit auth data back */ if (cpkt.cptype == MT_CPTYPE_ENCRYPTIONKEY) { memcpy(encryptionkey, cpkt.data, cpkt.length); send_auth(username, password); } /* If the (remaining) data did not have a control-packet magic byte sequence, the data is raw terminal data to be outputted to the terminal. */ else if (cpkt.cptype == MT_CPTYPE_PLAINDATA) { cpkt.data[cpkt.length] = 0; fputs((const char *)cpkt.data, stdout); } /* END_AUTH means that the user/password negotiation is done, and after this point terminal data may arrive, so we set up the terminal to raw mode. */ else if (cpkt.cptype == MT_CPTYPE_END_AUTH) { /* we have entered "terminal mode" */ terminal_mode = 1; if (is_a_tty) { /* stop input buffering at all levels. Give full control of terminal to RouterOS */ raw_term(); setvbuf(stdin, (char*)NULL, _IONBF, 0); /* Add resize signal handler */ signal(SIGWINCH, sig_winch); } } /* Parse next controlpacket */ success = parse_control_packet(NULL, 0, &cpkt); } } else if (pkthdr.ptype == MT_PTYPE_ACK) { /* Handled elsewhere */ } /* The server wants to terminate the connection, we have to oblige */ else if (pkthdr.ptype == MT_PTYPE_END) { struct mt_packet odata; /* Acknowledge the disconnection by sending a END packet in return */ init_packet(&odata, MT_PTYPE_END, srcmac, dstmac, pkthdr.seskey, 0); send_udp(&odata, 0); if (!quiet_mode) { fprintf(stderr, _("Connection closed.\n")); } /* exit */ running = 0; } else { fprintf(stderr, _("Unhandeled packet type: %d received from server %s\n"), pkthdr.ptype, ether_ntoa((struct ether_addr *)dstmac)); return -1; } return pkthdr.ptype; } static int find_interface() { fd_set read_fds; struct mt_packet data; struct sockaddr_in myip; unsigned char emptymac[ETH_ALEN]; int testsocket; struct timeval timeout; int optval = 1; struct net_interface *interface; /* TODO: reread interfaces on HUP */ //bzero(&interfaces, sizeof(struct net_interface) * MAX_INTERFACES); bzero(emptymac, ETH_ALEN); if (net_get_interfaces(&interfaces) <= 0) { fprintf(stderr, _("Error: No suitable devices found\n")); exit(1); } DL_FOREACH(interfaces, interface) { /* Skip loopback interfaces */ if (memcmp("lo", interface->name, 2) == 0) { continue; } /* Initialize receiving socket on the device chosen */ myip.sin_family = AF_INET; memcpy((void *)&myip.sin_addr, interface->ipv4_addr, IPV4_ALEN); myip.sin_port = htons(sourceport); /* Initialize socket and bind to udp port */ if ((testsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { continue; } setsockopt(testsocket, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)); setsockopt(testsocket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); if (bind(testsocket, (struct sockaddr *)&myip, sizeof(struct sockaddr_in)) == -1) { close(testsocket); continue; } /* Ensure that we have mac-address for this interface */ if (!interface->has_mac) { close(testsocket); continue; } /* Set the global socket handle and source mac address for send_udp() */ send_socket = testsocket; memcpy(srcmac, interface->mac_addr, ETH_ALEN); active_interface = interface; /* Send a SESSIONSTART message with the current device */ init_packet(&data, MT_PTYPE_SESSIONSTART, srcmac, dstmac, sessionkey, 0); send_udp(&data, 0); timeout.tv_sec = connect_timeout; timeout.tv_usec = 0; FD_ZERO(&read_fds); FD_SET(insockfd, &read_fds); select(insockfd + 1, &read_fds, NULL, NULL, &timeout); if (FD_ISSET(insockfd, &read_fds)) { /* We got a response, this is the correct device to use */ return 1; } close(testsocket); } return 0; } /* * TODO: Rewrite main() when all sub-functionality is tested */ int main (int argc, char **argv) { int result; struct mt_packet data; struct sockaddr_in si_me; struct autologin_profile *login_profile; struct net_interface *interface, *tmp; unsigned char buff[1500]; unsigned char print_help = 0, have_username = 0, have_password = 0; unsigned char drop_priv = 0; int c; int optval = 1; strncpy(autologin_path, AUTOLOGIN_PATH, 254); setlocale(LC_ALL, ""); bindtextdomain("mactelnet","/usr/share/locale"); textdomain("mactelnet"); while (1) { c = getopt(argc, argv, "lnqt:u:p:U:vh?BAa:"); if (c == -1) { break; } switch (c) { case 'n': use_raw_socket = 1; break; case 'u': /* Save username */ strncpy(username, optarg, sizeof(username) - 1); username[sizeof(username) - 1] = '\0'; have_username = 1; break; case 'p': /* Save password */ #if defined(__linux__) && defined(_POSIX_MEMLOCK_RANGE) mlock(password, sizeof(password)); #endif strncpy(password, optarg, sizeof(password) - 1); password[sizeof(password) - 1] = '\0'; have_password = 1; break; case 'U': /* Save nonpriv_username */ strncpy(nonpriv_username, optarg, sizeof(nonpriv_username) - 1); nonpriv_username[sizeof(nonpriv_username) - 1] = '\0'; drop_priv = 1; break; case 't': connect_timeout = atoi(optarg); mndp_timeout = connect_timeout; break; case 'v': print_version(); exit(0); break; case 'q': quiet_mode = 1; break; case 'l': run_mndp = 1; break; case 'B': batch_mode = 1; break; case 'A': no_autologin = 1; break; case 'a': strncpy(autologin_path, optarg, 254); break; case 'h': case '?': print_help = 1; break; } } if (run_mndp) { return mndp(mndp_timeout, batch_mode); } if (argc - optind < 1 || print_help) { print_version(); fprintf(stderr, _("Usage: %s [-h] [-n] [-a ] [-A] [-t ] [-u ] [-p ] [-U ] | -l [-B] [-t ]\n"), argv[0]); if (print_help) { fprintf(stderr, _("\nParameters:\n" " MAC MAC-Address of the RouterOS/mactelnetd device. Use mndp to\n" " discover it.\n" " identity The identity/name of your destination device. Uses\n" " MNDP protocol to find it.\n" " -l List/Search for routers nearby (MNDP). You may use -t to set timeout.\n" " -B Batch mode. Use computer readable output (CSV), for use with -l.\n" " -n Do not use broadcast packets. Less insecure but requires\n" " root privileges.\n" " -a Use specified path instead of the default: " AUTOLOGIN_PATH " for autologin config file.\n" " -A Disable autologin feature.\n" " -t Amount of seconds to wait for a response on each interface.\n" " -u Specify username on command line.\n" " -p Specify password on command line.\n" " -U Drop privileges to this user. Used in conjunction with -n\n" " for security.\n" " -q Quiet mode.\n" " -h This help.\n" "\n")); } return 1; } is_a_tty = isatty(fileno(stdout)) && isatty(fileno(stdin)); if (!is_a_tty) { quiet_mode = 1; } if (!no_autologin) { autologin_readfile(autologin_path); login_profile = autologin_find_profile(argv[optind]); if (!quiet_mode && login_profile != NULL && (login_profile->hasUsername || login_profile->hasPassword)) { fprintf(stderr, _("Using autologin credentials from %s\n"), autologin_path); } if (!have_username) { if (login_profile != NULL && login_profile->hasUsername) { have_username = 1; strncpy(username, login_profile->username, sizeof(username) - 1); username[sizeof(username) - 1] = '\0'; } } if (!have_password) { if (login_profile != NULL && login_profile->hasPassword) { have_password = 1; strncpy(password, login_profile->password, sizeof(password) - 1); password[sizeof(password) - 1] = '\0'; } } } /* Seed randomizer */ srand(time(NULL)); if (use_raw_socket) { if (geteuid() != 0) { fprintf(stderr, _("You need to have root privileges to use the -n parameter.\n")); return 1; } sockfd = net_init_raw_socket(); if (drop_priv) { drop_privileges(nonpriv_username); } } else if (drop_priv) { fprintf(stderr, _("The -U option must be used in conjunction with the -n parameter.\n")); return 1; } /* Receive regular udp packets with this socket */ insockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (insockfd < 0) { perror("insockfd"); return 1; } if (!use_raw_socket) { if (setsockopt(insockfd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof (optval))==-1) { perror("SO_BROADCAST"); return 1; } } /* Need to use, to be able to autodetect which interface to use */ setsockopt(insockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (optval)); /* Get mac-address from string, or check for hostname via mndp */ if (!query_mndp_or_mac(argv[optind], dstmac, !quiet_mode)) { /* No valid mac address found, abort */ return 1; } if (!have_username) { if (!quiet_mode) { printf(_("Login: ")); fflush(stdout); } scanf("%254s", username); } if (!have_password) { char *tmp; tmp = getpass(quiet_mode ? "" : _("Password: ")); #if defined(__linux__) && defined(_POSIX_MEMLOCK_RANGE) mlock(password, sizeof(password)); #endif strncpy(password, tmp, sizeof(password) - 1); password[sizeof(password) - 1] = '\0'; /* security */ memset(tmp, 0, strlen(tmp)); #ifdef __linux__ free(tmp); #endif } /* Set random source port */ sourceport = 1024 + (rand() % 1024); /* Set up global info about the connection */ inet_pton(AF_INET, (char *)"255.255.255.255", &destip); memcpy(&sourceip, &(si_me.sin_addr), IPV4_ALEN); /* Session key */ sessionkey = rand() % 65535; /* stop output buffering */ setvbuf(stdout, (char*)NULL, _IONBF, 0); if (!quiet_mode) { printf(_("Connecting to %s..."), ether_ntoa((struct ether_addr *)dstmac)); } /* Initialize receiving socket on the device chosen */ memset((char *) &si_me, 0, sizeof(si_me)); si_me.sin_family = AF_INET; si_me.sin_port = htons(sourceport); /* Bind to udp port */ if (bind(insockfd, (struct sockaddr *)&si_me, sizeof(si_me)) == -1) { fprintf(stderr, _("Error binding to %s:%d, %s\n"), inet_ntoa(si_me.sin_addr), sourceport, strerror(errno)); return 1; } if (!find_interface() || (result = recvfrom(insockfd, buff, 1400, 0, 0, 0)) < 1) { fprintf(stderr, _("Connection failed.\n")); return 1; } if (!quiet_mode) { printf(_("done\n")); } /* Handle first received packet */ handle_packet(buff, result); init_packet(&data, MT_PTYPE_DATA, srcmac, dstmac, sessionkey, 0); outcounter += add_control_packet(&data, MT_CPTYPE_BEGINAUTH, NULL, 0); /* TODO: handle result of send_udp */ result = send_udp(&data, 1); while (running) { fd_set read_fds; int reads; static int terminal_gone = 0; struct timeval timeout; /* Init select */ FD_ZERO(&read_fds); if (!terminal_gone) { FD_SET(0, &read_fds); } FD_SET(insockfd, &read_fds); timeout.tv_sec = 1; timeout.tv_usec = 0; /* Wait for data or timeout */ reads = select(insockfd+1, &read_fds, NULL, NULL, &timeout); if (reads > 0) { /* Handle data from server */ if (FD_ISSET(insockfd, &read_fds)) { bzero(buff, 1500); result = recvfrom(insockfd, buff, 1500, 0, 0, 0); handle_packet(buff, result); } /* Handle data from keyboard/local terminal */ if (FD_ISSET(0, &read_fds) && terminal_mode) { unsigned char keydata[512]; int datalen; datalen = read(STDIN_FILENO, &keydata, 512); if (datalen > 0) { /* Data received, transmit to server */ init_packet(&data, MT_PTYPE_DATA, srcmac, dstmac, sessionkey, outcounter); add_control_packet(&data, MT_CPTYPE_PLAINDATA, &keydata, datalen); outcounter += datalen; send_udp(&data, 1); } else { terminal_gone = 1; } } /* Handle select() timeout */ } else { /* handle keepalive counter, transmit keepalive packet every 10 seconds of inactivity */ if (keepalive_counter++ == 10) { struct mt_packet odata; init_packet(&odata, MT_PTYPE_ACK, srcmac, dstmac, sessionkey, outcounter); send_udp(&odata, 0); } } } if (is_a_tty && terminal_mode) { /* Reset terminal back to old settings */ reset_term(); } close(sockfd); close(insockfd); DL_FOREACH_SAFE(interfaces, interface, tmp) { DL_DELETE(interfaces, interface); free(interface); } return 0; } mactelnet-0.4.2/protocol.c0000664000175100017630000003401712622313406014147 0ustar haakoncy/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define _BSD_SOURCE #include #include #include #include #include #include #ifdef __LINUX__ #include #endif #include #include #if defined(__FreeBSD__) #include #include #include #else #include #endif #include #if defined(__FreeBSD__) #include #else #include #endif #include "protocol.h" #include "config.h" #define _(String) gettext (String) int init_packet(struct mt_packet *packet, enum mt_ptype ptype, unsigned char *srcmac, unsigned char *dstmac, unsigned short sessionkey, unsigned int counter) { unsigned char *data = packet->data; /* Packet version */ data[0] = 1; /* Packet type */ data[1] = ptype; /* src ethernet address */ memcpy(data + 2, srcmac, ETH_ALEN); /* dst ethernet address */ memcpy(data + 8, dstmac, ETH_ALEN); if (mt_direction_fromserver) { /* Session key */ sessionkey = htons(sessionkey); memcpy(data + 16, &sessionkey, sizeof(sessionkey)); /* Client type: Mac Telnet */ memcpy(data + 14, &mt_mactelnet_clienttype, sizeof(mt_mactelnet_clienttype)); } else { /* Session key */ sessionkey = htons(sessionkey); memcpy(data + 14, &sessionkey, sizeof(sessionkey)); /* Client type: Mac Telnet */ memcpy(data + 16, &mt_mactelnet_clienttype, sizeof(mt_mactelnet_clienttype)); } /* Received/sent data counter */ counter = htonl(counter); memcpy(data + 18, &counter, sizeof(counter)); /* 22 bytes header */ packet->size = 22; return 22; } int add_control_packet(struct mt_packet *packet, enum mt_cptype cptype, void *cpdata, int data_len) { unsigned char *data = packet->data + packet->size; /* Something is really wrong. Packets should never become over 1500 bytes */ if (packet->size + MT_CPHEADER_LEN + data_len > MT_PACKET_LEN) { fprintf(stderr, _("add_control_packet: ERROR, too large packet. Exceeds %d bytes\n"), MT_PACKET_LEN); return -1; //exit(1); } /* PLAINDATA isn't really a controlpacket, but we handle it here, since parseControlPacket also parses raw data as PLAINDATA */ if (cptype == MT_CPTYPE_PLAINDATA) { memcpy(data, cpdata, data_len); packet->size += data_len; return data_len; } /* Control Packet Magic id */ memcpy(data, mt_mactelnet_cpmagic, sizeof(mt_mactelnet_cpmagic)); /* Control packet type */ data[4] = cptype; /* Data length */ #if BYTE_ORDER == LITTLE_ENDIAN { unsigned int templen; templen = htonl(data_len); memcpy(data + 5, &templen, sizeof(templen)); } #else memcpy(data + 5, &data_len, sizeof(data_len)); #endif /* Insert data */ if (data_len > 0) { memcpy(data + MT_CPHEADER_LEN, cpdata, data_len); } packet->size += MT_CPHEADER_LEN + data_len; /* Control packet header length + data length */ return MT_CPHEADER_LEN + data_len; } int init_pingpacket(struct mt_packet *packet, unsigned char *srcmac, unsigned char *dstmac) { init_packet(packet, MT_PTYPE_PING, srcmac, dstmac, 0, 0); /* Zero out sessionkey & counter */ bzero(packet->data + 14, 4); /* Remove data counter field from header */ packet->size -= 4; return packet->size; } int init_pongpacket(struct mt_packet *packet, unsigned char *srcmac, unsigned char *dstmac) { init_packet(packet, MT_PTYPE_PONG, srcmac, dstmac, 0, 0); /* Zero out sessionkey & counter */ bzero(packet->data + 14, 4); /* Remove data counter field from header */ packet->size -= 4; return packet->size; } int add_packetdata(struct mt_packet *packet, unsigned char *data, unsigned short length) { if (packet->size + length > MT_PACKET_LEN) { fprintf(stderr, _("add_control_packet: ERROR, too large packet. Exceeds %d bytes\n"), MT_PACKET_LEN); return -1; } memcpy(packet->data + packet->size, data, length); packet->size += length; return length; } void parse_packet(unsigned char *data, struct mt_mactelnet_hdr *pkthdr) { /* Packet version */ pkthdr->ver = data[0]; /* Packet type */ pkthdr->ptype = data[1]; /* src ethernet addr */ memcpy(pkthdr->srcaddr, data + 2, ETH_ALEN); /* dst ethernet addr */ memcpy(pkthdr->dstaddr, data + 8, ETH_ALEN); if (mt_direction_fromserver) { /* Session key */ memcpy(&(pkthdr->seskey), data + 14, sizeof(pkthdr->seskey)); pkthdr->seskey = ntohs(pkthdr->seskey); /* server type */ memcpy(&(pkthdr->clienttype), data + 16, 2); } else { /* server type */ memcpy(&(pkthdr->clienttype), data + 14, 2); /* Session key */ memcpy(&(pkthdr->seskey), data + 16, sizeof(pkthdr->seskey)); pkthdr->seskey = ntohs(pkthdr->seskey); } /* Received/sent data counter */ memcpy(&(pkthdr->counter), data + 18, sizeof(pkthdr->counter)); pkthdr->counter = ntohl(pkthdr->counter); /* Set pointer to actual data */ pkthdr->data = data + 22; } int parse_control_packet(unsigned char *packetdata, int data_len, struct mt_mactelnet_control_hdr *cpkthdr) { static unsigned char *int_data; static unsigned int int_data_len; static unsigned int int_pos; unsigned char *data; /* Store info so we can call this function once with data, and then several times for each control packets. Letting this function control the data position. */ if (packetdata != NULL) { if (data_len <= 0) { return 0; } int_data = packetdata; int_data_len = data_len; int_pos = 0; } /* No more data to parse? */ if (int_pos >= int_data_len) { return 0; } /* Set current position in data buffer */ data = int_data + int_pos; /* Check for valid minimum packet length & magic header */ if (int_data_len >= 9 && memcmp(data, &mt_mactelnet_cpmagic, 4) == 0) { /* Control packet type */ cpkthdr->cptype = data[4]; /* Control packet data length */ memcpy(&(cpkthdr->length), data + 5, sizeof(cpkthdr->length)); cpkthdr->length = ntohl(cpkthdr->length); /* We want no buffer overflows */ if (cpkthdr->length >= MT_PACKET_LEN - 22 - int_pos) { cpkthdr->length = MT_PACKET_LEN - 1 - 22 - int_pos; } /* Set pointer to actual data */ cpkthdr->data = data + 9; /* Remember old position, for next call */ int_pos += cpkthdr->length + 9; /* Read data successfully */ return 1; } else { /* Mark data as raw terminal data */ cpkthdr->cptype = MT_CPTYPE_PLAINDATA; cpkthdr->length = int_data_len - int_pos; cpkthdr->data = data; /* Consume the whole rest of the packet */ int_pos = int_data_len; /* Read data successfully */ return 1; } } int mndp_init_packet(struct mt_packet *packet, unsigned char version, unsigned char ttl) { struct mt_mndp_hdr *header = (struct mt_mndp_hdr *)packet->data; header->version = version; header->ttl = ttl; header->cksum = 0; packet->size = sizeof(*header); return sizeof(*header); } int mndp_add_attribute(struct mt_packet *packet, enum mt_mndp_attrtype attrtype, void *attrdata, unsigned short data_len) { unsigned char *data = packet->data + packet->size; unsigned short type = attrtype; unsigned short len = data_len; /* Something is really wrong. Packets should never become over 1500 bytes */ if (packet->size + 4 + data_len > MT_PACKET_LEN) { fprintf(stderr, _("mndp_add_attribute: ERROR, too large packet. Exceeds %d bytes\n"), MT_PACKET_LEN); return -1; } type = htons(type); memcpy(data, &type, sizeof(type)); len = htons(len); memcpy(data + 2, &len, sizeof(len)); memcpy(data + 4, attrdata, data_len); packet->size += 4 + data_len; return 4 + data_len; } struct mt_mndp_info *parse_mndp(const unsigned char *data, const int packet_len) { const unsigned char *p; static struct mt_mndp_info packet; struct mt_mndp_info *packetp = &packet; struct mt_mndp_hdr *mndp_hdr; /* Check for valid packet length */ if (packet_len < 18) { return NULL; } bzero(packetp, sizeof(*packetp)); mndp_hdr = (struct mt_mndp_hdr*)data; memcpy(&packetp->header, mndp_hdr, sizeof(struct mt_mndp_hdr)); p = data + sizeof(struct mt_mndp_hdr); while(p < data + packet_len) { unsigned short type, len; memcpy(&type, p, 2); memcpy(&len, p + 2, 2); type = ntohs(type); len = ntohs(len); p += 4; /* Check if len is invalid */ if (p + len > data + packet_len) { fprintf(stderr, "%s: invalid data: " "%p + %u > %p + %d\n", __func__, p, len, data, packet_len); break; } switch (type) { case MT_MNDPTYPE_ADDRESS: if (len >= ETH_ALEN) { memcpy(packetp->address, p, ETH_ALEN); } break; case MT_MNDPTYPE_IDENTITY: if (len > MT_MNDP_MAX_STRING_LENGTH) { len = MT_MNDP_MAX_STRING_LENGTH; } memcpy(packetp->identity, p, len); packetp->identity[len] = '\0'; break; case MT_MNDPTYPE_PLATFORM: if (len > MT_MNDP_MAX_STRING_LENGTH) { len = MT_MNDP_MAX_STRING_LENGTH; } memcpy(packetp->platform, p, len); packetp->platform[len] = '\0'; break; case MT_MNDPTYPE_VERSION: if (len > MT_MNDP_MAX_STRING_LENGTH) { len = MT_MNDP_MAX_STRING_LENGTH; } memcpy(packetp->version, p, len); packetp->version[len] = '\0'; break; case MT_MNDPTYPE_TIMESTAMP: memcpy(&packetp->uptime, p, 4); /* Seems like ping uptime is transmitted as little endian? */ packetp->uptime = le32toh(packetp->uptime); break; case MT_MNDPTYPE_HARDWARE: if (len > MT_MNDP_MAX_STRING_LENGTH) { len = MT_MNDP_MAX_STRING_LENGTH; } memcpy(packetp->hardware, p, len); packetp->hardware[len] = '\0'; break; case MT_MNDPTYPE_SOFTID: if (len > MT_MNDP_MAX_STRING_LENGTH) { len = MT_MNDP_MAX_STRING_LENGTH; } memcpy(packetp->softid, p, len); packetp->softid[len] = '\0'; break; case MT_MNDPTYPE_IFNAME: if (len > MT_MNDP_MAX_STRING_LENGTH) { len = MT_MNDP_MAX_STRING_LENGTH; } memcpy(packetp->ifname, p, len); packetp->ifname[len] = '\0'; break; /*default: Unhandled MNDP type */ } p += len; } return packetp; } int query_mndp(const char *identity, unsigned char *mac) { int fastlookup = 0; int sock, length; int optval = 1; struct sockaddr_in si_me, si_remote; unsigned char buff[MT_PACKET_LEN]; unsigned int message = 0; struct timeval timeout; time_t start_time; fd_set read_fds; struct mt_mndp_info *packet; start_time = time(0); /* Open a UDP socket handle */ sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); /* Allow to share socket */ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); /* Set initialize address/port */ memset((char *) &si_me, 0, sizeof(si_me)); si_me.sin_family = AF_INET; si_me.sin_port = htons(MT_MNDP_PORT); si_me.sin_addr.s_addr = htonl(INADDR_ANY); /* Bind to specified address/port */ if (bind(sock, (struct sockaddr *)&si_me, sizeof(si_me)) == -1) { fprintf(stderr, _("Error binding to %s:%d\n"), inet_ntoa(si_me.sin_addr), MT_MNDP_PORT); close(sock); return 0; } /* Set the socket to allow sending broadcast packets */ setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &optval, sizeof (optval)); /* Request routers identify themselves */ memset((char *) &si_remote, 0, sizeof(si_remote)); si_remote.sin_family = AF_INET; si_remote.sin_port = htons(MT_MNDP_PORT); si_remote.sin_addr.s_addr = htonl(INADDR_BROADCAST); if (sendto(sock, &message, sizeof (message), 0, (struct sockaddr *)&si_remote, sizeof(si_remote)) == -1) { fprintf(stderr, _("Unable to send broadcast packet: Router lookup will be slow\n")); fastlookup = 0; } else { fastlookup = 1; } while (1) { /* Timeout, in case we receive a lot of packets, but from the wrong routers */ if (time(0) - start_time > (fastlookup ? MT_MNDP_TIMEOUT : MT_MNDP_LONGTIMEOUT)) { goto done; } FD_ZERO(&read_fds); FD_SET(sock, &read_fds); timeout.tv_sec = fastlookup ? MT_MNDP_TIMEOUT : MT_MNDP_LONGTIMEOUT; timeout.tv_usec = 0; select(sock + 1, &read_fds, NULL, NULL, &timeout); if (!FD_ISSET(sock, &read_fds)) { goto done; } /* Read UDP packet */ length = recvfrom(sock, buff, MT_PACKET_LEN, 0, 0, 0); if (length < 0) { goto done; } /* Parse MNDP packet */ packet = parse_mndp(buff, length); if (packet != NULL) { if (strcasecmp(identity, packet->identity) == 0) { memcpy(mac, packet->address, ETH_ALEN); close(sock); return 1; } } } done: close(sock); return 0; } /* * This function accepts either a full MAC address using : or - as seperators. * Or a router hostname. The hostname will be searched for via MNDP broadcast packets. */ int query_mndp_or_mac(char *address, unsigned char *dstmac, int verbose) { char *p = address; int colons = 0; int dashs = 0; while (*p++) { if (*p == ':') { colons++; } else if (*p == '-') { dashs++; } } /* * Windows users often enter macs with dash instead * of colon. */ if (colons == 0 && dashs == 5) { p = address; while (*p++) { if (*p == '-') { *p = ':'; } } colons = dashs; } if (colons != 5) { /* * Not a valid mac-address. * Search for Router by identity name, using MNDP */ if (verbose) { fprintf(stderr, _("Searching for '%s'..."), address); } if (!query_mndp(address, dstmac)) { if (verbose) { fprintf(stderr, _("not found\n")); } return 0; } /* Router found, display mac and continue */ if (verbose) { fprintf(stderr, _("found\n")); } } else { /* Convert mac address string to ether_addr struct */ ether_aton_r(address, (struct ether_addr *)dstmac); } return 1; } mactelnet-0.4.2/mndp.h0000664000175100017630000000012012622313406013235 0ustar haakoncy#ifndef _MNDP_H #define _MNDP_H int mndp(int timeout, int batch_mode); #endif mactelnet-0.4.2/docs/0000774000175100017630000000000012622313406013064 5ustar haakoncymactelnet-0.4.2/docs/mndp.10000664000175100017630000000121612622313406014105 0ustar haakoncy.TH MNDP 1 "February 27, 2011" .SH NAME mndp \- A tool for discovering other RouterOS or mactelnetd devices .SH SYNOPSIS .B mndp .SH DESCRIPTION This tool enables you to discover RouterOS or MAC-Telnetd enabled devices. It will display the MAC-address software version, and uptime of every device or machine it discovers. .PP To exit this application, use .B Control + C \. .SH SEE ALSO .BR mactelnet (1), .BR macping (1), .BR mactelnetd (1). .SH AUTHOR mndp was written by Håkon Nessjøen . .PP This manual page was written by Håkon Nessjøen , for the Debian project (and may be used by others). mactelnet-0.4.2/docs/macping.10000664000175100017630000000236012622313406014566 0ustar haakoncy.TH MACPING 1 "February 27, 2011" .SH NAME macping \- A tool for pinging other RouterOS or mactelnetd devices .SH SYNOPSIS .B mactelnet .RI [ options ] " " < MAC-Address | hostname > .SH DESCRIPTION This tool enables you to ping other RouterOS or MAC-Telnetd enabled devices. You can ping either a hostname or a MAC address. If specified, the hostname (identity) will be looked up via MNDP discovery. .SH OPTIONS These programs follow the usual GNU command line syntax. A summary of options is included below. .TP .B \-f Fast mode, do not wait before sending next ping request. The next ping will be sent immediately when the last ping is received. This cannot be used with .B -c 0 \. .TP .B \-s Specify the amount of bytes to send in each ping packet, up to ~1400 bytes. .TP .B \-c Number of packets to send before exiting. A value of .B 0 means unlimited packets and the tool must be exited with Control + C. .TP .B \-h Show summary of options. .TP .B \-v Show version of program. .SH SEE ALSO .BR mndp (1), .BR mactelnet (1), .BR mactelnetd (1). .SH AUTHOR macping was written by Håkon Nessjøen . .PP This manual page was written by Håkon Nessjøen , for the Debian project (and may be used by others). mactelnet-0.4.2/docs/mactelnet.10000664000175100017630000000363612622313406015133 0ustar haakoncy.TH MACTELNET 1 "February 27, 2011" .SH NAME mactelnet \- A tool for telneting via MAC addresses .SH SYNOPSIS .B mactelnet .RI [ options ] " " < MAC-Address | hostname > .SH DESCRIPTION This tool enables you to telnet other RouterOS or MAC-Telnetd enabled devices. You can connect to either a hostname or a MAC address. If specified, the hostname (identity) will be looked up via MNDP discovery. .SH OPTIONS These programs follow the usual GNU command line syntax. A summary of options is included below. .TP .B \-l This will discover RouterOS or MAC-Telnetd enabled devices. It will list the MAC-address software version, and uptime of every device or machine it discovers. To exit the discovery, use .B Control + C \. .TP .B \-n Do not use broadcast packets. A tad less insecure but requires root privileges. This means that ethernet packets will have the specified mac-address as the packet destination, instead of using the ethernet broadcast address. .TP .B \-t Amount of seconds to wait for a response on each interface. If you have several network interfaces, this is the timeout value per interface. .TP .B \-u Specify username. Without this option, you will need to enter the username in a interactive prompt. .TP .B \-p Specify password. Without this option, you will need to enter the password in a interactive prompt. .TP .B \-a Specify the path of the autologin configuration file. The default path for this file is ~/.mactelnet. The format for this file is standard INI file layout. .TP .B \-A Do not use the autologin configuration file. Interactively ask for username and password. .TP .B \-h Show summary of options. .TP .B \-v Show version of program. .SH SEE ALSO .BR mndp (1), .BR mactelnetd (1), .BR macping (1). .SH AUTHOR mactelnet was written by Håkon Nessjøen . .PP This manual page was written by Håkon Nessjøen , for the Debian project (and may be used by others). mactelnet-0.4.2/docs/mactelnetd.10000664000175100017630000000233712622313406015274 0ustar haakoncy.TH MACTELNETD 1 "February 27, 2011" .SH NAME mactelnetd \- Telnet daemon for MAC-address connections .SH SYNOPSIS .B mactelnetd .RI [ options ] .SH DESCRIPTION This daemon listens for telnet connections from Mikrotik RouterOS devices or mactelnet clients on the same physical network. It also announces it's hostname via the MNDP protocol every minute. .SH OPTIONS These programs follow the usual GNU command line syntax. A summary of options is included below. .TP .B \-n Do not use broadcast packets. A tad less insecure. This means that ethernet packets will have the mac-address of the client as the packet destination, instead of using the ethernet broadcast address. .TP .B \-h Show summary of options. .TP .B \-v Show version of program. .SH FILES .TP .B /etc/mactelnetd.users This file contains a line separated list of users that will have access to your machine. Usernames and passwords are separated by colon. This file is read each time a user connects. .SH SEE ALSO .BR mndp (1), .BR mactelnet (1), .BR macping (1). .SH AUTHOR mactelnetd was written by Håkon Nessjøen . .PP This manual page was written by Håkon Nessjøen , for the Debian project (and may be used by others). mactelnet-0.4.2/mndp.c0000664000175100017630000001225412622313406013243 0ustar haakoncy/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include #if defined(__FreeBSD__) #include #include #include #else #include #endif #include #include #include "protocol.h" #include "config.h" #define _(String) gettext (String) /* This file is also used for the -l option in mactelnet */ #ifndef FROM_MACTELNET /* Protocol data direction, not used here, but obligatory for protocol.c */ unsigned char mt_direction_fromserver = 0; int main(int argc, char **argv) { int batch_mode = 0; #else void sig_alarm(int signo) { exit(0); } int mndp(int timeout, int batch_mode) { #endif int sock,result; int optval = 1; struct sockaddr_in si_me, si_remote; unsigned char buff[MT_PACKET_LEN]; #ifdef FROM_MACTELNET /* mactelnet.c has this set to 1 */ mt_direction_fromserver = 0; signal(SIGALRM, sig_alarm); #endif setlocale(LC_ALL, ""); bindtextdomain("mactelnet","/usr/share/locale"); textdomain("mactelnet"); /* Open a UDP socket handle */ sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); /* Set initialize address/port */ memset((char *) &si_me, 0, sizeof(si_me)); si_me.sin_family = AF_INET; si_me.sin_port = htons(MT_MNDP_PORT); si_me.sin_addr.s_addr = htonl(INADDR_ANY); setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (optval)); /* Bind to specified address/port */ if (bind(sock, (struct sockaddr *)&si_me, sizeof(si_me))==-1) { fprintf(stderr, _("Error binding to %s:%d\n"), inet_ntoa(si_me.sin_addr), MT_MNDP_PORT); return 1; } /* Write informative message to STDERR to make it easier to use the output in simple scripts */ fprintf(stderr, _("Searching for MikroTik routers... Abort with CTRL+C.\n")); /* Set the socket to allow sending broadcast packets */ if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &optval, sizeof (optval))==-1) { fprintf(stderr, _("Unable to send broadcast packets: Operating in receive only mode.\n")); } else { /* Request routers identify themselves */ unsigned int message = 0; memset((char *) &si_remote, 0, sizeof(si_remote)); si_remote.sin_family = AF_INET; si_remote.sin_port = htons(MT_MNDP_PORT); si_remote.sin_addr.s_addr = htonl(INADDR_BROADCAST); if (sendto (sock, &message, sizeof (message), 0, (struct sockaddr *)&si_remote, sizeof(si_remote))==-1) { fprintf(stderr, _("Unable to send broadcast packet: Operating in receive only mode.\n")); } } if (batch_mode) { printf("%s\n", _("MAC-Address,Identity,Platform,Version,Hardware,Uptime,Softid,Ifname,IP")); } else { printf("\n\E[1m%-15s %-17s %s\E[m\n", _("IP"), _("MAC-Address"), _("Identity (platform version hardware) uptime")); } #ifdef FROM_MACTELNET if (timeout > 0) { alarm(timeout); } #endif while(1) { struct mt_mndp_info *packet; struct sockaddr_in addr; socklen_t addrlen = sizeof(addr); char ipstr[INET_ADDRSTRLEN]; memset(&addr, 0, addrlen); /* Wait for a UDP packet */ result = recvfrom(sock, buff, MT_PACKET_LEN, 0, (struct sockaddr *)&addr, &addrlen); if (result < 0) { fprintf(stderr, _("An error occured. aborting\n")); exit(1); } /* Parse MNDP packet */ packet = parse_mndp(buff, result); if (packet != NULL && !batch_mode) { /* Print it */ printf("%-15s ", inet_ntop(addr.sin_family, &addr.sin_addr, ipstr, sizeof ipstr)); printf("%-17s %s", ether_ntoa((struct ether_addr *)packet->address), packet->identity); if (packet->platform != NULL) { printf(" (%s %s %s)", packet->platform, packet->version, packet->hardware); } if (packet->uptime > 0) { printf(_(" up %d days %d hours"), packet->uptime / 86400, packet->uptime % 86400 / 3600); } if (packet->softid != NULL) { printf(" %s", packet->softid); } if (packet->ifname != NULL) { printf(" %s", packet->ifname); } putchar('\n'); } else if (packet != NULL) { /* Print it */ printf("'%s','%s',", ether_ntoa((struct ether_addr *)packet->address), packet->identity); printf("'%s','%s','%s',", packet->platform, packet->version, packet->hardware); printf("'%d','%s','%s'", packet->uptime, packet->softid, packet->ifname); printf(",'%s'", inet_ntop(addr.sin_family, &addr.sin_addr, ipstr, sizeof ipstr)); putchar('\n'); fflush(stdout); } } /* We'll never get here.. */ return 0; } mactelnet-0.4.2/po/0000774000175100017630000000000012622313406012552 5ustar haakoncymactelnet-0.4.2/po/mactelnet.pot0000664000175100017630000002134012622313406015253 0ustar haakoncy# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: mactelnet\n" "Report-Msgid-Bugs-To: haakon.nessjoen@gmail.com\n" "POT-Creation-Date: 2013-01-13 17:53+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: interfaces.c:287 #, c-format msgid "packet size too large\n" msgstr "" #: macping.c:89 #, c-format msgid "%d packets transmitted, %d packets received, %d%% packet loss\n" msgstr "" #: macping.c:90 #, c-format msgid "round-trip min/avg/max = %.2f/%.2f/%.2f ms\n" msgstr "" #: macping.c:149 #, c-format msgid "" "Number of packets to send must be more than 0 and less than 100 in fast " "mode.\n" msgstr "" #: macping.c:155 #, c-format msgid "Usage: %s [-h] [-f] [-c ] [-s ]\n" msgstr "" #: macping.c:158 #, c-format msgid "" "\n" "Parameters:\n" " MAC MAC-Address of the RouterOS/mactelnetd device.\n" " -f Fast mode, do not wait before sending next ping request.\n" " -s Specify size of ping packet.\n" " -c Number of packets to send. (0 = unlimited)\n" " -h This help.\n" "\n" msgstr "" #: macping.c:170 #, c-format msgid "Packet size must be between 18 and %d\n" msgstr "" #: macping.c:179 mactelnetd.c:954 #, c-format msgid "You need to have root privileges to use %s.\n" msgstr "" #: macping.c:207 mndp.c:78 protocol.c:429 #, c-format msgid "Error binding to %s:%d\n" msgstr "" #: macping.c:266 #, c-format msgid "Error sending packet.\n" msgstr "" #: macping.c:284 #, c-format msgid "%s ping timeout\n" msgstr "" #: macping.c:322 #, c-format msgid "%s %d byte, ping time %.2f ms%s\n" msgstr "" #: macping.c:324 #, c-format msgid "%s Reply of %d bytes of unequal data\n" msgstr "" #: mactelnet.c:104 #, c-format msgid "" "Failed dropping privileges. The user %s is not a valid username on local " "system.\n" msgstr "" #: mactelnet.c:110 #, c-format msgid "setgid: Error dropping group privileges\n" msgstr "" #: mactelnet.c:114 #, c-format msgid "setuid: Error dropping user privileges\n" msgstr "" #: mactelnet.c:119 #, c-format msgid "Failed to drop privileges\n" msgstr "" #: mactelnet.c:185 #, c-format msgid "" "\n" "Connection timed out\n" msgstr "" #: mactelnet.c:339 #, c-format msgid "Connection closed.\n" msgstr "" #: mactelnet.c:345 #, c-format msgid "Unhandeled packet type: %d received from server %s\n" msgstr "" #: mactelnet.c:367 #, c-format msgid "Error: No suitable devices found\n" msgstr "" #: mactelnet.c:517 #, c-format msgid "" "Usage: %s [-h] [-n] [-t ] [-u ] [-p " "] [-U ] | -l\n" msgstr "" #: mactelnet.c:520 #, c-format msgid "" "\n" "Parameters:\n" " MAC MAC-Address of the RouterOS/mactelnetd device. Use mndp to\n" " discover it.\n" " identity The identity/name of your destination device. Uses\n" " MNDP protocol to find it.\n" " -l List/Search for routers nearby (MNDP). You may use -t to " "set timeout.\n" " -B Batch mode. Use computer readable output (CSV), for use " "with -l.\n" " -n Do not use broadcast packets. Less insecure but requires\n" " root privileges.\n" " -t Amount of seconds to wait for a response on each " "interface.\n" " -u Specify username on command line.\n" " -p Specify password on command line.\n" " -U Drop privileges to this user. Used in conjunction with -n\n" " for security.\n" " -q Quiet mode.\n" " -h This help.\n" "\n" msgstr "" #: mactelnet.c:551 #, c-format msgid "You need to have root privileges to use the -n parameter.\n" msgstr "" #: mactelnet.c:561 #, c-format msgid "The -U option must be used in conjunction with the -n parameter.\n" msgstr "" #: mactelnet.c:590 #, c-format msgid "Login: " msgstr "" #: mactelnet.c:597 msgid "Password: " msgstr "" #: mactelnet.c:625 #, c-format msgid "Connecting to %s..." msgstr "" #: mactelnet.c:635 mactelnetd.c:245 mactelnetd.c:995 #, c-format msgid "Error binding to %s:%d, %s\n" msgstr "" #: mactelnet.c:640 #, c-format msgid "Connection failed.\n" msgstr "" #: mactelnet.c:644 #, c-format msgid "done\n" msgstr "" #: mactelnetd.c:250 #, c-format msgid "Listening on %s for %s\n" msgstr "" #: mactelnetd.c:418 #, c-format msgid "(%d) Invalid login by %s." msgstr "" #. _ Please include both \r and \n in translation, this is needed for the terminal emulator. #: mactelnetd.c:421 msgid "Login failed, incorrect username or password\r\n" msgstr "" #. _ Please include both \r and \n in translation, this is needed for the terminal emulator. #: mactelnetd.c:438 msgid "Terminal error\r\n" msgstr "" #: mactelnetd.c:449 #, c-format msgid "(%d) Login ok, but local user not accessible (%s)." msgstr "" #. _ Please include both \r and \n in translation, this is needed for the terminal emulator. #: mactelnetd.c:451 msgid "Local user not accessible\r\n" msgstr "" #: mactelnetd.c:460 #, c-format msgid "Error opening %s: %s" msgstr "" #. _ Please include both \r and \n in translation, this is needed for the terminal emulator. #: mactelnetd.c:462 msgid "Error opening terminal\r\n" msgstr "" #: mactelnetd.c:473 #, c-format msgid "(%d) User %s logged in." msgstr "" #: mactelnetd.c:511 #, c-format msgid "(%d) Could not log in %s (%d:%d): setuid/setgid: %s" msgstr "" #. _ Please include both \r and \n in translation, this is needed for the terminal emulator. #: mactelnetd.c:513 msgid "Internal error\r\n" msgstr "" #: mactelnetd.c:519 #, c-format msgid "(%d) User %s disconnected with " msgstr "" #: mactelnetd.c:615 #, c-format msgid "(%d) Unhandeled control packet type: %d" msgstr "" #: mactelnetd.c:661 #, c-format msgid "(%d) New connection from %s." msgstr "" #: mactelnetd.c:689 mactelnetd.c:1125 #, c-format msgid "(%d) Connection closed." msgstr "" #: mactelnetd.c:735 #, c-format msgid "(%d) Unhandeled packet type: %d" msgstr "" #. _ Please include both \r and \n in translation, this is needed for the terminal emulator. #: mactelnetd.c:830 msgid "" "\r\n" "\r\n" "Daemon shutting down.\r\n" msgstr "" #: mactelnetd.c:832 msgid "Daemon shutting down" msgstr "" #: mactelnetd.c:863 msgid "SIGHUP: Reloading interfaces" msgstr "" #: mactelnetd.c:874 msgid "No devices found! Exiting.\n" msgstr "" #: mactelnetd.c:888 #, c-format msgid "(%d) Connection closed because interface %s is gone." msgstr "" #: mactelnetd.c:941 #, c-format msgid "Usage: %s [-f|-n|-h]\n" msgstr "" #: mactelnetd.c:944 #, c-format msgid "" "\n" "Parameters:\n" " -f Run process in foreground.\n" " -n Do not use broadcast packets. Just a tad less insecure.\n" " -h This help.\n" "\n" msgstr "" #: mactelnetd.c:1017 #, c-format msgid "MNDP: Error binding to %s:%d, %s\n" msgstr "" #: mactelnetd.c:1021 #, c-format msgid "Bound to %s:%d" msgstr "" #: mactelnetd.c:1047 msgid "Unable to find any valid network interfaces\n" msgstr "" #: mactelnetd.c:1123 #, c-format msgid "(%d) Connection to user %s closed." msgstr "" #: mactelnetd.c:1133 #, c-format msgid "(%d) Waiting for ack\n" msgstr "" #: mactelnetd.c:1149 #, c-format msgid "(%d) Session timed out" msgstr "" #. _ Please include both \r and \n in translation, this is needed for the terminal emulator. #: mactelnetd.c:1152 msgid "Timeout\r\n" msgstr "" #: mndp.c:83 #, c-format msgid "Searching for MikroTik routers... Abort with CTRL+C.\n" msgstr "" #: mndp.c:87 #, c-format msgid "Unable to send broadcast packets: Operating in receive only mode.\n" msgstr "" #: mndp.c:97 #, c-format msgid "Unable to send broadcast packet: Operating in receive only mode.\n" msgstr "" #: mndp.c:102 msgid "MAC-Address,Identity,Platform,Version,Hardware,Uptime,Softid,Ifname" msgstr "" #: mndp.c:104 msgid "MAC-Address" msgstr "" #: mndp.c:104 msgid "Identity (platform version hardware) uptime" msgstr "" #: mndp.c:117 #, c-format msgid "An error occured. aborting\n" msgstr "" #: mndp.c:131 #, c-format msgid " up %d days %d hours" msgstr "" #: protocol.c:84 protocol.c:148 #, c-format msgid "add_control_packet: ERROR, too large packet. Exceeds %d bytes\n" msgstr "" #: protocol.c:280 #, c-format msgid "mndp_add_attribute: ERROR, too large packet. Exceeds %d bytes\n" msgstr "" #: protocol.c:444 #, c-format msgid "Unable to send broadcast packet: Router lookup will be slow\n" msgstr "" #: protocol.c:527 #, c-format msgid "Searching for '%s'..." msgstr "" #: protocol.c:531 #, c-format msgid "not found\n" msgstr "" #: protocol.c:538 #, c-format msgid "found\n" msgstr "" mactelnet-0.4.2/po/bg.po0000664000175100017630000003656012622313406013515 0ustar haakoncy# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: mactelnet\n" "Report-Msgid-Bugs-To: haakon.nessjoen@gmail.com\n" "POT-Creation-Date: 2012-07-17 21:29+0200\n" "PO-Revision-Date: 2012-11-30 09:49+0300\n" "Last-Translator: Boian Bonev \n" "Language-Team: Boian Bonev \n" "Language: bg\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: interfaces.c:287 #, c-format msgid "packet size too large\n" msgstr "размера на пакета е твърде голям\n" #: macping.c:89 #, c-format msgid "%d packets transmitted, %d packets received, %d%% packet loss\n" msgstr "%d изпратени пакета, %d получени пакета, %d%% изгубени пакети\n" #: macping.c:90 #, c-format msgid "round-trip min/avg/max = %.2f/%.2f/%.2f ms\n" msgstr "двупосочно време мин/ср/макс = %.2f/%.2f/%.2f мс\n" #: macping.c:149 #, c-format msgid "" "Number of packets to send must be more than 0 and less than 100 in fast " "mode.\n" msgstr "Броят на пакетите за изпращане трябва да е между 0 и 100 в бързия режим.\n" #: macping.c:155 #, c-format msgid "Usage: %s [-h] [-f] [-c ] [-s ]\n" msgstr "Използване: %s [-h] [-f] [-c <брой>] [-s <размер на пакета>]\n" #: macping.c:158 #, c-format msgid "" "\n" "Parameters:\n" " MAC MAC-Address of the RouterOS/mactelnetd device.\n" " -f Fast mode, do not wait before sending next ping request.\n" " -s Specify size of ping packet.\n" " -c Number of packets to send. (0 = unlimited)\n" " -h This help.\n" "\n" msgstr "" "\n" "Параметри:\n" " MAC MAC-Адрес на RouterOS/mactelnetd устройството.\n" " -f Бърз режим, не се чака преди изпращането на следващият пакет.\n" " -s Определя размера на пинг пакета.\n" " -c Брой на пакетите за изпращане. (0 = неограничен)\n" " -h Тази инструкция.\n" "\n" #: macping.c:170 #, c-format msgid "Packet size must be between 18 and %d\n" msgstr "Размерът на пакета трябва да е от 18 до %d\n" #: macping.c:179 mactelnetd.c:940 #, c-format msgid "You need to have root privileges to use %s.\n" msgstr "Необходими са права на потребител root, за да използвате %s.\n" #: macping.c:207 mndp.c:68 protocol.c:429 #, c-format msgid "Error binding to %s:%d\n" msgstr "Грешка при свързване от %s:%d\n" #: macping.c:266 #, c-format msgid "Error sending packet.\n" msgstr "Грешка при изпращане на пакет.\n" #: macping.c:284 #, c-format msgid "%s ping timeout\n" msgstr "%s изтекло време за изчакване\n" #: macping.c:322 #, c-format msgid "%s %d byte, ping time %.2f ms%s\n" msgstr "%s %d байта, време за ping %.2f мс%s\n" #: macping.c:324 #, c-format msgid "%s Reply of %d bytes of unequal data\n" msgstr "%s Отговор от %d байта с несъвпадащи данни\n" #: mactelnet.c:100 #, c-format msgid "" "Failed dropping privileges. The user %s is not a valid username on local " "system.\n" msgstr "" "Грешка при опит за намаляване на правата. Потребител %s не е валиден в локалната " "система.\n" #: mactelnet.c:106 #, c-format msgid "setgid: Error dropping group privileges\n" msgstr "setgid: Грешка при намаляване на груповите права\n" #: mactelnet.c:110 #, c-format msgid "setuid: Грешка при намаляване на потребителските права\n" msgstr "" #: mactelnet.c:115 #, c-format msgid "Failed to drop privileges\n" msgstr "Грешка при намаляване на правата\n" #: mactelnet.c:181 #, c-format msgid "" "\n" "Connection timed out\n" msgstr "" "\n" "Изтече времето за свързване\n" #: mactelnet.c:330 #, c-format msgid "Connection closed.\n" msgstr "Връзката е затворена.\n" #: mactelnet.c:336 #, c-format msgid "Unhandeled packet type: %d received from server %s\n" msgstr "Необработваем тип на пакет: %d, получен от %s\n" #: mactelnet.c:358 #, c-format msgid "Error: No suitable devices found\n" msgstr "Грешка: Няма намерено подходящо устройство\n" #: mactelnet.c:498 #, c-format msgid "" "Usage: %s [-h] [-n] [-t ] [-u ] [-p " "] [-U ] | -l\n" msgstr "" "Използване: %s [-h] [-n] [-t <изчакване>] [-u <потребител>] [-p " "<парола>] [-U <потребител>] | -l\n" #: mactelnet.c:501 #, c-format msgid "" "\n" "Parameters:\n" " MAC MAC-Address of the RouterOS/mactelnetd device. Use mndp to\n" " discover it.\n" " identity The identity/name of your destination device. Uses\n" " MNDP protocol to find it.\n" " -l List/Search for routers nearby. (using MNDP)\n" " -n Do not use broadcast packets. Less insecure but requires\n" " root privileges.\n" " -t Amount of seconds to wait for a response on each " "interface.\n" " -u Specify username on command line.\n" " -p Specify password on command line.\n" " -U Drop privileges to this user. Used in conjunction with -n\n" " for security.\n" " -q Quiet mode.\n" " -h This help.\n" "\n" msgstr "" "\n" "Параметри:\n" " MAC MAC-Адрес на RouterOS/mactelnetd устройството. Използвайте mndp,\n" " за да го откриете.\n" " идентификатор Идентификатор/име на далечното устройство. Открива се по\n" " MNDP протокол.\n" " -l Показва/Търси за устройства наоколо. (използва MNDP)\n" " -n Да не се използват броудкаст пакети. По-малко несигурно, но пък\n" " изисква права на потребител root.\n" " -t <изчакване> Брой секунди за изчакване на отговор за всеки интерфейс.\n" " -u <потребител> Задава потребител от командния ред.\n" " -p <парола> Задава парола от командния ред.\n" " -U Намалява правата до този потребител. Може да се използва заедно\n" " с -n за повишена сигурност.\n" " -q Тих режим.\n" " -h Тази инструкция.\n" "\n" #: mactelnet.c:531 #, c-format msgid "You need to have root privileges to use the -n parameter.\n" msgstr "Необходими са права на потребител root, за да използвате опция -n.\n" #: mactelnet.c:541 #, c-format msgid "The -U option must be used in conjunction with the -n parameter.\n" msgstr "Опция -U трябва да се използва заедно с опция -n.\n" #: mactelnet.c:570 #, c-format msgid "Login: " msgstr "Потребител: " #: mactelnet.c:577 msgid "Password: " msgstr "Парола: " #: mactelnet.c:602 #, c-format msgid "Connecting to %s..." msgstr "Свързване към %s..." #: mactelnet.c:612 mactelnetd.c:244 mactelnetd.c:981 #, c-format msgid "Error binding to %s:%d, %s\n" msgstr "Грешка при свързване от %s:%d, %s\n" #: mactelnet.c:617 #, c-format msgid "Connection failed.\n" msgstr "Връзката не е осъществена.\n" #: mactelnet.c:621 #, c-format msgid "done\n" msgstr "готово\n" #: mactelnetd.c:249 #, c-format msgid "Listening on %s for %s\n" msgstr "Слуша на %s за %s\n" #: mactelnetd.c:409 #, c-format msgid "(%d) Invalid login by %s." msgstr "(%d) Неправилен вход от %s." #. _ Please include both \r and \n in translation, this is needed for the terminal emulator. #: mactelnetd.c:412 msgid "Login failed, incorrect username or password\r\n" msgstr "Неуспешен вход, невалиден потребител или парола\r\n" #. _ Please include both \r and \n in translation, this is needed for the terminal emulator. #: mactelnetd.c:429 msgid "Terminal error\r\n" msgstr "Грешка в терминала\r\n" #: mactelnetd.c:440 #, c-format msgid "(%d) Login ok, but local user not accessible (%s)." msgstr "(%d) Успешен вход, но локалният потребител не е достъпен (%s)." #. _ Please include both \r and \n in translation, this is needed for the terminal emulator. #: mactelnetd.c:442 msgid "Local user not accessible\r\n" msgstr "Локалният потребител не е достъпен\r\n" #: mactelnetd.c:451 #, c-format msgid "Error opening %s: %s" msgstr "Грешка при отваряне %s: %s" #. _ Please include both \r and \n in translation, this is needed for the terminal emulator. #: mactelnetd.c:453 msgid "Error opening terminal\r\n" msgstr "Грешка при отваряне на терминал\r\n" #: mactelnetd.c:464 #, c-format msgid "(%d) User %s logged in." msgstr "(%d) Потребител %s влезе." #: mactelnetd.c:502 #, c-format msgid "(%d) Could not log in %s (%d:%d): setuid/setgid: %s" msgstr "(%d) Неуспешен вход %s (%d:%d): setuid/setgid: %s" #. _ Please include both \r and \n in translation, this is needed for the terminal emulator. #: mactelnetd.c:504 msgid "Internal error\r\n" msgstr "Вътрешна грешка\r\n" #: mactelnetd.c:510 #, c-format msgid "(%d) User %s disconnected with " msgstr "(%d) Потребител %s е изхвърлен с " #: mactelnetd.c:603 #, c-format msgid "(%d) Unhandeled control packet type: %d" msgstr "(%d) Необработваем контролен пакет от тип: %d" #: mactelnetd.c:649 #, c-format msgid "(%d) New connection from %s." msgstr "(%d) Нова връзка от %s." #: mactelnetd.c:677 mactelnetd.c:1111 #, c-format msgid "(%d) Connection closed." msgstr "(%d) Връзката е затворена." #: mactelnetd.c:723 #, c-format msgid "(%d) Unhandeled packet type: %d" msgstr "(%d) Необработваем пакет от тип: %d" #. _ Please include both \r and \n in translation, this is needed for the terminal emulator. #: mactelnetd.c:816 msgid "" "\r\n" "\r\n" "Daemon shutting down.\r\n" msgstr "" "\r\n" "\r\n" "Демон процеса прекратява работата си.\r\n" #: mactelnetd.c:818 msgid "Daemon shutting down" msgstr "Демон процеса прекратява работата си" #: mactelnetd.c:849 msgid "SIGHUP: Reloading interfaces" msgstr "SIGHUP: Презареждане на интерфейсите" #: mactelnetd.c:860 msgid "No devices found! Exiting.\n" msgstr "Няма намерени устройства! Изход.\n" #: mactelnetd.c:874 #, c-format msgid "(%d) Connection closed because interface %s is gone." msgstr "(%d) Връзката е затворена поради изчезнал интерфейс %s." #: mactelnetd.c:927 #, c-format msgid "Usage: %s [-f|-n|-h]\n" msgstr "Използване: %s [-f|-n|-h]\n" #: mactelnetd.c:930 #, c-format msgid "" "\n" "Parameters:\n" " -f Run process in foreground.\n" " -n Do not use broadcast packets. Just a tad less insecure.\n" " -h This help.\n" "\n" msgstr "" "\n" "Параметри:\n" " -f Стартиране на процеса на преден план.\n" " -n Да не се използват броудкаст пакети. Само с малко по-малко несигурно.\n" " -h Тази инструкция.\n" "\n" #: mactelnetd.c:1003 #, c-format msgid "MNDP: Error binding to %s:%d, %s\n" msgstr "MNDP: Грешка при свързване от %s:%d, %s\n" #: mactelnetd.c:1007 #, c-format msgid "Bound to %s:%d" msgstr "Свързване от %s:%d" #: mactelnetd.c:1033 msgid "Unable to find any valid network interfaces\n" msgstr "Няма валидни мрежови интерфейси\n" #: mactelnetd.c:1109 #, c-format msgid "(%d) Connection to user %s closed." msgstr "(%d) Връзката към потребител %s е прекъсната." #: mactelnetd.c:1119 #, c-format msgid "(%d) Waiting for ack\n" msgstr "(%d) Изчакване на потвърждение\n" #: mactelnetd.c:1135 #, c-format msgid "(%d) Session timed out" msgstr "(%d) Изтекло време за изчакване на сесията" #. _ Please include both \r and \n in translation, this is needed for the terminal emulator. #: mactelnetd.c:1138 msgid "Timeout\r\n" msgstr "Изтекло време за изчакване\r\n" #: mndp.c:73 #, c-format msgid "Searching for MikroTik routers... Abort with CTRL+C.\n" msgstr "Търсене на MikroTik рутери... Прекъсване с CTRL+C.\n" #: mndp.c:77 #, c-format msgid "Unable to send broadcast packets: Operating in receive only mode.\n" msgstr "Не е възможно да се изпращат броудкаст пакети: Програмата работи само в режим на приемане.\n" #: mndp.c:87 #, c-format msgid "Unable to send broadcast packet: Operating in receive only mode.\n" msgstr "Не е възможно да се изпрати броудкаст пакет: Програмата работи само в режим на приемане.\n" #: mndp.c:91 msgid "MAC-Address" msgstr "MAC-Адрес" #: mndp.c:91 msgid "Identity (platform version hardware) uptime" msgstr "Идентификатор (платформа версия хардуер) време от стартиране" #: mndp.c:98 #, c-format msgid "An error occured. aborting\n" msgstr "Грешка. изход\n" #: mndp.c:112 #, c-format msgid " up %d days %d hours" msgstr " от %d дни %d часа" #: protocol.c:84 protocol.c:148 #, c-format msgid "add_control_packet: ERROR, too large packet. Exceeds %d bytes\n" msgstr "add_control_packet: Грешка, пакетът е твърде голям. Надхвърля %d байта\n" #: protocol.c:280 #, c-format msgid "mndp_add_attribute: ERROR, too large packet. Exceeds %d bytes\n" msgstr "mndp_add_attribute: Грешка, пакетът е твърде голям. Надхвърля %d байта\n" #: protocol.c:444 #, c-format msgid "Unable to send broadcast packet: Router lookup will be slow\n" msgstr "Не е възможно да се изпрати броудкаст пакет: Търсенето на рутери ще работи бавно\n" #: protocol.c:527 #, c-format msgid "Searching for '%s'..." msgstr "Търсене за '%s'..." #: protocol.c:531 #, c-format msgid "not found\n" msgstr "не е намерен\n" #: protocol.c:538 #, c-format msgid "found\n" msgstr "намерен\n" mactelnet-0.4.2/po/nb.po0000664000175100017630000003165412622313406013523 0ustar haakoncy# SOME DESCRIPTIVE TITLE. # Copyright (C) 2013 Håkon Nessjøen # This file is distributed under the same license as the mactelnet package. # Håkon Nessjøen , 2013 # msgid "" msgstr "" "Project-Id-Version: mactelnet\n" "Report-Msgid-Bugs-To: haakon.nessjoen@gmail.com\n" "POT-Creation-Date: 2013-01-13 17:53+0100\n" "PO-Revision-Date: 2013-01-13 18:15+0100\n" "Last-Translator: Håkon Nessjøen \n" "Language-Team: Håkon Nessjøen \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: vim\n" "Language: nb\n" "X-Poedit-SourceCharset: UTF-8\n" #: interfaces.c:287 #, c-format msgid "packet size too large\n" msgstr "pakkestørrelse for stor\n" #: macping.c:89 #, c-format msgid "%d packets transmitted, %d packets received, %d%% packet loss\n" msgstr "%d pakker sendt, %d pakker mottatt, %d%% pakketap\n" #: macping.c:90 #, c-format msgid "round-trip min/avg/max = %.2f/%.2f/%.2f ms\n" msgstr "returtid min/gjennomsnitt/maks = %.2f/%.2f/%.2f ms\n" #: macping.c:149 #, c-format msgid "" "Number of packets to send must be more than 0 and less than 100 in fast " "mode.\n" msgstr "Antall pakker må være mer enn 0 og mindre enn 100 i hurtig-modus.\n" #: macping.c:155 #, c-format msgid "Usage: %s [-h] [-f] [-c ] [-s ]\n" msgstr "Bruksmåte: %s [-h] [-f] [-c ] [-s ]\n" #: macping.c:158 #, c-format msgid "" "\n" "Parameters:\n" " MAC MAC-Address of the RouterOS/mactelnetd device.\n" " -f Fast mode, do not wait before sending next ping request.\n" " -s Specify size of ping packet.\n" " -c Number of packets to send. (0 = unlimited)\n" " -h This help.\n" "\n" msgstr "" "\n" "Parametere:\n" " MAC MAC-Adressen til RouterOS/mactelnetd enheten.\n" " -f Hurtig-modus, send ping forespørsler uten pause.\n" " -s Spesifiser pakkestørrelsen.\n" " -c Antall pakker som skal sendes. (0 = uendelig)\n" " -h Denne hjelpen.\n" "\n" #: macping.c:170 #, c-format msgid "Packet size must be between 18 and %d\n" msgstr "Pakkestørrelse må være mellom 18 og %d\n" #: macping.c:179 mactelnetd.c:954 #, c-format msgid "You need to have root privileges to use %s.\n" msgstr "Du trenger superbruker-rettigheter for å bruke %s.\n" #: macping.c:207 mndp.c:78 protocol.c:429 #, c-format msgid "Error binding to %s:%d\n" msgstr "Klarte ikke binde mot %s:%d\n" #: macping.c:266 #, c-format msgid "Error sending packet.\n" msgstr "Klarte ikke sende pakke.\n" #: macping.c:284 #, c-format msgid "%s ping timeout\n" msgstr "%s ping tidsavbrudd\n" #: macping.c:322 #, c-format msgid "%s %d byte, ping time %.2f ms%s\n" msgstr "%s %d byte, ping tid %.2f ms%s\n" #: macping.c:324 #, c-format msgid "%s Reply of %d bytes of unequal data\n" msgstr "%s Retur av %d byter med usammensvarende data\n" #: mactelnet.c:104 #, c-format msgid "" "Failed dropping privileges. The user %s is not a valid username on local " "system.\n" msgstr "" "Klarte ikke droppe privilegier. Brukernavnet %s er ikke gyldig på det lokale " "systemet.\n" #: mactelnet.c:110 #, c-format msgid "setgid: Error dropping group privileges\n" msgstr "setgid: Klarte ikke droppe gruppeprivilegier\n" #: mactelnet.c:114 #, c-format msgid "setuid: Error dropping user privileges\n" msgstr "setud: Klarte ikke droppe brukerprivilegier\n" #: mactelnet.c:119 #, c-format msgid "Failed to drop privileges\n" msgstr "Klarte ikke droppe privilegier\n" #: mactelnet.c:185 #, c-format msgid "" "\n" "Connection timed out\n" msgstr "" "\n" "Tilkoblingen fikk tidsavbrudd\n" #: mactelnet.c:339 #, c-format msgid "Connection closed.\n" msgstr "Tilkoblingen ble stengt.\n" #: mactelnet.c:345 #, c-format msgid "Unhandeled packet type: %d received from server %s\n" msgstr "Uhåndtert pakketype: %d mottatt fra server %s\n" #: mactelnet.c:367 #, c-format msgid "Error: No suitable devices found\n" msgstr "Feil: Ingen brukbare enheter funnet\n" #: mactelnet.c:517 #, c-format msgid "" "Usage: %s [-h] [-n] [-t ] [-u ] [-p " "] [-U ] | -l\n" msgstr "" "Bruksmåte: %s [-h] [-n] [-t ] [-u " "] [-p ] [-U ] | -l\n" #: mactelnet.c:520 #, c-format msgid "" "\n" "Parameters:\n" " MAC MAC-Address of the RouterOS/mactelnetd device. Use mndp to\n" " discover it.\n" " identity The identity/name of your destination device. Uses\n" " MNDP protocol to find it.\n" " -l List/Search for routers nearby (MNDP). You may use -t to " "set timeout.\n" " -B Batch mode. Use computer readable output (CSV), for use " "with -l.\n" " -n Do not use broadcast packets. Less insecure but requires\n" " root privileges.\n" " -t Amount of seconds to wait for a response on each " "interface.\n" " -u Specify username on command line.\n" " -p Specify password on command line.\n" " -U Drop privileges to this user. Used in conjunction with -n\n" " for security.\n" " -q Quiet mode.\n" " -h This help.\n" "\n" msgstr "" "\n" "Parametere:\n" " MAC MAC-Adressen til RouterOS/mactelnetd enheten. Bruk mndb " "for\n" " å finne den.\n" " identitet Identiteten til enheten. Bruker MNDP protokollen\n" " til å finne den.\n" " -l List/Søk etter routere i nærheten (bruker MNDP). Du kan \n" " bruke -t til å sette timeout.\n" " -B Batch modus. Gir datamaskin-lesbar info for data fra -l.\n" " -n Ikke bruk broadcast pakker. Mindre usikkert, men bruker\n" " root privilegier.\n" " -t Antall sekunder å vente for respons på hvert grensesnitt.\n" " -u Spesifiser brukernavn på kommando-linjen.\n" " -p Spesifiser passord på kommando-linjen.\n" " -U Dropp privilegier til denne brukeren. Brukes i forbindelse\n" " med -n for sikkerhet.\n" " -q Stille-modus.\n" " -h Denne hjelpen.\n" "\n" #: mactelnet.c:551 #, c-format msgid "You need to have root privileges to use the -n parameter.\n" msgstr "Du trenger root privilegier for å bruke -n parameteren.\n" #: mactelnet.c:561 #, c-format msgid "The -U option must be used in conjunction with the -n parameter.\n" msgstr "-U parameteren må brukes i forbindelse med -n parameteren.\n" #: mactelnet.c:590 #, c-format msgid "Login: " msgstr "Bruker: " #: mactelnet.c:597 msgid "Password: " msgstr "Passord: " #: mactelnet.c:625 #, c-format msgid "Connecting to %s..." msgstr "Kobler til %s…" #: mactelnet.c:635 mactelnetd.c:245 mactelnetd.c:995 #, c-format msgid "Error binding to %s:%d, %s\n" msgstr "Problemer med å binde til %s:%d, %s\n" #: mactelnet.c:640 #, c-format msgid "Connection failed.\n" msgstr "Tilkobling feilet.\n" #: mactelnet.c:644 #, c-format msgid "done\n" msgstr "ferdig\n" #: mactelnetd.c:250 #, c-format msgid "Listening on %s for %s\n" msgstr "Lytter på %s for %s\n" #: mactelnetd.c:418 #, c-format msgid "(%d) Invalid login by %s." msgstr "(%d) Ugyldig login av %s." #. _ Please include both \r and \n in translation, this is needed for the terminal emulator. #: mactelnetd.c:421 msgid "Login failed, incorrect username or password\r\n" msgstr "Login feilet, ugyldig brukernavn eller passord\r\n" #. _ Please include both \r and \n in translation, this is needed for the terminal emulator. #: mactelnetd.c:438 msgid "Terminal error\r\n" msgstr "Terminalfeil\r\n" #: mactelnetd.c:449 #, c-format msgid "(%d) Login ok, but local user not accessible (%s)." msgstr "(%d) Login ok, men lokal bruker er ikke tilgjengelig (%s)." #. _ Please include both \r and \n in translation, this is needed for the terminal emulator. #: mactelnetd.c:451 msgid "Local user not accessible\r\n" msgstr "Lokal bruker er ikke tilgjengelig\r\n" #: mactelnetd.c:460 #, c-format msgid "Error opening %s: %s" msgstr "Klarer ikke åpne %s: %s" #. _ Please include both \r and \n in translation, this is needed for the terminal emulator. #: mactelnetd.c:462 msgid "Error opening terminal\r\n" msgstr "Klarer ikke åpne terminal\r\n" #: mactelnetd.c:473 #, c-format msgid "(%d) User %s logged in." msgstr "(%d) Bruker %s logget inn." #: mactelnetd.c:511 #, c-format msgid "(%d) Could not log in %s (%d:%d): setuid/setgid: %s" msgstr "(%d) Kunne ikke logge inn %s (%d:%d): setuid/setgid: %s" #. _ Please include both \r and \n in translation, this is needed for the terminal emulator. #: mactelnetd.c:513 msgid "Internal error\r\n" msgstr "Intern feil\r\n" #: mactelnetd.c:519 #, c-format msgid "(%d) User %s disconnected with " msgstr "(%d) Bruker %s frakoblet med " #: mactelnetd.c:615 #, c-format msgid "(%d) Unhandeled control packet type: %d" msgstr "(%d) Uhåndtert kontrollpakke-type: %d" #: mactelnetd.c:661 #, c-format msgid "(%d) New connection from %s." msgstr "(%d) Ny tilkobling fra %s." #: mactelnetd.c:689 mactelnetd.c:1125 #, c-format msgid "(%d) Connection closed." msgstr "(%d) Tilkobling lukket." #: mactelnetd.c:735 #, c-format msgid "(%d) Unhandeled packet type: %d" msgstr "(%d) Uhåndtert pakke-type: %d" #. _ Please include both \r and \n in translation, this is needed for the terminal emulator. #: mactelnetd.c:830 msgid "" "\r\n" "\r\n" "Daemon shutting down.\r\n" msgstr "" "\r\n" "\r\n" "Tjener avslutter.\r\n" #: mactelnetd.c:832 msgid "Daemon shutting down" msgstr "Tjener avslutter" #: mactelnetd.c:863 msgid "SIGHUP: Reloading interfaces" msgstr "SIGHUP: Laster grensesnitt på nytt" #: mactelnetd.c:874 msgid "No devices found! Exiting.\n" msgstr "Ingen enheter funnet! Avslutter.\n" #: mactelnetd.c:888 #, c-format msgid "(%d) Connection closed because interface %s is gone." msgstr "(%d) Tilkobling lukket på grunn av at %s er borte." #: mactelnetd.c:941 #, c-format msgid "Usage: %s [-f|-n|-h]\n" msgstr "Bruksmåte: %s [-f|-n|-h]\n" #: mactelnetd.c:944 #, c-format msgid "" "\n" "Parameters:\n" " -f Run process in foreground.\n" " -n Do not use broadcast packets. Just a tad less insecure.\n" " -h This help.\n" "\n" msgstr "" "\n" "Parametere:\n" " -f Kjør prosessen i forgrunn.\n" " -n Ikke bruk broadcast pakker. Bare såvidt litt mer usikkert.\n" " -h Denne hjelpen.\n" "\n" #: mactelnetd.c:1017 #, c-format msgid "MNDP: Error binding to %s:%d, %s\n" msgstr "MNDP: Klarte ikke binde til %s:%d, %s\n" #: mactelnetd.c:1021 #, c-format msgid "Bound to %s:%d" msgstr "Bundet to %s:%d" #: mactelnetd.c:1047 msgid "Unable to find any valid network interfaces\n" msgstr "Klarte ikke finne noen gyldige nettverksgrensesnitt\n" #: mactelnetd.c:1123 #, c-format msgid "(%d) Connection to user %s closed." msgstr "(%d) Tilkobling til bruker %s lukket." #: mactelnetd.c:1133 #, c-format msgid "(%d) Waiting for ack\n" msgstr "(%d) Venter på ack\n" #: mactelnetd.c:1149 #, c-format msgid "(%d) Session timed out" msgstr "(%d) Sesjonen utgikk på tidsavbrudd" #. _ Please include both \r and \n in translation, this is needed for the terminal emulator. #: mactelnetd.c:1152 msgid "Timeout\r\n" msgstr "Tidsavbrudd\r\n" #: mndp.c:83 #, c-format msgid "Searching for MikroTik routers... Abort with CTRL+C.\n" msgstr "Søker etter MikroTik rutere… Avbryt med CTRL+C.\n" #: mndp.c:87 #, c-format msgid "Unable to send broadcast packets: Operating in receive only mode.\n" msgstr "Klarer ikke sende broadcast pakker: Jobber i kun-motta-modus.\n" #: mndp.c:97 #, c-format msgid "Unable to send broadcast packet: Operating in receive only mode.\n" msgstr "Klarer ikke sende broadcast pakke: Jobber i kun-motta-modus.\n" #: mndp.c:102 msgid "MAC-Address,Identity,Platform,Version,Hardware,Uptime,Softid,Ifname" msgstr "MAC-Adresse,Identitet,Plattform,Versjon,Maskinvare,Oppetid,Softid,Enhetsnavn" #: mndp.c:104 msgid "MAC-Address" msgstr "MAC-Adresse" #: mndp.c:104 msgid "Identity (platform version hardware) uptime" msgstr "Identitet (plattform versjon maskinvare) oppetid" #: mndp.c:117 #, c-format msgid "An error occured. aborting\n" msgstr "En feil oppstod. avbryter\n" #: mndp.c:131 #, c-format msgid " up %d days %d hours" msgstr " oppe %d dager %d timer" #: protocol.c:84 protocol.c:148 #, c-format msgid "add_control_packet: ERROR, too large packet. Exceeds %d bytes\n" msgstr "add_control_packet: FEIL, for stor pakke. Overstiger %d byter\n" #: protocol.c:280 #, c-format msgid "mndp_add_attribute: ERROR, too large packet. Exceeds %d bytes\n" msgstr "mndp_add_attribute: FEIL, for stor pakke. Overstiger %d byter\n" #: protocol.c:444 #, c-format msgid "Unable to send broadcast packet: Router lookup will be slow\n" msgstr "Klarer ikke sende broadcast pakke: Ruter søk vil være tregt\n" #: protocol.c:527 #, c-format msgid "Searching for '%s'..." msgstr "Søker etter '%s'..." #: protocol.c:531 #, c-format msgid "not found\n" msgstr "ikke funnet\n" #: protocol.c:538 #, c-format msgid "found\n" msgstr "funnet\n" mactelnet-0.4.2/config.h0000664000175100017630000000330312622313406013552 0ustar haakoncy/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _CONFIG_H #define _CONFIG_H 1 #define DEBUG 0 #define PROGRAM_VERSION "0.4.2" #define AUTOLOGIN_PATH "~/.mactelnet" #if defined(__APPLE__) && defined(__MACH__) #define PLATFORM_NAME "Mac OS X" #elif defined(__FreeBSD__) #define PLATFORM_NAME "FreeBSD" #elif defined(__NetBSD__) #define PLATFORM_NAME "NetBSD" #elif defined(__OpenBSD__) #define PLATFORM_NAME "OpenBSD" #elif defined(__MINT__) #define PLATFORM_NAME "FreeMiNT" #elif defined(__bsdi__) #define PLATFORM_NAME "BSD/OS" #elif defined(linux) || defined(__linux__) #define PLATFORM_NAME "Linux" #elif defined(sun) #define PLATFORM_NAME "Solaris" #elif defined(__hpux) #define PLATFORM_NAME "HPUX" #elif defined(__riscos__) #define PLATFORM_NAME "RISC OS" #elif defined(__FreeBSD_kernel__) #define PLATFORM_NAME "kFreeBSD" #else #define PLATFORM_NAME "Unknown" #endif #endif mactelnet-0.4.2/mactelnetd.c0000664000175100017630000010155212622313406014425 0ustar haakoncy/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define _POSIX_C_SOURCE 199309L #define _XOPEN_SOURCE 600 #define _BSD_SOURCE #include #include #include #include #include #include #include #include #if defined(__FreeBSD__) #include #include #else #include #endif #include #include #include #include #include #if !defined(__FreeBSD__) #include #endif #include #include #include #include #ifdef __linux__ #include #include #else #include #endif #include #include #if defined(__linux__) #include #endif #include #if defined(__FreeBSD__) #include /* This is the really Posix interface the Linux code should have used !!*/ #include #else #include #endif #include #include #include "md5.h" #include "protocol.h" #include "console.h" #include "interfaces.h" #include "users.h" #include "config.h" #include "utlist.h" #define PROGRAM_NAME "MAC-Telnet Daemon" #define MAX_INSOCKETS 100 #define MT_INTERFACE_LEN 128 /* Max ~5 pings per second */ #define MT_MAXPPS MT_MNDP_BROADCAST_INTERVAL * 5 #define _(String) gettext (String) #define gettext_noop(String) String static int sockfd; static int insockfd; static int mndpsockfd; static int pings = 0; struct net_interface *interfaces = NULL; static int use_raw_socket = 0; static struct in_addr sourceip; static struct in_addr destip; static int sourceport; static time_t last_mndp_time = 0; /* Protocol data direction */ unsigned char mt_direction_fromserver = 1; /* Anti-timeout is every 10 seconds. Give up after 15. */ #define MT_CONNECTION_TIMEOUT 15 /* Connection states */ enum mt_connection_state { STATE_AUTH, STATE_CLOSED, STATE_ACTIVE }; /** Connection struct */ struct mt_connection { struct net_interface *interface; char interface_name[256]; unsigned short seskey; unsigned int incounter; unsigned int outcounter; unsigned int lastack; time_t lastdata; int terminal_mode; enum mt_connection_state state; int ptsfd; int slavefd; int pid; int wait_for_ack; int have_enckey; char username[30]; unsigned char trypassword[17]; unsigned char srcip[IPV4_ALEN]; unsigned char srcmac[ETH_ALEN]; unsigned short srcport; unsigned char dstmac[ETH_ALEN]; unsigned char enckey[16]; unsigned short terminal_width; unsigned short terminal_height; char terminal_type[30]; struct mt_connection *prev; struct mt_connection *next; }; static void uwtmp_login(struct mt_connection *); static void uwtmp_logout(struct mt_connection *); static struct mt_connection *connections_head = NULL; static void list_add_connection(struct mt_connection *conn) { DL_APPEND(connections_head, conn); } static void list_remove_connection(struct mt_connection *conn) { if (connections_head == NULL) { return; } if (conn->state == STATE_ACTIVE && conn->ptsfd > 0) { close(conn->ptsfd); } if (conn->state == STATE_ACTIVE && conn->slavefd > 0) { close(conn->slavefd); } uwtmp_logout(conn); DL_DELETE(connections_head, conn); free(conn); } static struct mt_connection *list_find_connection(unsigned short seskey, unsigned char *srcmac) { struct mt_connection *p; DL_FOREACH(connections_head, p) { if (p->seskey == seskey && memcmp(srcmac, p->srcmac, ETH_ALEN) == 0) { return p; } } return NULL; } static struct net_interface *find_socket(unsigned char *mac) { struct net_interface *interface; DL_FOREACH(interfaces, interface) { if (memcmp(mac, interface->mac_addr, ETH_ALEN) == 0) { return interface; } } return NULL; } static void setup_sockets() { struct net_interface *interface; DL_FOREACH(interfaces, interface) { int optval = 1; struct sockaddr_in si_me; struct ether_addr *mac = (struct ether_addr *)&(interface->mac_addr); if (!interface->has_mac) { continue; } if (!use_raw_socket) { interface->socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (interface->socketfd < 0) { continue; } if (setsockopt(interface->socketfd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof (optval))==-1) { perror("SO_BROADCAST"); continue; } setsockopt(interface->socketfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); /* Initialize receiving socket on the device chosen */ si_me.sin_family = AF_INET; si_me.sin_port = htons(MT_MACTELNET_PORT); memcpy(&(si_me.sin_addr.s_addr), interface->ipv4_addr, IPV4_ALEN); if (bind(interface->socketfd, (struct sockaddr *)&si_me, sizeof(si_me))==-1) { fprintf(stderr, _("Error binding to %s:%d, %s\n"), inet_ntoa(si_me.sin_addr), sourceport, strerror(errno)); continue; } } syslog(LOG_NOTICE, _("Listening on %s for %s\n"), interface->name, ether_ntoa(mac)); } } static int send_udp(const struct mt_connection *conn, const struct mt_packet *packet) { if (use_raw_socket) { return net_send_udp(sockfd, conn->interface, conn->dstmac, conn->srcmac, &sourceip, sourceport, &destip, conn->srcport, packet->data, packet->size); } else { /* Init SendTo struct */ struct sockaddr_in socket_address; socket_address.sin_family = AF_INET; socket_address.sin_port = htons(conn->srcport); socket_address.sin_addr.s_addr = htonl(INADDR_BROADCAST); return sendto(conn->interface->socketfd, packet->data, packet->size, 0, (struct sockaddr*)&socket_address, sizeof(socket_address)); } } static int send_special_udp(struct net_interface *interface, unsigned short port, const struct mt_packet *packet) { unsigned char dstmac[ETH_ALEN]; if (use_raw_socket) { memset(dstmac, 0xff, ETH_ALEN); return net_send_udp(sockfd, interface, interface->mac_addr, dstmac, (const struct in_addr *)&interface->ipv4_addr, port, &destip, port, packet->data, packet->size); } else { /* Init SendTo struct */ struct sockaddr_in socket_address; socket_address.sin_family = AF_INET; socket_address.sin_port = htons(port); socket_address.sin_addr.s_addr = htonl(INADDR_BROADCAST); return sendto(interface->socketfd, packet->data, packet->size, 0, (struct sockaddr*)&socket_address, sizeof(socket_address)); } } static void display_motd() { FILE *fp; int c; if ((fp = fopen("/etc/motd", "r"))) { while ((c = getc(fp)) != EOF) { putchar(c); } fclose(fp); } } static void display_nologin() { FILE *fp; int c; if ((fp = fopen(_PATH_NOLOGIN, "r"))) { while ((c = getc(fp)) != EOF) { putchar(c); } fclose(fp); } } static void uwtmp_login(struct mt_connection *conn) { #if defined(__FreeBSD__) struct utmpx utent; #else struct utmp utent; #endif pid_t pid; pid = getpid(); char *line = ttyname(conn->slavefd); if (strncmp(line, "/dev/", 5) == 0) { line += 5; } /* Setup utmp struct */ memset((void *) &utent, 0, sizeof(utent)); utent.ut_type = USER_PROCESS; utent.ut_pid = pid; strncpy(utent.ut_user, conn->username, sizeof(utent.ut_user)); strncpy(utent.ut_line, line, sizeof(utent.ut_line)); strncpy(utent.ut_id, utent.ut_line + 3, sizeof(utent.ut_id)); strncpy(utent.ut_host, ether_ntoa((const struct ether_addr *)conn->srcmac), sizeof(utent.ut_host)); #if defined(__FreeBSD__) gettimeofday(&utent.ut_tv, NULL); #else time((time_t *)&(utent.ut_time)); #endif /* Update utmp and/or wtmp */ #if defined(__FreeBSD__) setutxent(); pututxline(&utent); endutxent(); #else setutent(); pututline(&utent); endutent(); updwtmp(_PATH_WTMP, &utent); #endif } static void uwtmp_logout(struct mt_connection *conn) { if (conn->pid > 0) { #if defined(__FreeBSD__) struct utmpx *utentp; struct utmpx utent; setutxent(); #else struct utmp *utentp; struct utmp utent; setutent(); #endif #if defined(__FreeBSD__) while ((utentp = getutxent()) != NULL) { #else while ((utentp = getutent()) != NULL) { #endif if (utentp->ut_pid == conn->pid && utentp->ut_id) { break; } } if (utentp) { utent = *utentp; utent.ut_type = DEAD_PROCESS; utent.ut_tv.tv_sec = time(NULL); #if defined(__FreeBSD__) pututxline(&utent); endutxent(); #else pututline(&utent); endutent(); updwtmp(_PATH_WTMP, &utent); #endif } } } static void abort_connection(struct mt_connection *curconn, struct mt_mactelnet_hdr *pkthdr, char *message) { struct mt_packet pdata; init_packet(&pdata, MT_PTYPE_DATA, pkthdr->dstaddr, pkthdr->srcaddr, pkthdr->seskey, curconn->outcounter); add_control_packet(&pdata, MT_CPTYPE_PLAINDATA, message, strlen(message)); send_udp(curconn, &pdata); /* Make connection time out; lets the previous message get acked before disconnecting */ curconn->state = STATE_CLOSED; init_packet(&pdata, MT_PTYPE_END, pkthdr->dstaddr, pkthdr->srcaddr, pkthdr->seskey, curconn->outcounter); send_udp(curconn, &pdata); } static void user_login(struct mt_connection *curconn, struct mt_mactelnet_hdr *pkthdr) { struct mt_packet pdata; unsigned char md5sum[17]; char md5data[100]; struct mt_credentials *user; char *slavename; /* Reparse user file before each login */ read_userfile(); if ((user = find_user(curconn->username)) != NULL) { md5_state_t state; #if defined(__linux__) && defined(_POSIX_MEMLOCK_RANGE) mlock(md5data, sizeof(md5data)); mlock(md5sum, sizeof(md5sum)); if (user->password != NULL) { mlock(user->password, strlen(user->password)); } #endif /* Concat string of 0 + password + encryptionkey */ md5data[0] = 0; strncpy(md5data + 1, user->password, 82); memcpy(md5data + 1 + strlen(user->password), curconn->enckey, 16); /* Generate md5 sum of md5data with a leading 0 */ md5_init(&state); md5_append(&state, (const md5_byte_t *)md5data, strlen(user->password) + 17); md5_finish(&state, (md5_byte_t *)md5sum + 1); md5sum[0] = 0; init_packet(&pdata, MT_PTYPE_DATA, pkthdr->dstaddr, pkthdr->srcaddr, pkthdr->seskey, curconn->outcounter); curconn->outcounter += add_control_packet(&pdata, MT_CPTYPE_END_AUTH, NULL, 0); send_udp(curconn, &pdata); if (curconn->state == STATE_ACTIVE) { return; } } if (user == NULL || memcmp(md5sum, curconn->trypassword, 17) != 0) { syslog(LOG_NOTICE, _("(%d) Invalid login by %s."), curconn->seskey, curconn->username); /*_ Please include both \r and \n in translation, this is needed for the terminal emulator. */ abort_connection(curconn, pkthdr, _("Login failed, incorrect username or password\r\n")); /* TODO: should wait some time (not with sleep) before returning, to minimalize brute force attacks */ return; } /* User is logged in */ curconn->state = STATE_ACTIVE; /* Enter terminal mode */ curconn->terminal_mode = 1; /* Open pts handle */ curconn->ptsfd = posix_openpt(O_RDWR); if (curconn->ptsfd == -1 || grantpt(curconn->ptsfd) == -1 || unlockpt(curconn->ptsfd) == -1) { syslog(LOG_ERR, "posix_openpt: %s", strerror(errno)); /*_ Please include both \r and \n in translation, this is needed for the terminal emulator. */ abort_connection(curconn, pkthdr, _("Terminal error\r\n")); return; } /* Get file path for our pts */ slavename = ptsname(curconn->ptsfd); if (slavename != NULL) { pid_t pid; struct stat sb; struct passwd *user = (struct passwd *)malloc(sizeof(struct passwd)); struct passwd *tmpuser=user; char *buffer = malloc(1024); if (user == NULL || buffer == NULL) { syslog(LOG_CRIT, _("(%d) Error allocating memory."), curconn->seskey); /*_ Please include both \r and \n in translation, this is needed for the terminal emulator. */ abort_connection(curconn, pkthdr, _("System error, out of memory\r\n")); return; } if (getpwnam_r(curconn->username, user, buffer, 1024, &tmpuser) != 0) { syslog(LOG_WARNING, _("(%d) Login ok, but local user not accessible (%s)."), curconn->seskey, curconn->username); /*_ Please include both \r and \n in translation, this is needed for the terminal emulator. */ abort_connection(curconn, pkthdr, _("Local user not accessible\r\n")); free(user); free(buffer); return; } /* Change the owner of the slave pts */ chown(slavename, user->pw_uid, user->pw_gid); curconn->slavefd = open(slavename, O_RDWR); if (curconn->slavefd == -1) { syslog(LOG_ERR, _("Error opening %s: %s"), slavename, strerror(errno)); /*_ Please include both \r and \n in translation, this is needed for the terminal emulator. */ abort_connection(curconn, pkthdr, _("Error opening terminal\r\n")); list_remove_connection(curconn); return; } if ((pid = fork()) == 0) { struct net_interface *interface; /* Add login information to utmp/wtmp */ uwtmp_login(curconn); syslog(LOG_INFO, _("(%d) User %s logged in."), curconn->seskey, curconn->username); /* Initialize terminal environment */ setenv("USER", user->pw_name, 1); setenv("HOME", user->pw_dir, 1); setenv("SHELL", user->pw_shell, 1); setenv("TERM", curconn->terminal_type, 1); close(sockfd); close(insockfd); DL_FOREACH(interfaces, interface) { if (interface->socketfd > 0) { close(interface->socketfd); } } setsid(); /* Don't let shell process inherit slavefd */ fcntl (curconn->slavefd, F_SETFD, FD_CLOEXEC); close(curconn->ptsfd); /* Redirect STDIN/STDIO/STDERR */ close(0); dup(curconn->slavefd); close(1); dup(curconn->slavefd); close(2); dup(curconn->slavefd); /* Set controlling terminal */ ioctl(0, TIOCSCTTY, 1); tcsetpgrp(0, getpid()); /* Set user id/group id */ if ((setgid(user->pw_gid) != 0) || (setuid(user->pw_uid) != 0)) { syslog(LOG_ERR, _("(%d) Could not log in %s (%d:%d): setuid/setgid: %s"), curconn->seskey, curconn->username, user->pw_uid, user->pw_gid, strerror(errno)); /*_ Please include both \r and \n in translation, this is needed for the terminal emulator. */ abort_connection(curconn, pkthdr, _("Internal error\r\n")); exit(0); } /* Abort login if /etc/nologin exists */ if (stat(_PATH_NOLOGIN, &sb) == 0 && getuid() != 0) { syslog(LOG_NOTICE, _("(%d) User %s disconnected with " _PATH_NOLOGIN " message."), curconn->seskey, curconn->username); display_nologin(); curconn->state = STATE_CLOSED; init_packet(&pdata, MT_PTYPE_END, pkthdr->dstaddr, pkthdr->srcaddr, pkthdr->seskey, curconn->outcounter); send_udp(curconn, &pdata); exit(0); } /* Display MOTD */ display_motd(); chdir(user->pw_dir); /* Spawn shell */ /* TODO: Maybe use "login -f USER" instead? renders motd and executes shell correctly for system */ execl(user->pw_shell, user->pw_shell, "-", (char *) 0); exit(0); // just to be sure. } free(user); free(buffer); close(curconn->slavefd); curconn->pid = pid; set_terminal_size(curconn->ptsfd, curconn->terminal_width, curconn->terminal_height); } } static void handle_data_packet(struct mt_connection *curconn, struct mt_mactelnet_hdr *pkthdr, int data_len) { struct mt_mactelnet_control_hdr cpkt; struct mt_packet pdata; unsigned char *data = pkthdr->data; int got_user_packet = 0; int got_pass_packet = 0; int got_width_packet = 0; int got_height_packet = 0; int success; /* Parse first control packet */ success = parse_control_packet(data, data_len - MT_HEADER_LEN, &cpkt); while (success) { if (cpkt.cptype == MT_CPTYPE_BEGINAUTH) { int plen,i; if (!curconn->have_enckey) { for (i = 0; i < 16; ++i) { curconn->enckey[i] = rand() % 256; } curconn->have_enckey = 1; memset(curconn->trypassword, 0, sizeof(curconn->trypassword)); } init_packet(&pdata, MT_PTYPE_DATA, pkthdr->dstaddr, pkthdr->srcaddr, pkthdr->seskey, curconn->outcounter); plen = add_control_packet(&pdata, MT_CPTYPE_ENCRYPTIONKEY, (curconn->enckey), 16); curconn->outcounter += plen; send_udp(curconn, &pdata); } else if (cpkt.cptype == MT_CPTYPE_USERNAME) { memcpy(curconn->username, cpkt.data, cpkt.length > 29 ? 29 : cpkt.length); curconn->username[cpkt.length > 29 ? 29 : cpkt.length] = 0; got_user_packet = 1; } else if (cpkt.cptype == MT_CPTYPE_TERM_WIDTH) { unsigned short width; memcpy(&width, cpkt.data, 2); curconn->terminal_width = le16toh(width); got_width_packet = 1; } else if (cpkt.cptype == MT_CPTYPE_TERM_HEIGHT) { unsigned short height; memcpy(&height, cpkt.data, 2); curconn->terminal_height = le16toh(height); got_height_packet = 1; } else if (cpkt.cptype == MT_CPTYPE_TERM_TYPE) { memcpy(curconn->terminal_type, cpkt.data, cpkt.length > 29 ? 29 : cpkt.length); curconn->terminal_type[cpkt.length > 29 ? 29 : cpkt.length] = 0; } else if (cpkt.cptype == MT_CPTYPE_PASSWORD) { #if defined(__linux__) && defined(_POSIX_MEMLOCK_RANGE) mlock(curconn->trypassword, 17); #endif memcpy(curconn->trypassword, cpkt.data, 17); got_pass_packet = 1; } else if (cpkt.cptype == MT_CPTYPE_PLAINDATA) { /* relay data from client to shell */ if (curconn->state == STATE_ACTIVE && curconn->ptsfd != -1) { write(curconn->ptsfd, cpkt.data, cpkt.length); } } else { syslog(LOG_WARNING, _("(%d) Unhandeled control packet type: %d"), curconn->seskey, cpkt.cptype); } /* Parse next control packet */ success = parse_control_packet(NULL, 0, &cpkt); } if (got_user_packet && got_pass_packet) { user_login(curconn, pkthdr); } if (curconn->state == STATE_ACTIVE && (got_width_packet || got_height_packet)) { set_terminal_size(curconn->ptsfd, curconn->terminal_width, curconn->terminal_height); } } static void handle_packet(unsigned char *data, int data_len, const struct sockaddr_in *address) { struct mt_mactelnet_hdr pkthdr; struct mt_connection *curconn = NULL; struct mt_packet pdata; struct net_interface *interface; parse_packet(data, &pkthdr); /* Drop packets not belonging to us */ if ((interface = find_socket(pkthdr.dstaddr)) < 0) { return; } switch (pkthdr.ptype) { case MT_PTYPE_PING: if (pings++ > MT_MAXPPS) { break; } init_pongpacket(&pdata, (unsigned char *)&(pkthdr.dstaddr), (unsigned char *)&(pkthdr.srcaddr)); add_packetdata(&pdata, pkthdr.data - 4, data_len - (MT_HEADER_LEN - 4)); { if (index >= 0) { send_special_udp(interface, MT_MACTELNET_PORT, &pdata); } } break; case MT_PTYPE_SESSIONSTART: curconn = list_find_connection(pkthdr.seskey, (unsigned char *)&(pkthdr.srcaddr)); if (curconn != NULL) { /* Ignore multiple session starts from the same sender, this can be same mac but different interface */ break; } syslog(LOG_DEBUG, _("(%d) New connection from %s."), pkthdr.seskey, ether_ntoa((struct ether_addr*)&(pkthdr.srcaddr))); curconn = calloc(1, sizeof(struct mt_connection)); curconn->seskey = pkthdr.seskey; curconn->lastdata = time(NULL); curconn->state = STATE_AUTH; curconn->interface = interface; strncpy(curconn->interface_name, interface->name, 254); curconn->interface_name[255] = '\0'; memcpy(curconn->srcmac, pkthdr.srcaddr, ETH_ALEN); memcpy(curconn->srcip, &(address->sin_addr), IPV4_ALEN); curconn->srcport = htons(address->sin_port); memcpy(curconn->dstmac, pkthdr.dstaddr, ETH_ALEN); list_add_connection(curconn); init_packet(&pdata, MT_PTYPE_ACK, pkthdr.dstaddr, pkthdr.srcaddr, pkthdr.seskey, pkthdr.counter); send_udp(curconn, &pdata); break; case MT_PTYPE_END: curconn = list_find_connection(pkthdr.seskey, (unsigned char *)&(pkthdr.srcaddr)); if (curconn == NULL) { break; } if (curconn->state != STATE_CLOSED) { init_packet(&pdata, MT_PTYPE_END, pkthdr.dstaddr, pkthdr.srcaddr, pkthdr.seskey, pkthdr.counter); send_udp(curconn, &pdata); } syslog(LOG_DEBUG, _("(%d) Connection closed."), curconn->seskey); list_remove_connection(curconn); return; case MT_PTYPE_ACK: curconn = list_find_connection(pkthdr.seskey, (unsigned char *)&(pkthdr.srcaddr)); if (curconn == NULL) { break; } if (pkthdr.counter <= curconn->outcounter) { curconn->wait_for_ack = 0; curconn->lastack = pkthdr.counter; } if (time(0) - curconn->lastdata > 9 || pkthdr.counter == curconn->lastack) { // Answer to anti-timeout packet init_packet(&pdata, MT_PTYPE_ACK, pkthdr.dstaddr, pkthdr.srcaddr, pkthdr.seskey, pkthdr.counter); send_udp(curconn, &pdata); } curconn->lastdata = time(NULL); return; case MT_PTYPE_DATA: curconn = list_find_connection(pkthdr.seskey, (unsigned char *)&(pkthdr.srcaddr)); if (curconn == NULL) { break; } curconn->lastdata = time(NULL); /* ack the data packet */ init_packet(&pdata, MT_PTYPE_ACK, pkthdr.dstaddr, pkthdr.srcaddr, pkthdr.seskey, pkthdr.counter + (data_len - MT_HEADER_LEN)); send_udp(curconn, &pdata); /* Accept first packet, and all packets greater than incounter, and if counter has wrapped around. */ if (curconn->incounter == 0 || pkthdr.counter > curconn->incounter || (curconn->incounter - pkthdr.counter) > 16777216) { curconn->incounter = pkthdr.counter; } else { /* Ignore double or old packets */ return; } handle_data_packet(curconn, &pkthdr, data_len); break; default: if (curconn) { syslog(LOG_WARNING, _("(%d) Unhandeled packet type: %d"), curconn->seskey, pkthdr.ptype); init_packet(&pdata, MT_PTYPE_ACK, pkthdr.dstaddr, pkthdr.srcaddr, pkthdr.seskey, pkthdr.counter); send_udp(curconn, &pdata); } } if (0 && curconn != NULL) { printf("Packet, incounter %d, outcounter %d\n", curconn->incounter, curconn->outcounter); } } static void print_version() { fprintf(stderr, PROGRAM_NAME " " PROGRAM_VERSION "\n"); } void mndp_broadcast() { struct mt_packet pdata; struct utsname s_uname; struct net_interface *interface; unsigned int uptime; #ifdef __linux__ struct sysinfo s_sysinfo; if (sysinfo(&s_sysinfo) != 0) { return; } /* Seems like ping uptime is transmitted as little endian? */ uptime = htole32(s_sysinfo.uptime); #else struct timespec ts; if (clock_gettime(CLOCK_UPTIME, &ts) != -1) { uptime = htole32(((unsigned int)ts.tv_sec)); } #endif if (uname(&s_uname) != 0) { return; } DL_FOREACH(interfaces, interface) { struct mt_mndp_hdr *header = (struct mt_mndp_hdr *)&(pdata.data); if (interface->has_mac == 0) { continue; } mndp_init_packet(&pdata, 0, 1); mndp_add_attribute(&pdata, MT_MNDPTYPE_ADDRESS, interface->mac_addr, ETH_ALEN); mndp_add_attribute(&pdata, MT_MNDPTYPE_IDENTITY, s_uname.nodename, strlen(s_uname.nodename)); mndp_add_attribute(&pdata, MT_MNDPTYPE_VERSION, s_uname.release, strlen(s_uname.release)); mndp_add_attribute(&pdata, MT_MNDPTYPE_PLATFORM, PLATFORM_NAME, strlen(PLATFORM_NAME)); mndp_add_attribute(&pdata, MT_MNDPTYPE_HARDWARE, s_uname.machine, strlen(s_uname.machine)); mndp_add_attribute(&pdata, MT_MNDPTYPE_TIMESTAMP, &uptime, 4); mndp_add_attribute(&pdata, MT_MNDPTYPE_SOFTID, MT_SOFTID_MACTELNET, strlen(MT_SOFTID_MACTELNET)); mndp_add_attribute(&pdata, MT_MNDPTYPE_IFNAME, interface->name, strlen(interface->name)); header->cksum = in_cksum((unsigned short *)&(pdata.data), pdata.size); send_special_udp(interface, MT_MNDP_PORT, &pdata); } } void sigterm_handler() { struct mt_connection *p; struct mt_packet pdata; struct net_interface *interface, *tmp; /*_ Please include both \r and \n in translation, this is needed for the terminal emulator. */ char message[] = gettext_noop("\r\n\r\nDaemon shutting down.\r\n"); syslog(LOG_NOTICE, _("Daemon shutting down")); DL_FOREACH(connections_head, p) { if (p->state == STATE_ACTIVE) { init_packet(&pdata, MT_PTYPE_DATA, p->interface->mac_addr, p->srcmac, p->seskey, p->outcounter); add_control_packet(&pdata, MT_CPTYPE_PLAINDATA, _(message), strlen(_(message))); send_udp(p, &pdata); init_packet(&pdata, MT_PTYPE_END, p->interface->mac_addr, p->srcmac, p->seskey, p->outcounter); send_udp(p, &pdata); } } /* Doesn't hurt to tidy up */ close(sockfd); close(insockfd); if (!use_raw_socket) { DL_FOREACH(interfaces, interface) { if (interface->socketfd > 0) close(interface->socketfd); } } DL_FOREACH_SAFE(interfaces, interface, tmp) { DL_DELETE(interfaces, interface); free(interface); } closelog(); exit(0); } void sighup_handler() { struct mt_connection *p; syslog(LOG_NOTICE, _("SIGHUP: Reloading interfaces")); if (!use_raw_socket) { struct net_interface *interface, *tmp; DL_FOREACH_SAFE(interfaces, interface, tmp) { close(interface->socketfd); DL_DELETE(interfaces, interface); free(interface); } interfaces = NULL; } if (net_get_interfaces(&interfaces) <= 0) { syslog(LOG_ERR, _("No devices found! Exiting.\n")); exit(1); } setup_sockets(); /* Reassign outgoing interfaces to connections again, since they may have changed */ DL_FOREACH(connections_head, p) { if (p->interface_name != NULL) { struct net_interface *interface = net_get_interface_ptr(&interfaces, p->interface_name, 0); if (interface != NULL) { p->interface = interface; } else { struct mt_connection tmp; syslog(LOG_NOTICE, _("(%d) Connection closed because interface %s is gone."), p->seskey, p->interface_name); tmp.next = p->next; list_remove_connection(p); p = &tmp; } } } } /* * TODO: Rewrite main() when all sub-functionality is tested */ int main (int argc, char **argv) { int result; struct sockaddr_in si_me; struct sockaddr_in si_me_mndp; struct timeval timeout; struct mt_packet pdata; struct net_interface *interface; fd_set read_fds; int c,optval = 1; int print_help = 0; int foreground = 0; int interface_count = 0; setlocale(LC_ALL, ""); bindtextdomain("mactelnet","/usr/share/locale"); textdomain("mactelnet"); while ((c = getopt(argc, argv, "fnvh?")) != -1) { switch (c) { case 'f': foreground = 1; break; case 'n': use_raw_socket = 1; break; case 'v': print_version(); exit(0); break; case 'h': case '?': print_help = 1; break; } } if (print_help) { print_version(); fprintf(stderr, _("Usage: %s [-f|-n|-h]\n"), argv[0]); if (print_help) { fprintf(stderr, _("\nParameters:\n" " -f Run process in foreground.\n" " -n Do not use broadcast packets. Just a tad less insecure.\n" " -h This help.\n" "\n")); } return 1; } if (geteuid() != 0) { fprintf(stderr, _("You need to have root privileges to use %s.\n"), argv[0]); return 1; } /* Try to read user file */ read_userfile(); /* Seed randomizer */ srand(time(NULL)); if (use_raw_socket) { /* Transmit raw packets with this socket */ sockfd = net_init_raw_socket(); } /* Receive regular udp packets with this socket */ insockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (insockfd < 0) { perror("insockfd"); return 1; } /* Set source port */ sourceport = MT_MACTELNET_PORT; /* Listen address*/ inet_pton(AF_INET, (char *)"0.0.0.0", &sourceip); /* Set up global info about the connection */ inet_pton(AF_INET, (char *)"255.255.255.255", &destip); /* Initialize receiving socket on the device chosen */ memset((char *) &si_me, 0, sizeof(si_me)); si_me.sin_family = AF_INET; si_me.sin_port = htons(sourceport); memcpy(&(si_me.sin_addr), &sourceip, IPV4_ALEN); setsockopt(insockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (optval)); /* Bind to udp port */ if (bind(insockfd, (struct sockaddr *)&si_me, sizeof(si_me))==-1) { fprintf(stderr, _("Error binding to %s:%d, %s\n"), inet_ntoa(si_me.sin_addr), sourceport, strerror(errno)); return 1; } /* TODO: Move socket initialization out of main() */ /* Receive mndp udp packets with this socket */ mndpsockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (mndpsockfd < 0) { perror("mndpsockfd"); return 1; } memset((char *)&si_me_mndp, 0, sizeof(si_me_mndp)); si_me_mndp.sin_family = AF_INET; si_me_mndp.sin_port = htons(MT_MNDP_PORT); memcpy(&(si_me_mndp.sin_addr), &sourceip, IPV4_ALEN); setsockopt(mndpsockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (optval)); /* Bind to udp port */ if (bind(mndpsockfd, (struct sockaddr *)&si_me_mndp, sizeof(si_me_mndp))==-1) { fprintf(stderr, _("MNDP: Error binding to %s:%d, %s\n"), inet_ntoa(si_me_mndp.sin_addr), MT_MNDP_PORT, strerror(errno)); } openlog("mactelnetd", LOG_PID, LOG_DAEMON); syslog(LOG_NOTICE, _("Bound to %s:%d"), inet_ntoa(si_me.sin_addr), sourceport); /* Enumerate available interfaces */ net_get_interfaces(&interfaces); setup_sockets(); if (!foreground) { daemon(0, 0); } /* Handle zombies etc */ signal(SIGCHLD,SIG_IGN); signal(SIGTSTP,SIG_IGN); signal(SIGTTOU,SIG_IGN); signal(SIGTTIN,SIG_IGN); signal(SIGHUP, sighup_handler); signal(SIGTERM, sigterm_handler); DL_FOREACH(interfaces, interface) { if (interface->has_mac) { interface_count++; } } if (interface_count == 0) { syslog(LOG_ERR, _("Unable to find any valid network interfaces\n")); exit(1); } while (1) { int reads; struct mt_connection *p; int maxfd=0; time_t now; /* Init select */ FD_ZERO(&read_fds); FD_SET(insockfd, &read_fds); FD_SET(mndpsockfd, &read_fds); maxfd = insockfd > mndpsockfd ? insockfd : mndpsockfd; /* Add active connections to select queue */ DL_FOREACH(connections_head, p) { if (p->state == STATE_ACTIVE && p->wait_for_ack == 0 && p->ptsfd > 0) { FD_SET(p->ptsfd, &read_fds); if (p->ptsfd > maxfd) { maxfd = p->ptsfd; } } } timeout.tv_sec = 1; timeout.tv_usec = 0; /* Wait for data or timeout */ reads = select(maxfd+1, &read_fds, NULL, NULL, &timeout); if (reads > 0) { /* Handle data from clients TODO: Enable broadcast support (without raw sockets) */ if (FD_ISSET(insockfd, &read_fds)) { unsigned char buff[1500]; struct sockaddr_in saddress; unsigned int slen = sizeof(saddress); result = recvfrom(insockfd, buff, 1500, 0, (struct sockaddr *)&saddress, &slen); handle_packet(buff, result, &saddress); } if (FD_ISSET(mndpsockfd, &read_fds)) { unsigned char buff[1500]; struct sockaddr_in saddress; unsigned int slen = sizeof(saddress); result = recvfrom(mndpsockfd, buff, 1500, 0, (struct sockaddr *)&saddress, &slen); /* Handle MNDP broadcast request, max 1 rps */ if (result == 4 && time(NULL) - last_mndp_time > 0) { mndp_broadcast(); time(&last_mndp_time); } } /* Handle data from terminal sessions */ DL_FOREACH(connections_head, p) { /* Check if we have data ready in the pty buffer for the active session */ if (p->state == STATE_ACTIVE && p->ptsfd > 0 && p->wait_for_ack == 0 && FD_ISSET(p->ptsfd, &read_fds)) { unsigned char keydata[1024]; int datalen,plen; /* Read it */ datalen = read(p->ptsfd, &keydata, 1024); if (datalen > 0) { /* Send it */ init_packet(&pdata, MT_PTYPE_DATA, p->dstmac, p->srcmac, p->seskey, p->outcounter); plen = add_control_packet(&pdata, MT_CPTYPE_PLAINDATA, &keydata, datalen); p->outcounter += plen; p->wait_for_ack = 1; result = send_udp(p, &pdata); } else { /* Shell exited */ struct mt_connection tmp; init_packet(&pdata, MT_PTYPE_END, p->dstmac, p->srcmac, p->seskey, p->outcounter); send_udp(p, &pdata); if (p->username != NULL) { syslog(LOG_INFO, _("(%d) Connection to user %s closed."), p->seskey, p->username); } else { syslog(LOG_INFO, _("(%d) Connection closed."), p->seskey); } tmp.next = p->next; list_remove_connection(p); p = &tmp; } } else if (p->state == STATE_ACTIVE && p->ptsfd > 0 && p->wait_for_ack == 1 && FD_ISSET(p->ptsfd, &read_fds)) { printf(_("(%d) Waiting for ack\n"), p->seskey); } } /* Handle select() timeout */ } time(&now); if (now - last_mndp_time > MT_MNDP_BROADCAST_INTERVAL) { pings = 0; mndp_broadcast(); last_mndp_time = now; } if (connections_head != NULL) { struct mt_connection *p,tmp; DL_FOREACH(connections_head, p) { if (now - p->lastdata >= MT_CONNECTION_TIMEOUT) { syslog(LOG_INFO, _("(%d) Session timed out"), p->seskey); init_packet(&pdata, MT_PTYPE_DATA, p->dstmac, p->srcmac, p->seskey, p->outcounter); /*_ Please include both \r and \n in translation, this is needed for the terminal emulator. */ add_control_packet(&pdata, MT_CPTYPE_PLAINDATA, _("Timeout\r\n"), 9); send_udp(p, &pdata); init_packet(&pdata, MT_PTYPE_END, p->dstmac, p->srcmac, p->seskey, p->outcounter); send_udp(p, &pdata); tmp.next = p->next; list_remove_connection(p); p = &tmp; } } } } /* Never reached */ return 0; } mactelnet-0.4.2/autologin.c0000664000175100017630000001314712622313406014310 0ustar haakoncy/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include #include "autologin.h" #include "config.h" #define _(String) gettext (String) struct autologin_profile login_profiles[AUTOLOGIN_MAXPROFILES]; struct autologin_profile *autologin_find_profile(char *identifier) { int i; struct autologin_profile *default_profile = NULL; if (strlen(identifier) == 0) return NULL; for (i = 0; i < AUTOLOGIN_MAXPROFILES; ++i) { if (login_profiles[i].inuse && strcasecmp(identifier, login_profiles[i].identifier) == 0) { return &login_profiles[i]; } if (login_profiles[i].inuse && strcasecmp("default", login_profiles[i].identifier) == 0) { default_profile = &login_profiles[i]; } } return default_profile; } static char *tilde_to_path(char *path) { char *homepath; if (*path == '~' && (homepath = getenv("HOME"))) { static char newpath[256]; memset(newpath, 0, sizeof(newpath)); strncpy(newpath, homepath, 255); strncat(newpath, path+1, 255); return newpath; } return path; } int autologin_readfile(char *configfile) { FILE *fp; char c; int i = -1; char *p; char *file_to_read; char key[AUTOLOGIN_MAXSTR]; char value[AUTOLOGIN_MAXSTR]; int line_counter=1; enum autologin_state state = ALS_NONE; memset(login_profiles, 0, sizeof(login_profiles)); /* Convert ~/path to /home/username/path */ file_to_read = tilde_to_path(configfile); fp = fopen(file_to_read, "r"); if (fp <= 0) { if (strcmp(configfile, AUTOLOGIN_PATH) == 0) { /* Silent ignore? */ } else { fprintf(stderr, _("Error opening autologin file %s: %s\n"), file_to_read, strerror(errno)); } return 0; } while ((c = fgetc(fp)) && !feof(fp)) { if (c == '#') { while ((c = fgetc(fp)) != '\n' && !feof(fp)); } switch (state) { case ALS_PREIDENTIFIER: i++; if (i == AUTOLOGIN_MAXPROFILES) { goto done; } p = login_profiles[i].identifier; state++; break; case ALS_PREKEY: memset(key, 0, AUTOLOGIN_MAXSTR); memset(value, 0, AUTOLOGIN_MAXSTR); p = key; login_profiles[i].inuse = 1; state++; break; case ALS_PREVALUE: memset(value, 0, AUTOLOGIN_MAXSTR); p = value; state++; break; default: break; } switch (state) { case ALS_NONE: if (c == '[') { state = ALS_PREIDENTIFIER; } break; case ALS_IDENTIFIER: if (c == ']') { state = ALS_PREKEY; break; } if (c == '\n') { fprintf(stderr, _("Error on line %d in %s: New line in middle of identifier\n"), line_counter, configfile); state = ALS_NONE; break; } *p++ = c; if (p - login_profiles[i].identifier == AUTOLOGIN_MAXSTR-1) { *p = 0; fprintf(stderr, _("Error on line %d in %s: Identifier string too long.\n"), line_counter, configfile); while ((c = fgetc(fp)) != '\n' && c != ']' && !feof(fp)); state = ALS_PREKEY; break; } break; case ALS_KEY: if (p == key && c == '\n') break; if (c == '=') { state = ALS_PREVALUE; break; } if (c == '[') { state = ALS_PREIDENTIFIER; break; } if (c == ' ') { /* ignore whitespace */ break; } if (c == '\n') { fprintf(stderr, _("Error on line %d in %s: Newline before '=' character\n"), line_counter, configfile); state = ALS_PREKEY; break; } *p++ = c; if (p - key == AUTOLOGIN_MAXSTR-1) { *p = 0; fprintf(stderr, _("Error on line %d in %s: Key string too long.\n"), line_counter, configfile); while ((c = fgetc(fp)) != '\n' && c != '=' && !feof(fp)); if (c == '\n') { state = ALS_PREKEY; } else { state = ALS_PREVALUE; } } break; case ALS_VALUE: if (p == value && c == '\n') break; if (c == '\n') { if (strncasecmp(key, "user", AUTOLOGIN_MAXSTR) == 0) { strncpy(login_profiles[i].username, value, AUTOLOGIN_MAXSTR); login_profiles[i].hasUsername = 1; } else if (strncasecmp(key, "password", AUTOLOGIN_MAXSTR) == 0) { strncpy(login_profiles[i].password, value, AUTOLOGIN_MAXSTR); login_profiles[i].hasPassword = 1; } else { fprintf(stderr, _("Warning on line %d of %s: Unknown parameter %s, ignoring.\n"), line_counter, configfile, key); } state = ALS_PREKEY; break; } if (c == ' ') { /* ignore whitespace */ break; } *p++ = c; if (p - value == AUTOLOGIN_MAXSTR-1) { *p = 0; fprintf(stderr, _("Error on line %d in %s: Value string too long.\n"), line_counter, configfile); while ((c = fgetc(fp)) != '\n' && !feof(fp)); if (c == '\n') { state = ALS_PREKEY; } } break; default: break; } if (c == '\n') { line_counter++; } if (feof(fp)) { break; } } done: fclose(fp); return 1; } mactelnet-0.4.2/autologin.h0000664000175100017630000000263412622313406014314 0ustar haakoncy/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define AUTOLOGIN_MAXSTR 100 #define AUTOLOGIN_MAXPROFILES 100 struct autologin_profile { char identifier[AUTOLOGIN_MAXSTR]; char username[AUTOLOGIN_MAXSTR]; char password[AUTOLOGIN_MAXSTR]; char inuse:1; char hasUsername:1; char hasPassword:1; }; enum autologin_state { ALS_NONE, ALS_PREIDENTIFIER, ALS_IDENTIFIER, ALS_PREKEY, ALS_KEY, ALS_PREVALUE, ALS_VALUE }; extern struct autologin_profile login_profiles[AUTOLOGIN_MAXPROFILES]; struct autologin_profile *autologin_find_profile(char *identifier); int autologin_readfile(char *configfile); mactelnet-0.4.2/utlist.h0000664000175100017630000015511212622313406013637 0ustar haakoncy/* Copyright (c) 2007-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef UTLIST_H #define UTLIST_H #define UTLIST_VERSION 1.9.9 #include /* * This file contains macros to manipulate singly and doubly-linked lists. * * 1. LL_ macros: singly-linked lists. * 2. DL_ macros: doubly-linked lists. * 3. CDL_ macros: circular doubly-linked lists. * * To use singly-linked lists, your structure must have a "next" pointer. * To use doubly-linked lists, your structure must "prev" and "next" pointers. * Either way, the pointer to the head of the list must be initialized to NULL. * * ----------------.EXAMPLE ------------------------- * struct item { * int id; * struct item *prev, *next; * } * * struct item *list = NULL: * * int main() { * struct item *item; * ... allocate and populate item ... * DL_APPEND(list, item); * } * -------------------------------------------------- * * For doubly-linked lists, the append and delete macros are O(1) * For singly-linked lists, append and delete are O(n) but prepend is O(1) * The sort macro is O(n log(n)) for all types of single/double/circular lists. */ /* These macros use decltype or the earlier __typeof GNU extension. As decltype is only available in newer compilers (VS2010 or gcc 4.3+ when compiling c++ code), this code uses whatever method is needed or, for VS2008 where neither is available, uses casting workarounds. */ #ifdef _MSC_VER /* MS compiler */ #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ #define LDECLTYPE(x) decltype(x) #else /* VS2008 or older (or VS2010 in C mode) */ #define NO_DECLTYPE #define LDECLTYPE(x) char* #endif #elif defined(__ICCARM__) #define NO_DECLTYPE #define LDECLTYPE(x) char* #else /* GNU, Sun and other compilers */ #define LDECLTYPE(x) __typeof(x) #endif /* for VS2008 we use some workarounds to get around the lack of decltype, * namely, we always reassign our tmp variable to the list head if we need * to dereference its prev/next pointers, and save/restore the real head.*/ #ifdef NO_DECLTYPE #define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); } #define _NEXT(elt,list,next) ((char*)((list)->next)) #define _NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); } /* #define _PREV(elt,list,prev) ((char*)((list)->prev)) */ #define _PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); } #define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; } #define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); } #else #define _SV(elt,list) #define _NEXT(elt,list,next) ((elt)->next) #define _NEXTASGN(elt,list,to,next) ((elt)->next)=(to) /* #define _PREV(elt,list,prev) ((elt)->prev) */ #define _PREVASGN(elt,list,to,prev) ((elt)->prev)=(to) #define _RS(list) #define _CASTASGN(a,b) (a)=(b) #endif /****************************************************************************** * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort * * Unwieldy variable names used here to avoid shadowing passed-in variables. * *****************************************************************************/ #define LL_SORT(list, cmp) \ LL_SORT2(list, cmp, next) #define LL_SORT2(list, cmp, next) \ do { \ LDECLTYPE(list) _ls_p; \ LDECLTYPE(list) _ls_q; \ LDECLTYPE(list) _ls_e; \ LDECLTYPE(list) _ls_tail; \ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ if (list) { \ _ls_insize = 1; \ _ls_looping = 1; \ while (_ls_looping) { \ _CASTASGN(_ls_p,list); \ list = NULL; \ _ls_tail = NULL; \ _ls_nmerges = 0; \ while (_ls_p) { \ _ls_nmerges++; \ _ls_q = _ls_p; \ _ls_psize = 0; \ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ _ls_psize++; \ _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \ if (!_ls_q) break; \ } \ _ls_qsize = _ls_insize; \ while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ if (_ls_psize == 0) { \ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ } else if (_ls_qsize == 0 || !_ls_q) { \ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ } else if (cmp(_ls_p,_ls_q) <= 0) { \ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ } else { \ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ } \ if (_ls_tail) { \ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ } else { \ _CASTASGN(list,_ls_e); \ } \ _ls_tail = _ls_e; \ } \ _ls_p = _ls_q; \ } \ if (_ls_tail) { \ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \ } \ if (_ls_nmerges <= 1) { \ _ls_looping=0; \ } \ _ls_insize *= 2; \ } \ } \ } while (0) #define DL_SORT(list, cmp) \ DL_SORT2(list, cmp, prev, next) #define DL_SORT2(list, cmp, prev, next) \ do { \ LDECLTYPE(list) _ls_p; \ LDECLTYPE(list) _ls_q; \ LDECLTYPE(list) _ls_e; \ LDECLTYPE(list) _ls_tail; \ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ if (list) { \ _ls_insize = 1; \ _ls_looping = 1; \ while (_ls_looping) { \ _CASTASGN(_ls_p,list); \ list = NULL; \ _ls_tail = NULL; \ _ls_nmerges = 0; \ while (_ls_p) { \ _ls_nmerges++; \ _ls_q = _ls_p; \ _ls_psize = 0; \ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ _ls_psize++; \ _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \ if (!_ls_q) break; \ } \ _ls_qsize = _ls_insize; \ while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ if (_ls_psize == 0) { \ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ } else if (_ls_qsize == 0 || !_ls_q) { \ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ } else if (cmp(_ls_p,_ls_q) <= 0) { \ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ } else { \ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ } \ if (_ls_tail) { \ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ } else { \ _CASTASGN(list,_ls_e); \ } \ _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \ _ls_tail = _ls_e; \ } \ _ls_p = _ls_q; \ } \ _CASTASGN(list->prev, _ls_tail); \ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \ if (_ls_nmerges <= 1) { \ _ls_looping=0; \ } \ _ls_insize *= 2; \ } \ } \ } while (0) #define CDL_SORT(list, cmp) \ CDL_SORT2(list, cmp, prev, next) #define CDL_SORT2(list, cmp, prev, next) \ do { \ LDECLTYPE(list) _ls_p; \ LDECLTYPE(list) _ls_q; \ LDECLTYPE(list) _ls_e; \ LDECLTYPE(list) _ls_tail; \ LDECLTYPE(list) _ls_oldhead; \ LDECLTYPE(list) _tmp; \ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ if (list) { \ _ls_insize = 1; \ _ls_looping = 1; \ while (_ls_looping) { \ _CASTASGN(_ls_p,list); \ _CASTASGN(_ls_oldhead,list); \ list = NULL; \ _ls_tail = NULL; \ _ls_nmerges = 0; \ while (_ls_p) { \ _ls_nmerges++; \ _ls_q = _ls_p; \ _ls_psize = 0; \ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ _ls_psize++; \ _SV(_ls_q,list); \ if (_NEXT(_ls_q,list,next) == _ls_oldhead) { \ _ls_q = NULL; \ } else { \ _ls_q = _NEXT(_ls_q,list,next); \ } \ _RS(list); \ if (!_ls_q) break; \ } \ _ls_qsize = _ls_insize; \ while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ if (_ls_psize == 0) { \ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ } else if (_ls_qsize == 0 || !_ls_q) { \ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ } else if (cmp(_ls_p,_ls_q) <= 0) { \ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ } else { \ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ } \ if (_ls_tail) { \ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ } else { \ _CASTASGN(list,_ls_e); \ } \ _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \ _ls_tail = _ls_e; \ } \ _ls_p = _ls_q; \ } \ _CASTASGN(list->prev,_ls_tail); \ _CASTASGN(_tmp,list); \ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp,next); _RS(list); \ if (_ls_nmerges <= 1) { \ _ls_looping=0; \ } \ _ls_insize *= 2; \ } \ } \ } while (0) /****************************************************************************** * singly linked list macros (non-circular) * *****************************************************************************/ #define LL_PREPEND(head,add) \ LL_PREPEND2(head,add,next) #define LL_PREPEND2(head,add,next) \ do { \ (add)->next = head; \ head = add; \ } while (0) #define LL_CONCAT(head1,head2) \ LL_CONCAT2(head1,head2,next) #define LL_CONCAT2(head1,head2,next) \ do { \ LDECLTYPE(head1) _tmp; \ if (head1) { \ _tmp = head1; \ while (_tmp->next) { _tmp = _tmp->next; } \ _tmp->next=(head2); \ } else { \ (head1)=(head2); \ } \ } while (0) #define LL_APPEND(head,add) \ LL_APPEND2(head,add,next) #define LL_APPEND2(head,add,next) \ do { \ LDECLTYPE(head) _tmp; \ (add)->next=NULL; \ if (head) { \ _tmp = head; \ while (_tmp->next) { _tmp = _tmp->next; } \ _tmp->next=(add); \ } else { \ (head)=(add); \ } \ } while (0) #define LL_DELETE(head,del) \ LL_DELETE2(head,del,next) #define LL_DELETE2(head,del,next) \ do { \ LDECLTYPE(head) _tmp; \ if ((head) == (del)) { \ (head)=(head)->next; \ } else { \ _tmp = head; \ while (_tmp->next && (_tmp->next != (del))) { \ _tmp = _tmp->next; \ } \ if (_tmp->next) { \ _tmp->next = ((del)->next); \ } \ } \ } while (0) /* Here are VS2008 replacements for LL_APPEND and LL_DELETE */ #define LL_APPEND_VS2008(head,add) \ LL_APPEND2_VS2008(head,add,next) #define LL_APPEND2_VS2008(head,add,next) \ do { \ if (head) { \ (add)->next = head; /* use add->next as a temp variable */ \ while ((add)->next->next) { (add)->next = (add)->next->next; } \ (add)->next->next=(add); \ } else { \ (head)=(add); \ } \ (add)->next=NULL; \ } while (0) #define LL_DELETE_VS2008(head,del) \ LL_DELETE2_VS2008(head,del,next) #define LL_DELETE2_VS2008(head,del,next) \ do { \ if ((head) == (del)) { \ (head)=(head)->next; \ } else { \ char *_tmp = (char*)(head); \ while ((head)->next && ((head)->next != (del))) { \ head = (head)->next; \ } \ if ((head)->next) { \ (head)->next = ((del)->next); \ } \ { \ char **_head_alias = (char**)&(head); \ *_head_alias = _tmp; \ } \ } \ } while (0) #ifdef NO_DECLTYPE #undef LL_APPEND #define LL_APPEND LL_APPEND_VS2008 #undef LL_DELETE #define LL_DELETE LL_DELETE_VS2008 #undef LL_DELETE2 #define LL_DELETE2 LL_DELETE2_VS2008 #undef LL_APPEND2 #define LL_APPEND2 LL_APPEND2_VS2008 #undef LL_CONCAT /* no LL_CONCAT_VS2008 */ #undef DL_CONCAT /* no DL_CONCAT_VS2008 */ #endif /* end VS2008 replacements */ #define LL_COUNT(head,el,counter) \ LL_COUNT2(head,el,counter,next) \ #define LL_COUNT2(head,el,counter,next) \ { \ counter = 0; \ LL_FOREACH2(head,el,next){ ++counter; } \ } #define LL_FOREACH(head,el) \ LL_FOREACH2(head,el,next) #define LL_FOREACH2(head,el,next) \ for(el=head;el;el=(el)->next) #define LL_FOREACH_SAFE(head,el,tmp) \ LL_FOREACH_SAFE2(head,el,tmp,next) #define LL_FOREACH_SAFE2(head,el,tmp,next) \ for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) #define LL_SEARCH_SCALAR(head,out,field,val) \ LL_SEARCH_SCALAR2(head,out,field,val,next) #define LL_SEARCH_SCALAR2(head,out,field,val,next) \ do { \ LL_FOREACH2(head,out,next) { \ if ((out)->field == (val)) break; \ } \ } while(0) #define LL_SEARCH(head,out,elt,cmp) \ LL_SEARCH2(head,out,elt,cmp,next) #define LL_SEARCH2(head,out,elt,cmp,next) \ do { \ LL_FOREACH2(head,out,next) { \ if ((cmp(out,elt))==0) break; \ } \ } while(0) #define LL_REPLACE_ELEM(head, el, add) \ do { \ LDECLTYPE(head) _tmp; \ assert(head != NULL); \ assert(el != NULL); \ assert(add != NULL); \ (add)->next = (el)->next; \ if ((head) == (el)) { \ (head) = (add); \ } else { \ _tmp = head; \ while (_tmp->next && (_tmp->next != (el))) { \ _tmp = _tmp->next; \ } \ if (_tmp->next) { \ _tmp->next = (add); \ } \ } \ } while (0) #define LL_PREPEND_ELEM(head, el, add) \ do { \ LDECLTYPE(head) _tmp; \ assert(head != NULL); \ assert(el != NULL); \ assert(add != NULL); \ (add)->next = (el); \ if ((head) == (el)) { \ (head) = (add); \ } else { \ _tmp = head; \ while (_tmp->next && (_tmp->next != (el))) { \ _tmp = _tmp->next; \ } \ if (_tmp->next) { \ _tmp->next = (add); \ } \ } \ } while (0) \ /****************************************************************************** * doubly linked list macros (non-circular) * *****************************************************************************/ #define DL_PREPEND(head,add) \ DL_PREPEND2(head,add,prev,next) #define DL_PREPEND2(head,add,prev,next) \ do { \ (add)->next = head; \ if (head) { \ (add)->prev = (head)->prev; \ (head)->prev = (add); \ } else { \ (add)->prev = (add); \ } \ (head) = (add); \ } while (0) #define DL_APPEND(head,add) \ DL_APPEND2(head,add,prev,next) #define DL_APPEND2(head,add,prev,next) \ do { \ if (head) { \ (add)->prev = (head)->prev; \ (head)->prev->next = (add); \ (head)->prev = (add); \ (add)->next = NULL; \ } else { \ (head)=(add); \ (head)->prev = (head); \ (head)->next = NULL; \ } \ } while (0) #define DL_CONCAT(head1,head2) \ DL_CONCAT2(head1,head2,prev,next) #define DL_CONCAT2(head1,head2,prev,next) \ do { \ LDECLTYPE(head1) _tmp; \ if (head2) { \ if (head1) { \ _tmp = (head2)->prev; \ (head2)->prev = (head1)->prev; \ (head1)->prev->next = (head2); \ (head1)->prev = _tmp; \ } else { \ (head1)=(head2); \ } \ } \ } while (0) #define DL_DELETE(head,del) \ DL_DELETE2(head,del,prev,next) #define DL_DELETE2(head,del,prev,next) \ do { \ assert((del)->prev != NULL); \ if ((del)->prev == (del)) { \ (head)=NULL; \ } else if ((del)==(head)) { \ (del)->next->prev = (del)->prev; \ (head) = (del)->next; \ } else { \ (del)->prev->next = (del)->next; \ if ((del)->next) { \ (del)->next->prev = (del)->prev; \ } else { \ (head)->prev = (del)->prev; \ } \ } \ } while (0) #define DL_COUNT(head,el,counter) \ DL_COUNT2(head,el,counter,next) \ #define DL_COUNT2(head,el,counter,next) \ { \ counter = 0; \ DL_FOREACH2(head,el,next){ ++counter; } \ } #define DL_FOREACH(head,el) \ DL_FOREACH2(head,el,next) #define DL_FOREACH2(head,el,next) \ for(el=head;el;el=(el)->next) /* this version is safe for deleting the elements during iteration */ #define DL_FOREACH_SAFE(head,el,tmp) \ DL_FOREACH_SAFE2(head,el,tmp,next) #define DL_FOREACH_SAFE2(head,el,tmp,next) \ for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) /* these are identical to their singly-linked list counterparts */ #define DL_SEARCH_SCALAR LL_SEARCH_SCALAR #define DL_SEARCH LL_SEARCH #define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2 #define DL_SEARCH2 LL_SEARCH2 #define DL_REPLACE_ELEM(head, el, add) \ do { \ assert(head != NULL); \ assert(el != NULL); \ assert(add != NULL); \ if ((head) == (el)) { \ (head) = (add); \ (add)->next = (el)->next; \ if ((el)->next == NULL) { \ (add)->prev = (add); \ } else { \ (add)->prev = (el)->prev; \ (add)->next->prev = (add); \ } \ } else { \ (add)->next = (el)->next; \ (add)->prev = (el)->prev; \ (add)->prev->next = (add); \ if ((el)->next == NULL) { \ (head)->prev = (add); \ } else { \ (add)->next->prev = (add); \ } \ } \ } while (0) #define DL_PREPEND_ELEM(head, el, add) \ do { \ assert(head != NULL); \ assert(el != NULL); \ assert(add != NULL); \ (add)->next = (el); \ (add)->prev = (el)->prev; \ (el)->prev = (add); \ if ((head) == (el)) { \ (head) = (add); \ } else { \ (add)->prev->next = (add); \ } \ } while (0) \ /****************************************************************************** * circular doubly linked list macros * *****************************************************************************/ #define CDL_PREPEND(head,add) \ CDL_PREPEND2(head,add,prev,next) #define CDL_PREPEND2(head,add,prev,next) \ do { \ if (head) { \ (add)->prev = (head)->prev; \ (add)->next = (head); \ (head)->prev = (add); \ (add)->prev->next = (add); \ } else { \ (add)->prev = (add); \ (add)->next = (add); \ } \ (head)=(add); \ } while (0) #define CDL_DELETE(head,del) \ CDL_DELETE2(head,del,prev,next) #define CDL_DELETE2(head,del,prev,next) \ do { \ if ( ((head)==(del)) && ((head)->next == (head))) { \ (head) = 0L; \ } else { \ (del)->next->prev = (del)->prev; \ (del)->prev->next = (del)->next; \ if ((del) == (head)) (head)=(del)->next; \ } \ } while (0) #define CDL_COUNT(head,el,counter) \ CDL_COUNT2(head,el,counter,next) \ #define CDL_COUNT2(head, el, counter,next) \ { \ counter = 0; \ CDL_FOREACH2(head,el,next){ ++counter; } \ } #define CDL_FOREACH(head,el) \ CDL_FOREACH2(head,el,next) #define CDL_FOREACH2(head,el,next) \ for(el=head;el;el=((el)->next==head ? 0L : (el)->next)) #define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \ CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) #define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) \ for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL); \ (el) && ((tmp2)=(el)->next, 1); \ ((el) = (((el)==(tmp1)) ? 0L : (tmp2)))) #define CDL_SEARCH_SCALAR(head,out,field,val) \ CDL_SEARCH_SCALAR2(head,out,field,val,next) #define CDL_SEARCH_SCALAR2(head,out,field,val,next) \ do { \ CDL_FOREACH2(head,out,next) { \ if ((out)->field == (val)) break; \ } \ } while(0) #define CDL_SEARCH(head,out,elt,cmp) \ CDL_SEARCH2(head,out,elt,cmp,next) #define CDL_SEARCH2(head,out,elt,cmp,next) \ do { \ CDL_FOREACH2(head,out,next) { \ if ((cmp(out,elt))==0) break; \ } \ } while(0) #define CDL_REPLACE_ELEM(head, el, add) \ do { \ assert(head != NULL); \ assert(el != NULL); \ assert(add != NULL); \ if ((el)->next == (el)) { \ (add)->next = (add); \ (add)->prev = (add); \ (head) = (add); \ } else { \ (add)->next = (el)->next; \ (add)->prev = (el)->prev; \ (add)->next->prev = (add); \ (add)->prev->next = (add); \ if ((head) == (el)) { \ (head) = (add); \ } \ } \ } while (0) #define CDL_PREPEND_ELEM(head, el, add) \ do { \ assert(head != NULL); \ assert(el != NULL); \ assert(add != NULL); \ (add)->next = (el); \ (add)->prev = (el)->prev; \ (el)->prev = (add); \ (add)->prev->next = (add); \ if ((head) == (el)) { \ (head) = (add); \ } \ } while (0) \ #endif /* UTLIST_H */ mactelnet-0.4.2/README.markdown0000664000175100017630000000566712622313406014654 0ustar haakoncyMAC-Telnet for Linux ==================== Console tools for connecting to, and serving, devices using MikroTik RouterOS MAC-Telnet protocol. Installation ------------ Then download source tarball, extract, compile and install: wget http://github.com/haakonnessjoen/MAC-Telnet/tarball/master tar zxvf haakonness*.tar.gz cd haakonness*/ make all install Now you're ready. TIP: You can use the well known "expect" tool to automate/script dialogues via mactelnet! Usage ----- # mactelnet -h Usage: mactelnet [-h] [-n] [-t ] [-u ] [-p ] [-U ] | -l Parameters: MAC MAC-Address of the RouterOS/mactelnetd device. Use mndp to discover it. identity The identity/name of your destination device. Uses MNDP protocol to find it. -l List/Search for routers nearby. (using MNDP) -n Do not use broadcast packets. Less insecure but requires root privileges. -t Amount of seconds to wait for a response on each interface. -u Specify username on command line. -p Specify password on command line. -U Drop privileges to this user. Used in conjunction with -n for security. -q Quiet mode. -h This help. Example: $ mactelnet 0:c:42:43:58:a5 -u admin Password: Connecting to 0:c:42:43:58:a5...done MMM MMM KKK TTTTTTTTTTT KKK MMMM MMMM KKK TTTTTTTTTTT KKK MMM MMMM MMM III KKK KKK RRRRRR OOOOOO TTT III KKK KKK MMM MM MMM III KKKKK RRR RRR OOO OOO TTT III KKKKK MMM MMM III KKK KKK RRRRRR OOO OOO TTT III KKK KKK MMM MMM III KKK KKK RRR RRR OOOOOO TTT III KKK KKK MikroTik RouterOS 4.0 (c) 1999-2009 http://www.mikrotik.com/ [admin@HMG] > MAC-Ping usage -------------- # macping -h Usage: macping [-h] [-c ] [-s ] Parameters: MAC MAC-Address of the RouterOS/mactelnetd device. -s Specify size of ping packet. -c Number of packets to send. (0 = for ever) -h This help. Example: # macping 0:c:42:43:58:a5 0:c:42:43:58:a5 56 byte, ping time 1.17 ms 0:c:42:43:58:a5 56 byte, ping time 1.07 ms 0:c:42:43:58:a5 56 byte, ping time 1.20 ms 0:c:42:43:58:a5 56 byte, ping time 0.65 ms 0:c:42:43:58:a5 56 byte, ping time 1.19 ms 5 packets transmitted, 5 packets received, 0% packet loss round-trip min/avg/max = 0.65/1.06/1.20 ms Or for use in bash-scripting: # macping 0:c:42:43:58:a5 -c 2 >/dev/null 2>&1 || ( echo "No answer for 2 pings" | mail -s "router down" my.email@address.com ) mactelnet-0.4.2/interfaces.h0000664000175100017630000000341112622313406014430 0ustar haakoncy/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _INTERFACES_H #define _INTERFACES_H 1 #define MAX_INTERFACES 32 struct net_interface { char name[256]; unsigned char ipv4_addr[IPV4_ALEN]; unsigned char mac_addr[ETH_ALEN]; /* used by mactelnetd */ int socketfd; #ifdef __linux__ int ifindex; #endif int has_mac; int in_use; struct net_interface *prev; struct net_interface *next; }; extern int net_get_interfaces(struct net_interface **interfaces); extern struct net_interface *net_get_interface_ptr(struct net_interface **interfaces, char *name, int create); extern int net_init_raw_socket(); extern int net_send_udp(const int socket, struct net_interface *interface, const unsigned char *sourcemac, const unsigned char *destmac, const struct in_addr *sourceip, const int sourceport, const struct in_addr *destip, const int destport, const unsigned char *data, const int datalen); extern unsigned short in_cksum(unsigned short *addr, int len); #endif mactelnet-0.4.2/console.c0000664000175100017630000000415012622313406013743 0ustar haakoncy/* Mac-Telnet - Connect to RouterOS or mactelnetd devices via MAC address Copyright (C) 2010, Håkon Nessjøen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include struct termios orig_term; int raw_term() { struct termios new; if (tcgetattr(STDIN_FILENO, &orig_term) < 0) { perror("tcgetattr"); return -1; } memcpy(&new, &orig_term, sizeof(struct termios) ); /* raw mode, from tcsetattr man page */ new.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); new.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); new.c_cflag &= ~(CSIZE|PARENB); new.c_cflag |= CS8; if (tcsetattr(STDIN_FILENO, TCSANOW, &new) < 0) { perror("tcsetattr"); return -1; } return 0; } int reset_term() { if (tcsetattr(STDIN_FILENO, TCSANOW, &orig_term) < 0) { perror("tcsetattr"); return -1; } return 0; } int get_terminal_size(unsigned short *width, unsigned short *height) { struct winsize ws; if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) != 0) { perror("TIOCGWINSZ"); return -1; } *width = ws.ws_col; *height = ws.ws_row; return 0; } int set_terminal_size(int fd, unsigned short width, unsigned short height) { struct winsize ws; ws.ws_col = width; ws.ws_row = height; if (ioctl(fd, TIOCSWINSZ, &ws) != 0) { perror("TIOCSWINSZ"); return -1; } return 0; }