d6def2ee0e8abd8419877f6abb24129199b6f35c
[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);
92         if(buffer) {
93             fread(buffer, 1, length, f);
94         }
95         fclose(f);
96     }
97
98     return buffer;
99 }
100
101 int get_int_from_string_with_default(const char *string, int default_value) {
102     int rc;
103     int value = default_value;
104
105     if(string != 0) {
106         rc = sscanf(string, "%d", &value);
107         if (rc != 1) {
108             value = default_value;
109         }
110     }
111     return value;
112 }
113
114 char *get_current_date_and_time(void) {
115     char *date_and_time = 0;
116
117         time_t t = time(0);
118         struct tm tm = *localtime(&t);
119         struct timeval tv;
120         int millisec;
121
122         gettimeofday(&tv, 0);
123         millisec = lrint(tv.tv_usec/1000.0); // Round to nearest millisec
124         if(millisec>=1000)      { // Allow for rounding up to nearest second
125                 millisec -=1000;
126                 tv.tv_sec++;
127                 millisec /= 100;
128         }
129
130         asprintf(&date_and_time, "%04d-%02d-%02dT%02d:%02d:%02d.%01dZ",
131                 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
132                 tm.tm_hour, tm.tm_min, tm.tm_sec, millisec/100);
133
134     return date_and_time;
135 }
136
137 long int get_microseconds_since_epoch(void) {
138     time_t t = time(0);
139     struct timeval tv;
140     long int useconds;
141
142     gettimeofday(&tv, 0);
143     useconds = t*1000000 + tv.tv_usec; //add the microseconds to the seconds
144
145     return useconds;
146 }
147
148
149 bool get_local_ips(const char *ifname, char **ipv4, char **ipv6) {
150     assert(ifname);
151     assert(ipv4);
152     assert(ipv6);
153
154     int s;
155     struct ifaddrs *ifaddr;
156     struct ifaddrs *ifa;
157     char host[NI_MAXHOST];
158     bool ret = true;
159
160     *ipv4 = 0;
161     *ipv6 = 0;
162
163     if (getifaddrs(&ifaddr) == -1)  {
164         ret = false;
165         goto get_local_ips_free;
166     }
167
168     for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)  {
169         if (ifa->ifa_addr == NULL) {
170             continue;
171         }
172
173         s = getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in),host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
174         if((strcmp(ifa->ifa_name, ifname) == 0) && (ifa->ifa_addr->sa_family == AF_INET)) {
175             if (s != 0) {
176                 ret = false;
177                 goto get_local_ips_free;
178             }
179             
180             *ipv4 = strdup(host);
181             break;
182         }
183     }
184
185
186     for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)  {
187         if (ifa->ifa_addr == NULL) {
188             continue;
189         }
190
191         s = getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in6),host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
192         if((strcmp(ifa->ifa_name, ifname) == 0) && (ifa->ifa_addr->sa_family == AF_INET6)) {
193             if (s != 0) {
194                 ret = false;
195                 goto get_local_ips_free;
196             }
197             
198             *ipv6 = strdup(host);
199             break;
200         }
201     }
202
203     get_local_ips_free:
204     if(ret == false) {
205         free(*ipv4);
206         free(*ipv6);
207         *ipv4 = 0;
208         *ipv6 = 0;
209     }
210
211     freeifaddrs(ifaddr);
212     return ret;
213 }
214
215 bool check_port_open(const char *host, uint16_t port) {
216     assert(host);
217
218     int simpleSocket = 0;
219     int returnStatus = 0; 
220     struct addrinfo simpleServer;
221     struct addrinfo *res;
222
223     memset(&simpleServer, 0, sizeof simpleServer);
224     simpleServer.ai_family = AF_UNSPEC;  // use IPv4 or IPv6, whichever
225     simpleServer.ai_socktype = SOCK_STREAM;
226     simpleServer.ai_flags = AI_ADDRCONFIG;
227
228     char sport[10];
229     sprintf(sport, "%d", port);
230
231     returnStatus = getaddrinfo(host, sport, &simpleServer, &res);
232     if(returnStatus != 0) {
233         return false;
234     }
235
236     simpleSocket = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
237     if(simpleSocket < 0) {
238         freeaddrinfo(res);
239         return false;
240     }
241
242     char s[INET6_ADDRSTRLEN];
243     switch(res->ai_addr->sa_family) {
244         case AF_INET: {
245             struct sockaddr_in *addr_in = (struct sockaddr_in *)res->ai_addr; 
246             inet_ntop(AF_INET, &(addr_in->sin_addr), s, INET_ADDRSTRLEN);
247             returnStatus = connect(simpleSocket, res->ai_addr, res->ai_addrlen);
248             break;
249         }
250
251         case AF_INET6: {
252             struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)res->ai_addr;
253             inet_ntop(AF_INET6, &(addr_in6->sin6_addr), s, INET6_ADDRSTRLEN);
254             returnStatus = connect(simpleSocket, res->ai_addr, res->ai_addrlen);
255             break;
256         }
257
258         default:
259             break;
260     }
261
262     freeaddrinfo(res);
263     close(simpleSocket);
264     if(returnStatus == 0) {    
265         return true;
266     }
267     
268     return false;
269 }
270
271 char *b64_encode(const uint8_t *data, size_t input_length) {
272     assert(data);
273     assert(input_length);
274
275     int output_length = 4 * ((input_length + 2) / 3);
276
277     char *encoded_data = (char *)malloc(sizeof(char) * (output_length + 1));
278     if (encoded_data == 0) {
279         return 0;
280     }
281
282     for (int i = 0, j = 0; i < input_length;) {
283         uint32_t octet_a = i < input_length ? (unsigned char)data[i++] : 0;
284         uint32_t octet_b = i < input_length ? (unsigned char)data[i++] : 0;
285         uint32_t octet_c = i < input_length ? (unsigned char)data[i++] : 0;
286
287         uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
288
289         encoded_data[j++] = b64_encoding_table[(triple >> 3 * 6) & 0x3F];
290         encoded_data[j++] = b64_encoding_table[(triple >> 2 * 6) & 0x3F];
291         encoded_data[j++] = b64_encoding_table[(triple >> 1 * 6) & 0x3F];
292         encoded_data[j++] = b64_encoding_table[(triple >> 0 * 6) & 0x3F];
293     }
294
295     for (int i = 0; i < b64_mod_table[input_length % 3]; i++) {
296         encoded_data[output_length - 1 - i] = '=';
297     }
298
299     encoded_data[output_length] = 0;
300
301     return encoded_data;
302 }
303
304 uint8_t *b64_decode(const char *data, size_t input_length, size_t *output_length) {
305     assert(data);
306     assert(input_length);
307     assert(output_length);
308
309     int i, j;
310
311     //one time compute decoding table
312     if(b64_decoding_table['A'] == 0) {
313         for(i = 0; i < 64; i++) {
314             b64_decoding_table[(unsigned char)b64_encoding_table[i]] = i;
315         }
316     }
317
318     if(input_length % 4 != 0) {
319         return 0;
320     }
321
322     *output_length = input_length / 4 * 3;
323     if(data[input_length - 1] == '=') {
324         (*output_length )--;
325     }
326     if(data[input_length - 2] == '=') {
327         (*output_length )--;
328     }
329
330     uint8_t *decoded_data = (uint8_t*)malloc(*output_length + 1);
331     if(decoded_data == 0) {
332         return 0;
333     }
334
335     for(i = 0, j = 0; i < input_length;) {
336         uint32_t sextet_a = data[i] == '=' ? 0 & i++ : b64_decoding_table[(int)data[i++]];
337         uint32_t sextet_b = data[i] == '=' ? 0 & i++ : b64_decoding_table[(int)data[i++]];
338         uint32_t sextet_c = data[i] == '=' ? 0 & i++ : b64_decoding_table[(int)data[i++]];
339         uint32_t sextet_d = data[i] == '=' ? 0 & i++ : b64_decoding_table[(int)data[i++]];
340         uint32_t triple = ( sextet_a << 3 * 6 ) + ( sextet_b << 2 * 6 ) + ( sextet_c << 1 * 6 ) + ( sextet_d << 0 * 6 );
341
342         if(j < *output_length) {
343             decoded_data[j++] = (triple >> 2 * 8) & 0xFF;
344         }
345
346         if(j < *output_length) {
347             decoded_data[j++] = (triple >> 1 * 8) & 0xFF;
348         }
349
350         if(j < *output_length) {
351             decoded_data[j++] = (triple >> 0 * 8) & 0xFF;
352         }
353     }
354
355     return decoded_data;
356 }
357
358 char *str_replace(const char *orig, const char *rep, const char *with) {
359     assert(orig);
360     assert(rep);
361     assert(with);
362
363     char *result; // the return string
364     const char *ins;    // the next insert point
365     char *tmp;    // varies
366     int len_rep;  // length of rep (the string to remove)
367     int len_with; // length of with (the string to replace rep with)
368     int len_front; // distance between rep and end of last rep
369     int count;    // number of replacements
370
371     // sanity checks and initialization
372     if(!orig || !rep) {
373         return 0;
374     }
375
376     len_rep = strlen(rep);
377     if(len_rep == 0) {
378         return 0; // empty rep causes infinite loop during count
379     }
380
381     if (!with) {
382         with = "";
383     }
384     len_with = strlen(with);
385
386     // count the number of replacements needed
387     ins = orig;
388     for(count = 0; (tmp = strstr(ins, rep)); ++count) {
389         ins = tmp + len_rep;
390     }
391
392     tmp = result = malloc(strlen(orig) + (len_with - len_rep) * count + 1);
393
394     if(!result) {
395         return 0;
396     }
397
398     // first time through the loop, all the variable are set correctly
399     // from here on,
400     //    tmp points to the end of the result string
401     //    ins points to the next occurrence of rep in orig
402     //    orig points to the remainder of orig after "end of rep"
403     while(count--) {
404         ins = strstr(orig, rep);
405         len_front = ins - orig;
406         tmp = strncpy(tmp, orig, len_front) + len_front;
407         tmp = strcpy(tmp, with) + len_with;
408         orig += len_front + len_rep; // move to next "end of rep"
409     }
410
411     strcpy(tmp, orig);
412     return result;
413 }
414
415 char *read_key(const char *filename) {
416     assert(filename);
417
418     FILE * fp = 0;
419     char * line = 0;
420     size_t len = 0;
421     ssize_t read;
422     char *key_string = 0;
423
424     fp = fopen(filename, "r");
425     if(fp == 0) {
426         log_error("could not open file %s\n", filename);
427         return 0;
428     }
429
430     while((read = getline(&line, &len, fp)) != -1) {
431         // we ignore the first and last lines forPrivate keys, Public keys and Certificates
432         if(strstr(line, "PRIVATE KEY-----") || strstr(line, "PUBLIC KEY-----") || strstr(line, "CERTIFICATE-----")) {
433             free(line);
434             line = 0;
435             len = 0;
436             continue;
437         }
438         else {
439             if(key_string) {
440                 key_string = (char *)realloc(key_string, strlen(key_string) + read + 1);
441                 if(key_string == 0) {
442                     log_error("bad allocation\n");
443                     free(line);
444                     return 0;
445                 }
446
447                 strcat(key_string, line);
448             }
449             else {
450                 key_string = strdup(line);
451                 if(key_string == 0) {
452                     log_error("bad allocation\n");
453                     free(line);
454                     return 0;
455                 }
456             }
457             
458             free(line);
459             line = 0;
460             len = 0;
461         }
462     }
463
464     fclose(fp);
465     if(line) {
466         free(line);
467     }
468
469     return key_string;
470 }
471
472 void vsftp_daemon_init(void) {
473     system("/usr/sbin/vsftpd &");
474 }
475
476 void vsftp_daemon_deinit(void) {
477     system("killall -9 vsftpd");
478 }
479
480 void sftp_daemon_init(void) {
481     system("/usr/sbin/sshd -D &");
482 }
483
484 void sftp_daemon_deinit(void) {
485     system("killall -9 sshd");
486 }