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/types.h>
26#include <sys/socket.h>
27#include <sys/poll.h>
28#include <sys/utsname.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <unistd.h>
32#include <string.h>
33#include <ctype.h>
34#include <errno.h>
35#include <arpa/inet.h>
36#include <linux/hyperv.h>
37#include <linux/netlink.h>
38#include <ifaddrs.h>
39#include <netdb.h>
40#include <syslog.h>
41#include <sys/stat.h>
42#include <fcntl.h>
43#include <dirent.h>
44#include <net/if.h>
45#include <getopt.h>
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60enum key_index {
61 FullyQualifiedDomainName = 0,
62 IntegrationServicesVersion,
63 NetworkAddressIPv4,
64 NetworkAddressIPv6,
65 OSBuildNumber,
66 OSName,
67 OSMajorVersion,
68 OSMinorVersion,
69 OSVersion,
70 ProcessorArchitecture
71};
72
73
74enum {
75 IPADDR = 0,
76 NETMASK,
77 GATEWAY,
78 DNS
79};
80
81static int in_hand_shake = 1;
82
83static char *os_name = "";
84static char *os_major = "";
85static char *os_minor = "";
86static char *processor_arch;
87static char *os_build;
88static char *os_version;
89static char *lic_version = "Unknown version";
90static char full_domain_name[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
91static struct utsname uts_buf;
92
93
94
95
96
97#define KVP_CONFIG_LOC "/var/lib/hyperv"
98
99#define MAX_FILE_NAME 100
100#define ENTRIES_PER_BLOCK 50
101
102#ifndef SOL_NETLINK
103#define SOL_NETLINK 270
104#endif
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, *q, *x;
603 char *if_name = NULL;
604 char buf[256];
605 char *kvp_net_dir = "/sys/class/net/";
606 char dev_id[256];
607
608 dir = opendir(kvp_net_dir);
609 if (dir == NULL)
610 return NULL;
611
612 snprintf(dev_id, sizeof(dev_id), "%s", kvp_net_dir);
613 q = dev_id + strlen(kvp_net_dir);
614
615 while ((entry = readdir(dir)) != NULL) {
616
617
618
619 *q = '\0';
620 strcat(dev_id, entry->d_name);
621 strcat(dev_id, "/device/device_id");
622
623 file = fopen(dev_id, "r");
624 if (file == NULL)
625 continue;
626
627 p = fgets(buf, sizeof(buf), file);
628 if (p) {
629 x = strchr(p, '\n');
630 if (x)
631 *x = '\0';
632
633 if (!strcmp(p, guid)) {
634
635
636
637
638 if_name = strdup(entry->d_name);
639 fclose(file);
640 break;
641 }
642 }
643 fclose(file);
644 }
645
646 closedir(dir);
647 return if_name;
648}
649
650
651
652
653
654static char *kvp_if_name_to_mac(char *if_name)
655{
656 FILE *file;
657 char *p, *x;
658 char buf[256];
659 char addr_file[256];
660 unsigned int i;
661 char *mac_addr = NULL;
662
663 snprintf(addr_file, sizeof(addr_file), "%s%s%s", "/sys/class/net/",
664 if_name, "/address");
665
666 file = fopen(addr_file, "r");
667 if (file == NULL)
668 return NULL;
669
670 p = fgets(buf, sizeof(buf), file);
671 if (p) {
672 x = strchr(p, '\n');
673 if (x)
674 *x = '\0';
675 for (i = 0; i < strlen(p); i++)
676 p[i] = toupper(p[i]);
677 mac_addr = strdup(p);
678 }
679
680 fclose(file);
681 return mac_addr;
682}
683
684
685
686
687
688
689static char *kvp_mac_to_if_name(char *mac)
690{
691 DIR *dir;
692 struct dirent *entry;
693 FILE *file;
694 char *p, *q, *x;
695 char *if_name = NULL;
696 char buf[256];
697 char *kvp_net_dir = "/sys/class/net/";
698 char dev_id[256];
699 unsigned int i;
700
701 dir = opendir(kvp_net_dir);
702 if (dir == NULL)
703 return NULL;
704
705 snprintf(dev_id, sizeof(dev_id), kvp_net_dir);
706 q = dev_id + strlen(kvp_net_dir);
707
708 while ((entry = readdir(dir)) != NULL) {
709
710
711
712 *q = '\0';
713
714 strcat(dev_id, entry->d_name);
715 strcat(dev_id, "/address");
716
717 file = fopen(dev_id, "r");
718 if (file == NULL)
719 continue;
720
721 p = fgets(buf, sizeof(buf), file);
722 if (p) {
723 x = strchr(p, '\n');
724 if (x)
725 *x = '\0';
726
727 for (i = 0; i < strlen(p); i++)
728 p[i] = toupper(p[i]);
729
730 if (!strcmp(p, mac)) {
731
732
733
734
735 if_name = strdup(entry->d_name);
736 fclose(file);
737 break;
738 }
739 }
740 fclose(file);
741 }
742
743 closedir(dir);
744 return if_name;
745}
746
747
748static void kvp_process_ipconfig_file(char *cmd,
749 char *config_buf, unsigned int len,
750 int element_size, int offset)
751{
752 char buf[256];
753 char *p;
754 char *x;
755 FILE *file;
756
757
758
759
760 file = popen(cmd, "r");
761 if (file == NULL)
762 return;
763
764 if (offset == 0)
765 memset(config_buf, 0, len);
766 while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
767 if (len < strlen(config_buf) + element_size + 1)
768 break;
769
770 x = strchr(p, '\n');
771 if (x)
772 *x = '\0';
773
774 strcat(config_buf, p);
775 strcat(config_buf, ";");
776 }
777 pclose(file);
778}
779
780static void kvp_get_ipconfig_info(char *if_name,
781 struct hv_kvp_ipaddr_value *buffer)
782{
783 char cmd[512];
784 char dhcp_info[128];
785 char *p;
786 FILE *file;
787
788
789
790
791 sprintf(cmd, "%s %s", "ip route show dev", if_name);
792 strcat(cmd, " | awk '/default/ {print $3 }'");
793
794
795
796
797 kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
798 (MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0);
799
800
801
802
803 sprintf(cmd, "%s %s", "ip -f inet6 route show dev", if_name);
804 strcat(cmd, " | awk '/default/ {print $3 }'");
805
806
807
808
809 kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
810 (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1);
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828 sprintf(cmd, "%s", "hv_get_dns_info");
829
830
831
832
833 kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr,
834 (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0);
835
836
837
838
839
840
841
842
843
844
845 sprintf(cmd, "%s %s", "hv_get_dhcp_info", if_name);
846
847 file = popen(cmd, "r");
848 if (file == NULL)
849 return;
850
851 p = fgets(dhcp_info, sizeof(dhcp_info), file);
852 if (p == NULL) {
853 pclose(file);
854 return;
855 }
856
857 if (!strncmp(p, "Enabled", 7))
858 buffer->dhcp_enabled = 1;
859 else
860 buffer->dhcp_enabled = 0;
861
862 pclose(file);
863}
864
865
866static unsigned int hweight32(unsigned int *w)
867{
868 unsigned int res = *w - ((*w >> 1) & 0x55555555);
869 res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
870 res = (res + (res >> 4)) & 0x0F0F0F0F;
871 res = res + (res >> 8);
872 return (res + (res >> 16)) & 0x000000FF;
873}
874
875static int kvp_process_ip_address(void *addrp,
876 int family, char *buffer,
877 int length, int *offset)
878{
879 struct sockaddr_in *addr;
880 struct sockaddr_in6 *addr6;
881 int addr_length;
882 char tmp[50];
883 const char *str;
884
885 if (family == AF_INET) {
886 addr = (struct sockaddr_in *)addrp;
887 str = inet_ntop(family, &addr->sin_addr, tmp, 50);
888 addr_length = INET_ADDRSTRLEN;
889 } else {
890 addr6 = (struct sockaddr_in6 *)addrp;
891 str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50);
892 addr_length = INET6_ADDRSTRLEN;
893 }
894
895 if ((length - *offset) < addr_length + 2)
896 return HV_E_FAIL;
897 if (str == NULL) {
898 strcpy(buffer, "inet_ntop failed\n");
899 return HV_E_FAIL;
900 }
901 if (*offset == 0)
902 strcpy(buffer, tmp);
903 else {
904 strcat(buffer, ";");
905 strcat(buffer, tmp);
906 }
907
908 *offset += strlen(str) + 1;
909
910 return 0;
911}
912
913static int
914kvp_get_ip_info(int family, char *if_name, int op,
915 void *out_buffer, unsigned int length)
916{
917 struct ifaddrs *ifap;
918 struct ifaddrs *curp;
919 int offset = 0;
920 int sn_offset = 0;
921 int error = 0;
922 char *buffer;
923 struct hv_kvp_ipaddr_value *ip_buffer;
924 char cidr_mask[5];
925 int weight;
926 int i;
927 unsigned int *w;
928 char *sn_str;
929 struct sockaddr_in6 *addr6;
930
931 if (op == KVP_OP_ENUMERATE) {
932 buffer = out_buffer;
933 } else {
934 ip_buffer = out_buffer;
935 buffer = (char *)ip_buffer->ip_addr;
936 ip_buffer->addr_family = 0;
937 }
938
939
940
941
942
943 if (getifaddrs(&ifap)) {
944 strcpy(buffer, "getifaddrs failed\n");
945 return HV_E_FAIL;
946 }
947
948 curp = ifap;
949 while (curp != NULL) {
950 if (curp->ifa_addr == NULL) {
951 curp = curp->ifa_next;
952 continue;
953 }
954
955 if ((if_name != NULL) &&
956 (strncmp(curp->ifa_name, if_name, strlen(if_name)))) {
957
958
959
960
961 curp = curp->ifa_next;
962 continue;
963 }
964
965
966
967
968
969
970
971 if ((((family != 0) &&
972 (curp->ifa_addr->sa_family != family))) ||
973 (curp->ifa_flags & IFF_LOOPBACK)) {
974 curp = curp->ifa_next;
975 continue;
976 }
977 if ((curp->ifa_addr->sa_family != AF_INET) &&
978 (curp->ifa_addr->sa_family != AF_INET6)) {
979 curp = curp->ifa_next;
980 continue;
981 }
982
983 if (op == KVP_OP_GET_IP_INFO) {
984
985
986
987
988 if (curp->ifa_addr->sa_family == AF_INET) {
989 ip_buffer->addr_family |= ADDR_FAMILY_IPV4;
990
991
992
993 error = kvp_process_ip_address(
994 curp->ifa_netmask,
995 AF_INET,
996 (char *)
997 ip_buffer->sub_net,
998 length,
999 &sn_offset);
1000 if (error)
1001 goto gather_ipaddr;
1002 } else {
1003 ip_buffer->addr_family |= ADDR_FAMILY_IPV6;
1004
1005
1006
1007
1008 weight = 0;
1009 sn_str = (char *)ip_buffer->sub_net;
1010 addr6 = (struct sockaddr_in6 *)
1011 curp->ifa_netmask;
1012 w = addr6->sin6_addr.s6_addr32;
1013
1014 for (i = 0; i < 4; i++)
1015 weight += hweight32(&w[i]);
1016
1017 sprintf(cidr_mask, "/%d", weight);
1018 if (length < sn_offset + strlen(cidr_mask) + 1)
1019 goto gather_ipaddr;
1020
1021 if (sn_offset == 0)
1022 strcpy(sn_str, cidr_mask);
1023 else {
1024 strcat((char *)ip_buffer->sub_net, ";");
1025 strcat(sn_str, cidr_mask);
1026 }
1027 sn_offset += strlen(sn_str) + 1;
1028 }
1029
1030
1031
1032
1033
1034 kvp_get_ipconfig_info(if_name, ip_buffer);
1035 }
1036
1037gather_ipaddr:
1038 error = kvp_process_ip_address(curp->ifa_addr,
1039 curp->ifa_addr->sa_family,
1040 buffer,
1041 length, &offset);
1042 if (error)
1043 goto getaddr_done;
1044
1045 curp = curp->ifa_next;
1046 }
1047
1048getaddr_done:
1049 freeifaddrs(ifap);
1050 return error;
1051}
1052
1053
1054static int expand_ipv6(char *addr, int type)
1055{
1056 int ret;
1057 struct in6_addr v6_addr;
1058
1059 ret = inet_pton(AF_INET6, addr, &v6_addr);
1060
1061 if (ret != 1) {
1062 if (type == NETMASK)
1063 return 1;
1064 return 0;
1065 }
1066
1067 sprintf(addr, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
1068 "%02x%02x:%02x%02x:%02x%02x",
1069 (int)v6_addr.s6_addr[0], (int)v6_addr.s6_addr[1],
1070 (int)v6_addr.s6_addr[2], (int)v6_addr.s6_addr[3],
1071 (int)v6_addr.s6_addr[4], (int)v6_addr.s6_addr[5],
1072 (int)v6_addr.s6_addr[6], (int)v6_addr.s6_addr[7],
1073 (int)v6_addr.s6_addr[8], (int)v6_addr.s6_addr[9],
1074 (int)v6_addr.s6_addr[10], (int)v6_addr.s6_addr[11],
1075 (int)v6_addr.s6_addr[12], (int)v6_addr.s6_addr[13],
1076 (int)v6_addr.s6_addr[14], (int)v6_addr.s6_addr[15]);
1077
1078 return 1;
1079
1080}
1081
1082static int is_ipv4(char *addr)
1083{
1084 int ret;
1085 struct in_addr ipv4_addr;
1086
1087 ret = inet_pton(AF_INET, addr, &ipv4_addr);
1088
1089 if (ret == 1)
1090 return 1;
1091 return 0;
1092}
1093
1094static int parse_ip_val_buffer(char *in_buf, int *offset,
1095 char *out_buf, int out_len)
1096{
1097 char *x;
1098 char *start;
1099
1100
1101
1102
1103
1104
1105 start = in_buf + *offset;
1106
1107 x = strchr(start, ';');
1108 if (x)
1109 *x = 0;
1110 else
1111 x = start + strlen(start);
1112
1113 if (strlen(start) != 0) {
1114 int i = 0;
1115
1116
1117
1118 while (start[i] == ' ')
1119 i++;
1120
1121 if ((x - start) <= out_len) {
1122 strcpy(out_buf, (start + i));
1123 *offset += (x - start) + 1;
1124 return 1;
1125 }
1126 }
1127 return 0;
1128}
1129
1130static int kvp_write_file(FILE *f, char *s1, char *s2, char *s3)
1131{
1132 int ret;
1133
1134 ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3);
1135
1136 if (ret < 0)
1137 return HV_E_FAIL;
1138
1139 return 0;
1140}
1141
1142
1143static int process_ip_string(FILE *f, char *ip_string, int type)
1144{
1145 int error = 0;
1146 char addr[INET6_ADDRSTRLEN];
1147 int i = 0;
1148 int j = 0;
1149 char str[256];
1150 char sub_str[10];
1151 int offset = 0;
1152
1153 memset(addr, 0, sizeof(addr));
1154
1155 while (parse_ip_val_buffer(ip_string, &offset, addr,
1156 (MAX_IP_ADDR_SIZE * 2))) {
1157
1158 sub_str[0] = 0;
1159 if (is_ipv4(addr)) {
1160 switch (type) {
1161 case IPADDR:
1162 snprintf(str, sizeof(str), "%s", "IPADDR");
1163 break;
1164 case NETMASK:
1165 snprintf(str, sizeof(str), "%s", "NETMASK");
1166 break;
1167 case GATEWAY:
1168 snprintf(str, sizeof(str), "%s", "GATEWAY");
1169 break;
1170 case DNS:
1171 snprintf(str, sizeof(str), "%s", "DNS");
1172 break;
1173 }
1174
1175 if (type == DNS) {
1176 snprintf(sub_str, sizeof(sub_str), "%d", ++i);
1177 } else if (type == GATEWAY && i == 0) {
1178 ++i;
1179 } else {
1180 snprintf(sub_str, sizeof(sub_str), "%d", i++);
1181 }
1182
1183
1184 } else if (expand_ipv6(addr, type)) {
1185 switch (type) {
1186 case IPADDR:
1187 snprintf(str, sizeof(str), "%s", "IPV6ADDR");
1188 break;
1189 case NETMASK:
1190 snprintf(str, sizeof(str), "%s", "IPV6NETMASK");
1191 break;
1192 case GATEWAY:
1193 snprintf(str, sizeof(str), "%s",
1194 "IPV6_DEFAULTGW");
1195 break;
1196 case DNS:
1197 snprintf(str, sizeof(str), "%s", "DNS");
1198 break;
1199 }
1200
1201 if (type == DNS) {
1202 snprintf(sub_str, sizeof(sub_str), "%d", ++i);
1203 } else if (j == 0) {
1204 ++j;
1205 } else {
1206 snprintf(sub_str, sizeof(sub_str), "_%d", j++);
1207 }
1208 } else {
1209 return HV_INVALIDARG;
1210 }
1211
1212 error = kvp_write_file(f, str, sub_str, addr);
1213 if (error)
1214 return error;
1215 memset(addr, 0, sizeof(addr));
1216 }
1217
1218 return 0;
1219}
1220
1221static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
1222{
1223 int error = 0;
1224 char if_file[128];
1225 FILE *file;
1226 char cmd[512];
1227 char *mac_addr;
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
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276 snprintf(if_file, sizeof(if_file), "%s%s%s", KVP_CONFIG_LOC,
1277 "/ifcfg-", if_name);
1278
1279 file = fopen(if_file, "w");
1280
1281 if (file == NULL) {
1282 syslog(LOG_ERR, "Failed to open config file; error: %d %s",
1283 errno, strerror(errno));
1284 return HV_E_FAIL;
1285 }
1286
1287
1288
1289
1290
1291 mac_addr = kvp_if_name_to_mac(if_name);
1292 if (mac_addr == NULL) {
1293 error = HV_E_FAIL;
1294 goto setval_error;
1295 }
1296
1297 error = kvp_write_file(file, "HWADDR", "", mac_addr);
1298 free(mac_addr);
1299 if (error)
1300 goto setval_error;
1301
1302 error = kvp_write_file(file, "DEVICE", "", if_name);
1303 if (error)
1304 goto setval_error;
1305
1306
1307
1308
1309
1310
1311
1312 if (new_val->dhcp_enabled) {
1313 error = kvp_write_file(file, "BOOTPROTO", "", "dhcp");
1314 if (error)
1315 goto setval_error;
1316
1317 } else {
1318 error = kvp_write_file(file, "BOOTPROTO", "", "none");
1319 if (error)
1320 goto setval_error;
1321 }
1322
1323
1324
1325
1326
1327
1328 error = process_ip_string(file, (char *)new_val->ip_addr, IPADDR);
1329 if (error)
1330 goto setval_error;
1331
1332 error = process_ip_string(file, (char *)new_val->sub_net, NETMASK);
1333 if (error)
1334 goto setval_error;
1335
1336 error = process_ip_string(file, (char *)new_val->gate_way, GATEWAY);
1337 if (error)
1338 goto setval_error;
1339
1340 error = process_ip_string(file, (char *)new_val->dns_addr, DNS);
1341 if (error)
1342 goto setval_error;
1343
1344 fclose(file);
1345
1346
1347
1348
1349
1350
1351 snprintf(cmd, sizeof(cmd), "%s %s", "hv_set_ifconfig", if_file);
1352 if (system(cmd)) {
1353 syslog(LOG_ERR, "Failed to execute cmd '%s'; error: %d %s",
1354 cmd, errno, strerror(errno));
1355 return HV_E_FAIL;
1356 }
1357 return 0;
1358
1359setval_error:
1360 syslog(LOG_ERR, "Failed to write config file");
1361 fclose(file);
1362 return error;
1363}
1364
1365
1366static void
1367kvp_get_domain_name(char *buffer, int length)
1368{
1369 struct addrinfo hints, *info ;
1370 int error = 0;
1371
1372 gethostname(buffer, length);
1373 memset(&hints, 0, sizeof(hints));
1374 hints.ai_family = AF_INET;
1375 hints.ai_socktype = SOCK_STREAM;
1376 hints.ai_flags = AI_CANONNAME;
1377
1378 error = getaddrinfo(buffer, NULL, &hints, &info);
1379 if (error != 0) {
1380 snprintf(buffer, length, "getaddrinfo failed: 0x%x %s",
1381 error, gai_strerror(error));
1382 return;
1383 }
1384 snprintf(buffer, length, "%s", info->ai_canonname);
1385 freeaddrinfo(info);
1386}
1387
1388void print_usage(char *argv[])
1389{
1390 fprintf(stderr, "Usage: %s [options]\n"
1391 "Options are:\n"
1392 " -n, --no-daemon stay in foreground, don't daemonize\n"
1393 " -h, --help print this help\n", argv[0]);
1394}
1395
1396int main(int argc, char *argv[])
1397{
1398 int kvp_fd, len;
1399 int error;
1400 struct pollfd pfd;
1401 char *p;
1402 struct hv_kvp_msg hv_msg[1];
1403 char *key_value;
1404 char *key_name;
1405 int op;
1406 int pool;
1407 char *if_name;
1408 struct hv_kvp_ipaddr_value *kvp_ip_val;
1409 int daemonize = 1, long_index = 0, opt;
1410
1411 static struct option long_options[] = {
1412 {"help", no_argument, 0, 'h' },
1413 {"no-daemon", no_argument, 0, 'n' },
1414 {0, 0, 0, 0 }
1415 };
1416
1417 while ((opt = getopt_long(argc, argv, "hn", long_options,
1418 &long_index)) != -1) {
1419 switch (opt) {
1420 case 'n':
1421 daemonize = 0;
1422 break;
1423 case 'h':
1424 default:
1425 print_usage(argv);
1426 exit(EXIT_FAILURE);
1427 }
1428 }
1429
1430 if (daemonize && daemon(1, 0))
1431 return 1;
1432
1433 openlog("KVP", 0, LOG_USER);
1434 syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
1435
1436 kvp_fd = open("/dev/vmbus/hv_kvp", O_RDWR);
1437
1438 if (kvp_fd < 0) {
1439 syslog(LOG_ERR, "open /dev/vmbus/hv_kvp failed; error: %d %s",
1440 errno, strerror(errno));
1441 exit(EXIT_FAILURE);
1442 }
1443
1444
1445
1446
1447 kvp_get_os_info();
1448
1449
1450
1451
1452 kvp_get_domain_name(full_domain_name, sizeof(full_domain_name));
1453
1454 if (kvp_file_init()) {
1455 syslog(LOG_ERR, "Failed to initialize the pools");
1456 exit(EXIT_FAILURE);
1457 }
1458
1459
1460
1461
1462 hv_msg->kvp_hdr.operation = KVP_OP_REGISTER1;
1463 len = write(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg));
1464 if (len != sizeof(struct hv_kvp_msg)) {
1465 syslog(LOG_ERR, "registration to kernel failed; error: %d %s",
1466 errno, strerror(errno));
1467 close(kvp_fd);
1468 exit(EXIT_FAILURE);
1469 }
1470
1471 pfd.fd = kvp_fd;
1472
1473 while (1) {
1474 pfd.events = POLLIN;
1475 pfd.revents = 0;
1476
1477 if (poll(&pfd, 1, -1) < 0) {
1478 syslog(LOG_ERR, "poll failed; error: %d %s", errno, strerror(errno));
1479 if (errno == EINVAL) {
1480 close(kvp_fd);
1481 exit(EXIT_FAILURE);
1482 }
1483 else
1484 continue;
1485 }
1486
1487 len = read(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg));
1488
1489 if (len != sizeof(struct hv_kvp_msg)) {
1490 syslog(LOG_ERR, "read failed; error:%d %s",
1491 errno, strerror(errno));
1492
1493 close(kvp_fd);
1494 return EXIT_FAILURE;
1495 }
1496
1497
1498
1499
1500
1501
1502 op = hv_msg->kvp_hdr.operation;
1503 pool = hv_msg->kvp_hdr.pool;
1504 hv_msg->error = HV_S_OK;
1505
1506 if ((in_hand_shake) && (op == KVP_OP_REGISTER1)) {
1507
1508
1509
1510
1511 in_hand_shake = 0;
1512 p = (char *)hv_msg->body.kvp_register.version;
1513 lic_version = malloc(strlen(p) + 1);
1514 if (lic_version) {
1515 strcpy(lic_version, p);
1516 syslog(LOG_INFO, "KVP LIC Version: %s",
1517 lic_version);
1518 } else {
1519 syslog(LOG_ERR, "malloc failed");
1520 }
1521 continue;
1522 }
1523
1524 switch (op) {
1525 case KVP_OP_GET_IP_INFO:
1526 kvp_ip_val = &hv_msg->body.kvp_ip_val;
1527 if_name =
1528 kvp_mac_to_if_name((char *)kvp_ip_val->adapter_id);
1529
1530 if (if_name == NULL) {
1531
1532
1533
1534
1535 hv_msg->error = HV_E_FAIL;
1536 break;
1537 }
1538 error = kvp_get_ip_info(
1539 0, if_name, KVP_OP_GET_IP_INFO,
1540 kvp_ip_val,
1541 (MAX_IP_ADDR_SIZE * 2));
1542
1543 if (error)
1544 hv_msg->error = error;
1545
1546 free(if_name);
1547 break;
1548
1549 case KVP_OP_SET_IP_INFO:
1550 kvp_ip_val = &hv_msg->body.kvp_ip_val;
1551 if_name = kvp_get_if_name(
1552 (char *)kvp_ip_val->adapter_id);
1553 if (if_name == NULL) {
1554
1555
1556
1557
1558 hv_msg->error = HV_GUID_NOTFOUND;
1559 break;
1560 }
1561 error = kvp_set_ip_info(if_name, kvp_ip_val);
1562 if (error)
1563 hv_msg->error = error;
1564
1565 free(if_name);
1566 break;
1567
1568 case KVP_OP_SET:
1569 if (kvp_key_add_or_modify(pool,
1570 hv_msg->body.kvp_set.data.key,
1571 hv_msg->body.kvp_set.data.key_size,
1572 hv_msg->body.kvp_set.data.value,
1573 hv_msg->body.kvp_set.data.value_size))
1574 hv_msg->error = HV_S_CONT;
1575 break;
1576
1577 case KVP_OP_GET:
1578 if (kvp_get_value(pool,
1579 hv_msg->body.kvp_set.data.key,
1580 hv_msg->body.kvp_set.data.key_size,
1581 hv_msg->body.kvp_set.data.value,
1582 hv_msg->body.kvp_set.data.value_size))
1583 hv_msg->error = HV_S_CONT;
1584 break;
1585
1586 case KVP_OP_DELETE:
1587 if (kvp_key_delete(pool,
1588 hv_msg->body.kvp_delete.key,
1589 hv_msg->body.kvp_delete.key_size))
1590 hv_msg->error = HV_S_CONT;
1591 break;
1592
1593 default:
1594 break;
1595 }
1596
1597 if (op != KVP_OP_ENUMERATE)
1598 goto kvp_done;
1599
1600
1601
1602
1603
1604
1605 if (pool != KVP_POOL_AUTO) {
1606 if (kvp_pool_enumerate(pool,
1607 hv_msg->body.kvp_enum_data.index,
1608 hv_msg->body.kvp_enum_data.data.key,
1609 HV_KVP_EXCHANGE_MAX_KEY_SIZE,
1610 hv_msg->body.kvp_enum_data.data.value,
1611 HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
1612 hv_msg->error = HV_S_CONT;
1613 goto kvp_done;
1614 }
1615
1616 key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
1617 key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
1618
1619 switch (hv_msg->body.kvp_enum_data.index) {
1620 case FullyQualifiedDomainName:
1621 strcpy(key_value, full_domain_name);
1622 strcpy(key_name, "FullyQualifiedDomainName");
1623 break;
1624 case IntegrationServicesVersion:
1625 strcpy(key_name, "IntegrationServicesVersion");
1626 strcpy(key_value, lic_version);
1627 break;
1628 case NetworkAddressIPv4:
1629 kvp_get_ip_info(AF_INET, NULL, KVP_OP_ENUMERATE,
1630 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1631 strcpy(key_name, "NetworkAddressIPv4");
1632 break;
1633 case NetworkAddressIPv6:
1634 kvp_get_ip_info(AF_INET6, NULL, KVP_OP_ENUMERATE,
1635 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1636 strcpy(key_name, "NetworkAddressIPv6");
1637 break;
1638 case OSBuildNumber:
1639 strcpy(key_value, os_build);
1640 strcpy(key_name, "OSBuildNumber");
1641 break;
1642 case OSName:
1643 strcpy(key_value, os_name);
1644 strcpy(key_name, "OSName");
1645 break;
1646 case OSMajorVersion:
1647 strcpy(key_value, os_major);
1648 strcpy(key_name, "OSMajorVersion");
1649 break;
1650 case OSMinorVersion:
1651 strcpy(key_value, os_minor);
1652 strcpy(key_name, "OSMinorVersion");
1653 break;
1654 case OSVersion:
1655 strcpy(key_value, os_version);
1656 strcpy(key_name, "OSVersion");
1657 break;
1658 case ProcessorArchitecture:
1659 strcpy(key_value, processor_arch);
1660 strcpy(key_name, "ProcessorArchitecture");
1661 break;
1662 default:
1663 hv_msg->error = HV_S_CONT;
1664 break;
1665 }
1666
1667
1668kvp_done:
1669 len = write(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg));
1670 if (len != sizeof(struct hv_kvp_msg)) {
1671 syslog(LOG_ERR, "write failed; error: %d %s", errno,
1672 strerror(errno));
1673 exit(EXIT_FAILURE);
1674 }
1675 }
1676
1677 close(kvp_fd);
1678 exit(0);
1679}
1680