implement worker_batch_pass
[mkp224o.git] / yaml.c
blobebe03abd5ea7721ee32650786f0fe3ea19345d8e
1 #define _POSIX_C_SOURCE 200112L
3 #include <assert.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <stdint.h>
7 #include <string.h>
8 #include <time.h>
9 #include <pthread.h>
11 #ifndef _WIN32
12 #include <signal.h>
13 #endif
15 #include "types.h"
16 #include "yaml.h"
17 #include "ioutil.h"
18 #include "base32.h"
19 #include "base64.h"
20 #include "common.h"
22 #define LINEFEED_LEN (sizeof(char))
23 #define NULLTERM_LEN (sizeof(char))
24 #define PATH_SEPARATOR_LEN (sizeof(char))
26 static const char keys_field_generated[] = "---";
27 static const char keys_field_hostname[] = "hostname: ";
28 static const char keys_field_publickey[] = "hs_ed25519_public_key: ";
29 static const char keys_field_secretkey[] = "hs_ed25519_secret_key: ";
30 static const char keys_field_time[] = "time: ";
32 #define KEYS_FIELD_GENERATED_LEN (sizeof(keys_field_generated) - NULLTERM_LEN)
33 #define KEYS_FIELD_HOSTNAME_LEN (sizeof(keys_field_hostname) - NULLTERM_LEN)
34 #define KEYS_FIELD_PUBLICKEY_LEN (sizeof(keys_field_publickey) - NULLTERM_LEN)
35 #define KEYS_FIELD_SECRETKEY_LEN (sizeof(keys_field_secretkey) - NULLTERM_LEN)
36 #define KEYS_FIELD_TIME_LEN (sizeof(keys_field_time) - NULLTERM_LEN)
38 #define B64_PUBKEY_LEN (BASE64_TO_LEN(FORMATTED_PUBLIC_LEN))
39 #define B64_SECKEY_LEN (BASE64_TO_LEN(FORMATTED_SECRET_LEN))
40 #define TIME_LEN (21 * sizeof(char)) // strlen("2018-07-04 21:31:20 Z")
42 #define KEYS_LEN ( \
43 KEYS_FIELD_GENERATED_LEN + LINEFEED_LEN + \
44 KEYS_FIELD_HOSTNAME_LEN + ONION_LEN + LINEFEED_LEN + \
45 KEYS_FIELD_PUBLICKEY_LEN + B64_PUBKEY_LEN + LINEFEED_LEN + \
46 KEYS_FIELD_SECRETKEY_LEN + B64_SECKEY_LEN + LINEFEED_LEN + \
47 KEYS_FIELD_TIME_LEN + TIME_LEN + LINEFEED_LEN \
50 static pthread_mutex_t tminfo_mutex;
52 void yamlout_init(void)
54 pthread_mutex_init(&tminfo_mutex,0);
57 void yamlout_clean(void)
59 pthread_mutex_destroy(&tminfo_mutex);
62 #define BUF_APPEND(buf,offset,src,srclen) \
63 do { \
64 memcpy(&buf[offset],(src),(srclen)); \
65 offset += (srclen); \
66 } while (0)
67 #define BUF_APPEND_CSTR(buf,offset,src) BUF_APPEND(buf,offset,src,strlen(src))
68 #define BUF_APPEND_CHAR(buf,offset,c) buf[offset++] = (c)
70 void yamlout_writekeys(const char *hostname,const u8 *formated_public,const u8 *formated_secret)
72 char keysbuf[KEYS_LEN];
73 char pubkeybuf[B64_PUBKEY_LEN + NULLTERM_LEN];
74 char seckeybuf[B64_SECKEY_LEN + NULLTERM_LEN];
75 char timebuf[TIME_LEN + NULLTERM_LEN];
76 size_t offset = 0;
78 BUF_APPEND(keysbuf,offset,keys_field_generated,KEYS_FIELD_GENERATED_LEN);
79 BUF_APPEND_CHAR(keysbuf,offset,'\n');
81 BUF_APPEND(keysbuf,offset,keys_field_hostname,KEYS_FIELD_HOSTNAME_LEN);
82 BUF_APPEND(keysbuf,offset,hostname,ONION_LEN);
83 BUF_APPEND_CHAR(keysbuf,offset,'\n');
85 BUF_APPEND(keysbuf,offset,keys_field_publickey,KEYS_FIELD_PUBLICKEY_LEN);
86 base64_to(pubkeybuf,formated_public,FORMATTED_PUBLIC_LEN);
87 BUF_APPEND(keysbuf,offset,pubkeybuf,B64_PUBKEY_LEN);
88 BUF_APPEND_CHAR(keysbuf,offset,'\n');
90 BUF_APPEND(keysbuf,offset,keys_field_secretkey,KEYS_FIELD_SECRETKEY_LEN);
91 base64_to(seckeybuf,formated_secret,FORMATTED_SECRET_LEN);
92 BUF_APPEND(keysbuf,offset,seckeybuf,B64_SECKEY_LEN);
93 BUF_APPEND_CHAR(keysbuf,offset,'\n');
95 BUF_APPEND(keysbuf,offset,keys_field_time,KEYS_FIELD_TIME_LEN);
97 time_t currtime;
98 time(&currtime);
99 struct tm *tm_info;
101 pthread_mutex_lock(&tminfo_mutex);
102 tm_info = gmtime(&currtime);
103 strftime(timebuf,sizeof(timebuf),"%Y-%m-%d %H:%M:%S Z",tm_info);
104 pthread_mutex_unlock(&tminfo_mutex);
106 BUF_APPEND(keysbuf,offset,timebuf,TIME_LEN);
107 BUF_APPEND_CHAR(keysbuf,offset,'\n');
109 assert(offset == KEYS_LEN);
111 pthread_mutex_lock(&fout_mutex);
112 fwrite(keysbuf,sizeof(keysbuf),1,fout);
113 fflush(fout);
114 pthread_mutex_unlock(&fout_mutex);
117 #undef BUF_APPEND_CHAR
118 #undef BUF_APPEND_CSTR
119 #undef BUF_APPEND
121 // pseudo YAML parser
122 int yamlin_parseandcreate(FILE *fin,char *sname,const char *hostname)
124 char line[256];
125 size_t len,cnt;
126 u8 pubbuf[BASE64_DATA_ALIGN(FORMATTED_PUBLIC_LEN)];
127 u8 secbuf[BASE64_DATA_ALIGN(FORMATTED_SECRET_LEN)];
128 int hashost = 0,haspub = 0,hassec = 0,skipthis = 0;
129 enum keytype { HOST, PUB, SEC } keyt;
131 while (!feof(fin) && !ferror(fin)) {
132 if (!fgets(line,sizeof(line),fin))
133 break;
135 len = strlen(line);
137 // trim whitespace from the end
138 while (len != 0 && (line[len-1] == ' ' || line[len-1] == '\n' || line[len-1] == '\r'))
139 line[--len] = '\0';
141 // skip empty lines
142 if (len == 0)
143 continue;
145 if (len >= 3 && line[0] == '-' && line[1] == '-' && line[2] == '-') {
146 // end of document indicator
147 if (!skipthis && (hashost || haspub || hassec)) {
148 fprintf(stderr,"ERROR: incomplete record\n");
149 return 1;
151 hashost = haspub = hassec = skipthis = 0;
152 continue;
155 if (skipthis)
156 continue;
158 char *start = line;
159 // trim whitespace
160 while (len != 0 && *start == ' ') {
161 ++start;
162 --len;
164 // find ':'
165 char *p = start;
166 for (;*p != '\0';++p) {
167 if (*p == ':') {
168 *p++ = '\0';
169 goto foundkey;
172 // not `key: value`
173 fprintf(stderr,"ERROR: invalid syntax\n");
174 return 1; // XXX could continue too there but eh
176 foundkey:
178 if (!strcmp(start,"hostname"))
179 keyt = HOST;
180 else if (!strcmp(start,"hs_ed25519_public_key"))
181 keyt = PUB;
182 else if (!strcmp(start,"hs_ed25519_secret_key"))
183 keyt = SEC;
184 else
185 continue; // uninterested
187 // skip WS
188 while (*p == ' ')
189 ++p;
190 if (*p == '!') {
191 // skip ! tag
192 while (*p != '\0' && *p != ' ')
193 ++p;
194 // skip WS
195 while (*p == ' ')
196 ++p;
198 len = strlen(p);
199 switch (keyt) {
200 case HOST:
201 if (len != ONION_LEN ||
202 base32_valid(p,&cnt) ||
203 cnt != BASE32_TO_LEN(PUBONION_LEN) ||
204 strcmp(&p[cnt],".onion") != 0)
206 fprintf(stderr,"ERROR: invalid hostname syntax\n");
207 return 1;
209 if (!hostname || !strcmp(hostname,p)) {
210 memcpy(&sname[direndpos],p,len + 1);
211 hashost = 1;
212 } else
213 skipthis = 1;
214 break;
215 case PUB:
216 if (len != B64_PUBKEY_LEN || !base64_valid(p,0) ||
217 base64_from(pubbuf,p,len) != FORMATTED_PUBLIC_LEN)
219 fprintf(stderr,"ERROR: invalid pubkey syntax\n");
220 return 1;
222 haspub = 1;
223 break;
224 case SEC:
225 if (len != B64_SECKEY_LEN || !base64_valid(p,0) ||
226 base64_from(secbuf,p,len) != FORMATTED_SECRET_LEN)
228 fprintf(stderr,"ERROR: invalid seckey syntax\n");
229 return 1;
231 hassec = 1;
232 break;
234 if (hashost && haspub && hassec) {
235 #ifndef _WIN32
236 sigset_t nset,oset;
237 sigemptyset(&nset);
238 sigaddset(&nset,SIGINT);
239 sigaddset(&nset,SIGTERM);
240 sigprocmask(SIG_BLOCK,&nset,&oset);
241 #endif
242 if (createdir(sname,1) != 0) {
243 fprintf(stderr,"ERROR: could not create directory for key output\n");
244 return 1;
247 strcpy(&sname[onionendpos],"/hs_ed25519_secret_key");
248 writetofile(sname,secbuf,FORMATTED_SECRET_LEN,1);
250 strcpy(&sname[onionendpos],"/hs_ed25519_public_key");
251 writetofile(sname,pubbuf,FORMATTED_PUBLIC_LEN,0);
253 strcpy(&sname[onionendpos],"/hostname");
254 FILE *hfile = fopen(sname,"w");
255 sname[onionendpos] = '\n';
256 if (hfile) {
257 fwrite(&sname[direndpos],ONION_LEN + 1,1,hfile);
258 fclose(hfile);
260 if (fout) {
261 fwrite(&sname[printstartpos],printlen,1,fout);
262 fflush(fout);
264 #ifndef _WIN32
265 sigprocmask(SIG_SETMASK,&oset,0);
266 #endif
267 if (hostname)
268 return 0; // finished
269 skipthis = 1;
273 if (!feof(fin)) {
274 fprintf(stderr,"error while reading input\n");
275 return 1;
278 if (hostname) {
279 fprintf(stderr,"hostname wasn't found in input\n");
280 return 1;
283 return 0;