CI: Update RTD configuration file
[sim/o1-interface.git] / ntsimulator / ntsim-ng / utils / sys_utils.c
1 /*************************************************************************
2 *
3 * Copyright 2020 highstreet technologies GmbH and others
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 ***************************************************************************/
17
18 #define _GNU_SOURCE
19
20 #include "sys_utils.h"
21 #include "log_utils.h"
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include <math.h>
28 #include <unistd.h>
29 #include <time.h>
30 #include <ifaddrs.h>
31 #include <netdb.h>
32 #include <sys/time.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <sys/socket.h>
36 #include <arpa/inet.h>
37 #include <linux/if_link.h>
38 #include <assert.h>
39
40 static char b64_encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
41                                     'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
42                                     'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
43                                     'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
44                                     'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
45                                     'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
46                                     'w', 'x', 'y', 'z', '0', '1', '2', '3',
47                                     '4', '5', '6', '7', '8', '9', '+', '/'};
48
49 static char b64_decoding_table[256] = {0};
50
51 static int b64_mod_table[] = {0, 2, 1};
52
53 bool dir_exists(const char *path) {
54     assert(path);
55
56     struct stat st = {0};
57     return (stat(path, &st) != -1);
58 }
59
60 bool file_exists(const char *fname) {
61     assert(fname);
62
63     return (access(fname, F_OK) != -1);
64 }
65
66 void file_touch(const char *fname, const char *content) {
67     assert(fname);
68
69     FILE *f = fopen(fname, "w");
70     if(f == 0) {
71         log_error("fopen failed\n");
72         return;
73     }
74
75     if(content) {
76         fprintf(f, "%s", content);
77     }
78     fclose(f);
79 }
80
81 char *file_read_content(const char *fname) {
82     assert(fname);
83
84     char *buffer = 0;
85     long length;
86     FILE *f = fopen(fname, "rb");
87     if(f) {
88         fseek(f, 0, SEEK_END);
89         length = ftell(f);
90         fseek(f, 0, SEEK_SET);
91         buffer = (char*)malloc(sizeof(char) * (length + 1));
92         if(buffer) {
93             fread(buffer, 1, length, f);
94                 buffer[length] = 0;
95         }
96         fclose(f);
97     }
98
99     return buffer;
100 }
101
102 int get_int_from_string_with_default(const char *string, int default_value) {
103     int rc;
104     int value = default_value;
105
106     if(string != 0) {
107         rc = sscanf(string, "%d", &value);
108         if (rc != 1) {
109             value = default_value;
110         }
111     }
112     return value;
113 }
114
115 char *get_current_date_and_time(void) {
116     char *date_and_time = 0;
117
118         time_t t = time(0);
119         struct tm tm = *localtime(&t);
120         struct timeval tv;
121         int millisec;
122
123         gettimeofday(&tv, 0);
124         millisec = lrint(tv.tv_usec/1000.0); // Round to nearest millisec
125         if(millisec>=1000)      { // Allow for rounding up to nearest second
126                 millisec -=1000;
127                 tv.tv_sec++;
128                 millisec /= 100;
129         }
130
131         asprintf(&date_and_time, "%04d-%02d-%02dT%02d:%02d:%02d.%01dZ",
132                 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
133                 tm.tm_hour, tm.tm_min, tm.tm_sec, millisec/100);
134
135     return date_and_time;
136 }
137
138 char *get_current_date_and_time_delay_seconds(int seconds) {
139     char *date_and_time = 0;
140
141         time_t t = time(0);
142         struct tm tm = *localtime(&t);
143         struct timeval tv;
144
145         gettimeofday(&tv, 0);
146
147     tm.tm_sec += seconds;
148     mktime(&tm);
149
150         asprintf(&date_and_time, "%04d-%02d-%02dT%02d:%02d:%02d.0Z",
151                 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
152                 tm.tm_hour, tm.tm_min, tm.tm_sec);
153
154     return date_and_time;
155 }
156
157 long int get_microseconds_since_epoch(void) {
158     time_t t = time(0);
159     struct timeval tv;
160     long int useconds;
161
162     gettimeofday(&tv, 0);
163     useconds = t*1000000 + tv.tv_usec; //add the microseconds to the seconds
164
165     return useconds;
166 }
167
168
169 bool get_local_ips(const char *ifname, char **ipv4, char **ipv6) {
170     assert(ifname);
171     assert(ipv4);
172     assert(ipv6);
173
174     int s;
175     struct ifaddrs *ifaddr;
176     struct ifaddrs *ifa;
177     char host[NI_MAXHOST];
178     bool ret = true;
179
180     *ipv4 = 0;
181     *ipv6 = 0;
182
183     if (getifaddrs(&ifaddr) == -1)  {
184         ret = false;
185         goto get_local_ips_free;
186     }
187
188     for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)  {
189         if (ifa->ifa_addr == NULL) {
190             continue;
191         }
192
193         s = getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in),host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
194         if((strcmp(ifa->ifa_name, ifname) == 0) && (ifa->ifa_addr->sa_family == AF_INET)) {
195             if (s != 0) {
196                 ret = false;
197                 goto get_local_ips_free;
198             }
199
200             *ipv4 = strdup(host);
201             break;
202         }
203     }
204
205
206     for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)  {
207         if (ifa->ifa_addr == NULL) {
208             continue;
209         }
210
211         s = getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in6),host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
212         if((strcmp(ifa->ifa_name, ifname) == 0) && (ifa->ifa_addr->sa_family == AF_INET6)) {
213             if (s != 0) {
214                 ret = false;
215                 goto get_local_ips_free;
216             }
217
218             *ipv6 = strdup(host);
219             break;
220         }
221     }
222
223     get_local_ips_free:
224     if(ret == false) {
225         free(*ipv4);
226         free(*ipv6);
227         *ipv4 = 0;
228         *ipv6 = 0;
229     }
230
231     freeifaddrs(ifaddr);
232     return ret;
233 }
234
235 bool check_port_open(const char *host, uint16_t port) {
236     assert(host);
237
238     int simpleSocket = 0;
239     int returnStatus = 0;
240     struct addrinfo simpleServer;
241     struct addrinfo *res;
242
243     memset(&simpleServer, 0, sizeof simpleServer);
244     simpleServer.ai_family = AF_UNSPEC;  // use IPv4 or IPv6, whichever
245     simpleServer.ai_socktype = SOCK_STREAM;
246     simpleServer.ai_flags = AI_ADDRCONFIG;
247
248     char sport[10];
249     sprintf(sport, "%d", port);
250
251     returnStatus = getaddrinfo(host, sport, &simpleServer, &res);
252     if(returnStatus != 0) {
253         return false;
254     }
255
256     simpleSocket = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
257     if(simpleSocket < 0) {
258         freeaddrinfo(res);
259         return false;
260     }
261
262     char s[INET6_ADDRSTRLEN];
263     switch(res->ai_addr->sa_family) {
264         case AF_INET: {
265             struct sockaddr_in *addr_in = (struct sockaddr_in *)res->ai_addr;
266             inet_ntop(AF_INET, &(addr_in->sin_addr), s, INET_ADDRSTRLEN);
267             returnStatus = connect(simpleSocket, res->ai_addr, res->ai_addrlen);
268             break;
269         }
270
271         case AF_INET6: {
272             struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)res->ai_addr;
273             inet_ntop(AF_INET6, &(addr_in6->sin6_addr), s, INET6_ADDRSTRLEN);
274             returnStatus = connect(simpleSocket, res->ai_addr, res->ai_addrlen);
275             break;
276         }
277
278         default:
279             break;
280     }
281
282     freeaddrinfo(res);
283     close(simpleSocket);
284     if(returnStatus == 0) {
285         return true;
286     }
287
288     return false;
289 }
290
291 char *b64_encode(const uint8_t *data, size_t input_length) {
292     assert(data);
293     assert(input_length);
294
295     int output_length = 4 * ((input_length + 2) / 3);
296
297     char *encoded_data = (char *)malloc(sizeof(char) * (output_length + 1));
298     if (encoded_data == 0) {
299         return 0;
300     }
301
302     for (int i = 0, j = 0; i < input_length;) {
303         uint32_t octet_a = i < input_length ? (unsigned char)data[i++] : 0;
304         uint32_t octet_b = i < input_length ? (unsigned char)data[i++] : 0;
305         uint32_t octet_c = i < input_length ? (unsigned char)data[i++] : 0;
306
307         uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
308
309         encoded_data[j++] = b64_encoding_table[(triple >> 3 * 6) & 0x3F];
310         encoded_data[j++] = b64_encoding_table[(triple >> 2 * 6) & 0x3F];
311         encoded_data[j++] = b64_encoding_table[(triple >> 1 * 6) & 0x3F];
312         encoded_data[j++] = b64_encoding_table[(triple >> 0 * 6) & 0x3F];
313     }
314
315     for (int i = 0; i < b64_mod_table[input_length % 3]; i++) {
316         encoded_data[output_length - 1 - i] = '=';
317     }
318
319     encoded_data[output_length] = 0;
320
321     return encoded_data;
322 }
323
324 uint8_t *b64_decode(const char *data, size_t input_length, size_t *output_length) {
325     assert(data);
326     assert(input_length);
327     assert(output_length);
328
329     int i, j;
330
331     //one time compute decoding table
332     if(b64_decoding_table['A'] == 0) {
333         for(i = 0; i < 64; i++) {
334             b64_decoding_table[(unsigned char)b64_encoding_table[i]] = i;
335         }
336     }
337
338     if(input_length % 4 != 0) {
339         return 0;
340     }
341
342     *output_length = input_length / 4 * 3;
343     if(data[input_length - 1] == '=') {
344         (*output_length )--;
345     }
346     if(data[input_length - 2] == '=') {
347         (*output_length )--;
348     }
349
350     uint8_t *decoded_data = (uint8_t*)malloc(*output_length + 1);
351     if(decoded_data == 0) {
352         return 0;
353     }
354
355     for(i = 0, j = 0; i < input_length;) {
356         uint32_t sextet_a = data[i] == '=' ? 0 & i++ : b64_decoding_table[(int)data[i++]];
357         uint32_t sextet_b = data[i] == '=' ? 0 & i++ : b64_decoding_table[(int)data[i++]];
358         uint32_t sextet_c = data[i] == '=' ? 0 & i++ : b64_decoding_table[(int)data[i++]];
359         uint32_t sextet_d = data[i] == '=' ? 0 & i++ : b64_decoding_table[(int)data[i++]];
360         uint32_t triple = ( sextet_a << 3 * 6 ) + ( sextet_b << 2 * 6 ) + ( sextet_c << 1 * 6 ) + ( sextet_d << 0 * 6 );
361
362         if(j < *output_length) {
363             decoded_data[j++] = (triple >> 2 * 8) & 0xFF;
364         }
365
366         if(j < *output_length) {
367             decoded_data[j++] = (triple >> 1 * 8) & 0xFF;
368         }
369
370         if(j < *output_length) {
371             decoded_data[j++] = (triple >> 0 * 8) & 0xFF;
372         }
373     }
374
375     return decoded_data;
376 }
377
378 char *str_replace(const char *orig, const char *rep, const char *with) {
379     assert(orig);
380     assert(rep);
381     assert(with);
382
383     char *result; // the return string
384     const char *ins;    // the next insert point
385     char *tmp;    // varies
386     int len_rep;  // length of rep (the string to remove)
387     int len_with; // length of with (the string to replace rep with)
388     int len_front; // distance between rep and end of last rep
389     int count;    // number of replacements
390
391     // sanity checks and initialization
392     if(!orig || !rep) {
393         return 0;
394     }
395
396     len_rep = strlen(rep);
397     if(len_rep == 0) {
398         return 0; // empty rep causes infinite loop during count
399     }
400
401     if (!with) {
402         with = "";
403     }
404     len_with = strlen(with);
405
406     // count the number of replacements needed
407     ins = orig;
408     for(count = 0; (tmp = strstr(ins, rep)); ++count) {
409         ins = tmp + len_rep;
410     }
411
412     tmp = result = malloc(strlen(orig) + (len_with - len_rep) * count + 1);
413
414     if(!result) {
415         return 0;
416     }
417
418     // first time through the loop, all the variable are set correctly
419     // from here on,
420     //    tmp points to the end of the result string
421     //    ins points to the next occurrence of rep in orig
422     //    orig points to the remainder of orig after "end of rep"
423     while(count--) {
424         ins = strstr(orig, rep);
425         len_front = ins - orig;
426         tmp = strncpy(tmp, orig, len_front) + len_front;
427         tmp = strcpy(tmp, with) + len_with;
428         orig += len_front + len_rep; // move to next "end of rep"
429     }
430
431     strcpy(tmp, orig);
432     return result;
433 }
434
435 char *read_key(const char *filename) {
436     assert(filename);
437
438     FILE * fp = 0;
439     char * line = 0;
440     size_t len = 0;
441     ssize_t read;
442     char *key_string = 0;
443
444     fp = fopen(filename, "r");
445     if(fp == 0) {
446         log_error("could not open file %s\n", filename);
447         return 0;
448     }
449
450     while((read = getline(&line, &len, fp)) != -1) {
451         // we ignore the first and last lines forPrivate keys, Public keys and Certificates
452         if(strstr(line, "PRIVATE KEY-----") || strstr(line, "PUBLIC KEY-----") || strstr(line, "CERTIFICATE-----")) {
453             free(line);
454             line = 0;
455             len = 0;
456             continue;
457         }
458         else {
459             if(key_string) {
460                 key_string = (char *)realloc(key_string, strlen(key_string) + read + 1);
461                 if(key_string == 0) {
462                     log_error("bad allocation\n");
463                     free(line);
464                     return 0;
465                 }
466
467                 strcat(key_string, line);
468             }
469             else {
470                 key_string = strdup(line);
471                 if(key_string == 0) {
472                     log_error("bad allocation\n");
473                     free(line);
474                     return 0;
475                 }
476             }
477
478             free(line);
479             line = 0;
480             len = 0;
481         }
482     }
483
484     fclose(fp);
485     if(line) {
486         free(line);
487     }
488
489     return key_string;
490 }
491
492 void vsftp_daemon_init(void) {
493     system("/usr/sbin/vsftpd &");
494 }
495
496 void vsftp_daemon_deinit(void) {
497     system("killall -9 vsftpd");
498 }
499
500 void sftp_daemon_init(void) {
501     system("/usr/sbin/sshd -D &");
502 }
503
504 void sftp_daemon_deinit(void) {
505     system("killall -9 sshd");
506 }