1 /*
2  * An implementation of key value pair (KVP) functionality for Linux.
3  *
4  *
5  * Copyright (C) 2010, Novell, Inc.
6  * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License version 2 as published
10  * by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
15  * NON INFRINGEMENT.  See the GNU General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  */
23 
24 
25 #include <sys/poll.h>
26 #include <sys/utsname.h>
27 #include <stdbool.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <errno.h>
34 #include <arpa/inet.h>
35 #include <linux/hyperv.h>
36 #include <ifaddrs.h>
37 #include <netdb.h>
38 #include <syslog.h>
39 #include <sys/stat.h>
40 #include <fcntl.h>
41 #include <dirent.h>
42 #include <net/if.h>
43 #include <limits.h>
44 #include <getopt.h>
45 
46 /*
47  * KVP protocol: The user mode component first registers with the
48  * kernel component. Subsequently, the kernel component requests, data
49  * for the specified keys. In response to this message the user mode component
50  * fills in the value corresponding to the specified key. We overload the
51  * sequence field in the cn_msg header to define our KVP message types.
52  *
53  * We use this infrastructure for also supporting queries from user mode
54  * application for state that may be maintained in the KVP kernel component.
55  *
56  */
57 
58 
59 enum key_index {
60 	FullyQualifiedDomainName = 0,
61 	IntegrationServicesVersion, /*This key is serviced in the kernel*/
62 	NetworkAddressIPv4,
63 	NetworkAddressIPv6,
64 	OSBuildNumber,
65 	OSName,
66 	OSMajorVersion,
67 	OSMinorVersion,
68 	OSVersion,
69 	ProcessorArchitecture
70 };
71 
72 
73 enum {
74 	IPADDR = 0,
75 	NETMASK,
76 	GATEWAY,
77 	DNS
78 };
79 
80 enum {
81 	IPV4 = 1,
82 	IPV6,
83 	IP_TYPE_MAX
84 };
85 
86 static int in_hand_shake;
87 
88 static char *os_name = "";
89 static char *os_major = "";
90 static char *os_minor = "";
91 static char *processor_arch;
92 static char *os_build;
93 static char *os_version;
94 static char *lic_version = "Unknown version";
95 static char full_domain_name[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
96 static struct utsname uts_buf;
97 
98 /*
99  * The location of the interface configuration file.
100  */
101 
102 #define KVP_CONFIG_LOC	"/var/lib/hyperv"
103 
104 #ifndef KVP_SCRIPTS_PATH
105 #define KVP_SCRIPTS_PATH "/usr/libexec/hypervkvpd/"
106 #endif
107 
108 #define KVP_NET_DIR "/sys/class/net/"
109 
110 #define MAX_FILE_NAME 100
111 #define ENTRIES_PER_BLOCK 50
112 /*
113  * Change this entry if the number of addresses increases in future
114  */
115 #define MAX_IP_ENTRIES 64
116 #define OUTSTR_BUF_SIZE ((INET6_ADDRSTRLEN + 1) * MAX_IP_ENTRIES)
117 
118 struct kvp_record {
119 	char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
120 	char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
121 };
122 
123 struct kvp_file_state {
124 	int fd;
125 	int num_blocks;
126 	struct kvp_record *records;
127 	int num_records;
128 	char fname[MAX_FILE_NAME];
129 };
130 
131 static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT];
132 
kvp_acquire_lock(int pool)133 static void kvp_acquire_lock(int pool)
134 {
135 	struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0};
136 	fl.l_pid = getpid();
137 
138 	if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
139 		syslog(LOG_ERR, "Failed to acquire the lock pool: %d; error: %d %s", pool,
140 				errno, strerror(errno));
141 		exit(EXIT_FAILURE);
142 	}
143 }
144 
kvp_release_lock(int pool)145 static void kvp_release_lock(int pool)
146 {
147 	struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
148 	fl.l_pid = getpid();
149 
150 	if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
151 		syslog(LOG_ERR, "Failed to release the lock pool: %d; error: %d %s", pool,
152 				errno, strerror(errno));
153 		exit(EXIT_FAILURE);
154 	}
155 }
156 
kvp_update_file(int pool)157 static void kvp_update_file(int pool)
158 {
159 	FILE *filep;
160 
161 	/*
162 	 * We are going to write our in-memory registry out to
163 	 * disk; acquire the lock first.
164 	 */
165 	kvp_acquire_lock(pool);
166 
167 	filep = fopen(kvp_file_info[pool].fname, "we");
168 	if (!filep) {
169 		syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool,
170 				errno, strerror(errno));
171 		kvp_release_lock(pool);
172 		exit(EXIT_FAILURE);
173 	}
174 
175 	fwrite(kvp_file_info[pool].records, sizeof(struct kvp_record),
176 				kvp_file_info[pool].num_records, filep);
177 
178 	if (ferror(filep) || fclose(filep)) {
179 		kvp_release_lock(pool);
180 		syslog(LOG_ERR, "Failed to write file, pool: %d", pool);
181 		exit(EXIT_FAILURE);
182 	}
183 
184 	kvp_release_lock(pool);
185 }
186 
kvp_update_mem_state(int pool)187 static void kvp_update_mem_state(int pool)
188 {
189 	FILE *filep;
190 	size_t records_read = 0;
191 	struct kvp_record *record = kvp_file_info[pool].records;
192 	struct kvp_record *readp;
193 	int num_blocks = kvp_file_info[pool].num_blocks;
194 	int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
195 
196 	kvp_acquire_lock(pool);
197 
198 	filep = fopen(kvp_file_info[pool].fname, "re");
199 	if (!filep) {
200 		syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool,
201 				errno, strerror(errno));
202 		kvp_release_lock(pool);
203 		exit(EXIT_FAILURE);
204 	}
205 	for (;;) {
206 		readp = &record[records_read];
207 		records_read += fread(readp, sizeof(struct kvp_record),
208 				ENTRIES_PER_BLOCK * num_blocks - records_read,
209 				filep);
210 
211 		if (ferror(filep)) {
212 			syslog(LOG_ERR,
213 				"Failed to read file, pool: %d; error: %d %s",
214 				 pool, errno, strerror(errno));
215 			kvp_release_lock(pool);
216 			exit(EXIT_FAILURE);
217 		}
218 
219 		if (!feof(filep)) {
220 			/*
221 			 * We have more data to read.
222 			 */
223 			num_blocks++;
224 			record = realloc(record, alloc_unit * num_blocks);
225 
226 			if (record == NULL) {
227 				syslog(LOG_ERR, "malloc failed");
228 				kvp_release_lock(pool);
229 				exit(EXIT_FAILURE);
230 			}
231 			continue;
232 		}
233 		break;
234 	}
235 
236 	kvp_file_info[pool].num_blocks = num_blocks;
237 	kvp_file_info[pool].records = record;
238 	kvp_file_info[pool].num_records = records_read;
239 
240 	fclose(filep);
241 	kvp_release_lock(pool);
242 }
243 
kvp_file_init(void)244 static int kvp_file_init(void)
245 {
246 	int  fd;
247 	char *fname;
248 	int i;
249 	int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
250 
251 	if (access(KVP_CONFIG_LOC, F_OK)) {
252 		if (mkdir(KVP_CONFIG_LOC, 0755 /* rwxr-xr-x */)) {
253 			syslog(LOG_ERR, "Failed to create '%s'; error: %d %s", KVP_CONFIG_LOC,
254 					errno, strerror(errno));
255 			exit(EXIT_FAILURE);
256 		}
257 	}
258 
259 	for (i = 0; i < KVP_POOL_COUNT; i++) {
260 		fname = kvp_file_info[i].fname;
261 		sprintf(fname, "%s/.kvp_pool_%d", KVP_CONFIG_LOC, i);
262 		fd = open(fname, O_RDWR | O_CREAT | O_CLOEXEC, 0644 /* rw-r--r-- */);
263 
264 		if (fd == -1)
265 			return 1;
266 
267 		kvp_file_info[i].fd = fd;
268 		kvp_file_info[i].num_blocks = 1;
269 		kvp_file_info[i].records = malloc(alloc_unit);
270 		if (kvp_file_info[i].records == NULL)
271 			return 1;
272 		kvp_file_info[i].num_records = 0;
273 		kvp_update_mem_state(i);
274 	}
275 
276 	return 0;
277 }
278 
kvp_key_delete(int pool,const __u8 * key,int key_size)279 static int kvp_key_delete(int pool, const __u8 *key, int key_size)
280 {
281 	int i;
282 	int j, k;
283 	int num_records;
284 	struct kvp_record *record;
285 
286 	/*
287 	 * First update the in-memory state.
288 	 */
289 	kvp_update_mem_state(pool);
290 
291 	num_records = kvp_file_info[pool].num_records;
292 	record = kvp_file_info[pool].records;
293 
294 	for (i = 0; i < num_records; i++) {
295 		if (memcmp(key, record[i].key, key_size))
296 			continue;
297 		/*
298 		 * Found a match; just move the remaining
299 		 * entries up.
300 		 */
301 		if (i == (num_records - 1)) {
302 			kvp_file_info[pool].num_records--;
303 			kvp_update_file(pool);
304 			return 0;
305 		}
306 
307 		j = i;
308 		k = j + 1;
309 		for (; k < num_records; k++) {
310 			strcpy(record[j].key, record[k].key);
311 			strcpy(record[j].value, record[k].value);
312 			j++;
313 		}
314 
315 		kvp_file_info[pool].num_records--;
316 		kvp_update_file(pool);
317 		return 0;
318 	}
319 	return 1;
320 }
321 
kvp_key_add_or_modify(int pool,const __u8 * key,int key_size,const __u8 * value,int value_size)322 static int kvp_key_add_or_modify(int pool, const __u8 *key, int key_size,
323 				 const __u8 *value, int value_size)
324 {
325 	int i;
326 	int num_records;
327 	struct kvp_record *record;
328 	int num_blocks;
329 
330 	if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
331 		(value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
332 		return 1;
333 
334 	/*
335 	 * First update the in-memory state.
336 	 */
337 	kvp_update_mem_state(pool);
338 
339 	num_records = kvp_file_info[pool].num_records;
340 	record = kvp_file_info[pool].records;
341 	num_blocks = kvp_file_info[pool].num_blocks;
342 
343 	for (i = 0; i < num_records; i++) {
344 		if (memcmp(key, record[i].key, key_size))
345 			continue;
346 		/*
347 		 * Found a match; just update the value -
348 		 * this is the modify case.
349 		 */
350 		memcpy(record[i].value, value, value_size);
351 		kvp_update_file(pool);
352 		return 0;
353 	}
354 
355 	/*
356 	 * Need to add a new entry;
357 	 */
358 	if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
359 		/* Need to allocate a larger array for reg entries. */
360 		record = realloc(record, sizeof(struct kvp_record) *
361 			 ENTRIES_PER_BLOCK * (num_blocks + 1));
362 
363 		if (record == NULL)
364 			return 1;
365 		kvp_file_info[pool].num_blocks++;
366 
367 	}
368 	memcpy(record[i].value, value, value_size);
369 	memcpy(record[i].key, key, key_size);
370 	kvp_file_info[pool].records = record;
371 	kvp_file_info[pool].num_records++;
372 	kvp_update_file(pool);
373 	return 0;
374 }
375 
kvp_get_value(int pool,const __u8 * key,int key_size,__u8 * value,int value_size)376 static int kvp_get_value(int pool, const __u8 *key, int key_size, __u8 *value,
377 			int value_size)
378 {
379 	int i;
380 	int num_records;
381 	struct kvp_record *record;
382 
383 	if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
384 		(value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
385 		return 1;
386 
387 	/*
388 	 * First update the in-memory state.
389 	 */
390 	kvp_update_mem_state(pool);
391 
392 	num_records = kvp_file_info[pool].num_records;
393 	record = kvp_file_info[pool].records;
394 
395 	for (i = 0; i < num_records; i++) {
396 		if (memcmp(key, record[i].key, key_size))
397 			continue;
398 		/*
399 		 * Found a match; just copy the value out.
400 		 */
401 		memcpy(value, record[i].value, value_size);
402 		return 0;
403 	}
404 
405 	return 1;
406 }
407 
kvp_pool_enumerate(int pool,int index,__u8 * key,int key_size,__u8 * value,int value_size)408 static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
409 				__u8 *value, int value_size)
410 {
411 	struct kvp_record *record;
412 
413 	/*
414 	 * First update our in-memory database.
415 	 */
416 	kvp_update_mem_state(pool);
417 	record = kvp_file_info[pool].records;
418 
419 	if (index >= kvp_file_info[pool].num_records) {
420 		return 1;
421 	}
422 
423 	memcpy(key, record[index].key, key_size);
424 	memcpy(value, record[index].value, value_size);
425 	return 0;
426 }
427 
428 
kvp_get_os_info(void)429 void kvp_get_os_info(void)
430 {
431 	FILE	*file;
432 	char	*p, buf[512];
433 
434 	uname(&uts_buf);
435 	os_version = uts_buf.release;
436 	os_build = strdup(uts_buf.release);
437 
438 	os_name = uts_buf.sysname;
439 	processor_arch = uts_buf.machine;
440 
441 	/*
442 	 * The current windows host (win7) expects the build
443 	 * string to be of the form: x.y.z
444 	 * Strip additional information we may have.
445 	 */
446 	p = strchr(os_version, '-');
447 	if (p)
448 		*p = '\0';
449 
450 	/*
451 	 * Parse the /etc/os-release file if present:
452 	 * https://www.freedesktop.org/software/systemd/man/os-release.html
453 	 */
454 	file = fopen("/etc/os-release", "r");
455 	if (file != NULL) {
456 		while (fgets(buf, sizeof(buf), file)) {
457 			char *value, *q;
458 
459 			/* Ignore comments */
460 			if (buf[0] == '#')
461 				continue;
462 
463 			/* Split into name=value */
464 			p = strchr(buf, '=');
465 			if (!p)
466 				continue;
467 			*p++ = 0;
468 
469 			/* Remove quotes and newline; un-escape */
470 			value = p;
471 			q = p;
472 			while (*p) {
473 				if (*p == '\\') {
474 					++p;
475 					if (!*p)
476 						break;
477 					*q++ = *p++;
478 				} else if (*p == '\'' || *p == '"' ||
479 					   *p == '\n') {
480 					++p;
481 				} else {
482 					*q++ = *p++;
483 				}
484 			}
485 			*q = 0;
486 
487 			if (!strcmp(buf, "NAME")) {
488 				p = strdup(value);
489 				if (!p)
490 					break;
491 				os_name = p;
492 			} else if (!strcmp(buf, "VERSION_ID")) {
493 				p = strdup(value);
494 				if (!p)
495 					break;
496 				os_major = p;
497 			}
498 		}
499 		fclose(file);
500 		return;
501 	}
502 
503 	/* Fallback for older RH/SUSE releases */
504 	file = fopen("/etc/SuSE-release", "r");
505 	if (file != NULL)
506 		goto kvp_osinfo_found;
507 	file  = fopen("/etc/redhat-release", "r");
508 	if (file != NULL)
509 		goto kvp_osinfo_found;
510 
511 	/*
512 	 * We don't have information about the os.
513 	 */
514 	return;
515 
516 kvp_osinfo_found:
517 	/* up to three lines */
518 	p = fgets(buf, sizeof(buf), file);
519 	if (p) {
520 		p = strchr(buf, '\n');
521 		if (p)
522 			*p = '\0';
523 		p = strdup(buf);
524 		if (!p)
525 			goto done;
526 		os_name = p;
527 
528 		/* second line */
529 		p = fgets(buf, sizeof(buf), file);
530 		if (p) {
531 			p = strchr(buf, '\n');
532 			if (p)
533 				*p = '\0';
534 			p = strdup(buf);
535 			if (!p)
536 				goto done;
537 			os_major = p;
538 
539 			/* third line */
540 			p = fgets(buf, sizeof(buf), file);
541 			if (p)  {
542 				p = strchr(buf, '\n');
543 				if (p)
544 					*p = '\0';
545 				p = strdup(buf);
546 				if (p)
547 					os_minor = p;
548 			}
549 		}
550 	}
551 
552 done:
553 	fclose(file);
554 	return;
555 }
556 
557 
558 
559 /*
560  * Retrieve an interface name corresponding to the specified guid.
561  * If there is a match, the function returns a pointer
562  * to the interface name and if not, a NULL is returned.
563  * If a match is found, the caller is responsible for
564  * freeing the memory.
565  */
566 
kvp_get_if_name(char * guid)567 static char *kvp_get_if_name(char *guid)
568 {
569 	DIR *dir;
570 	struct dirent *entry;
571 	FILE    *file;
572 	char    *p, *x;
573 	char    *if_name = NULL;
574 	char    buf[256];
575 	char dev_id[PATH_MAX];
576 
577 	dir = opendir(KVP_NET_DIR);
578 	if (dir == NULL)
579 		return NULL;
580 
581 	while ((entry = readdir(dir)) != NULL) {
582 		/*
583 		 * Set the state for the next pass.
584 		 */
585 		snprintf(dev_id, sizeof(dev_id), "%s%s/device/device_id",
586 			 KVP_NET_DIR, entry->d_name);
587 
588 		file = fopen(dev_id, "r");
589 		if (file == NULL)
590 			continue;
591 
592 		p = fgets(buf, sizeof(buf), file);
593 		if (p) {
594 			x = strchr(p, '\n');
595 			if (x)
596 				*x = '\0';
597 
598 			if (!strcmp(p, guid)) {
599 				/*
600 				 * Found the guid match; return the interface
601 				 * name. The caller will free the memory.
602 				 */
603 				if_name = strdup(entry->d_name);
604 				fclose(file);
605 				break;
606 			}
607 		}
608 		fclose(file);
609 	}
610 
611 	closedir(dir);
612 	return if_name;
613 }
614 
615 /*
616  * Retrieve the MAC address given the interface name.
617  */
618 
kvp_if_name_to_mac(char * if_name)619 static char *kvp_if_name_to_mac(char *if_name)
620 {
621 	FILE    *file;
622 	char    *p, *x;
623 	char    buf[256];
624 	char addr_file[PATH_MAX];
625 	unsigned int i;
626 	char *mac_addr = NULL;
627 
628 	snprintf(addr_file, sizeof(addr_file), "%s%s%s", KVP_NET_DIR,
629 		 if_name, "/address");
630 
631 	file = fopen(addr_file, "r");
632 	if (file == NULL)
633 		return NULL;
634 
635 	p = fgets(buf, sizeof(buf), file);
636 	if (p) {
637 		x = strchr(p, '\n');
638 		if (x)
639 			*x = '\0';
640 		for (i = 0; i < strlen(p); i++)
641 			p[i] = toupper(p[i]);
642 		mac_addr = strdup(p);
643 	}
644 
645 	fclose(file);
646 	return mac_addr;
647 }
648 
kvp_process_ipconfig_file(char * cmd,char * config_buf,unsigned int len,int element_size,int offset)649 static void kvp_process_ipconfig_file(char *cmd,
650 					char *config_buf, unsigned int len,
651 					int element_size, int offset)
652 {
653 	char buf[256];
654 	char *p;
655 	char *x;
656 	FILE *file;
657 
658 	/*
659 	 * First execute the command.
660 	 */
661 	file = popen(cmd, "r");
662 	if (file == NULL)
663 		return;
664 
665 	if (offset == 0)
666 		memset(config_buf, 0, len);
667 	while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
668 		if (len < strlen(config_buf) + element_size + 1)
669 			break;
670 
671 		x = strchr(p, '\n');
672 		if (x)
673 			*x = '\0';
674 
675 		strcat(config_buf, p);
676 		strcat(config_buf, ";");
677 	}
678 	pclose(file);
679 }
680 
kvp_verify_ip_address(const void * address_string)681 static bool kvp_verify_ip_address(const void *address_string)
682 {
683 	char verify_buf[sizeof(struct in6_addr)];
684 
685 	if (inet_pton(AF_INET, address_string, verify_buf) == 1)
686 		return true;
687 	if (inet_pton(AF_INET6, address_string, verify_buf) == 1)
688 		return true;
689 	return false;
690 }
691 
kvp_extract_routes(const char * line,void ** output,size_t * remaining)692 static void kvp_extract_routes(const char *line, void **output, size_t *remaining)
693 {
694 	static const char needle[] = "via ";
695 	const char *match, *haystack = line;
696 
697 	while ((match = strstr(haystack, needle))) {
698 		const char *address, *next_char;
699 
700 		/* Address starts after needle. */
701 		address = match + strlen(needle);
702 
703 		/* The char following address is a space or end of line. */
704 		next_char = strpbrk(address, " \t\\");
705 		if (!next_char)
706 			next_char = address + strlen(address) + 1;
707 
708 		/* Enough room for address and semicolon. */
709 		if (*remaining >= (next_char - address) + 1) {
710 			memcpy(*output, address, next_char - address);
711 			/* Terminate string for verification. */
712 			memcpy(*output + (next_char - address), "", 1);
713 			if (kvp_verify_ip_address(*output)) {
714 				/* Advance output buffer. */
715 				*output += next_char - address;
716 				*remaining -= next_char - address;
717 
718 				/* Each address needs a trailing semicolon. */
719 				memcpy(*output, ";", 1);
720 				*output += 1;
721 				*remaining -= 1;
722 			}
723 		}
724 		haystack = next_char;
725 	}
726 }
727 
kvp_get_gateway(void * buffer,size_t buffer_len)728 static void kvp_get_gateway(void *buffer, size_t buffer_len)
729 {
730 	static const char needle[] = "default ";
731 	FILE *f;
732 	void *output = buffer;
733 	char *line = NULL;
734 	size_t alloc_size = 0, remaining = buffer_len - 1;
735 	ssize_t num_chars;
736 
737 	/* Show route information in a single line, for each address family */
738 	f = popen("ip --oneline -4 route show;ip --oneline -6 route show", "r");
739 	if (!f) {
740 		/* Convert buffer into C-String. */
741 		memcpy(output, "", 1);
742 		return;
743 	}
744 	while ((num_chars = getline(&line, &alloc_size, f)) > 0) {
745 		/* Skip short lines. */
746 		if (num_chars <= strlen(needle))
747 			continue;
748 		/* Skip lines without default route. */
749 		if (memcmp(line, needle, strlen(needle)))
750 			continue;
751 		/* Remove trailing newline to simplify further parsing. */
752 		if (line[num_chars - 1] == '\n')
753 			line[num_chars - 1] = '\0';
754 		/* Search routes after match. */
755 		kvp_extract_routes(line + strlen(needle), &output, &remaining);
756 	}
757 	/* Convert buffer into C-String. */
758 	memcpy(output, "", 1);
759 	free(line);
760 	pclose(f);
761 }
762 
kvp_get_ipconfig_info(char * if_name,struct hv_kvp_ipaddr_value * buffer)763 static void kvp_get_ipconfig_info(char *if_name,
764 				 struct hv_kvp_ipaddr_value *buffer)
765 {
766 	char cmd[512];
767 	char dhcp_info[128];
768 	char *p;
769 	FILE *file;
770 
771 	kvp_get_gateway(buffer->gate_way, sizeof(buffer->gate_way));
772 
773 	/*
774 	 * Gather the DNS state.
775 	 * Since there is no standard way to get this information
776 	 * across various distributions of interest; we just invoke
777 	 * an external script that needs to be ported across distros
778 	 * of interest.
779 	 *
780 	 * Following is the expected format of the information from the script:
781 	 *
782 	 * ipaddr1 (nameserver1)
783 	 * ipaddr2 (nameserver2)
784 	 * .
785 	 * .
786 	 */
787 
788 	sprintf(cmd, "exec %s %s", KVP_SCRIPTS_PATH "hv_get_dns_info", if_name);
789 
790 	/*
791 	 * Execute the command to gather DNS info.
792 	 */
793 	kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr,
794 				(MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0);
795 
796 	/*
797 	 * Gather the DHCP state.
798 	 * We will gather this state by invoking an external script.
799 	 * The parameter to the script is the interface name.
800 	 * Here is the expected output:
801 	 *
802 	 * Enabled: DHCP enabled.
803 	 */
804 
805 	sprintf(cmd, "exec %s %s", KVP_SCRIPTS_PATH "hv_get_dhcp_info", if_name);
806 
807 	file = popen(cmd, "r");
808 	if (file == NULL)
809 		return;
810 
811 	p = fgets(dhcp_info, sizeof(dhcp_info), file);
812 	if (p == NULL) {
813 		pclose(file);
814 		return;
815 	}
816 
817 	if (!strncmp(p, "Enabled", 7))
818 		buffer->dhcp_enabled = 1;
819 	else
820 		buffer->dhcp_enabled = 0;
821 
822 	pclose(file);
823 }
824 
825 
hweight32(unsigned int * w)826 static unsigned int hweight32(unsigned int *w)
827 {
828 	unsigned int res = *w - ((*w >> 1) & 0x55555555);
829 	res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
830 	res = (res + (res >> 4)) & 0x0F0F0F0F;
831 	res = res + (res >> 8);
832 	return (res + (res >> 16)) & 0x000000FF;
833 }
834 
kvp_process_ip_address(void * addrp,int family,char * buffer,int length,int * offset)835 static int kvp_process_ip_address(void *addrp,
836 				int family, char *buffer,
837 				int length,  int *offset)
838 {
839 	struct sockaddr_in *addr;
840 	struct sockaddr_in6 *addr6;
841 	int addr_length;
842 	char tmp[50];
843 	const char *str;
844 
845 	if (family == AF_INET) {
846 		addr = addrp;
847 		str = inet_ntop(family, &addr->sin_addr, tmp, 50);
848 		addr_length = INET_ADDRSTRLEN;
849 	} else {
850 		addr6 = addrp;
851 		str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50);
852 		addr_length = INET6_ADDRSTRLEN;
853 	}
854 
855 	if ((length - *offset) < addr_length + 2)
856 		return HV_E_FAIL;
857 	if (str == NULL) {
858 		strcpy(buffer, "inet_ntop failed\n");
859 		return HV_E_FAIL;
860 	}
861 	if (*offset == 0)
862 		strcpy(buffer, tmp);
863 	else {
864 		strcat(buffer, ";");
865 		strcat(buffer, tmp);
866 	}
867 
868 	*offset += strlen(str) + 1;
869 
870 	return 0;
871 }
872 
873 static int
kvp_get_ip_info(int family,char * if_name,int op,void * out_buffer,unsigned int length)874 kvp_get_ip_info(int family, char *if_name, int op,
875 		 void  *out_buffer, unsigned int length)
876 {
877 	struct ifaddrs *ifap;
878 	struct ifaddrs *curp;
879 	int offset = 0;
880 	int sn_offset = 0;
881 	int error = 0;
882 	char *buffer;
883 	struct hv_kvp_ipaddr_value *ip_buffer = NULL;
884 	char cidr_mask[5]; /* /xyz */
885 	int weight;
886 	int i;
887 	unsigned int *w;
888 	char *sn_str;
889 	struct sockaddr_in6 *addr6;
890 
891 	if (op == KVP_OP_ENUMERATE) {
892 		buffer = out_buffer;
893 	} else {
894 		ip_buffer = out_buffer;
895 		buffer = (char *)ip_buffer->ip_addr;
896 		ip_buffer->addr_family = 0;
897 	}
898 	/*
899 	 * On entry into this function, the buffer is capable of holding the
900 	 * maximum key value.
901 	 */
902 
903 	if (getifaddrs(&ifap)) {
904 		strcpy(buffer, "getifaddrs failed\n");
905 		return HV_E_FAIL;
906 	}
907 
908 	curp = ifap;
909 	while (curp != NULL) {
910 		if (curp->ifa_addr == NULL) {
911 			curp = curp->ifa_next;
912 			continue;
913 		}
914 
915 		if ((if_name != NULL) &&
916 			(strncmp(curp->ifa_name, if_name, strlen(if_name)))) {
917 			/*
918 			 * We want info about a specific interface;
919 			 * just continue.
920 			 */
921 			curp = curp->ifa_next;
922 			continue;
923 		}
924 
925 		/*
926 		 * We only support two address families: AF_INET and AF_INET6.
927 		 * If a family value of 0 is specified, we collect both
928 		 * supported address families; if not we gather info on
929 		 * the specified address family.
930 		 */
931 		if ((((family != 0) &&
932 			 (curp->ifa_addr->sa_family != family))) ||
933 			 (curp->ifa_flags & IFF_LOOPBACK)) {
934 			curp = curp->ifa_next;
935 			continue;
936 		}
937 		if ((curp->ifa_addr->sa_family != AF_INET) &&
938 			(curp->ifa_addr->sa_family != AF_INET6)) {
939 			curp = curp->ifa_next;
940 			continue;
941 		}
942 
943 		if (op == KVP_OP_GET_IP_INFO) {
944 			/*
945 			 * Gather info other than the IP address.
946 			 * IP address info will be gathered later.
947 			 */
948 			if (curp->ifa_addr->sa_family == AF_INET) {
949 				ip_buffer->addr_family |= ADDR_FAMILY_IPV4;
950 				/*
951 				 * Get subnet info.
952 				 */
953 				error = kvp_process_ip_address(
954 							     curp->ifa_netmask,
955 							     AF_INET,
956 							     (char *)
957 							     ip_buffer->sub_net,
958 							     length,
959 							     &sn_offset);
960 				if (error)
961 					goto gather_ipaddr;
962 			} else {
963 				ip_buffer->addr_family |= ADDR_FAMILY_IPV6;
964 
965 				/*
966 				 * Get subnet info in CIDR format.
967 				 */
968 				weight = 0;
969 				sn_str = (char *)ip_buffer->sub_net;
970 				addr6 = (struct sockaddr_in6 *)
971 					curp->ifa_netmask;
972 				w = addr6->sin6_addr.s6_addr32;
973 
974 				for (i = 0; i < 4; i++)
975 					weight += hweight32(&w[i]);
976 
977 				sprintf(cidr_mask, "/%d", weight);
978 				if (length < sn_offset + strlen(cidr_mask) + 1)
979 					goto gather_ipaddr;
980 
981 				if (sn_offset == 0)
982 					strcpy(sn_str, cidr_mask);
983 				else {
984 					strcat((char *)ip_buffer->sub_net, ";");
985 					strcat(sn_str, cidr_mask);
986 				}
987 				sn_offset += strlen(sn_str) + 1;
988 			}
989 
990 			/*
991 			 * Collect other ip related configuration info.
992 			 */
993 
994 			kvp_get_ipconfig_info(if_name, ip_buffer);
995 		}
996 
997 gather_ipaddr:
998 		error = kvp_process_ip_address(curp->ifa_addr,
999 						curp->ifa_addr->sa_family,
1000 						buffer,
1001 						length, &offset);
1002 		if (error)
1003 			goto getaddr_done;
1004 
1005 		curp = curp->ifa_next;
1006 	}
1007 
1008 getaddr_done:
1009 	freeifaddrs(ifap);
1010 	return error;
1011 }
1012 
1013 /*
1014  * Retrieve the IP given the MAC address.
1015  */
kvp_mac_to_ip(struct hv_kvp_ipaddr_value * kvp_ip_val)1016 static int kvp_mac_to_ip(struct hv_kvp_ipaddr_value *kvp_ip_val)
1017 {
1018 	char *mac = (char *)kvp_ip_val->adapter_id;
1019 	DIR *dir;
1020 	struct dirent *entry;
1021 	FILE    *file;
1022 	char    *p, *x;
1023 	char    *if_name = NULL;
1024 	char    buf[256];
1025 	char dev_id[PATH_MAX];
1026 	unsigned int i;
1027 	int error = HV_E_FAIL;
1028 
1029 	dir = opendir(KVP_NET_DIR);
1030 	if (dir == NULL)
1031 		return HV_E_FAIL;
1032 
1033 	while ((entry = readdir(dir)) != NULL) {
1034 		/*
1035 		 * Set the state for the next pass.
1036 		 */
1037 		snprintf(dev_id, sizeof(dev_id), "%s%s/address", KVP_NET_DIR,
1038 			 entry->d_name);
1039 
1040 		file = fopen(dev_id, "r");
1041 		if (file == NULL)
1042 			continue;
1043 
1044 		p = fgets(buf, sizeof(buf), file);
1045 		fclose(file);
1046 		if (!p)
1047 			continue;
1048 
1049 		x = strchr(p, '\n');
1050 		if (x)
1051 			*x = '\0';
1052 
1053 		for (i = 0; i < strlen(p); i++)
1054 			p[i] = toupper(p[i]);
1055 
1056 		if (strcmp(p, mac))
1057 			continue;
1058 
1059 		/*
1060 		 * Found the MAC match.
1061 		 * A NIC (e.g. VF) matching the MAC, but without IP, is skipped.
1062 		 */
1063 		if_name = entry->d_name;
1064 		if (!if_name)
1065 			continue;
1066 
1067 		error = kvp_get_ip_info(0, if_name, KVP_OP_GET_IP_INFO,
1068 					kvp_ip_val, MAX_IP_ADDR_SIZE * 2);
1069 
1070 		if (!error && strlen((char *)kvp_ip_val->ip_addr))
1071 			break;
1072 	}
1073 
1074 	closedir(dir);
1075 	return error;
1076 }
1077 
expand_ipv6(char * addr,int type)1078 static int expand_ipv6(char *addr, int type)
1079 {
1080 	int ret;
1081 	struct in6_addr v6_addr;
1082 
1083 	ret = inet_pton(AF_INET6, addr, &v6_addr);
1084 
1085 	if (ret != 1) {
1086 		if (type == NETMASK)
1087 			return 1;
1088 		return 0;
1089 	}
1090 
1091 	sprintf(addr, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
1092 		"%02x%02x:%02x%02x:%02x%02x",
1093 		(int)v6_addr.s6_addr[0], (int)v6_addr.s6_addr[1],
1094 		(int)v6_addr.s6_addr[2], (int)v6_addr.s6_addr[3],
1095 		(int)v6_addr.s6_addr[4], (int)v6_addr.s6_addr[5],
1096 		(int)v6_addr.s6_addr[6], (int)v6_addr.s6_addr[7],
1097 		(int)v6_addr.s6_addr[8], (int)v6_addr.s6_addr[9],
1098 		(int)v6_addr.s6_addr[10], (int)v6_addr.s6_addr[11],
1099 		(int)v6_addr.s6_addr[12], (int)v6_addr.s6_addr[13],
1100 		(int)v6_addr.s6_addr[14], (int)v6_addr.s6_addr[15]);
1101 
1102 	return 1;
1103 
1104 }
1105 
is_ipv4(char * addr)1106 static int is_ipv4(char *addr)
1107 {
1108 	int ret;
1109 	struct in_addr ipv4_addr;
1110 
1111 	ret = inet_pton(AF_INET, addr, &ipv4_addr);
1112 
1113 	if (ret == 1)
1114 		return 1;
1115 	return 0;
1116 }
1117 
parse_ip_val_buffer(char * in_buf,int * offset,char * out_buf,int out_len)1118 static int parse_ip_val_buffer(char *in_buf, int *offset,
1119 				char *out_buf, int out_len)
1120 {
1121 	char *x;
1122 	char *start;
1123 
1124 	/*
1125 	 * in_buf has sequence of characters that are separated by
1126 	 * the character ';'. The last sequence does not have the
1127 	 * terminating ";" character.
1128 	 */
1129 	start = in_buf + *offset;
1130 
1131 	x = strchr(start, ';');
1132 	if (x)
1133 		*x = 0;
1134 	else
1135 		x = start + strlen(start);
1136 
1137 	if (strlen(start) != 0) {
1138 		int i = 0;
1139 		/*
1140 		 * Get rid of leading spaces.
1141 		 */
1142 		while (start[i] == ' ')
1143 			i++;
1144 
1145 		if ((x - start) <= out_len) {
1146 			strcpy(out_buf, (start + i));
1147 			*offset += (x - start) + 1;
1148 			return 1;
1149 		}
1150 	}
1151 	return 0;
1152 }
1153 
kvp_write_file(FILE * f,char * s1,char * s2,char * s3)1154 static int kvp_write_file(FILE *f, char *s1, char *s2, char *s3)
1155 {
1156 	int ret;
1157 
1158 	ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3);
1159 
1160 	if (ret < 0)
1161 		return HV_E_FAIL;
1162 
1163 	return 0;
1164 }
1165 
1166 
process_ip_string(FILE * f,char * ip_string,int type)1167 static int process_ip_string(FILE *f, char *ip_string, int type)
1168 {
1169 	int error = 0;
1170 	char addr[INET6_ADDRSTRLEN];
1171 	int i = 0;
1172 	int j = 0;
1173 	char str[256];
1174 	char sub_str[13];
1175 	int offset = 0;
1176 
1177 	memset(addr, 0, sizeof(addr));
1178 
1179 	while (parse_ip_val_buffer(ip_string, &offset, addr,
1180 					(MAX_IP_ADDR_SIZE * 2))) {
1181 
1182 		sub_str[0] = 0;
1183 		if (is_ipv4(addr)) {
1184 			switch (type) {
1185 			case IPADDR:
1186 				snprintf(str, sizeof(str), "%s", "IPADDR");
1187 				break;
1188 			case NETMASK:
1189 				snprintf(str, sizeof(str), "%s", "NETMASK");
1190 				break;
1191 			case GATEWAY:
1192 				snprintf(str, sizeof(str), "%s", "GATEWAY");
1193 				break;
1194 			case DNS:
1195 				snprintf(str, sizeof(str), "%s", "DNS");
1196 				break;
1197 			}
1198 
1199 			if (type == DNS) {
1200 				snprintf(sub_str, sizeof(sub_str), "%d", ++i);
1201 			} else if (type == GATEWAY && i == 0) {
1202 				++i;
1203 			} else {
1204 				snprintf(sub_str, sizeof(sub_str), "%d", i++);
1205 			}
1206 
1207 
1208 		} else if (expand_ipv6(addr, type)) {
1209 			switch (type) {
1210 			case IPADDR:
1211 				snprintf(str, sizeof(str), "%s", "IPV6ADDR");
1212 				break;
1213 			case NETMASK:
1214 				snprintf(str, sizeof(str), "%s", "IPV6NETMASK");
1215 				break;
1216 			case GATEWAY:
1217 				snprintf(str, sizeof(str), "%s",
1218 					"IPV6_DEFAULTGW");
1219 				break;
1220 			case DNS:
1221 				snprintf(str, sizeof(str), "%s",  "DNS");
1222 				break;
1223 			}
1224 
1225 			if (type == DNS) {
1226 				snprintf(sub_str, sizeof(sub_str), "%d", ++i);
1227 			} else if (j == 0) {
1228 				++j;
1229 			} else {
1230 				snprintf(sub_str, sizeof(sub_str), "_%d", j++);
1231 			}
1232 		} else {
1233 			return  HV_INVALIDARG;
1234 		}
1235 
1236 		error = kvp_write_file(f, str, sub_str, addr);
1237 		if (error)
1238 			return error;
1239 		memset(addr, 0, sizeof(addr));
1240 	}
1241 
1242 	return 0;
1243 }
1244 
ip_version_check(const char * input_addr)1245 int ip_version_check(const char *input_addr)
1246 {
1247 	struct in6_addr addr;
1248 
1249 	if (inet_pton(AF_INET, input_addr, &addr))
1250 		return IPV4;
1251 	else if (inet_pton(AF_INET6, input_addr, &addr))
1252 		return IPV6;
1253 
1254 	return -EINVAL;
1255 }
1256 
1257 /*
1258  * Only IPv4 subnet strings needs to be converted to plen
1259  * For IPv6 the subnet is already privided in plen format
1260  */
kvp_subnet_to_plen(char * subnet_addr_str)1261 static int kvp_subnet_to_plen(char *subnet_addr_str)
1262 {
1263 	int plen = 0;
1264 	struct in_addr subnet_addr4;
1265 
1266 	/*
1267 	 * Convert subnet address to binary representation
1268 	 */
1269 	if (inet_pton(AF_INET, subnet_addr_str, &subnet_addr4) == 1) {
1270 		uint32_t subnet_mask = ntohl(subnet_addr4.s_addr);
1271 
1272 		while (subnet_mask & 0x80000000) {
1273 			plen++;
1274 			subnet_mask <<= 1;
1275 		}
1276 	} else {
1277 		return -1;
1278 	}
1279 
1280 	return plen;
1281 }
1282 
process_dns_gateway_nm(FILE * f,char * ip_string,int type,int ip_sec)1283 static int process_dns_gateway_nm(FILE *f, char *ip_string, int type,
1284 				  int ip_sec)
1285 {
1286 	char addr[INET6_ADDRSTRLEN], *output_str;
1287 	int ip_offset = 0, error = 0, ip_ver;
1288 	char *param_name;
1289 
1290 	if (type == DNS)
1291 		param_name = "dns";
1292 	else if (type == GATEWAY)
1293 		param_name = "gateway";
1294 	else
1295 		return -EINVAL;
1296 
1297 	output_str = (char *)calloc(OUTSTR_BUF_SIZE, sizeof(char));
1298 	if (!output_str)
1299 		return -ENOMEM;
1300 
1301 	while (1) {
1302 		memset(addr, 0, sizeof(addr));
1303 
1304 		if (!parse_ip_val_buffer(ip_string, &ip_offset, addr,
1305 					 (MAX_IP_ADDR_SIZE * 2)))
1306 			break;
1307 
1308 		ip_ver = ip_version_check(addr);
1309 		if (ip_ver < 0)
1310 			continue;
1311 
1312 		if ((ip_ver == IPV4 && ip_sec == IPV4) ||
1313 		    (ip_ver == IPV6 && ip_sec == IPV6)) {
1314 			/*
1315 			 * do a bound check to avoid out-of bound writes
1316 			 */
1317 			if ((OUTSTR_BUF_SIZE - strlen(output_str)) >
1318 			    (strlen(addr) + 1)) {
1319 				strncat(output_str, addr,
1320 					OUTSTR_BUF_SIZE -
1321 					strlen(output_str) - 1);
1322 				strncat(output_str, ",",
1323 					OUTSTR_BUF_SIZE -
1324 					strlen(output_str) - 1);
1325 			}
1326 		} else {
1327 			continue;
1328 		}
1329 	}
1330 
1331 	if (strlen(output_str)) {
1332 		/*
1333 		 * This is to get rid of that extra comma character
1334 		 * in the end of the string
1335 		 */
1336 		output_str[strlen(output_str) - 1] = '\0';
1337 		error = fprintf(f, "%s=%s\n", param_name, output_str);
1338 	}
1339 
1340 	free(output_str);
1341 	return error;
1342 }
1343 
process_ip_string_nm(FILE * f,char * ip_string,char * subnet,int ip_sec)1344 static int process_ip_string_nm(FILE *f, char *ip_string, char *subnet,
1345 				int ip_sec)
1346 {
1347 	char addr[INET6_ADDRSTRLEN];
1348 	char subnet_addr[INET6_ADDRSTRLEN];
1349 	int error = 0, i = 0;
1350 	int ip_offset = 0, subnet_offset = 0;
1351 	int plen, ip_ver;
1352 
1353 	memset(addr, 0, sizeof(addr));
1354 	memset(subnet_addr, 0, sizeof(subnet_addr));
1355 
1356 	while (parse_ip_val_buffer(ip_string, &ip_offset, addr,
1357 				   (MAX_IP_ADDR_SIZE * 2)) &&
1358 				   parse_ip_val_buffer(subnet,
1359 						       &subnet_offset,
1360 						       subnet_addr,
1361 						       (MAX_IP_ADDR_SIZE *
1362 							2))) {
1363 		ip_ver = ip_version_check(addr);
1364 		if (ip_ver < 0)
1365 			continue;
1366 
1367 		if (ip_ver == IPV4 && ip_sec == IPV4)
1368 			plen = kvp_subnet_to_plen((char *)subnet_addr);
1369 		else if (ip_ver == IPV6 && ip_sec == IPV6)
1370 			plen = atoi(subnet_addr);
1371 		else
1372 			continue;
1373 
1374 		if (plen < 0)
1375 			return plen;
1376 
1377 		error = fprintf(f, "address%d=%s/%d\n", ++i, (char *)addr,
1378 				plen);
1379 		if (error < 0)
1380 			return error;
1381 
1382 		memset(addr, 0, sizeof(addr));
1383 		memset(subnet_addr, 0, sizeof(subnet_addr));
1384 	}
1385 
1386 	return error;
1387 }
1388 
kvp_set_ip_info(char * if_name,struct hv_kvp_ipaddr_value * new_val)1389 static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
1390 {
1391 	int error = 0, ip_ver;
1392 	char if_filename[PATH_MAX];
1393 	char nm_filename[PATH_MAX];
1394 	FILE *ifcfg_file, *nmfile;
1395 	char cmd[PATH_MAX];
1396 	char *mac_addr;
1397 	int str_len;
1398 
1399 	/*
1400 	 * Set the configuration for the specified interface with
1401 	 * the information provided. Since there is no standard
1402 	 * way to configure an interface, we will have an external
1403 	 * script that does the job of configuring the interface and
1404 	 * flushing the configuration.
1405 	 *
1406 	 * The parameters passed to this external script are:
1407 	 * 1. A configuration file that has the specified configuration.
1408 	 *
1409 	 * We will embed the name of the interface in the configuration
1410 	 * file: ifcfg-ethx (where ethx is the interface name).
1411 	 *
1412 	 * The information provided here may be more than what is needed
1413 	 * in a given distro to configure the interface and so are free
1414 	 * ignore information that may not be relevant.
1415 	 *
1416 	 * Here is the ifcfg format of the ip configuration file:
1417 	 *
1418 	 * HWADDR=macaddr
1419 	 * DEVICE=interface name
1420 	 * BOOTPROTO=<protocol> (where <protocol> is "dhcp" if DHCP is configured
1421 	 *                       or "none" if no boot-time protocol should be used)
1422 	 *
1423 	 * IPADDR0=ipaddr1
1424 	 * IPADDR1=ipaddr2
1425 	 * IPADDRx=ipaddry (where y = x + 1)
1426 	 *
1427 	 * NETMASK0=netmask1
1428 	 * NETMASKx=netmasky (where y = x + 1)
1429 	 *
1430 	 * GATEWAY=ipaddr1
1431 	 * GATEWAYx=ipaddry (where y = x + 1)
1432 	 *
1433 	 * DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc)
1434 	 *
1435 	 * IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be
1436 	 * tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as
1437 	 * IPV6NETMASK.
1438 	 *
1439 	 * Here is the keyfile format of the ip configuration file:
1440 	 *
1441 	 * [ethernet]
1442 	 * mac-address=macaddr
1443 	 * [connection]
1444 	 * interface-name=interface name
1445 	 *
1446 	 * [ipv4]
1447 	 * method=<protocol> (where <protocol> is "auto" if DHCP is configured
1448 	 *                       or "manual" if no boot-time protocol should be used)
1449 	 *
1450 	 * address1=ipaddr1/plen
1451 	 * address2=ipaddr2/plen
1452 	 *
1453 	 * gateway=gateway1;gateway2
1454 	 *
1455 	 * dns=dns1;dns2
1456 	 *
1457 	 * [ipv6]
1458 	 * address1=ipaddr1/plen
1459 	 * address2=ipaddr2/plen
1460 	 *
1461 	 * gateway=gateway1;gateway2
1462 	 *
1463 	 * dns=dns1;dns2
1464 	 *
1465 	 * The host can specify multiple ipv4 and ipv6 addresses to be
1466 	 * configured for the interface. Furthermore, the configuration
1467 	 * needs to be persistent. A subsequent GET call on the interface
1468 	 * is expected to return the configuration that is set via the SET
1469 	 * call.
1470 	 */
1471 
1472 	/*
1473 	 * We are populating both ifcfg and nmconnection files
1474 	 */
1475 	snprintf(if_filename, sizeof(if_filename), "%s%s%s", KVP_CONFIG_LOC,
1476 		 "/ifcfg-", if_name);
1477 
1478 	ifcfg_file = fopen(if_filename, "w");
1479 
1480 	if (!ifcfg_file) {
1481 		syslog(LOG_ERR, "Failed to open config file; error: %d %s",
1482 		       errno, strerror(errno));
1483 		return HV_E_FAIL;
1484 	}
1485 
1486 	snprintf(nm_filename, sizeof(nm_filename), "%s%s%s%s", KVP_CONFIG_LOC,
1487 		 "/", if_name, ".nmconnection");
1488 
1489 	nmfile = fopen(nm_filename, "w");
1490 
1491 	if (!nmfile) {
1492 		syslog(LOG_ERR, "Failed to open config file; error: %d %s",
1493 		       errno, strerror(errno));
1494 		fclose(ifcfg_file);
1495 		return HV_E_FAIL;
1496 	}
1497 
1498 	/*
1499 	 * First write out the MAC address.
1500 	 */
1501 
1502 	mac_addr = kvp_if_name_to_mac(if_name);
1503 	if (mac_addr == NULL) {
1504 		error = HV_E_FAIL;
1505 		goto setval_error;
1506 	}
1507 
1508 	error = kvp_write_file(ifcfg_file, "HWADDR", "", mac_addr);
1509 	if (error < 0)
1510 		goto setmac_error;
1511 
1512 	error = kvp_write_file(ifcfg_file, "DEVICE", "", if_name);
1513 	if (error < 0)
1514 		goto setmac_error;
1515 
1516 	error = fprintf(nmfile, "\n[connection]\n");
1517 	if (error < 0)
1518 		goto setmac_error;
1519 
1520 	error = kvp_write_file(nmfile, "interface-name", "", if_name);
1521 	if (error)
1522 		goto setmac_error;
1523 
1524 	error = fprintf(nmfile, "\n[ethernet]\n");
1525 	if (error < 0)
1526 		goto setmac_error;
1527 
1528 	error = kvp_write_file(nmfile, "mac-address", "", mac_addr);
1529 	if (error)
1530 		goto setmac_error;
1531 
1532 	free(mac_addr);
1533 
1534 	/*
1535 	 * The dhcp_enabled flag is only for IPv4. In the case the host only
1536 	 * injects an IPv6 address, the flag is true, but we still need to
1537 	 * proceed to parse and pass the IPv6 information to the
1538 	 * disto-specific script hv_set_ifconfig.
1539 	 */
1540 
1541 	/*
1542 	 * First populate the ifcfg file format
1543 	 */
1544 	if (new_val->dhcp_enabled) {
1545 		error = kvp_write_file(ifcfg_file, "BOOTPROTO", "", "dhcp");
1546 		if (error)
1547 			goto setval_error;
1548 	} else {
1549 		error = kvp_write_file(ifcfg_file, "BOOTPROTO", "", "none");
1550 		if (error)
1551 			goto setval_error;
1552 	}
1553 
1554 	error = process_ip_string(ifcfg_file, (char *)new_val->ip_addr,
1555 				  IPADDR);
1556 	if (error)
1557 		goto setval_error;
1558 
1559 	error = process_ip_string(ifcfg_file, (char *)new_val->sub_net,
1560 				  NETMASK);
1561 	if (error)
1562 		goto setval_error;
1563 
1564 	error = process_ip_string(ifcfg_file, (char *)new_val->gate_way,
1565 				  GATEWAY);
1566 	if (error)
1567 		goto setval_error;
1568 
1569 	error = process_ip_string(ifcfg_file, (char *)new_val->dns_addr, DNS);
1570 	if (error)
1571 		goto setval_error;
1572 
1573 	/*
1574 	 * Now we populate the keyfile format
1575 	 *
1576 	 * The keyfile format expects the IPv6 and IPv4 configuration in
1577 	 * different sections. Therefore we iterate through the list twice,
1578 	 * once to populate the IPv4 section and the next time for IPv6
1579 	 */
1580 	ip_ver = IPV4;
1581 	do {
1582 		if (ip_ver == IPV4) {
1583 			error = fprintf(nmfile, "\n[ipv4]\n");
1584 			if (error < 0)
1585 				goto setval_error;
1586 		} else {
1587 			error = fprintf(nmfile, "\n[ipv6]\n");
1588 			if (error < 0)
1589 				goto setval_error;
1590 		}
1591 
1592 		/*
1593 		 * Write the configuration for ipaddress, netmask, gateway and
1594 		 * name services
1595 		 */
1596 		error = process_ip_string_nm(nmfile, (char *)new_val->ip_addr,
1597 					     (char *)new_val->sub_net,
1598 					     ip_ver);
1599 		if (error < 0)
1600 			goto setval_error;
1601 
1602 		/*
1603 		 * As dhcp_enabled is only valid for ipv4, we do not set dhcp
1604 		 * methods for ipv6 based on dhcp_enabled flag.
1605 		 *
1606 		 * For ipv4, set method to manual only when dhcp_enabled is
1607 		 * false and specific ipv4 addresses are configured. If neither
1608 		 * dhcp_enabled is true and no ipv4 addresses are configured,
1609 		 * set method to 'disabled'.
1610 		 *
1611 		 * For ipv6, set method to manual when we configure ipv6
1612 		 * addresses. Otherwise set method to 'auto' so that SLAAC from
1613 		 * RA may be used.
1614 		 */
1615 		if (ip_ver == IPV4) {
1616 			if (new_val->dhcp_enabled) {
1617 				error = kvp_write_file(nmfile, "method", "",
1618 						       "auto");
1619 				if (error < 0)
1620 					goto setval_error;
1621 			} else if (error) {
1622 				error = kvp_write_file(nmfile, "method", "",
1623 						       "manual");
1624 				if (error < 0)
1625 					goto setval_error;
1626 			} else {
1627 				error = kvp_write_file(nmfile, "method", "",
1628 						       "disabled");
1629 				if (error < 0)
1630 					goto setval_error;
1631 			}
1632 		} else if (ip_ver == IPV6) {
1633 			if (error) {
1634 				error = kvp_write_file(nmfile, "method", "",
1635 						       "manual");
1636 				if (error < 0)
1637 					goto setval_error;
1638 			} else {
1639 				error = kvp_write_file(nmfile, "method", "",
1640 						       "auto");
1641 				if (error < 0)
1642 					goto setval_error;
1643 			}
1644 		}
1645 
1646 		error = process_dns_gateway_nm(nmfile,
1647 					       (char *)new_val->gate_way,
1648 					       GATEWAY, ip_ver);
1649 		if (error < 0)
1650 			goto setval_error;
1651 
1652 		error = process_dns_gateway_nm(nmfile,
1653 					       (char *)new_val->dns_addr, DNS,
1654 					       ip_ver);
1655 		if (error < 0)
1656 			goto setval_error;
1657 
1658 		ip_ver++;
1659 	} while (ip_ver < IP_TYPE_MAX);
1660 
1661 	fclose(nmfile);
1662 	fclose(ifcfg_file);
1663 
1664 	/*
1665 	 * Now that we have populated the configuration file,
1666 	 * invoke the external script to do its magic.
1667 	 */
1668 
1669 	str_len = snprintf(cmd, sizeof(cmd), "exec %s %s %s",
1670 			   KVP_SCRIPTS_PATH "hv_set_ifconfig",
1671 			   if_filename, nm_filename);
1672 	/*
1673 	 * This is a little overcautious, but it's necessary to suppress some
1674 	 * false warnings from gcc 8.0.1.
1675 	 */
1676 	if (str_len <= 0 || (unsigned int)str_len >= sizeof(cmd)) {
1677 		syslog(LOG_ERR, "Cmd '%s' (len=%d) may be too long",
1678 		       cmd, str_len);
1679 		return HV_E_FAIL;
1680 	}
1681 
1682 	if (system(cmd)) {
1683 		syslog(LOG_ERR, "Failed to execute cmd '%s'; error: %d %s",
1684 		       cmd, errno, strerror(errno));
1685 		return HV_E_FAIL;
1686 	}
1687 	return 0;
1688 setmac_error:
1689 	free(mac_addr);
1690 setval_error:
1691 	syslog(LOG_ERR, "Failed to write config file");
1692 	fclose(ifcfg_file);
1693 	fclose(nmfile);
1694 	return error;
1695 }
1696 
1697 
1698 static void
kvp_get_domain_name(char * buffer,int length)1699 kvp_get_domain_name(char *buffer, int length)
1700 {
1701 	struct addrinfo	hints, *info ;
1702 	int error = 0;
1703 
1704 	gethostname(buffer, length);
1705 	memset(&hints, 0, sizeof(hints));
1706 	hints.ai_family = AF_INET; /*Get only ipv4 addrinfo. */
1707 	hints.ai_socktype = SOCK_STREAM;
1708 	hints.ai_flags = AI_CANONNAME;
1709 
1710 	error = getaddrinfo(buffer, NULL, &hints, &info);
1711 	if (error != 0) {
1712 		snprintf(buffer, length, "getaddrinfo failed: 0x%x %s",
1713 			error, gai_strerror(error));
1714 		return;
1715 	}
1716 	snprintf(buffer, length, "%s", info->ai_canonname);
1717 	freeaddrinfo(info);
1718 }
1719 
print_usage(char * argv[])1720 void print_usage(char *argv[])
1721 {
1722 	fprintf(stderr, "Usage: %s [options]\n"
1723 		"Options are:\n"
1724 		"  -n, --no-daemon        stay in foreground, don't daemonize\n"
1725 		"  -h, --help             print this help\n", argv[0]);
1726 }
1727 
main(int argc,char * argv[])1728 int main(int argc, char *argv[])
1729 {
1730 	int kvp_fd = -1, len;
1731 	int error;
1732 	struct pollfd pfd;
1733 	char    *p;
1734 	struct hv_kvp_msg hv_msg[1];
1735 	char	*key_value;
1736 	char	*key_name;
1737 	int	op;
1738 	int	pool;
1739 	char	*if_name;
1740 	struct hv_kvp_ipaddr_value *kvp_ip_val;
1741 	int daemonize = 1, long_index = 0, opt;
1742 
1743 	static struct option long_options[] = {
1744 		{"help",	no_argument,	   0,  'h' },
1745 		{"no-daemon",	no_argument,	   0,  'n' },
1746 		{0,		0,		   0,  0   }
1747 	};
1748 
1749 	while ((opt = getopt_long(argc, argv, "hn", long_options,
1750 				  &long_index)) != -1) {
1751 		switch (opt) {
1752 		case 'n':
1753 			daemonize = 0;
1754 			break;
1755 		case 'h':
1756 			print_usage(argv);
1757 			exit(0);
1758 		default:
1759 			print_usage(argv);
1760 			exit(EXIT_FAILURE);
1761 		}
1762 	}
1763 
1764 	if (daemonize && daemon(1, 0))
1765 		return 1;
1766 
1767 	openlog("KVP", 0, LOG_USER);
1768 	syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
1769 
1770 	/*
1771 	 * Retrieve OS release information.
1772 	 */
1773 	kvp_get_os_info();
1774 	/*
1775 	 * Cache Fully Qualified Domain Name because getaddrinfo takes an
1776 	 * unpredictable amount of time to finish.
1777 	 */
1778 	kvp_get_domain_name(full_domain_name, sizeof(full_domain_name));
1779 
1780 	if (kvp_file_init()) {
1781 		syslog(LOG_ERR, "Failed to initialize the pools");
1782 		exit(EXIT_FAILURE);
1783 	}
1784 
1785 reopen_kvp_fd:
1786 	if (kvp_fd != -1)
1787 		close(kvp_fd);
1788 	in_hand_shake = 1;
1789 	kvp_fd = open("/dev/vmbus/hv_kvp", O_RDWR | O_CLOEXEC);
1790 
1791 	if (kvp_fd < 0) {
1792 		syslog(LOG_ERR, "open /dev/vmbus/hv_kvp failed; error: %d %s",
1793 		       errno, strerror(errno));
1794 		exit(EXIT_FAILURE);
1795 	}
1796 
1797 	/*
1798 	 * Register ourselves with the kernel.
1799 	 */
1800 	hv_msg->kvp_hdr.operation = KVP_OP_REGISTER1;
1801 	len = write(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg));
1802 	if (len != sizeof(struct hv_kvp_msg)) {
1803 		syslog(LOG_ERR, "registration to kernel failed; error: %d %s",
1804 		       errno, strerror(errno));
1805 		close(kvp_fd);
1806 		exit(EXIT_FAILURE);
1807 	}
1808 
1809 	pfd.fd = kvp_fd;
1810 
1811 	while (1) {
1812 		pfd.events = POLLIN;
1813 		pfd.revents = 0;
1814 
1815 		if (poll(&pfd, 1, -1) < 0) {
1816 			syslog(LOG_ERR, "poll failed; error: %d %s", errno, strerror(errno));
1817 			if (errno == EINVAL) {
1818 				close(kvp_fd);
1819 				exit(EXIT_FAILURE);
1820 			}
1821 			else
1822 				continue;
1823 		}
1824 
1825 		len = read(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg));
1826 
1827 		if (len != sizeof(struct hv_kvp_msg)) {
1828 			syslog(LOG_ERR, "read failed; error:%d %s",
1829 			       errno, strerror(errno));
1830 			goto reopen_kvp_fd;
1831 		}
1832 
1833 		/*
1834 		 * We will use the KVP header information to pass back
1835 		 * the error from this daemon. So, first copy the state
1836 		 * and set the error code to success.
1837 		 */
1838 		op = hv_msg->kvp_hdr.operation;
1839 		pool = hv_msg->kvp_hdr.pool;
1840 		hv_msg->error = HV_S_OK;
1841 
1842 		if ((in_hand_shake) && (op == KVP_OP_REGISTER1)) {
1843 			/*
1844 			 * Driver is registering with us; stash away the version
1845 			 * information.
1846 			 */
1847 			in_hand_shake = 0;
1848 			p = (char *)hv_msg->body.kvp_register.version;
1849 			lic_version = malloc(strlen(p) + 1);
1850 			if (lic_version) {
1851 				strcpy(lic_version, p);
1852 				syslog(LOG_INFO, "KVP LIC Version: %s",
1853 				       lic_version);
1854 			} else {
1855 				syslog(LOG_ERR, "malloc failed");
1856 			}
1857 			continue;
1858 		}
1859 
1860 		switch (op) {
1861 		case KVP_OP_GET_IP_INFO:
1862 			kvp_ip_val = &hv_msg->body.kvp_ip_val;
1863 
1864 			error = kvp_mac_to_ip(kvp_ip_val);
1865 
1866 			if (error)
1867 				hv_msg->error = error;
1868 
1869 			break;
1870 
1871 		case KVP_OP_SET_IP_INFO:
1872 			kvp_ip_val = &hv_msg->body.kvp_ip_val;
1873 			if_name = kvp_get_if_name(
1874 					(char *)kvp_ip_val->adapter_id);
1875 			if (if_name == NULL) {
1876 				/*
1877 				 * We could not map the guid to an
1878 				 * interface name; return error.
1879 				 */
1880 				hv_msg->error = HV_GUID_NOTFOUND;
1881 				break;
1882 			}
1883 			error = kvp_set_ip_info(if_name, kvp_ip_val);
1884 			if (error)
1885 				hv_msg->error = error;
1886 
1887 			free(if_name);
1888 			break;
1889 
1890 		case KVP_OP_SET:
1891 			if (kvp_key_add_or_modify(pool,
1892 					hv_msg->body.kvp_set.data.key,
1893 					hv_msg->body.kvp_set.data.key_size,
1894 					hv_msg->body.kvp_set.data.value,
1895 					hv_msg->body.kvp_set.data.value_size))
1896 					hv_msg->error = HV_S_CONT;
1897 			break;
1898 
1899 		case KVP_OP_GET:
1900 			if (kvp_get_value(pool,
1901 					hv_msg->body.kvp_set.data.key,
1902 					hv_msg->body.kvp_set.data.key_size,
1903 					hv_msg->body.kvp_set.data.value,
1904 					hv_msg->body.kvp_set.data.value_size))
1905 					hv_msg->error = HV_S_CONT;
1906 			break;
1907 
1908 		case KVP_OP_DELETE:
1909 			if (kvp_key_delete(pool,
1910 					hv_msg->body.kvp_delete.key,
1911 					hv_msg->body.kvp_delete.key_size))
1912 					hv_msg->error = HV_S_CONT;
1913 			break;
1914 
1915 		default:
1916 			break;
1917 		}
1918 
1919 		if (op != KVP_OP_ENUMERATE)
1920 			goto kvp_done;
1921 
1922 		/*
1923 		 * If the pool is KVP_POOL_AUTO, dynamically generate
1924 		 * both the key and the value; if not read from the
1925 		 * appropriate pool.
1926 		 */
1927 		if (pool != KVP_POOL_AUTO) {
1928 			if (kvp_pool_enumerate(pool,
1929 					hv_msg->body.kvp_enum_data.index,
1930 					hv_msg->body.kvp_enum_data.data.key,
1931 					HV_KVP_EXCHANGE_MAX_KEY_SIZE,
1932 					hv_msg->body.kvp_enum_data.data.value,
1933 					HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
1934 					hv_msg->error = HV_S_CONT;
1935 			goto kvp_done;
1936 		}
1937 
1938 		key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
1939 		key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
1940 
1941 		switch (hv_msg->body.kvp_enum_data.index) {
1942 		case FullyQualifiedDomainName:
1943 			strcpy(key_value, full_domain_name);
1944 			strcpy(key_name, "FullyQualifiedDomainName");
1945 			break;
1946 		case IntegrationServicesVersion:
1947 			strcpy(key_name, "IntegrationServicesVersion");
1948 			strcpy(key_value, lic_version);
1949 			break;
1950 		case NetworkAddressIPv4:
1951 			kvp_get_ip_info(AF_INET, NULL, KVP_OP_ENUMERATE,
1952 				key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1953 			strcpy(key_name, "NetworkAddressIPv4");
1954 			break;
1955 		case NetworkAddressIPv6:
1956 			kvp_get_ip_info(AF_INET6, NULL, KVP_OP_ENUMERATE,
1957 				key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1958 			strcpy(key_name, "NetworkAddressIPv6");
1959 			break;
1960 		case OSBuildNumber:
1961 			strcpy(key_value, os_build);
1962 			strcpy(key_name, "OSBuildNumber");
1963 			break;
1964 		case OSName:
1965 			strcpy(key_value, os_name);
1966 			strcpy(key_name, "OSName");
1967 			break;
1968 		case OSMajorVersion:
1969 			strcpy(key_value, os_major);
1970 			strcpy(key_name, "OSMajorVersion");
1971 			break;
1972 		case OSMinorVersion:
1973 			strcpy(key_value, os_minor);
1974 			strcpy(key_name, "OSMinorVersion");
1975 			break;
1976 		case OSVersion:
1977 			strcpy(key_value, os_version);
1978 			strcpy(key_name, "OSVersion");
1979 			break;
1980 		case ProcessorArchitecture:
1981 			strcpy(key_value, processor_arch);
1982 			strcpy(key_name, "ProcessorArchitecture");
1983 			break;
1984 		default:
1985 			hv_msg->error = HV_S_CONT;
1986 			break;
1987 		}
1988 
1989 		/*
1990 		 * Send the value back to the kernel. Note: the write() may
1991 		 * return an error due to hibernation; we can ignore the error
1992 		 * by resetting the dev file, i.e. closing and re-opening it.
1993 		 */
1994 kvp_done:
1995 		len = write(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg));
1996 		if (len != sizeof(struct hv_kvp_msg)) {
1997 			syslog(LOG_ERR, "write failed; error: %d %s", errno,
1998 			       strerror(errno));
1999 			goto reopen_kvp_fd;
2000 		}
2001 	}
2002 
2003 	close(kvp_fd);
2004 	exit(0);
2005 }
2006