1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
47
48
49
50
51
52
53
54
55
56
57
58enum key_index {
59 FullyQualifiedDomainName = 0,
60 IntegrationServicesVersion,
61 NetworkAddressIPv4,
62 NetworkAddressIPv6,
63 OSBuildNumber,
64 OSName,
65 OSMajorVersion,
66 OSMinorVersion,
67 OSVersion,
68 ProcessorArchitecture
69};
70
71
72enum {
73 IPADDR = 0,
74 NETMASK,
75 GATEWAY,
76 DNS
77};
78
79static int in_hand_shake = 1;
80
81static char *os_name = "";
82static char *os_major = "";
83static char *os_minor = "";
84static char *processor_arch;
85static char *os_build;
86static char *os_version;
87static char *lic_version = "Unknown version";
88static char full_domain_name[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
89static struct utsname uts_buf;
90
91
92
93
94
95#define KVP_CONFIG_LOC "/var/lib/hyperv"
96
97#ifndef KVP_SCRIPTS_PATH
98#define KVP_SCRIPTS_PATH "/usr/libexec/hypervkvpd/"
99#endif
100
101#define KVP_NET_DIR "/sys/class/net/"
102
103#define MAX_FILE_NAME 100
104#define ENTRIES_PER_BLOCK 50
105
106struct kvp_record {
107 char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
108 char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
109};
110
111struct kvp_file_state {
112 int fd;
113 int num_blocks;
114 struct kvp_record *records;
115 int num_records;
116 char fname[MAX_FILE_NAME];
117};
118
119static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT];
120
121static void kvp_acquire_lock(int pool)
122{
123 struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0};
124 fl.l_pid = getpid();
125
126 if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
127 syslog(LOG_ERR, "Failed to acquire the lock pool: %d; error: %d %s", pool,
128 errno, strerror(errno));
129 exit(EXIT_FAILURE);
130 }
131}
132
133static void kvp_release_lock(int pool)
134{
135 struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
136 fl.l_pid = getpid();
137
138 if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
139 syslog(LOG_ERR, "Failed to release the lock pool: %d; error: %d %s", pool,
140 errno, strerror(errno));
141 exit(EXIT_FAILURE);
142 }
143}
144
145static void kvp_update_file(int pool)
146{
147 FILE *filep;
148
149
150
151
152
153 kvp_acquire_lock(pool);
154
155 filep = fopen(kvp_file_info[pool].fname, "we");
156 if (!filep) {
157 syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool,
158 errno, strerror(errno));
159 kvp_release_lock(pool);
160 exit(EXIT_FAILURE);
161 }
162
163 fwrite(kvp_file_info[pool].records, sizeof(struct kvp_record),
164 kvp_file_info[pool].num_records, filep);
165
166 if (ferror(filep) || fclose(filep)) {
167 kvp_release_lock(pool);
168 syslog(LOG_ERR, "Failed to write file, pool: %d", pool);
169 exit(EXIT_FAILURE);
170 }
171
172 kvp_release_lock(pool);
173}
174
175static void kvp_update_mem_state(int pool)
176{
177 FILE *filep;
178 size_t records_read = 0;
179 struct kvp_record *record = kvp_file_info[pool].records;
180 struct kvp_record *readp;
181 int num_blocks = kvp_file_info[pool].num_blocks;
182 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
183
184 kvp_acquire_lock(pool);
185
186 filep = fopen(kvp_file_info[pool].fname, "re");
187 if (!filep) {
188 syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool,
189 errno, strerror(errno));
190 kvp_release_lock(pool);
191 exit(EXIT_FAILURE);
192 }
193 for (;;) {
194 readp = &record[records_read];
195 records_read += fread(readp, sizeof(struct kvp_record),
196 ENTRIES_PER_BLOCK * num_blocks,
197 filep);
198
199 if (ferror(filep)) {
200 syslog(LOG_ERR, "Failed to read file, pool: %d", pool);
201 exit(EXIT_FAILURE);
202 }
203
204 if (!feof(filep)) {
205
206
207
208 num_blocks++;
209 record = realloc(record, alloc_unit * num_blocks);
210
211 if (record == NULL) {
212 syslog(LOG_ERR, "malloc failed");
213 exit(EXIT_FAILURE);
214 }
215 continue;
216 }
217 break;
218 }
219
220 kvp_file_info[pool].num_blocks = num_blocks;
221 kvp_file_info[pool].records = record;
222 kvp_file_info[pool].num_records = records_read;
223
224 fclose(filep);
225 kvp_release_lock(pool);
226}
227static int kvp_file_init(void)
228{
229 int fd;
230 FILE *filep;
231 size_t records_read;
232 char *fname;
233 struct kvp_record *record;
234 struct kvp_record *readp;
235 int num_blocks;
236 int i;
237 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
238
239 if (access(KVP_CONFIG_LOC, F_OK)) {
240 if (mkdir(KVP_CONFIG_LOC, 0755 )) {
241 syslog(LOG_ERR, "Failed to create '%s'; error: %d %s", KVP_CONFIG_LOC,
242 errno, strerror(errno));
243 exit(EXIT_FAILURE);
244 }
245 }
246
247 for (i = 0; i < KVP_POOL_COUNT; i++) {
248 fname = kvp_file_info[i].fname;
249 records_read = 0;
250 num_blocks = 1;
251 sprintf(fname, "%s/.kvp_pool_%d", KVP_CONFIG_LOC, i);
252 fd = open(fname, O_RDWR | O_CREAT | O_CLOEXEC, 0644 );
253
254 if (fd == -1)
255 return 1;
256
257
258 filep = fopen(fname, "re");
259 if (!filep) {
260 close(fd);
261 return 1;
262 }
263
264 record = malloc(alloc_unit * num_blocks);
265 if (record == NULL) {
266 fclose(filep);
267 close(fd);
268 return 1;
269 }
270 for (;;) {
271 readp = &record[records_read];
272 records_read += fread(readp, sizeof(struct kvp_record),
273 ENTRIES_PER_BLOCK,
274 filep);
275
276 if (ferror(filep)) {
277 syslog(LOG_ERR, "Failed to read file, pool: %d",
278 i);
279 exit(EXIT_FAILURE);
280 }
281
282 if (!feof(filep)) {
283
284
285
286 num_blocks++;
287 record = realloc(record, alloc_unit *
288 num_blocks);
289 if (record == NULL) {
290 fclose(filep);
291 close(fd);
292 return 1;
293 }
294 continue;
295 }
296 break;
297 }
298 kvp_file_info[i].fd = fd;
299 kvp_file_info[i].num_blocks = num_blocks;
300 kvp_file_info[i].records = record;
301 kvp_file_info[i].num_records = records_read;
302 fclose(filep);
303
304 }
305
306 return 0;
307}
308
309static int kvp_key_delete(int pool, const __u8 *key, int key_size)
310{
311 int i;
312 int j, k;
313 int num_records;
314 struct kvp_record *record;
315
316
317
318
319 kvp_update_mem_state(pool);
320
321 num_records = kvp_file_info[pool].num_records;
322 record = kvp_file_info[pool].records;
323
324 for (i = 0; i < num_records; i++) {
325 if (memcmp(key, record[i].key, key_size))
326 continue;
327
328
329
330
331 if (i == num_records) {
332 kvp_file_info[pool].num_records--;
333 kvp_update_file(pool);
334 return 0;
335 }
336
337 j = i;
338 k = j + 1;
339 for (; k < num_records; k++) {
340 strcpy(record[j].key, record[k].key);
341 strcpy(record[j].value, record[k].value);
342 j++;
343 }
344
345 kvp_file_info[pool].num_records--;
346 kvp_update_file(pool);
347 return 0;
348 }
349 return 1;
350}
351
352static int kvp_key_add_or_modify(int pool, const __u8 *key, int key_size,
353 const __u8 *value, int value_size)
354{
355 int i;
356 int num_records;
357 struct kvp_record *record;
358 int num_blocks;
359
360 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
361 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
362 return 1;
363
364
365
366
367 kvp_update_mem_state(pool);
368
369 num_records = kvp_file_info[pool].num_records;
370 record = kvp_file_info[pool].records;
371 num_blocks = kvp_file_info[pool].num_blocks;
372
373 for (i = 0; i < num_records; i++) {
374 if (memcmp(key, record[i].key, key_size))
375 continue;
376
377
378
379
380 memcpy(record[i].value, value, value_size);
381 kvp_update_file(pool);
382 return 0;
383 }
384
385
386
387
388 if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
389
390 record = realloc(record, sizeof(struct kvp_record) *
391 ENTRIES_PER_BLOCK * (num_blocks + 1));
392
393 if (record == NULL)
394 return 1;
395 kvp_file_info[pool].num_blocks++;
396
397 }
398 memcpy(record[i].value, value, value_size);
399 memcpy(record[i].key, key, key_size);
400 kvp_file_info[pool].records = record;
401 kvp_file_info[pool].num_records++;
402 kvp_update_file(pool);
403 return 0;
404}
405
406static int kvp_get_value(int pool, const __u8 *key, int key_size, __u8 *value,
407 int value_size)
408{
409 int i;
410 int num_records;
411 struct kvp_record *record;
412
413 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
414 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
415 return 1;
416
417
418
419
420 kvp_update_mem_state(pool);
421
422 num_records = kvp_file_info[pool].num_records;
423 record = kvp_file_info[pool].records;
424
425 for (i = 0; i < num_records; i++) {
426 if (memcmp(key, record[i].key, key_size))
427 continue;
428
429
430
431 memcpy(value, record[i].value, value_size);
432 return 0;
433 }
434
435 return 1;
436}
437
438static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
439 __u8 *value, int value_size)
440{
441 struct kvp_record *record;
442
443
444
445
446 kvp_update_mem_state(pool);
447 record = kvp_file_info[pool].records;
448
449 if (index >= kvp_file_info[pool].num_records) {
450 return 1;
451 }
452
453 memcpy(key, record[index].key, key_size);
454 memcpy(value, record[index].value, value_size);
455 return 0;
456}
457
458
459void kvp_get_os_info(void)
460{
461 FILE *file;
462 char *p, buf[512];
463
464 uname(&uts_buf);
465 os_version = uts_buf.release;
466 os_build = strdup(uts_buf.release);
467
468 os_name = uts_buf.sysname;
469 processor_arch = uts_buf.machine;
470
471
472
473
474
475
476 p = strchr(os_version, '-');
477 if (p)
478 *p = '\0';
479
480
481
482
483
484 file = fopen("/etc/os-release", "r");
485 if (file != NULL) {
486 while (fgets(buf, sizeof(buf), file)) {
487 char *value, *q;
488
489
490 if (buf[0] == '#')
491 continue;
492
493
494 p = strchr(buf, '=');
495 if (!p)
496 continue;
497 *p++ = 0;
498
499
500 value = p;
501 q = p;
502 while (*p) {
503 if (*p == '\\') {
504 ++p;
505 if (!*p)
506 break;
507 *q++ = *p++;
508 } else if (*p == '\'' || *p == '"' ||
509 *p == '\n') {
510 ++p;
511 } else {
512 *q++ = *p++;
513 }
514 }
515 *q = 0;
516
517 if (!strcmp(buf, "NAME")) {
518 p = strdup(value);
519 if (!p)
520 break;
521 os_name = p;
522 } else if (!strcmp(buf, "VERSION_ID")) {
523 p = strdup(value);
524 if (!p)
525 break;
526 os_major = p;
527 }
528 }
529 fclose(file);
530 return;
531 }
532
533
534 file = fopen("/etc/SuSE-release", "r");
535 if (file != NULL)
536 goto kvp_osinfo_found;
537 file = fopen("/etc/redhat-release", "r");
538 if (file != NULL)
539 goto kvp_osinfo_found;
540
541
542
543
544 return;
545
546kvp_osinfo_found:
547
548 p = fgets(buf, sizeof(buf), file);
549 if (p) {
550 p = strchr(buf, '\n');
551 if (p)
552 *p = '\0';
553 p = strdup(buf);
554 if (!p)
555 goto done;
556 os_name = p;
557
558
559 p = fgets(buf, sizeof(buf), file);
560 if (p) {
561 p = strchr(buf, '\n');
562 if (p)
563 *p = '\0';
564 p = strdup(buf);
565 if (!p)
566 goto done;
567 os_major = p;
568
569
570 p = fgets(buf, sizeof(buf), file);
571 if (p) {
572 p = strchr(buf, '\n');
573 if (p)
574 *p = '\0';
575 p = strdup(buf);
576 if (p)
577 os_minor = p;
578 }
579 }
580 }
581
582done:
583 fclose(file);
584 return;
585}
586
587
588
589
590
591
592
593
594
595
596
597static char *kvp_get_if_name(char *guid)
598{
599 DIR *dir;
600 struct dirent *entry;
601 FILE *file;
602 char *p, *x;
603 char *if_name = NULL;
604 char buf[256];
605 char dev_id[PATH_MAX];
606
607 dir = opendir(KVP_NET_DIR);
608 if (dir == NULL)
609 return NULL;
610
611 while ((entry = readdir(dir)) != NULL) {
612
613
614
615 snprintf(dev_id, sizeof(dev_id), "%s%s/device/device_id",
616 KVP_NET_DIR, entry->d_name);
617
618 file = fopen(dev_id, "r");
619 if (file == NULL)
620 continue;
621
622 p = fgets(buf, sizeof(buf), file);
623 if (p) {
624 x = strchr(p, '\n');
625 if (x)
626 *x = '\0';
627
628 if (!strcmp(p, guid)) {
629
630
631
632
633 if_name = strdup(entry->d_name);
634 fclose(file);
635 break;
636 }
637 }
638 fclose(file);
639 }
640
641 closedir(dir);
642 return if_name;
643}
644
645
646
647
648
649static char *kvp_if_name_to_mac(char *if_name)
650{
651 FILE *file;
652 char *p, *x;
653 char buf[256];
654 char addr_file[PATH_MAX];
655 unsigned int i;
656 char *mac_addr = NULL;
657
658 snprintf(addr_file, sizeof(addr_file), "%s%s%s", KVP_NET_DIR,
659 if_name, "/address");
660
661 file = fopen(addr_file, "r");
662 if (file == NULL)
663 return NULL;
664
665 p = fgets(buf, sizeof(buf), file);
666 if (p) {
667 x = strchr(p, '\n');
668 if (x)
669 *x = '\0';
670 for (i = 0; i < strlen(p); i++)
671 p[i] = toupper(p[i]);
672 mac_addr = strdup(p);
673 }
674
675 fclose(file);
676 return mac_addr;
677}
678
679
680
681
682
683
684static char *kvp_mac_to_if_name(char *mac)
685{
686 DIR *dir;
687 struct dirent *entry;
688 FILE *file;
689 char *p, *x;
690 char *if_name = NULL;
691 char buf[256];
692 char dev_id[PATH_MAX];
693 unsigned int i;
694
695 dir = opendir(KVP_NET_DIR);
696 if (dir == NULL)
697 return NULL;
698
699 while ((entry = readdir(dir)) != NULL) {
700
701
702
703 snprintf(dev_id, sizeof(dev_id), "%s%s/address", KVP_NET_DIR,
704 entry->d_name);
705
706 file = fopen(dev_id, "r");
707 if (file == NULL)
708 continue;
709
710 p = fgets(buf, sizeof(buf), file);
711 if (p) {
712 x = strchr(p, '\n');
713 if (x)
714 *x = '\0';
715
716 for (i = 0; i < strlen(p); i++)
717 p[i] = toupper(p[i]);
718
719 if (!strcmp(p, mac)) {
720
721
722
723
724 if_name = strdup(entry->d_name);
725 fclose(file);
726 break;
727 }
728 }
729 fclose(file);
730 }
731
732 closedir(dir);
733 return if_name;
734}
735
736
737static void kvp_process_ipconfig_file(char *cmd,
738 char *config_buf, unsigned int len,
739 int element_size, int offset)
740{
741 char buf[256];
742 char *p;
743 char *x;
744 FILE *file;
745
746
747
748
749 file = popen(cmd, "r");
750 if (file == NULL)
751 return;
752
753 if (offset == 0)
754 memset(config_buf, 0, len);
755 while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
756 if (len < strlen(config_buf) + element_size + 1)
757 break;
758
759 x = strchr(p, '\n');
760 if (x)
761 *x = '\0';
762
763 strcat(config_buf, p);
764 strcat(config_buf, ";");
765 }
766 pclose(file);
767}
768
769static void kvp_get_ipconfig_info(char *if_name,
770 struct hv_kvp_ipaddr_value *buffer)
771{
772 char cmd[512];
773 char dhcp_info[128];
774 char *p;
775 FILE *file;
776
777
778
779
780 sprintf(cmd, "%s %s", "ip route show dev", if_name);
781 strcat(cmd, " | awk '/default/ {print $3 }'");
782
783
784
785
786 kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
787 (MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0);
788
789
790
791
792 sprintf(cmd, "%s %s", "ip -f inet6 route show dev", if_name);
793 strcat(cmd, " | awk '/default/ {print $3 }'");
794
795
796
797
798 kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
799 (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1);
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817 sprintf(cmd, KVP_SCRIPTS_PATH "%s", "hv_get_dns_info");
818
819
820
821
822 kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr,
823 (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0);
824
825
826
827
828
829
830
831
832
833
834 sprintf(cmd, KVP_SCRIPTS_PATH "%s %s", "hv_get_dhcp_info", if_name);
835
836 file = popen(cmd, "r");
837 if (file == NULL)
838 return;
839
840 p = fgets(dhcp_info, sizeof(dhcp_info), file);
841 if (p == NULL) {
842 pclose(file);
843 return;
844 }
845
846 if (!strncmp(p, "Enabled", 7))
847 buffer->dhcp_enabled = 1;
848 else
849 buffer->dhcp_enabled = 0;
850
851 pclose(file);
852}
853
854
855static unsigned int hweight32(unsigned int *w)
856{
857 unsigned int res = *w - ((*w >> 1) & 0x55555555);
858 res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
859 res = (res + (res >> 4)) & 0x0F0F0F0F;
860 res = res + (res >> 8);
861 return (res + (res >> 16)) & 0x000000FF;
862}
863
864static int kvp_process_ip_address(void *addrp,
865 int family, char *buffer,
866 int length, int *offset)
867{
868 struct sockaddr_in *addr;
869 struct sockaddr_in6 *addr6;
870 int addr_length;
871 char tmp[50];
872 const char *str;
873
874 if (family == AF_INET) {
875 addr = (struct sockaddr_in *)addrp;
876 str = inet_ntop(family, &addr->sin_addr, tmp, 50);
877 addr_length = INET_ADDRSTRLEN;
878 } else {
879 addr6 = (struct sockaddr_in6 *)addrp;
880 str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50);
881 addr_length = INET6_ADDRSTRLEN;
882 }
883
884 if ((length - *offset) < addr_length + 2)
885 return HV_E_FAIL;
886 if (str == NULL) {
887 strcpy(buffer, "inet_ntop failed\n");
888 return HV_E_FAIL;
889 }
890 if (*offset == 0)
891 strcpy(buffer, tmp);
892 else {
893 strcat(buffer, ";");
894 strcat(buffer, tmp);
895 }
896
897 *offset += strlen(str) + 1;
898
899 return 0;
900}
901
902static int
903kvp_get_ip_info(int family, char *if_name, int op,
904 void *out_buffer, unsigned int length)
905{
906 struct ifaddrs *ifap;
907 struct ifaddrs *curp;
908 int offset = 0;
909 int sn_offset = 0;
910 int error = 0;
911 char *buffer;
912 struct hv_kvp_ipaddr_value *ip_buffer;
913 char cidr_mask[5];
914 int weight;
915 int i;
916 unsigned int *w;
917 char *sn_str;
918 struct sockaddr_in6 *addr6;
919
920 if (op == KVP_OP_ENUMERATE) {
921 buffer = out_buffer;
922 } else {
923 ip_buffer = out_buffer;
924 buffer = (char *)ip_buffer->ip_addr;
925 ip_buffer->addr_family = 0;
926 }
927
928
929
930
931
932 if (getifaddrs(&ifap)) {
933 strcpy(buffer, "getifaddrs failed\n");
934 return HV_E_FAIL;
935 }
936
937 curp = ifap;
938 while (curp != NULL) {
939 if (curp->ifa_addr == NULL) {
940 curp = curp->ifa_next;
941 continue;
942 }
943
944 if ((if_name != NULL) &&
945 (strncmp(curp->ifa_name, if_name, strlen(if_name)))) {
946
947
948
949
950 curp = curp->ifa_next;
951 continue;
952 }
953
954
955
956
957
958
959
960 if ((((family != 0) &&
961 (curp->ifa_addr->sa_family != family))) ||
962 (curp->ifa_flags & IFF_LOOPBACK)) {
963 curp = curp->ifa_next;
964 continue;
965 }
966 if ((curp->ifa_addr->sa_family != AF_INET) &&
967 (curp->ifa_addr->sa_family != AF_INET6)) {
968 curp = curp->ifa_next;
969 continue;
970 }
971
972 if (op == KVP_OP_GET_IP_INFO) {
973
974
975
976
977 if (curp->ifa_addr->sa_family == AF_INET) {
978 ip_buffer->addr_family |= ADDR_FAMILY_IPV4;
979
980
981
982 error = kvp_process_ip_address(
983 curp->ifa_netmask,
984 AF_INET,
985 (char *)
986 ip_buffer->sub_net,
987 length,
988 &sn_offset);
989 if (error)
990 goto gather_ipaddr;
991 } else {
992 ip_buffer->addr_family |= ADDR_FAMILY_IPV6;
993
994
995
996
997 weight = 0;
998 sn_str = (char *)ip_buffer->sub_net;
999 addr6 = (struct sockaddr_in6 *)
1000 curp->ifa_netmask;
1001 w = addr6->sin6_addr.s6_addr32;
1002
1003 for (i = 0; i < 4; i++)
1004 weight += hweight32(&w[i]);
1005
1006 sprintf(cidr_mask, "/%d", weight);
1007 if (length < sn_offset + strlen(cidr_mask) + 1)
1008 goto gather_ipaddr;
1009
1010 if (sn_offset == 0)
1011 strcpy(sn_str, cidr_mask);
1012 else {
1013 strcat((char *)ip_buffer->sub_net, ";");
1014 strcat(sn_str, cidr_mask);
1015 }
1016 sn_offset += strlen(sn_str) + 1;
1017 }
1018
1019
1020
1021
1022
1023 kvp_get_ipconfig_info(if_name, ip_buffer);
1024 }
1025
1026gather_ipaddr:
1027 error = kvp_process_ip_address(curp->ifa_addr,
1028 curp->ifa_addr->sa_family,
1029 buffer,
1030 length, &offset);
1031 if (error)
1032 goto getaddr_done;
1033
1034 curp = curp->ifa_next;
1035 }
1036
1037getaddr_done:
1038 freeifaddrs(ifap);
1039 return error;
1040}
1041
1042
1043static int expand_ipv6(char *addr, int type)
1044{
1045 int ret;
1046 struct in6_addr v6_addr;
1047
1048 ret = inet_pton(AF_INET6, addr, &v6_addr);
1049
1050 if (ret != 1) {
1051 if (type == NETMASK)
1052 return 1;
1053 return 0;
1054 }
1055
1056 sprintf(addr, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
1057 "%02x%02x:%02x%02x:%02x%02x",
1058 (int)v6_addr.s6_addr[0], (int)v6_addr.s6_addr[1],
1059 (int)v6_addr.s6_addr[2], (int)v6_addr.s6_addr[3],
1060 (int)v6_addr.s6_addr[4], (int)v6_addr.s6_addr[5],
1061 (int)v6_addr.s6_addr[6], (int)v6_addr.s6_addr[7],
1062 (int)v6_addr.s6_addr[8], (int)v6_addr.s6_addr[9],
1063 (int)v6_addr.s6_addr[10], (int)v6_addr.s6_addr[11],
1064 (int)v6_addr.s6_addr[12], (int)v6_addr.s6_addr[13],
1065 (int)v6_addr.s6_addr[14], (int)v6_addr.s6_addr[15]);
1066
1067 return 1;
1068
1069}
1070
1071static int is_ipv4(char *addr)
1072{
1073 int ret;
1074 struct in_addr ipv4_addr;
1075
1076 ret = inet_pton(AF_INET, addr, &ipv4_addr);
1077
1078 if (ret == 1)
1079 return 1;
1080 return 0;
1081}
1082
1083static int parse_ip_val_buffer(char *in_buf, int *offset,
1084 char *out_buf, int out_len)
1085{
1086 char *x;
1087 char *start;
1088
1089
1090
1091
1092
1093
1094 start = in_buf + *offset;
1095
1096 x = strchr(start, ';');
1097 if (x)
1098 *x = 0;
1099 else
1100 x = start + strlen(start);
1101
1102 if (strlen(start) != 0) {
1103 int i = 0;
1104
1105
1106
1107 while (start[i] == ' ')
1108 i++;
1109
1110 if ((x - start) <= out_len) {
1111 strcpy(out_buf, (start + i));
1112 *offset += (x - start) + 1;
1113 return 1;
1114 }
1115 }
1116 return 0;
1117}
1118
1119static int kvp_write_file(FILE *f, char *s1, char *s2, char *s3)
1120{
1121 int ret;
1122
1123 ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3);
1124
1125 if (ret < 0)
1126 return HV_E_FAIL;
1127
1128 return 0;
1129}
1130
1131
1132static int process_ip_string(FILE *f, char *ip_string, int type)
1133{
1134 int error = 0;
1135 char addr[INET6_ADDRSTRLEN];
1136 int i = 0;
1137 int j = 0;
1138 char str[256];
1139 char sub_str[13];
1140 int offset = 0;
1141
1142 memset(addr, 0, sizeof(addr));
1143
1144 while (parse_ip_val_buffer(ip_string, &offset, addr,
1145 (MAX_IP_ADDR_SIZE * 2))) {
1146
1147 sub_str[0] = 0;
1148 if (is_ipv4(addr)) {
1149 switch (type) {
1150 case IPADDR:
1151 snprintf(str, sizeof(str), "%s", "IPADDR");
1152 break;
1153 case NETMASK:
1154 snprintf(str, sizeof(str), "%s", "NETMASK");
1155 break;
1156 case GATEWAY:
1157 snprintf(str, sizeof(str), "%s", "GATEWAY");
1158 break;
1159 case DNS:
1160 snprintf(str, sizeof(str), "%s", "DNS");
1161 break;
1162 }
1163
1164 if (type == DNS) {
1165 snprintf(sub_str, sizeof(sub_str), "%d", ++i);
1166 } else if (type == GATEWAY && i == 0) {
1167 ++i;
1168 } else {
1169 snprintf(sub_str, sizeof(sub_str), "%d", i++);
1170 }
1171
1172
1173 } else if (expand_ipv6(addr, type)) {
1174 switch (type) {
1175 case IPADDR:
1176 snprintf(str, sizeof(str), "%s", "IPV6ADDR");
1177 break;
1178 case NETMASK:
1179 snprintf(str, sizeof(str), "%s", "IPV6NETMASK");
1180 break;
1181 case GATEWAY:
1182 snprintf(str, sizeof(str), "%s",
1183 "IPV6_DEFAULTGW");
1184 break;
1185 case DNS:
1186 snprintf(str, sizeof(str), "%s", "DNS");
1187 break;
1188 }
1189
1190 if (type == DNS) {
1191 snprintf(sub_str, sizeof(sub_str), "%d", ++i);
1192 } else if (j == 0) {
1193 ++j;
1194 } else {
1195 snprintf(sub_str, sizeof(sub_str), "_%d", j++);
1196 }
1197 } else {
1198 return HV_INVALIDARG;
1199 }
1200
1201 error = kvp_write_file(f, str, sub_str, addr);
1202 if (error)
1203 return error;
1204 memset(addr, 0, sizeof(addr));
1205 }
1206
1207 return 0;
1208}
1209
1210static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
1211{
1212 int error = 0;
1213 char if_file[PATH_MAX];
1214 FILE *file;
1215 char cmd[PATH_MAX];
1216 char *mac_addr;
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265 snprintf(if_file, sizeof(if_file), "%s%s%s", KVP_CONFIG_LOC,
1266 "/ifcfg-", if_name);
1267
1268 file = fopen(if_file, "w");
1269
1270 if (file == NULL) {
1271 syslog(LOG_ERR, "Failed to open config file; error: %d %s",
1272 errno, strerror(errno));
1273 return HV_E_FAIL;
1274 }
1275
1276
1277
1278
1279
1280 mac_addr = kvp_if_name_to_mac(if_name);
1281 if (mac_addr == NULL) {
1282 error = HV_E_FAIL;
1283 goto setval_error;
1284 }
1285
1286 error = kvp_write_file(file, "HWADDR", "", mac_addr);
1287 free(mac_addr);
1288 if (error)
1289 goto setval_error;
1290
1291 error = kvp_write_file(file, "DEVICE", "", if_name);
1292 if (error)
1293 goto setval_error;
1294
1295
1296
1297
1298
1299
1300
1301 if (new_val->dhcp_enabled) {
1302 error = kvp_write_file(file, "BOOTPROTO", "", "dhcp");
1303 if (error)
1304 goto setval_error;
1305
1306 } else {
1307 error = kvp_write_file(file, "BOOTPROTO", "", "none");
1308 if (error)
1309 goto setval_error;
1310 }
1311
1312
1313
1314
1315
1316
1317 error = process_ip_string(file, (char *)new_val->ip_addr, IPADDR);
1318 if (error)
1319 goto setval_error;
1320
1321 error = process_ip_string(file, (char *)new_val->sub_net, NETMASK);
1322 if (error)
1323 goto setval_error;
1324
1325 error = process_ip_string(file, (char *)new_val->gate_way, GATEWAY);
1326 if (error)
1327 goto setval_error;
1328
1329 error = process_ip_string(file, (char *)new_val->dns_addr, DNS);
1330 if (error)
1331 goto setval_error;
1332
1333 fclose(file);
1334
1335
1336
1337
1338
1339
1340 snprintf(cmd, sizeof(cmd), KVP_SCRIPTS_PATH "%s %s",
1341 "hv_set_ifconfig", if_file);
1342 if (system(cmd)) {
1343 syslog(LOG_ERR, "Failed to execute cmd '%s'; error: %d %s",
1344 cmd, errno, strerror(errno));
1345 return HV_E_FAIL;
1346 }
1347 return 0;
1348
1349setval_error:
1350 syslog(LOG_ERR, "Failed to write config file");
1351 fclose(file);
1352 return error;
1353}
1354
1355
1356static void
1357kvp_get_domain_name(char *buffer, int length)
1358{
1359 struct addrinfo hints, *info ;
1360 int error = 0;
1361
1362 gethostname(buffer, length);
1363 memset(&hints, 0, sizeof(hints));
1364 hints.ai_family = AF_INET;
1365 hints.ai_socktype = SOCK_STREAM;
1366 hints.ai_flags = AI_CANONNAME;
1367
1368 error = getaddrinfo(buffer, NULL, &hints, &info);
1369 if (error != 0) {
1370 snprintf(buffer, length, "getaddrinfo failed: 0x%x %s",
1371 error, gai_strerror(error));
1372 return;
1373 }
1374 snprintf(buffer, length, "%s", info->ai_canonname);
1375 freeaddrinfo(info);
1376}
1377
1378void print_usage(char *argv[])
1379{
1380 fprintf(stderr, "Usage: %s [options]\n"
1381 "Options are:\n"
1382 " -n, --no-daemon stay in foreground, don't daemonize\n"
1383 " -h, --help print this help\n", argv[0]);
1384}
1385
1386int main(int argc, char *argv[])
1387{
1388 int kvp_fd, len;
1389 int error;
1390 struct pollfd pfd;
1391 char *p;
1392 struct hv_kvp_msg hv_msg[1];
1393 char *key_value;
1394 char *key_name;
1395 int op;
1396 int pool;
1397 char *if_name;
1398 struct hv_kvp_ipaddr_value *kvp_ip_val;
1399 int daemonize = 1, long_index = 0, opt;
1400
1401 static struct option long_options[] = {
1402 {"help", no_argument, 0, 'h' },
1403 {"no-daemon", no_argument, 0, 'n' },
1404 {0, 0, 0, 0 }
1405 };
1406
1407 while ((opt = getopt_long(argc, argv, "hn", long_options,
1408 &long_index)) != -1) {
1409 switch (opt) {
1410 case 'n':
1411 daemonize = 0;
1412 break;
1413 case 'h':
1414 default:
1415 print_usage(argv);
1416 exit(EXIT_FAILURE);
1417 }
1418 }
1419
1420 if (daemonize && daemon(1, 0))
1421 return 1;
1422
1423 openlog("KVP", 0, LOG_USER);
1424 syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
1425
1426 kvp_fd = open("/dev/vmbus/hv_kvp", O_RDWR | O_CLOEXEC);
1427
1428 if (kvp_fd < 0) {
1429 syslog(LOG_ERR, "open /dev/vmbus/hv_kvp failed; error: %d %s",
1430 errno, strerror(errno));
1431 exit(EXIT_FAILURE);
1432 }
1433
1434
1435
1436
1437 kvp_get_os_info();
1438
1439
1440
1441
1442 kvp_get_domain_name(full_domain_name, sizeof(full_domain_name));
1443
1444 if (kvp_file_init()) {
1445 syslog(LOG_ERR, "Failed to initialize the pools");
1446 exit(EXIT_FAILURE);
1447 }
1448
1449
1450
1451
1452 hv_msg->kvp_hdr.operation = KVP_OP_REGISTER1;
1453 len = write(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg));
1454 if (len != sizeof(struct hv_kvp_msg)) {
1455 syslog(LOG_ERR, "registration to kernel failed; error: %d %s",
1456 errno, strerror(errno));
1457 close(kvp_fd);
1458 exit(EXIT_FAILURE);
1459 }
1460
1461 pfd.fd = kvp_fd;
1462
1463 while (1) {
1464 pfd.events = POLLIN;
1465 pfd.revents = 0;
1466
1467 if (poll(&pfd, 1, -1) < 0) {
1468 syslog(LOG_ERR, "poll failed; error: %d %s", errno, strerror(errno));
1469 if (errno == EINVAL) {
1470 close(kvp_fd);
1471 exit(EXIT_FAILURE);
1472 }
1473 else
1474 continue;
1475 }
1476
1477 len = read(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg));
1478
1479 if (len != sizeof(struct hv_kvp_msg)) {
1480 syslog(LOG_ERR, "read failed; error:%d %s",
1481 errno, strerror(errno));
1482
1483 close(kvp_fd);
1484 return EXIT_FAILURE;
1485 }
1486
1487
1488
1489
1490
1491
1492 op = hv_msg->kvp_hdr.operation;
1493 pool = hv_msg->kvp_hdr.pool;
1494 hv_msg->error = HV_S_OK;
1495
1496 if ((in_hand_shake) && (op == KVP_OP_REGISTER1)) {
1497
1498
1499
1500
1501 in_hand_shake = 0;
1502 p = (char *)hv_msg->body.kvp_register.version;
1503 lic_version = malloc(strlen(p) + 1);
1504 if (lic_version) {
1505 strcpy(lic_version, p);
1506 syslog(LOG_INFO, "KVP LIC Version: %s",
1507 lic_version);
1508 } else {
1509 syslog(LOG_ERR, "malloc failed");
1510 }
1511 continue;
1512 }
1513
1514 switch (op) {
1515 case KVP_OP_GET_IP_INFO:
1516 kvp_ip_val = &hv_msg->body.kvp_ip_val;
1517 if_name =
1518 kvp_mac_to_if_name((char *)kvp_ip_val->adapter_id);
1519
1520 if (if_name == NULL) {
1521
1522
1523
1524
1525 hv_msg->error = HV_E_FAIL;
1526 break;
1527 }
1528 error = kvp_get_ip_info(
1529 0, if_name, KVP_OP_GET_IP_INFO,
1530 kvp_ip_val,
1531 (MAX_IP_ADDR_SIZE * 2));
1532
1533 if (error)
1534 hv_msg->error = error;
1535
1536 free(if_name);
1537 break;
1538
1539 case KVP_OP_SET_IP_INFO:
1540 kvp_ip_val = &hv_msg->body.kvp_ip_val;
1541 if_name = kvp_get_if_name(
1542 (char *)kvp_ip_val->adapter_id);
1543 if (if_name == NULL) {
1544
1545
1546
1547
1548 hv_msg->error = HV_GUID_NOTFOUND;
1549 break;
1550 }
1551 error = kvp_set_ip_info(if_name, kvp_ip_val);
1552 if (error)
1553 hv_msg->error = error;
1554
1555 free(if_name);
1556 break;
1557
1558 case KVP_OP_SET:
1559 if (kvp_key_add_or_modify(pool,
1560 hv_msg->body.kvp_set.data.key,
1561 hv_msg->body.kvp_set.data.key_size,
1562 hv_msg->body.kvp_set.data.value,
1563 hv_msg->body.kvp_set.data.value_size))
1564 hv_msg->error = HV_S_CONT;
1565 break;
1566
1567 case KVP_OP_GET:
1568 if (kvp_get_value(pool,
1569 hv_msg->body.kvp_set.data.key,
1570 hv_msg->body.kvp_set.data.key_size,
1571 hv_msg->body.kvp_set.data.value,
1572 hv_msg->body.kvp_set.data.value_size))
1573 hv_msg->error = HV_S_CONT;
1574 break;
1575
1576 case KVP_OP_DELETE:
1577 if (kvp_key_delete(pool,
1578 hv_msg->body.kvp_delete.key,
1579 hv_msg->body.kvp_delete.key_size))
1580 hv_msg->error = HV_S_CONT;
1581 break;
1582
1583 default:
1584 break;
1585 }
1586
1587 if (op != KVP_OP_ENUMERATE)
1588 goto kvp_done;
1589
1590
1591
1592
1593
1594
1595 if (pool != KVP_POOL_AUTO) {
1596 if (kvp_pool_enumerate(pool,
1597 hv_msg->body.kvp_enum_data.index,
1598 hv_msg->body.kvp_enum_data.data.key,
1599 HV_KVP_EXCHANGE_MAX_KEY_SIZE,
1600 hv_msg->body.kvp_enum_data.data.value,
1601 HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
1602 hv_msg->error = HV_S_CONT;
1603 goto kvp_done;
1604 }
1605
1606 key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
1607 key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
1608
1609 switch (hv_msg->body.kvp_enum_data.index) {
1610 case FullyQualifiedDomainName:
1611 strcpy(key_value, full_domain_name);
1612 strcpy(key_name, "FullyQualifiedDomainName");
1613 break;
1614 case IntegrationServicesVersion:
1615 strcpy(key_name, "IntegrationServicesVersion");
1616 strcpy(key_value, lic_version);
1617 break;
1618 case NetworkAddressIPv4:
1619 kvp_get_ip_info(AF_INET, NULL, KVP_OP_ENUMERATE,
1620 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1621 strcpy(key_name, "NetworkAddressIPv4");
1622 break;
1623 case NetworkAddressIPv6:
1624 kvp_get_ip_info(AF_INET6, NULL, KVP_OP_ENUMERATE,
1625 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1626 strcpy(key_name, "NetworkAddressIPv6");
1627 break;
1628 case OSBuildNumber:
1629 strcpy(key_value, os_build);
1630 strcpy(key_name, "OSBuildNumber");
1631 break;
1632 case OSName:
1633 strcpy(key_value, os_name);
1634 strcpy(key_name, "OSName");
1635 break;
1636 case OSMajorVersion:
1637 strcpy(key_value, os_major);
1638 strcpy(key_name, "OSMajorVersion");
1639 break;
1640 case OSMinorVersion:
1641 strcpy(key_value, os_minor);
1642 strcpy(key_name, "OSMinorVersion");
1643 break;
1644 case OSVersion:
1645 strcpy(key_value, os_version);
1646 strcpy(key_name, "OSVersion");
1647 break;
1648 case ProcessorArchitecture:
1649 strcpy(key_value, processor_arch);
1650 strcpy(key_name, "ProcessorArchitecture");
1651 break;
1652 default:
1653 hv_msg->error = HV_S_CONT;
1654 break;
1655 }
1656
1657
1658kvp_done:
1659 len = write(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg));
1660 if (len != sizeof(struct hv_kvp_msg)) {
1661 syslog(LOG_ERR, "write failed; error: %d %s", errno,
1662 strerror(errno));
1663 exit(EXIT_FAILURE);
1664 }
1665 }
1666
1667 close(kvp_fd);
1668 exit(0);
1669}
1670