]>
Commit | Line | Data |
---|---|---|
ab4c538f | 1 | /* |
ec84794b | 2 | * Copyright (C) 2012-2019 Red Hat, Inc. All rights reserved. |
ab4c538f FDN |
3 | * |
4 | * Author: Fabio M. Di Nitto <fabbione@kronosnet.org> | |
5 | * | |
6 | * This software licensed under GPL-2.0+, LGPL-2.0+ | |
7 | */ | |
8 | ||
b1f47355 FDN |
9 | #include "config.h" |
10 | ||
11 | #include <stdio.h> | |
12 | #include <string.h> | |
13 | #include <limits.h> | |
14 | #include <unistd.h> | |
15 | #include <stdlib.h> | |
16 | #include <sys/types.h> | |
17 | #include <sys/stat.h> | |
18 | #include <fcntl.h> | |
19 | ||
9a5ccc0b FDN |
20 | #include <libknet.h> |
21 | ||
b1f47355 | 22 | static char *output_file = NULL; |
9a5ccc0b | 23 | static ssize_t keylen = KNET_MAX_KEY_LEN; |
b1f47355 FDN |
24 | |
25 | static void print_usage(void) | |
26 | { | |
27 | printf("\nUsage:\n\n"); | |
28 | printf("knet-keygen -o <output_file> [-s <size>]\n\n"); | |
29 | }; | |
30 | ||
31 | #define OPTION_STRING "ho:s:" | |
32 | ||
33 | static int read_arguments(int argc, char **argv) | |
34 | { | |
35 | int cont = 1; | |
36 | int optchar; | |
37 | ||
38 | while (cont) { | |
39 | optchar = getopt(argc, argv, OPTION_STRING); | |
40 | ||
41 | switch (optchar) { | |
42 | ||
43 | case 'o': | |
44 | output_file = strdup(optarg); | |
45 | if (!output_file) { | |
46 | fprintf(stderr, "Error: Unable to allocate memory\n"); | |
47 | return -1; | |
48 | } | |
49 | if (strlen(output_file) > PATH_MAX) { | |
50 | fprintf(stderr, "Seriously? WTF\n"); | |
51 | return -1; | |
52 | } | |
53 | break; | |
54 | ||
55 | case 's': | |
56 | keylen = atoi(optarg); | |
9a5ccc0b | 57 | if ((keylen < KNET_MIN_KEY_LEN) || (keylen > KNET_MAX_KEY_LEN)) { |
801bb12d | 58 | fprintf(stderr, "Error: Key size should be a value between %d and %d (default) included\n", |
9a5ccc0b | 59 | KNET_MIN_KEY_LEN, KNET_MAX_KEY_LEN); |
b1f47355 FDN |
60 | return -1; |
61 | } | |
62 | break; | |
63 | ||
64 | case 'h': | |
65 | print_usage(); | |
66 | exit(EXIT_SUCCESS); | |
67 | break; | |
68 | ||
69 | case EOF: | |
70 | cont = 0; | |
71 | break; | |
72 | ||
73 | default: | |
74 | fprintf(stderr, "Error: unknown option: %c\n", optchar); | |
75 | print_usage(); | |
76 | return -1; | |
77 | break; | |
78 | ||
79 | } | |
80 | } | |
81 | if (!output_file) { | |
82 | fprintf(stderr, "Error: no output file specified\n"); | |
83 | print_usage(); | |
84 | return -1; | |
85 | } | |
86 | return 0; | |
87 | } | |
88 | ||
89 | int main (int argc, char *argv[]) | |
90 | { | |
91 | int ret = 0; | |
92 | int fd = -1; | |
93 | ssize_t res; | |
94 | ssize_t bytes_read = 0; | |
95 | char *keybuf = NULL; | |
96 | ||
97 | printf (PACKAGE " key generator.\n"); | |
98 | ||
99 | if (read_arguments(argc, argv) < 0) { | |
100 | goto exit_error; | |
101 | } | |
102 | ||
103 | if (geteuid() != 0) { | |
104 | fprintf(stderr, "Error: Authorization key must be generated as root user.\n"); | |
105 | goto exit_error; | |
106 | } | |
107 | ||
108 | fd = open ("/dev/random", O_RDONLY); | |
109 | if (fd < 0) { | |
110 | fprintf(stderr, "Error: Unable to open /dev/random\n"); | |
111 | goto exit_error; | |
112 | } | |
113 | ||
114 | keybuf = malloc(keylen); | |
115 | if (!keybuf) { | |
116 | fprintf(stderr, "Error: Unable to allocate memory for key\n"); | |
117 | goto exit_error; | |
118 | } | |
119 | ||
801bb12d | 120 | printf("Gathering %zd bytes for key from /dev/random.\n", keylen); |
b1f47355 FDN |
121 | printf("This process might take a long time due the amount on entropy required\n"); |
122 | printf("Press keys on your keyboard, perform any kind of disk I/O and/or network to generate entropy faster.\n"); | |
123 | ||
124 | keep_reading: | |
125 | res = read(fd, &keybuf[bytes_read], keylen - bytes_read); | |
126 | if (res == -1) { | |
127 | fprintf(stderr, "Error: Unable to read from /dev/random.\n"); | |
128 | goto exit_error; | |
129 | } | |
130 | bytes_read += res; | |
131 | if (bytes_read != keylen) { | |
801bb12d | 132 | printf("bytes read = %zd, missing = %zd.\n", bytes_read, keylen - bytes_read); |
b1f47355 FDN |
133 | goto keep_reading; |
134 | } | |
135 | close (fd); | |
136 | fd = -1; | |
137 | ||
138 | fd = open (output_file, O_CREAT|O_WRONLY, 600); | |
139 | if (fd == -1) { | |
140 | fprintf(stderr, "Error: Could not create %s\n", output_file); | |
141 | goto exit_error; | |
142 | } | |
143 | ||
144 | /* | |
145 | * Make sure file is owned by root and mode 0400 | |
146 | */ | |
147 | if (fchown(fd, 0, 0)) { | |
148 | fprintf(stderr, "Error: Could not set uid 0 (root) and gid 0 (root) on keyfile %s\n", output_file); | |
149 | goto exit_error; | |
150 | } | |
151 | if (fchmod(fd, 0400)) { | |
152 | fprintf(stderr, "Error: Could not set read-only permissions on keyfile %s\n", output_file); | |
153 | goto exit_error; | |
154 | } | |
155 | ||
156 | printf("Writing private key to %s\n", output_file); | |
157 | ||
158 | if (write(fd, keybuf, keylen) != keylen) { | |
159 | fprintf(stderr, "Error: Could not write key to file %s\n", output_file); | |
160 | goto exit_error; | |
161 | } | |
162 | ||
163 | printf("Done.\n"); | |
164 | printf("Please copy this file in " DEFAULT_CONFIG_DIR "/cryptokeys.d/<knet_interface_name>\n"); | |
165 | printf("on all nodes participating in the same kronosnet instance\n"); | |
166 | ||
167 | exit_clean: | |
168 | if (output_file) | |
169 | free(output_file); | |
170 | if (keybuf) | |
171 | free(keybuf); | |
172 | if (fd > -1) | |
173 | close(fd); | |
174 | ||
175 | return ret; | |
176 | ||
177 | exit_error: | |
178 | ret = -1; | |
179 | goto exit_clean; | |
180 | } |