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