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