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