finger.c (2716B)
1 /* Copyright (c) 2021 hhvn <dev@hhvn.uk> */ 2 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <string.h> 6 #include <stdarg.h> 7 #include <libgen.h> 8 #include <unistd.h> 9 #include <netdb.h> 10 #include <errno.h> 11 #include <sys/types.h> 12 #include <sys/socket.h> 13 #include "arg.h" 14 15 #define EXIT_USAGE 2 16 #ifndef __OpenBSD__ 17 #define pledge(a,b) 0 18 #endif 19 20 enum { ISUSER, ISHOST, ISPORT }; 21 char *user_dflt = ""; 22 char *host_dflt = "localhost"; 23 char *port_dflt = "79"; 24 25 char *argv0; 26 int verbose = 0; 27 28 void 29 usage(void) { 30 fprintf(stderr, "usage: %s [-lv] [user]@[host[:port]] ...\n", basename(argv0)); 31 exit(EXIT_USAGE); 32 } 33 34 void 35 die(const int exitc, const char *format, ...) { 36 va_list ap; 37 38 va_start(ap, format); 39 fprintf(stderr, "Fatal: "); 40 vfprintf(stderr, format, ap); 41 va_end(ap); 42 43 exit(exitc); 44 } 45 46 void 47 finger(char *user, char *host, char *port, int w) { 48 struct addrinfo hints; 49 struct addrinfo *ai; 50 char buf; 51 int sret, sock; 52 53 memset(&hints, 0, sizeof(hints)); 54 hints.ai_family = AF_UNSPEC; 55 hints.ai_socktype = SOCK_STREAM; 56 57 if ((sret = getaddrinfo(host, port, &hints, &ai)) != 0 || ai == NULL) 58 die(1, "%s%s: %s:%s\n", verbose ? "getaddrinfo(): " : "", gai_strerror(sret), host, port); 59 if ((sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) == 1) 60 die(1, "%s%s: %s:%s\n", verbose ? "socket(): " : "", strerror(errno), host, port); 61 if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) 62 die(1, "%s%s: %s:%s\n", verbose ? "connect(): " : "", strerror(errno), host, port); 63 64 freeaddrinfo(ai); 65 66 if (strcmp(port, "79") == 0) 67 printf("[%s@%s]\n", user, host); 68 else 69 printf("[%s@%s:%s]\n", user, host, port); 70 71 dprintf(sock, "%s\r\n", user); 72 while (read(sock, &buf, sizeof(char)) != 0) 73 if (buf != '\r') 74 printf("%c", buf); 75 76 printf("\n"); /* add extra newline */ 77 } 78 79 int 80 main(int argc, char *argv[]) { 81 char *user, 82 *host, 83 *port; 84 int sendw = 0; 85 int segment; 86 int i; 87 88 ARGBEGIN { 89 case 'l': 90 sendw = 1; 91 break; 92 case 'v': 93 verbose = 1; 94 break; 95 default: 96 usage(); 97 } ARGEND; 98 99 if (pledge("stdio inet dns", NULL) == -1) 100 die(1, "pledge: %s\n", strerror(errno)); 101 102 if (argc < 1) 103 die(1, "no targets specified\n"); 104 105 for (i=0; i < argc; i++) { 106 user = user_dflt; 107 host = host_dflt; 108 port = port_dflt; 109 110 segment = ISUSER; 111 user = argv[i]; 112 for (; argv[i] && *argv[i]; argv[i]++) { 113 if (segment == ISUSER && *argv[i] == '@') { 114 *argv[i] = '\0'; 115 host = argv[i]+1; 116 segment = ISHOST; 117 } 118 if (segment == ISHOST && *argv[i] == ':') { 119 *argv[i] = '\0'; 120 port = argv[i]+1; 121 segment = ISPORT; 122 } 123 } 124 125 if (host[0] == '\0') 126 die(1, "no hostname\n"); 127 if (port[0] == '\0') 128 die(1, "no port\n"); 129 finger(user, host, port, sendw); 130 } 131 132 return EXIT_SUCCESS; 133 }