1 /*- 2 * Copyright (c) 2010 Alistair Crooks <agc@NetBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 #include <sys/types.h> 26 #include <sys/param.h> 27 #include <sys/socket.h> 28 29 #include <netinet/in.h> 30 31 #include <errno.h> 32 #include <inttypes.h> 33 #include <netdb.h> 34 #include <netpgp.h> 35 #include <regex.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <unistd.h> 40 41 #include "hkpc.h" 42 43 /* get a socket and connect it to the server */ 44 int 45 hkpc_connect(const char *hostname, const int port, const int fam) 46 { 47 struct addrinfo hints; 48 struct addrinfo *res; 49 char portstr[32]; 50 int sock; 51 int rc = 0; 52 53 (void) memset(&hints, 0, sizeof(hints)); 54 hints.ai_family = (fam == 4) ? PF_INET : PF_INET6; 55 hints.ai_socktype = SOCK_STREAM; 56 (void) snprintf(portstr, sizeof(portstr), "%d", port); 57 if ((rc = getaddrinfo(hostname, portstr, &hints, &res)) != 0) { 58 hints.ai_flags = 0; 59 if ((rc = getaddrinfo(hostname, "hkp", &hints, &res)) != 0) { 60 (void) fprintf(stderr, "getaddrinfo: %s", 61 gai_strerror(rc)); 62 return -1; 63 } 64 } 65 if ((sock = socket((fam == 4) ? AF_INET : AF_INET6, SOCK_STREAM, 0)) < 0) { 66 (void) fprintf(stderr, "socket failed %d\n", errno); 67 freeaddrinfo(res); 68 return -1; 69 } 70 if ((rc = connect(sock, res->ai_addr, res->ai_addrlen)) < 0) { 71 (void) fprintf(stderr, "connect failed %d\n", errno); 72 freeaddrinfo(res); 73 return -1; 74 } 75 freeaddrinfo(res); 76 if (rc < 0) { 77 (void) fprintf(stderr, "connect() to %s:%d failed (rc %d)\n", 78 hostname, port, rc); 79 } 80 return sock; 81 } 82 83 #define MB(x) ((x) * 1024 * 1024) 84 85 /* get required info from the server */ 86 int 87 hkpc_get(char **info, const char *server, const int port, const int family, const char *type, const char *userid) 88 { 89 char buf[MB(1)]; 90 int sock; 91 int cc; 92 int rc; 93 94 if ((sock = hkpc_connect(server, port, family)) < 0) { 95 (void) fprintf(stderr, "hkpc_get: can't connect to server '%s'\n", server); 96 return -1; 97 } 98 cc = snprintf(buf, sizeof(buf), "GET /pks/lookup?op=%s&search=%s&options=json", type, userid); 99 if (write(sock, buf, cc) != cc) { 100 (void) fprintf(stderr, "hkpc_get: short write\n"); 101 return -1; 102 } 103 for (cc = 0 ; (rc = read(sock, &buf[cc], sizeof(buf) - cc)) > 0 ; cc += rc) { 104 } 105 *info = calloc(1, cc + 1); 106 (void) memcpy(*info, buf, cc); 107 (*info)[cc] = 0x0; 108 (void) close(sock); 109 return cc; 110 } 111 112 /* jump over http header, then pass the json to the key-formatting function */ 113 int 114 hkpc_print_key(FILE *fp, const char *op, const char *res) 115 { 116 static regex_t text; 117 static int compiled; 118 regmatch_t matches[10]; 119 int ret; 120 121 if (!compiled) { 122 compiled = 1; 123 (void) regcomp(&text, "\r\n\r\n", REG_EXTENDED); 124 } 125 if (regexec(&text, res, 10, matches, 0) != 0) { 126 return 0; 127 } 128 if (strcmp(op, "index") == 0 || strcmp(op, "vindex") == 0) { 129 ret = netpgp_format_json(fp, &res[(int)matches[0].rm_eo], 1); 130 } else { 131 (void) fprintf(fp, "%s\n", &res[(int)matches[0].rm_eo]); 132 ret = 1; 133 } 134 return ret; 135 } 136