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