1 /*************************************************************************
3 * Copyright 2020 highstreet technologies GmbH and others
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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 ***************************************************************************/
20 #include "sys_utils.h"
21 #include "log_utils.h"
33 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <arpa/inet.h>
37 #include <linux/if_link.h>
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', '+', '/'};
49 static char b64_decoding_table[256] = {0};
51 static int b64_mod_table[] = {0, 2, 1};
53 bool dir_exists(const char *path) {
57 return (stat(path, &st) != -1);
60 bool file_exists(const char *fname) {
63 return (access(fname, F_OK) != -1);
66 void file_touch(const char *fname, const char *content) {
69 FILE *f = fopen(fname, "w");
71 log_error("fopen failed\n");
76 fprintf(f, "%s", content);
81 char *file_read_content(const char *fname) {
86 FILE *f = fopen(fname, "rb");
88 fseek(f, 0, SEEK_END);
90 fseek(f, 0, SEEK_SET);
91 buffer = (char*)malloc(sizeof(char) * (length + 1));
93 fread(buffer, 1, length, f);
102 int get_int_from_string_with_default(const char *string, int default_value) {
104 int value = default_value;
107 rc = sscanf(string, "%d", &value);
109 value = default_value;
115 char *get_current_date_and_time(void) {
116 char *date_and_time = 0;
119 struct tm tm = *localtime(&t);
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
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);
135 return date_and_time;
138 char *get_current_date_and_time_delay_seconds(int seconds) {
139 char *date_and_time = 0;
142 struct tm tm = *localtime(&t);
145 gettimeofday(&tv, 0);
147 tm.tm_sec += seconds;
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);
154 return date_and_time;
157 long int get_microseconds_since_epoch(void) {
162 gettimeofday(&tv, 0);
163 useconds = t*1000000 + tv.tv_usec; //add the microseconds to the seconds
169 bool get_local_ips(const char *ifname, char **ipv4, char **ipv6) {
175 struct ifaddrs *ifaddr;
177 char host[NI_MAXHOST];
183 if (getifaddrs(&ifaddr) == -1) {
185 goto get_local_ips_free;
188 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
189 if (ifa->ifa_addr == NULL) {
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)) {
197 goto get_local_ips_free;
200 *ipv4 = strdup(host);
206 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
207 if (ifa->ifa_addr == NULL) {
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)) {
215 goto get_local_ips_free;
218 *ipv6 = strdup(host);
235 bool check_port_open(const char *host, uint16_t port) {
238 int simpleSocket = 0;
239 int returnStatus = 0;
240 struct addrinfo simpleServer;
241 struct addrinfo *res;
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;
249 sprintf(sport, "%d", port);
251 returnStatus = getaddrinfo(host, sport, &simpleServer, &res);
252 if(returnStatus != 0) {
256 simpleSocket = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
257 if(simpleSocket < 0) {
262 char s[INET6_ADDRSTRLEN];
263 switch(res->ai_addr->sa_family) {
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);
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);
284 if(returnStatus == 0) {
291 char *b64_encode(const uint8_t *data, size_t input_length) {
293 assert(input_length);
295 int output_length = 4 * ((input_length + 2) / 3);
297 char *encoded_data = (char *)malloc(sizeof(char) * (output_length + 1));
298 if (encoded_data == 0) {
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;
307 uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
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];
315 for (int i = 0; i < b64_mod_table[input_length % 3]; i++) {
316 encoded_data[output_length - 1 - i] = '=';
319 encoded_data[output_length] = 0;
324 uint8_t *b64_decode(const char *data, size_t input_length, size_t *output_length) {
326 assert(input_length);
327 assert(output_length);
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;
338 if(input_length % 4 != 0) {
342 *output_length = input_length / 4 * 3;
343 if(data[input_length - 1] == '=') {
346 if(data[input_length - 2] == '=') {
350 uint8_t *decoded_data = (uint8_t*)malloc(*output_length + 1);
351 if(decoded_data == 0) {
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 );
362 if(j < *output_length) {
363 decoded_data[j++] = (triple >> 2 * 8) & 0xFF;
366 if(j < *output_length) {
367 decoded_data[j++] = (triple >> 1 * 8) & 0xFF;
370 if(j < *output_length) {
371 decoded_data[j++] = (triple >> 0 * 8) & 0xFF;
378 char *str_replace(const char *orig, const char *rep, const char *with) {
383 char *result; // the return string
384 const char *ins; // the next insert point
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
391 // sanity checks and initialization
396 len_rep = strlen(rep);
398 return 0; // empty rep causes infinite loop during count
404 len_with = strlen(with);
406 // count the number of replacements needed
408 for(count = 0; (tmp = strstr(ins, rep)); ++count) {
412 tmp = result = malloc(strlen(orig) + (len_with - len_rep) * count + 1);
418 // first time through the loop, all the variable are set correctly
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"
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"
435 char *read_key(const char *filename) {
442 char *key_string = 0;
444 fp = fopen(filename, "r");
446 log_error("could not open file %s\n", filename);
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-----")) {
460 key_string = (char *)realloc(key_string, strlen(key_string) + read + 1);
461 if(key_string == 0) {
462 log_error("bad allocation\n");
467 strcat(key_string, line);
470 key_string = strdup(line);
471 if(key_string == 0) {
472 log_error("bad allocation\n");
492 void vsftp_daemon_init(void) {
493 system("/usr/sbin/vsftpd &");
496 void vsftp_daemon_deinit(void) {
497 system("killall -9 vsftpd");
500 void sftp_daemon_init(void) {
501 system("/usr/sbin/sshd -D &");
504 void sftp_daemon_deinit(void) {
505 system("killall -9 sshd");