1    	/*
2    	 * Copyright (C) 2017-2026 Red Hat, Inc.  All rights reserved.
3    	 *
4    	 * Author: Fabio M. Di Nitto <fabbione@kronosnet.org>
5    	 *
6    	 * This software licensed under LGPL-2.0+
7    	 */
8    	
9    	#include "config.h"
10   	
11   	#include <errno.h>
12   	#include <stdlib.h>
13   	#include <string.h>
14   	#include <sys/types.h>
15   	#include <sys/stat.h>
16   	#include <sys/wait.h>
17   	#include <unistd.h>
18   	#include <limits.h>
19   	#include <stdio.h>
20   	#include <stdint.h>
21   	#include <netinet/in.h>
22   	#include <arpa/inet.h>
23   	
24   	#include "libnozzle.h"
25   	#include "internals.h"
26   	
27   	static int read_pipe(int fd, char **file, size_t *length)
28   	{
29   		char buf[4096];
30   		int n;
31   		int done = 0;
32   	
33   		*file = NULL;
34   		*length = 0;
35   	
36   		memset(buf, 0, sizeof(buf));
37   	
(1) Event path: Condition "!done", taking true branch.
(8) Event path: Condition "!done", taking true branch.
(16) Event path: Condition "!done", taking true branch.
(27) Event path: Condition "!done", taking false branch.
38   		while (!done) {
39   	
40   			n = read(fd, buf, sizeof(buf));
41   	
(2) Event path: Condition "n < 0", taking false branch.
(9) Event path: Condition "n < 0", taking false branch.
(17) Event path: Condition "n < 0", taking false branch.
42   			if (n < 0) {
43   				if (errno == EINTR)
44   					continue;
45   	
46   				if (*file)
47   					free(*file);
48   	
49   				return n;
50   			}
51   	
(3) Event path: Condition "n == 0", taking false branch.
(10) Event path: Condition "n == 0", taking false branch.
(18) Event path: Condition "n == 0", taking true branch.
(19) Event path: Condition "!*length", taking false branch.
52   			if (n == 0 && (!*length))
53   				return 0;
54   	
(4) Event path: Condition "n == 0", taking false branch.
(11) Event path: Condition "n == 0", taking false branch.
(20) Event path: Condition "n == 0", taking true branch.
55   			if (n == 0)
56   				done = 1;
57   	
(5) Event path: Condition "*file", taking false branch.
(12) Event path: Condition "*file", taking true branch.
(21) Event path: Condition "*file", taking true branch.
58   			if (*file)
(13) Event path: Falling through to end of if statement.
(22) Event alloc_fn: Storage is returned from allocation function "realloc".
(23) Event assign: Assigning: "*file" = "realloc(*file, *length + n + done)".
(24) Event path: Falling through to end of if statement.
59   				*file = realloc(*file, (*length) + n + done);
60   			else
61   				*file = malloc(n + done);
62   	
(6) Event path: Condition "!*file", taking false branch.
(14) Event path: Condition "!*file", taking false branch.
(25) Event path: Condition "!*file", taking false branch.
63   			if (!*file)
64   				return -1;
65   	
66   			memmove((*file) + (*length), buf, n);
67   			*length += (done + n);
(7) Event path: Jumping back to the beginning of the loop.
(15) Event path: Jumping back to the beginning of the loop.
(26) Event path: Jumping back to the beginning of the loop.
68   		}
69   	
70   		/* Null terminator */
71   		(*file)[(*length) - 1] = 0;
72   	
73   		return 0;
74   	}
75   	
76   	int execute_bin_sh_command(const char *command, char **error_string)
77   	{
78   		pid_t pid;
79   		int status, err = 0;
80   		int fd[2];
81   		size_t size = 0;
82   	
(1) Event path: Condition "command == NULL", taking false branch.
(2) Event path: Condition "!error_string", taking false branch.
83   		if ((command == NULL) || (!error_string)) {
84   			errno = EINVAL;
85   			return -1;
86   		}
87   	
88   		*error_string = NULL;
89   	
90   		err = pipe(fd);
(3) Event path: Condition "err", taking false branch.
91   		if (err)
92   			goto out_clean;
93   	
94   		pid = fork();
(4) Event path: Condition "pid < 0", taking false branch.
95   		if (pid < 0) {
96   			err = pid;
97   			goto out_clean;
98   		}
99   	
(5) Event path: Condition "pid", taking true branch.
100  		if (pid) { /* parent */
101  	
102  			close(fd[1]);
(6) Event alloc_arg: "read_pipe" allocates memory that is stored into "*error_string". [details]
103  			err = read_pipe(fd[0], error_string, &size);
(7) Event path: Condition "err", taking false branch.
104  			if (err)
105  				goto out_clean0;
106  	
107  			waitpid(pid, &status, 0);
(8) Event path: Condition "!((status & 0x7f) == 0)", taking true branch.
108  			if (!WIFEXITED(status)) {
109  				err = -1;
(9) Event path: Jumping to label "out_clean0".
110  				goto out_clean0;
111  			}
112  			if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
113  				err = WEXITSTATUS(status);
114  				goto out_clean0;
115  			}
116  			goto out_clean0;
117  		} else { /* child */
118  			close(0);
119  			close(1);
120  			close(2);
121  	
122  			close(fd[0]);
123  			dup2(fd[1], 1);
124  			dup2(fd[1], 2);
125  			close(fd[1]);
126  	
127  			execlp("/bin/sh", "/bin/sh", "-c", command, NULL);
128  			exit(EXIT_FAILURE);
129  		}
130  	
131  	out_clean:
132  		close(fd[1]);
133  	out_clean0:
134  		close(fd[0]);
135  	
136  		return err;
137  	}
138  	
139  	char *generate_v4_broadcast(const char *ipaddr, const char *prefix)
140  	{
141  		int prefix_len;
142  		struct in_addr mask;
143  		struct in_addr broadcast;
144  		struct in_addr address;
145  		char buf[INET6_ADDRSTRLEN];
146  	
147  		prefix_len = atoi(prefix);
148  	
149  		if ((prefix_len > 32) || (prefix_len <= 0))
150  			return NULL;
151  	
152  		if (inet_pton(AF_INET, ipaddr, &address) <= 0)
153  			return NULL;
154  	
155  		mask.s_addr = htonl(~((1 << (32 - prefix_len)) - 1));
156  	
157  		memset(&broadcast, 0, sizeof(broadcast));
158  		broadcast.s_addr = (address.s_addr & mask.s_addr) | ~mask.s_addr;
159  	
160  		return strdup(inet_ntop(AF_INET, (void *)&broadcast, buf, sizeof(buf)));
161  	}
162  	
163  	int _determine_family(const char *ipaddr)
164  	{
165  		if (!strchr(ipaddr, ':')) {
166  			return AF_INET;
167  		}
168  		return AF_INET6;
169  	}
170  	
171  	int _validate_prefix(int family, const char *prefix)
172  	{
173  		int prefix_len;
174  	
175  		prefix_len = atoi(prefix);
176  	
177  		if (family == AF_INET) {
178  			if (prefix_len <= 0 || prefix_len > 32) {
179  				errno = EINVAL;
180  				return -1;
181  			}
182  		} else {
183  			if (prefix_len <= 0 || prefix_len > 128) {
184  				errno = EINVAL;
185  				return -1;
186  			}
187  		}
188  	
189  		return prefix_len;
190  	}
191  	
192  	uint32_t _ipv4_prefix_to_netmask(int prefix_len)
193  	{
194  		return htonl(~((1 << (32 - prefix_len)) - 1));
195  	}
196  	
197  	void _ipv6_prefix_to_mask(int prefix_len, struct in6_addr *mask)
198  	{
199  		int i;
200  	
201  		for (i = 0; i < (int)sizeof(struct in6_addr); i++) {
202  			if (prefix_len >= 8) {
203  				mask->s6_addr[i] = 0xff;
204  				prefix_len -= 8;
205  			} else if (prefix_len > 0) {
206  				mask->s6_addr[i] = (0xff << (8 - prefix_len)) & 0xff;
207  				prefix_len = 0;
208  			} else {
209  				mask->s6_addr[i] = 0;
210  			}
211  		}
212  	}
213  	
214  	int find_ip(nozzle_t nozzle,
215  		    const char *ipaddr, const char *prefix,
216  		    struct nozzle_ip **ip, struct nozzle_ip **ip_prev)
217  	{
218  		struct nozzle_ip *local_ip, *local_ip_prev;
219  		int found = 0;
220  	
221  		local_ip = local_ip_prev = nozzle->ip;
222  	
223  		while(local_ip) {
224  			if ((!strcmp(local_ip->ipaddr, ipaddr)) && (!strcmp(local_ip->prefix, prefix))) {
225  				found = 1;
226  				break;
227  			}
228  			local_ip_prev = local_ip;
229  			local_ip = local_ip->next;
230  		}
231  	
232  		if (found) {
233  			*ip = local_ip;
234  			*ip_prev = local_ip_prev;
235  		}
236  	
237  		return found;
238  	}
239