]> the.earth.li Git - onak.git/blob - keydctl.c
Fix issue with looking up keys by fingerprint via HKP interface
[onak.git] / keydctl.c
1 /*
2  * keydctl.c - A simple program to control a running keyd instance
3  *
4  * Copyright 2011 Jonathan McDowell <noodles@earth.li>
5  *
6  * This program is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program; if not, write to the Free Software Foundation, Inc., 51
17  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19
20 #include <errno.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <time.h>
25 #include <unistd.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <sys/un.h>
29
30 #include "keyd.h"
31 #include "onak-conf.h"
32 #include "version.h"
33
34 /* HACK: We need to stop onak-conf.o requiring this. */
35 void *DBINIT = NULL;
36
37 static int keyd_fd = -1;
38 static int verbose = 0;
39
40 static int keyd_do_command(enum keyd_ops cmd, void *buf, size_t len)
41 {
42         uint32_t tmp;
43
44         if (keyd_fd < 0) {
45                 return -1;
46         }
47
48         tmp = cmd;
49         if (write(keyd_fd, &tmp, sizeof(tmp)) != sizeof(tmp)) {
50                 if (verbose >= 0) {
51                         fprintf(stderr,
52                                 "Couldn't write keyd command %d: %s (%d)\n",
53                                 cmd, strerror(errno), errno);
54                 }
55                 exit(EXIT_FAILURE);
56         } else if (read(keyd_fd, &tmp, sizeof(tmp)) != sizeof(tmp)) {
57                 if (verbose >= 0) {
58                         fprintf(stderr,
59                                 "Couldn't read keyd command %d reply: "
60                                 "%s (%d)\n",
61                                 cmd, strerror(errno), errno);
62                         }
63                 exit(EXIT_FAILURE);
64         } else if (tmp != KEYD_REPLY_OK) {
65                 return -1;
66         } else if (buf == NULL) {
67                 return 0;
68         } else if (read(keyd_fd, &tmp, sizeof(tmp)) != sizeof(tmp)) {
69                 if (verbose >= 0) {
70                         fprintf(stderr,
71                                 "Couldn't read keyd command %d reply length: "
72                                 "%s (%d)\n",
73                                 cmd, strerror(errno), errno);
74                 }
75                 exit(EXIT_FAILURE);
76         } else if (tmp > len) {
77                 /* TODO: Read what we can into buf and skip the rest */
78                 return -1;
79         } else {
80                 return read(keyd_fd, buf, tmp);
81         }
82 }
83
84 static void keyd_connect(void)
85 {
86         struct sockaddr_un sock;
87         uint32_t           reply = KEYD_REPLY_UNKNOWN_CMD;
88
89         keyd_fd = socket(PF_UNIX, SOCK_STREAM, 0);
90         if (keyd_fd < 0) {
91                 if (verbose >= 0) {
92                         fprintf(stderr,
93                                 "Couldn't open socket: %s (%d)\n",
94                                 strerror(errno),
95                                 errno);
96                 }
97                 exit(EXIT_FAILURE);
98         }
99
100         sock.sun_family = AF_UNIX;
101         snprintf(sock.sun_path, sizeof(sock.sun_path) - 1, "%s/%s",
102                         config.db_dir,
103                         KEYD_SOCKET);
104         if (connect(keyd_fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) {
105                 if (verbose >= 0) {
106                         fprintf(stderr,
107                                 "Couldn't connect to socket %s: %s (%d)\n",
108                                 sock.sun_path,
109                                 strerror(errno),
110                                 errno);
111                 }
112                 exit(EXIT_FAILURE);
113         }
114
115         keyd_do_command(KEYD_CMD_VERSION, &reply, sizeof(reply));
116         if (reply != keyd_version) {
117                 if (verbose >= 0) {
118                         fprintf(stderr, "Error! keyd protocol version "
119                                 "mismatch. (us = %d, it = %d)\n",
120                                 keyd_version, reply);
121                 }
122                 exit(EXIT_FAILURE);
123         }
124
125         return;
126 }
127
128 static void keyd_close(void)
129 {
130         uint32_t cmd = KEYD_CMD_CLOSE;
131
132         if (write(keyd_fd, &cmd, sizeof(cmd)) != sizeof(cmd) && verbose >= 0) {
133                 fprintf(stderr, "Couldn't send close cmd: %s (%d)\n",
134                                 strerror(errno),
135                                 errno);
136         }
137
138         if (shutdown(keyd_fd, SHUT_RDWR) < 0 && verbose >= 0) {
139                 fprintf(stderr, "Error shutting down socket: %d\n",
140                                 errno);
141         }
142         if (close(keyd_fd) < 0 && verbose >= 0) {
143                 fprintf(stderr, "Error closing down socket: %d\n",
144                                 errno);
145         }
146         keyd_fd = -1;
147
148         return;
149
150 }
151
152 static void keyd_status(void)
153 {
154         uint32_t reply;
155         struct keyd_stats stats;
156
157         if (keyd_do_command(KEYD_CMD_VERSION, &reply, sizeof(reply)) == -1) {
158                 printf("Got failure asking for keyd version.\n");
159                 return;
160         }
161         printf("Using keyd protocol version %d.\n", reply);
162
163         if (keyd_do_command(KEYD_CMD_STATS, &stats, sizeof(stats)) == -1) {
164                 printf("Got failure asking for keyd statistics.\n");
165                 return;
166         }
167
168         printf("keyd running since %s", ctime(&stats.started));
169         printf("%d client connections received\n", stats.connects);
170
171         printf("Command statistics:\n");
172         printf("  Version:          %d\n",
173                 stats.command_stats[KEYD_CMD_VERSION]);
174         printf("  Get key by ID:    %d\n",
175                 stats.command_stats[KEYD_CMD_GET_ID]);
176         printf("  Get key by FP:    %d\n",
177                 stats.command_stats[KEYD_CMD_GET_FP]);
178         printf("  Store key:        %d\n",
179                 stats.command_stats[KEYD_CMD_STORE]);
180         printf("  Delete key:       %d\n",
181                 stats.command_stats[KEYD_CMD_DELETE]);
182         printf("  Search key:       %d\n",
183                 stats.command_stats[KEYD_CMD_GET_TEXT]);
184         printf("  Get full keyid:   %d\n",
185                 stats.command_stats[KEYD_CMD_GETFULLKEYID]);
186         printf("  Iterate all keys: %d\n",
187                 stats.command_stats[KEYD_CMD_KEYITER]);
188         printf("  Close:            %d\n",
189                 stats.command_stats[KEYD_CMD_CLOSE]);
190         printf("  Quit:             %d\n", stats.command_stats[KEYD_CMD_QUIT]);
191         printf("  Get statistics:   %d\n",
192                 stats.command_stats[KEYD_CMD_STATS]);
193         printf("  Unknown:          %d\n",
194                 stats.command_stats[KEYD_CMD_UNKNOWN]);
195
196         return;
197 }
198
199 static void usage(void)
200 {
201         puts("keydctl " ONAK_VERSION " - control an onak keyd instance.\n");
202         puts("Usage:\n");
203         puts("\tkeydctl [options] <command> <parameters>\n");
204         puts("\tCommands:\n");
205         puts("\tcheck    - check if keyd is running");
206         puts("\tquit     - request that keyd cleanly shuts down");
207         puts("\tstatus   - display running keyd status");
208         exit(EXIT_FAILURE);
209 }
210
211 int main(int argc, char *argv[])
212 {
213         int      optchar;
214         char    *configfile = NULL;
215
216         while ((optchar = getopt(argc, argv, "c:h")) != -1 ) {
217                 switch (optchar) {
218                 case 'c':
219                         configfile = strdup(optarg);
220                         break;
221                 case 'h':
222                 default:
223                         usage();
224                         break;
225                 }
226         }
227
228         readconfig(configfile);
229         free(configfile);
230         configfile = NULL;
231
232         if ((argc - optind) < 1) {
233                 cleanupconfig();
234                 usage();
235         } else if (!strcmp("check", argv[optind])) {
236                 /* Just do the connect and close quietly */
237                 verbose = -1;
238                 keyd_connect();
239                 keyd_close();
240         } else if (!strcmp("status", argv[optind])) {
241                 keyd_connect();
242                 keyd_status();
243                 keyd_close();
244         } else if (!strcmp("quit", argv[optind])) {
245                 keyd_connect();
246                 keyd_do_command(KEYD_CMD_QUIT, NULL, 0);
247                 keyd_close();
248         } else {
249                 cleanupconfig();
250                 usage();
251         }
252
253         cleanupconfig();
254
255         exit(EXIT_SUCCESS);
256 }