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