0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025 #include <sys/poll.h>
0026 #include <sys/utsname.h>
0027 #include <stdio.h>
0028 #include <stdlib.h>
0029 #include <unistd.h>
0030 #include <string.h>
0031 #include <ctype.h>
0032 #include <errno.h>
0033 #include <arpa/inet.h>
0034 #include <linux/hyperv.h>
0035 #include <ifaddrs.h>
0036 #include <netdb.h>
0037 #include <syslog.h>
0038 #include <sys/stat.h>
0039 #include <fcntl.h>
0040 #include <dirent.h>
0041 #include <net/if.h>
0042 #include <limits.h>
0043 #include <getopt.h>
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058 enum key_index {
0059 FullyQualifiedDomainName = 0,
0060 IntegrationServicesVersion,
0061 NetworkAddressIPv4,
0062 NetworkAddressIPv6,
0063 OSBuildNumber,
0064 OSName,
0065 OSMajorVersion,
0066 OSMinorVersion,
0067 OSVersion,
0068 ProcessorArchitecture
0069 };
0070
0071
0072 enum {
0073 IPADDR = 0,
0074 NETMASK,
0075 GATEWAY,
0076 DNS
0077 };
0078
0079 static int in_hand_shake;
0080
0081 static char *os_name = "";
0082 static char *os_major = "";
0083 static char *os_minor = "";
0084 static char *processor_arch;
0085 static char *os_build;
0086 static char *os_version;
0087 static char *lic_version = "Unknown version";
0088 static char full_domain_name[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
0089 static struct utsname uts_buf;
0090
0091
0092
0093
0094
0095 #define KVP_CONFIG_LOC "/var/lib/hyperv"
0096
0097 #ifndef KVP_SCRIPTS_PATH
0098 #define KVP_SCRIPTS_PATH "/usr/libexec/hypervkvpd/"
0099 #endif
0100
0101 #define KVP_NET_DIR "/sys/class/net/"
0102
0103 #define MAX_FILE_NAME 100
0104 #define ENTRIES_PER_BLOCK 50
0105
0106 struct kvp_record {
0107 char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
0108 char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
0109 };
0110
0111 struct kvp_file_state {
0112 int fd;
0113 int num_blocks;
0114 struct kvp_record *records;
0115 int num_records;
0116 char fname[MAX_FILE_NAME];
0117 };
0118
0119 static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT];
0120
0121 static void kvp_acquire_lock(int pool)
0122 {
0123 struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0};
0124 fl.l_pid = getpid();
0125
0126 if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
0127 syslog(LOG_ERR, "Failed to acquire the lock pool: %d; error: %d %s", pool,
0128 errno, strerror(errno));
0129 exit(EXIT_FAILURE);
0130 }
0131 }
0132
0133 static void kvp_release_lock(int pool)
0134 {
0135 struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
0136 fl.l_pid = getpid();
0137
0138 if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
0139 syslog(LOG_ERR, "Failed to release the lock pool: %d; error: %d %s", pool,
0140 errno, strerror(errno));
0141 exit(EXIT_FAILURE);
0142 }
0143 }
0144
0145 static void kvp_update_file(int pool)
0146 {
0147 FILE *filep;
0148
0149
0150
0151
0152
0153 kvp_acquire_lock(pool);
0154
0155 filep = fopen(kvp_file_info[pool].fname, "we");
0156 if (!filep) {
0157 syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool,
0158 errno, strerror(errno));
0159 kvp_release_lock(pool);
0160 exit(EXIT_FAILURE);
0161 }
0162
0163 fwrite(kvp_file_info[pool].records, sizeof(struct kvp_record),
0164 kvp_file_info[pool].num_records, filep);
0165
0166 if (ferror(filep) || fclose(filep)) {
0167 kvp_release_lock(pool);
0168 syslog(LOG_ERR, "Failed to write file, pool: %d", pool);
0169 exit(EXIT_FAILURE);
0170 }
0171
0172 kvp_release_lock(pool);
0173 }
0174
0175 static void kvp_update_mem_state(int pool)
0176 {
0177 FILE *filep;
0178 size_t records_read = 0;
0179 struct kvp_record *record = kvp_file_info[pool].records;
0180 struct kvp_record *readp;
0181 int num_blocks = kvp_file_info[pool].num_blocks;
0182 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
0183
0184 kvp_acquire_lock(pool);
0185
0186 filep = fopen(kvp_file_info[pool].fname, "re");
0187 if (!filep) {
0188 syslog(LOG_ERR, "Failed to open file, pool: %d; error: %d %s", pool,
0189 errno, strerror(errno));
0190 kvp_release_lock(pool);
0191 exit(EXIT_FAILURE);
0192 }
0193 for (;;) {
0194 readp = &record[records_read];
0195 records_read += fread(readp, sizeof(struct kvp_record),
0196 ENTRIES_PER_BLOCK * num_blocks - records_read,
0197 filep);
0198
0199 if (ferror(filep)) {
0200 syslog(LOG_ERR,
0201 "Failed to read file, pool: %d; error: %d %s",
0202 pool, errno, strerror(errno));
0203 kvp_release_lock(pool);
0204 exit(EXIT_FAILURE);
0205 }
0206
0207 if (!feof(filep)) {
0208
0209
0210
0211 num_blocks++;
0212 record = realloc(record, alloc_unit * num_blocks);
0213
0214 if (record == NULL) {
0215 syslog(LOG_ERR, "malloc failed");
0216 kvp_release_lock(pool);
0217 exit(EXIT_FAILURE);
0218 }
0219 continue;
0220 }
0221 break;
0222 }
0223
0224 kvp_file_info[pool].num_blocks = num_blocks;
0225 kvp_file_info[pool].records = record;
0226 kvp_file_info[pool].num_records = records_read;
0227
0228 fclose(filep);
0229 kvp_release_lock(pool);
0230 }
0231
0232 static int kvp_file_init(void)
0233 {
0234 int fd;
0235 char *fname;
0236 int i;
0237 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
0238
0239 if (access(KVP_CONFIG_LOC, F_OK)) {
0240 if (mkdir(KVP_CONFIG_LOC, 0755 )) {
0241 syslog(LOG_ERR, "Failed to create '%s'; error: %d %s", KVP_CONFIG_LOC,
0242 errno, strerror(errno));
0243 exit(EXIT_FAILURE);
0244 }
0245 }
0246
0247 for (i = 0; i < KVP_POOL_COUNT; i++) {
0248 fname = kvp_file_info[i].fname;
0249 sprintf(fname, "%s/.kvp_pool_%d", KVP_CONFIG_LOC, i);
0250 fd = open(fname, O_RDWR | O_CREAT | O_CLOEXEC, 0644 );
0251
0252 if (fd == -1)
0253 return 1;
0254
0255 kvp_file_info[i].fd = fd;
0256 kvp_file_info[i].num_blocks = 1;
0257 kvp_file_info[i].records = malloc(alloc_unit);
0258 if (kvp_file_info[i].records == NULL)
0259 return 1;
0260 kvp_file_info[i].num_records = 0;
0261 kvp_update_mem_state(i);
0262 }
0263
0264 return 0;
0265 }
0266
0267 static int kvp_key_delete(int pool, const __u8 *key, int key_size)
0268 {
0269 int i;
0270 int j, k;
0271 int num_records;
0272 struct kvp_record *record;
0273
0274
0275
0276
0277 kvp_update_mem_state(pool);
0278
0279 num_records = kvp_file_info[pool].num_records;
0280 record = kvp_file_info[pool].records;
0281
0282 for (i = 0; i < num_records; i++) {
0283 if (memcmp(key, record[i].key, key_size))
0284 continue;
0285
0286
0287
0288
0289 if (i == (num_records - 1)) {
0290 kvp_file_info[pool].num_records--;
0291 kvp_update_file(pool);
0292 return 0;
0293 }
0294
0295 j = i;
0296 k = j + 1;
0297 for (; k < num_records; k++) {
0298 strcpy(record[j].key, record[k].key);
0299 strcpy(record[j].value, record[k].value);
0300 j++;
0301 }
0302
0303 kvp_file_info[pool].num_records--;
0304 kvp_update_file(pool);
0305 return 0;
0306 }
0307 return 1;
0308 }
0309
0310 static int kvp_key_add_or_modify(int pool, const __u8 *key, int key_size,
0311 const __u8 *value, int value_size)
0312 {
0313 int i;
0314 int num_records;
0315 struct kvp_record *record;
0316 int num_blocks;
0317
0318 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
0319 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
0320 return 1;
0321
0322
0323
0324
0325 kvp_update_mem_state(pool);
0326
0327 num_records = kvp_file_info[pool].num_records;
0328 record = kvp_file_info[pool].records;
0329 num_blocks = kvp_file_info[pool].num_blocks;
0330
0331 for (i = 0; i < num_records; i++) {
0332 if (memcmp(key, record[i].key, key_size))
0333 continue;
0334
0335
0336
0337
0338 memcpy(record[i].value, value, value_size);
0339 kvp_update_file(pool);
0340 return 0;
0341 }
0342
0343
0344
0345
0346 if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
0347
0348 record = realloc(record, sizeof(struct kvp_record) *
0349 ENTRIES_PER_BLOCK * (num_blocks + 1));
0350
0351 if (record == NULL)
0352 return 1;
0353 kvp_file_info[pool].num_blocks++;
0354
0355 }
0356 memcpy(record[i].value, value, value_size);
0357 memcpy(record[i].key, key, key_size);
0358 kvp_file_info[pool].records = record;
0359 kvp_file_info[pool].num_records++;
0360 kvp_update_file(pool);
0361 return 0;
0362 }
0363
0364 static int kvp_get_value(int pool, const __u8 *key, int key_size, __u8 *value,
0365 int value_size)
0366 {
0367 int i;
0368 int num_records;
0369 struct kvp_record *record;
0370
0371 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
0372 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
0373 return 1;
0374
0375
0376
0377
0378 kvp_update_mem_state(pool);
0379
0380 num_records = kvp_file_info[pool].num_records;
0381 record = kvp_file_info[pool].records;
0382
0383 for (i = 0; i < num_records; i++) {
0384 if (memcmp(key, record[i].key, key_size))
0385 continue;
0386
0387
0388
0389 memcpy(value, record[i].value, value_size);
0390 return 0;
0391 }
0392
0393 return 1;
0394 }
0395
0396 static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
0397 __u8 *value, int value_size)
0398 {
0399 struct kvp_record *record;
0400
0401
0402
0403
0404 kvp_update_mem_state(pool);
0405 record = kvp_file_info[pool].records;
0406
0407 if (index >= kvp_file_info[pool].num_records) {
0408 return 1;
0409 }
0410
0411 memcpy(key, record[index].key, key_size);
0412 memcpy(value, record[index].value, value_size);
0413 return 0;
0414 }
0415
0416
0417 void kvp_get_os_info(void)
0418 {
0419 FILE *file;
0420 char *p, buf[512];
0421
0422 uname(&uts_buf);
0423 os_version = uts_buf.release;
0424 os_build = strdup(uts_buf.release);
0425
0426 os_name = uts_buf.sysname;
0427 processor_arch = uts_buf.machine;
0428
0429
0430
0431
0432
0433
0434 p = strchr(os_version, '-');
0435 if (p)
0436 *p = '\0';
0437
0438
0439
0440
0441
0442 file = fopen("/etc/os-release", "r");
0443 if (file != NULL) {
0444 while (fgets(buf, sizeof(buf), file)) {
0445 char *value, *q;
0446
0447
0448 if (buf[0] == '#')
0449 continue;
0450
0451
0452 p = strchr(buf, '=');
0453 if (!p)
0454 continue;
0455 *p++ = 0;
0456
0457
0458 value = p;
0459 q = p;
0460 while (*p) {
0461 if (*p == '\\') {
0462 ++p;
0463 if (!*p)
0464 break;
0465 *q++ = *p++;
0466 } else if (*p == '\'' || *p == '"' ||
0467 *p == '\n') {
0468 ++p;
0469 } else {
0470 *q++ = *p++;
0471 }
0472 }
0473 *q = 0;
0474
0475 if (!strcmp(buf, "NAME")) {
0476 p = strdup(value);
0477 if (!p)
0478 break;
0479 os_name = p;
0480 } else if (!strcmp(buf, "VERSION_ID")) {
0481 p = strdup(value);
0482 if (!p)
0483 break;
0484 os_major = p;
0485 }
0486 }
0487 fclose(file);
0488 return;
0489 }
0490
0491
0492 file = fopen("/etc/SuSE-release", "r");
0493 if (file != NULL)
0494 goto kvp_osinfo_found;
0495 file = fopen("/etc/redhat-release", "r");
0496 if (file != NULL)
0497 goto kvp_osinfo_found;
0498
0499
0500
0501
0502 return;
0503
0504 kvp_osinfo_found:
0505
0506 p = fgets(buf, sizeof(buf), file);
0507 if (p) {
0508 p = strchr(buf, '\n');
0509 if (p)
0510 *p = '\0';
0511 p = strdup(buf);
0512 if (!p)
0513 goto done;
0514 os_name = p;
0515
0516
0517 p = fgets(buf, sizeof(buf), file);
0518 if (p) {
0519 p = strchr(buf, '\n');
0520 if (p)
0521 *p = '\0';
0522 p = strdup(buf);
0523 if (!p)
0524 goto done;
0525 os_major = p;
0526
0527
0528 p = fgets(buf, sizeof(buf), file);
0529 if (p) {
0530 p = strchr(buf, '\n');
0531 if (p)
0532 *p = '\0';
0533 p = strdup(buf);
0534 if (p)
0535 os_minor = p;
0536 }
0537 }
0538 }
0539
0540 done:
0541 fclose(file);
0542 return;
0543 }
0544
0545
0546
0547
0548
0549
0550
0551
0552
0553
0554
0555 static char *kvp_get_if_name(char *guid)
0556 {
0557 DIR *dir;
0558 struct dirent *entry;
0559 FILE *file;
0560 char *p, *x;
0561 char *if_name = NULL;
0562 char buf[256];
0563 char dev_id[PATH_MAX];
0564
0565 dir = opendir(KVP_NET_DIR);
0566 if (dir == NULL)
0567 return NULL;
0568
0569 while ((entry = readdir(dir)) != NULL) {
0570
0571
0572
0573 snprintf(dev_id, sizeof(dev_id), "%s%s/device/device_id",
0574 KVP_NET_DIR, entry->d_name);
0575
0576 file = fopen(dev_id, "r");
0577 if (file == NULL)
0578 continue;
0579
0580 p = fgets(buf, sizeof(buf), file);
0581 if (p) {
0582 x = strchr(p, '\n');
0583 if (x)
0584 *x = '\0';
0585
0586 if (!strcmp(p, guid)) {
0587
0588
0589
0590
0591 if_name = strdup(entry->d_name);
0592 fclose(file);
0593 break;
0594 }
0595 }
0596 fclose(file);
0597 }
0598
0599 closedir(dir);
0600 return if_name;
0601 }
0602
0603
0604
0605
0606
0607 static char *kvp_if_name_to_mac(char *if_name)
0608 {
0609 FILE *file;
0610 char *p, *x;
0611 char buf[256];
0612 char addr_file[PATH_MAX];
0613 unsigned int i;
0614 char *mac_addr = NULL;
0615
0616 snprintf(addr_file, sizeof(addr_file), "%s%s%s", KVP_NET_DIR,
0617 if_name, "/address");
0618
0619 file = fopen(addr_file, "r");
0620 if (file == NULL)
0621 return NULL;
0622
0623 p = fgets(buf, sizeof(buf), file);
0624 if (p) {
0625 x = strchr(p, '\n');
0626 if (x)
0627 *x = '\0';
0628 for (i = 0; i < strlen(p); i++)
0629 p[i] = toupper(p[i]);
0630 mac_addr = strdup(p);
0631 }
0632
0633 fclose(file);
0634 return mac_addr;
0635 }
0636
0637 static void kvp_process_ipconfig_file(char *cmd,
0638 char *config_buf, unsigned int len,
0639 int element_size, int offset)
0640 {
0641 char buf[256];
0642 char *p;
0643 char *x;
0644 FILE *file;
0645
0646
0647
0648
0649 file = popen(cmd, "r");
0650 if (file == NULL)
0651 return;
0652
0653 if (offset == 0)
0654 memset(config_buf, 0, len);
0655 while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
0656 if (len < strlen(config_buf) + element_size + 1)
0657 break;
0658
0659 x = strchr(p, '\n');
0660 if (x)
0661 *x = '\0';
0662
0663 strcat(config_buf, p);
0664 strcat(config_buf, ";");
0665 }
0666 pclose(file);
0667 }
0668
0669 static void kvp_get_ipconfig_info(char *if_name,
0670 struct hv_kvp_ipaddr_value *buffer)
0671 {
0672 char cmd[512];
0673 char dhcp_info[128];
0674 char *p;
0675 FILE *file;
0676
0677
0678
0679
0680 sprintf(cmd, "%s %s", "ip route show dev", if_name);
0681 strcat(cmd, " | awk '/default/ {print $3 }'");
0682
0683
0684
0685
0686 kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
0687 (MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0);
0688
0689
0690
0691
0692 sprintf(cmd, "%s %s", "ip -f inet6 route show dev", if_name);
0693 strcat(cmd, " | awk '/default/ {print $3 }'");
0694
0695
0696
0697
0698 kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
0699 (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1);
0700
0701
0702
0703
0704
0705
0706
0707
0708
0709
0710
0711
0712
0713
0714
0715
0716
0717 sprintf(cmd, KVP_SCRIPTS_PATH "%s", "hv_get_dns_info");
0718
0719
0720
0721
0722 kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr,
0723 (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0);
0724
0725
0726
0727
0728
0729
0730
0731
0732
0733
0734 sprintf(cmd, KVP_SCRIPTS_PATH "%s %s", "hv_get_dhcp_info", if_name);
0735
0736 file = popen(cmd, "r");
0737 if (file == NULL)
0738 return;
0739
0740 p = fgets(dhcp_info, sizeof(dhcp_info), file);
0741 if (p == NULL) {
0742 pclose(file);
0743 return;
0744 }
0745
0746 if (!strncmp(p, "Enabled", 7))
0747 buffer->dhcp_enabled = 1;
0748 else
0749 buffer->dhcp_enabled = 0;
0750
0751 pclose(file);
0752 }
0753
0754
0755 static unsigned int hweight32(unsigned int *w)
0756 {
0757 unsigned int res = *w - ((*w >> 1) & 0x55555555);
0758 res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
0759 res = (res + (res >> 4)) & 0x0F0F0F0F;
0760 res = res + (res >> 8);
0761 return (res + (res >> 16)) & 0x000000FF;
0762 }
0763
0764 static int kvp_process_ip_address(void *addrp,
0765 int family, char *buffer,
0766 int length, int *offset)
0767 {
0768 struct sockaddr_in *addr;
0769 struct sockaddr_in6 *addr6;
0770 int addr_length;
0771 char tmp[50];
0772 const char *str;
0773
0774 if (family == AF_INET) {
0775 addr = addrp;
0776 str = inet_ntop(family, &addr->sin_addr, tmp, 50);
0777 addr_length = INET_ADDRSTRLEN;
0778 } else {
0779 addr6 = addrp;
0780 str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50);
0781 addr_length = INET6_ADDRSTRLEN;
0782 }
0783
0784 if ((length - *offset) < addr_length + 2)
0785 return HV_E_FAIL;
0786 if (str == NULL) {
0787 strcpy(buffer, "inet_ntop failed\n");
0788 return HV_E_FAIL;
0789 }
0790 if (*offset == 0)
0791 strcpy(buffer, tmp);
0792 else {
0793 strcat(buffer, ";");
0794 strcat(buffer, tmp);
0795 }
0796
0797 *offset += strlen(str) + 1;
0798
0799 return 0;
0800 }
0801
0802 static int
0803 kvp_get_ip_info(int family, char *if_name, int op,
0804 void *out_buffer, unsigned int length)
0805 {
0806 struct ifaddrs *ifap;
0807 struct ifaddrs *curp;
0808 int offset = 0;
0809 int sn_offset = 0;
0810 int error = 0;
0811 char *buffer;
0812 struct hv_kvp_ipaddr_value *ip_buffer = NULL;
0813 char cidr_mask[5];
0814 int weight;
0815 int i;
0816 unsigned int *w;
0817 char *sn_str;
0818 struct sockaddr_in6 *addr6;
0819
0820 if (op == KVP_OP_ENUMERATE) {
0821 buffer = out_buffer;
0822 } else {
0823 ip_buffer = out_buffer;
0824 buffer = (char *)ip_buffer->ip_addr;
0825 ip_buffer->addr_family = 0;
0826 }
0827
0828
0829
0830
0831
0832 if (getifaddrs(&ifap)) {
0833 strcpy(buffer, "getifaddrs failed\n");
0834 return HV_E_FAIL;
0835 }
0836
0837 curp = ifap;
0838 while (curp != NULL) {
0839 if (curp->ifa_addr == NULL) {
0840 curp = curp->ifa_next;
0841 continue;
0842 }
0843
0844 if ((if_name != NULL) &&
0845 (strncmp(curp->ifa_name, if_name, strlen(if_name)))) {
0846
0847
0848
0849
0850 curp = curp->ifa_next;
0851 continue;
0852 }
0853
0854
0855
0856
0857
0858
0859
0860 if ((((family != 0) &&
0861 (curp->ifa_addr->sa_family != family))) ||
0862 (curp->ifa_flags & IFF_LOOPBACK)) {
0863 curp = curp->ifa_next;
0864 continue;
0865 }
0866 if ((curp->ifa_addr->sa_family != AF_INET) &&
0867 (curp->ifa_addr->sa_family != AF_INET6)) {
0868 curp = curp->ifa_next;
0869 continue;
0870 }
0871
0872 if (op == KVP_OP_GET_IP_INFO) {
0873
0874
0875
0876
0877 if (curp->ifa_addr->sa_family == AF_INET) {
0878 ip_buffer->addr_family |= ADDR_FAMILY_IPV4;
0879
0880
0881
0882 error = kvp_process_ip_address(
0883 curp->ifa_netmask,
0884 AF_INET,
0885 (char *)
0886 ip_buffer->sub_net,
0887 length,
0888 &sn_offset);
0889 if (error)
0890 goto gather_ipaddr;
0891 } else {
0892 ip_buffer->addr_family |= ADDR_FAMILY_IPV6;
0893
0894
0895
0896
0897 weight = 0;
0898 sn_str = (char *)ip_buffer->sub_net;
0899 addr6 = (struct sockaddr_in6 *)
0900 curp->ifa_netmask;
0901 w = addr6->sin6_addr.s6_addr32;
0902
0903 for (i = 0; i < 4; i++)
0904 weight += hweight32(&w[i]);
0905
0906 sprintf(cidr_mask, "/%d", weight);
0907 if (length < sn_offset + strlen(cidr_mask) + 1)
0908 goto gather_ipaddr;
0909
0910 if (sn_offset == 0)
0911 strcpy(sn_str, cidr_mask);
0912 else {
0913 strcat((char *)ip_buffer->sub_net, ";");
0914 strcat(sn_str, cidr_mask);
0915 }
0916 sn_offset += strlen(sn_str) + 1;
0917 }
0918
0919
0920
0921
0922
0923 kvp_get_ipconfig_info(if_name, ip_buffer);
0924 }
0925
0926 gather_ipaddr:
0927 error = kvp_process_ip_address(curp->ifa_addr,
0928 curp->ifa_addr->sa_family,
0929 buffer,
0930 length, &offset);
0931 if (error)
0932 goto getaddr_done;
0933
0934 curp = curp->ifa_next;
0935 }
0936
0937 getaddr_done:
0938 freeifaddrs(ifap);
0939 return error;
0940 }
0941
0942
0943
0944
0945 static int kvp_mac_to_ip(struct hv_kvp_ipaddr_value *kvp_ip_val)
0946 {
0947 char *mac = (char *)kvp_ip_val->adapter_id;
0948 DIR *dir;
0949 struct dirent *entry;
0950 FILE *file;
0951 char *p, *x;
0952 char *if_name = NULL;
0953 char buf[256];
0954 char dev_id[PATH_MAX];
0955 unsigned int i;
0956 int error = HV_E_FAIL;
0957
0958 dir = opendir(KVP_NET_DIR);
0959 if (dir == NULL)
0960 return HV_E_FAIL;
0961
0962 while ((entry = readdir(dir)) != NULL) {
0963
0964
0965
0966 snprintf(dev_id, sizeof(dev_id), "%s%s/address", KVP_NET_DIR,
0967 entry->d_name);
0968
0969 file = fopen(dev_id, "r");
0970 if (file == NULL)
0971 continue;
0972
0973 p = fgets(buf, sizeof(buf), file);
0974 fclose(file);
0975 if (!p)
0976 continue;
0977
0978 x = strchr(p, '\n');
0979 if (x)
0980 *x = '\0';
0981
0982 for (i = 0; i < strlen(p); i++)
0983 p[i] = toupper(p[i]);
0984
0985 if (strcmp(p, mac))
0986 continue;
0987
0988
0989
0990
0991
0992 if_name = entry->d_name;
0993 if (!if_name)
0994 continue;
0995
0996 error = kvp_get_ip_info(0, if_name, KVP_OP_GET_IP_INFO,
0997 kvp_ip_val, MAX_IP_ADDR_SIZE * 2);
0998
0999 if (!error && strlen((char *)kvp_ip_val->ip_addr))
1000 break;
1001 }
1002
1003 closedir(dir);
1004 return error;
1005 }
1006
1007 static int expand_ipv6(char *addr, int type)
1008 {
1009 int ret;
1010 struct in6_addr v6_addr;
1011
1012 ret = inet_pton(AF_INET6, addr, &v6_addr);
1013
1014 if (ret != 1) {
1015 if (type == NETMASK)
1016 return 1;
1017 return 0;
1018 }
1019
1020 sprintf(addr, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
1021 "%02x%02x:%02x%02x:%02x%02x",
1022 (int)v6_addr.s6_addr[0], (int)v6_addr.s6_addr[1],
1023 (int)v6_addr.s6_addr[2], (int)v6_addr.s6_addr[3],
1024 (int)v6_addr.s6_addr[4], (int)v6_addr.s6_addr[5],
1025 (int)v6_addr.s6_addr[6], (int)v6_addr.s6_addr[7],
1026 (int)v6_addr.s6_addr[8], (int)v6_addr.s6_addr[9],
1027 (int)v6_addr.s6_addr[10], (int)v6_addr.s6_addr[11],
1028 (int)v6_addr.s6_addr[12], (int)v6_addr.s6_addr[13],
1029 (int)v6_addr.s6_addr[14], (int)v6_addr.s6_addr[15]);
1030
1031 return 1;
1032
1033 }
1034
1035 static int is_ipv4(char *addr)
1036 {
1037 int ret;
1038 struct in_addr ipv4_addr;
1039
1040 ret = inet_pton(AF_INET, addr, &ipv4_addr);
1041
1042 if (ret == 1)
1043 return 1;
1044 return 0;
1045 }
1046
1047 static int parse_ip_val_buffer(char *in_buf, int *offset,
1048 char *out_buf, int out_len)
1049 {
1050 char *x;
1051 char *start;
1052
1053
1054
1055
1056
1057
1058 start = in_buf + *offset;
1059
1060 x = strchr(start, ';');
1061 if (x)
1062 *x = 0;
1063 else
1064 x = start + strlen(start);
1065
1066 if (strlen(start) != 0) {
1067 int i = 0;
1068
1069
1070
1071 while (start[i] == ' ')
1072 i++;
1073
1074 if ((x - start) <= out_len) {
1075 strcpy(out_buf, (start + i));
1076 *offset += (x - start) + 1;
1077 return 1;
1078 }
1079 }
1080 return 0;
1081 }
1082
1083 static int kvp_write_file(FILE *f, char *s1, char *s2, char *s3)
1084 {
1085 int ret;
1086
1087 ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3);
1088
1089 if (ret < 0)
1090 return HV_E_FAIL;
1091
1092 return 0;
1093 }
1094
1095
1096 static int process_ip_string(FILE *f, char *ip_string, int type)
1097 {
1098 int error = 0;
1099 char addr[INET6_ADDRSTRLEN];
1100 int i = 0;
1101 int j = 0;
1102 char str[256];
1103 char sub_str[13];
1104 int offset = 0;
1105
1106 memset(addr, 0, sizeof(addr));
1107
1108 while (parse_ip_val_buffer(ip_string, &offset, addr,
1109 (MAX_IP_ADDR_SIZE * 2))) {
1110
1111 sub_str[0] = 0;
1112 if (is_ipv4(addr)) {
1113 switch (type) {
1114 case IPADDR:
1115 snprintf(str, sizeof(str), "%s", "IPADDR");
1116 break;
1117 case NETMASK:
1118 snprintf(str, sizeof(str), "%s", "NETMASK");
1119 break;
1120 case GATEWAY:
1121 snprintf(str, sizeof(str), "%s", "GATEWAY");
1122 break;
1123 case DNS:
1124 snprintf(str, sizeof(str), "%s", "DNS");
1125 break;
1126 }
1127
1128 if (type == DNS) {
1129 snprintf(sub_str, sizeof(sub_str), "%d", ++i);
1130 } else if (type == GATEWAY && i == 0) {
1131 ++i;
1132 } else {
1133 snprintf(sub_str, sizeof(sub_str), "%d", i++);
1134 }
1135
1136
1137 } else if (expand_ipv6(addr, type)) {
1138 switch (type) {
1139 case IPADDR:
1140 snprintf(str, sizeof(str), "%s", "IPV6ADDR");
1141 break;
1142 case NETMASK:
1143 snprintf(str, sizeof(str), "%s", "IPV6NETMASK");
1144 break;
1145 case GATEWAY:
1146 snprintf(str, sizeof(str), "%s",
1147 "IPV6_DEFAULTGW");
1148 break;
1149 case DNS:
1150 snprintf(str, sizeof(str), "%s", "DNS");
1151 break;
1152 }
1153
1154 if (type == DNS) {
1155 snprintf(sub_str, sizeof(sub_str), "%d", ++i);
1156 } else if (j == 0) {
1157 ++j;
1158 } else {
1159 snprintf(sub_str, sizeof(sub_str), "_%d", j++);
1160 }
1161 } else {
1162 return HV_INVALIDARG;
1163 }
1164
1165 error = kvp_write_file(f, str, sub_str, addr);
1166 if (error)
1167 return error;
1168 memset(addr, 0, sizeof(addr));
1169 }
1170
1171 return 0;
1172 }
1173
1174 static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
1175 {
1176 int error = 0;
1177 char if_file[PATH_MAX];
1178 FILE *file;
1179 char cmd[PATH_MAX];
1180 char *mac_addr;
1181 int str_len;
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230 snprintf(if_file, sizeof(if_file), "%s%s%s", KVP_CONFIG_LOC,
1231 "/ifcfg-", if_name);
1232
1233 file = fopen(if_file, "w");
1234
1235 if (file == NULL) {
1236 syslog(LOG_ERR, "Failed to open config file; error: %d %s",
1237 errno, strerror(errno));
1238 return HV_E_FAIL;
1239 }
1240
1241
1242
1243
1244
1245 mac_addr = kvp_if_name_to_mac(if_name);
1246 if (mac_addr == NULL) {
1247 error = HV_E_FAIL;
1248 goto setval_error;
1249 }
1250
1251 error = kvp_write_file(file, "HWADDR", "", mac_addr);
1252 free(mac_addr);
1253 if (error)
1254 goto setval_error;
1255
1256 error = kvp_write_file(file, "DEVICE", "", if_name);
1257 if (error)
1258 goto setval_error;
1259
1260
1261
1262
1263
1264
1265
1266 if (new_val->dhcp_enabled) {
1267 error = kvp_write_file(file, "BOOTPROTO", "", "dhcp");
1268 if (error)
1269 goto setval_error;
1270
1271 } else {
1272 error = kvp_write_file(file, "BOOTPROTO", "", "none");
1273 if (error)
1274 goto setval_error;
1275 }
1276
1277
1278
1279
1280
1281
1282 error = process_ip_string(file, (char *)new_val->ip_addr, IPADDR);
1283 if (error)
1284 goto setval_error;
1285
1286 error = process_ip_string(file, (char *)new_val->sub_net, NETMASK);
1287 if (error)
1288 goto setval_error;
1289
1290 error = process_ip_string(file, (char *)new_val->gate_way, GATEWAY);
1291 if (error)
1292 goto setval_error;
1293
1294 error = process_ip_string(file, (char *)new_val->dns_addr, DNS);
1295 if (error)
1296 goto setval_error;
1297
1298 fclose(file);
1299
1300
1301
1302
1303
1304
1305 str_len = snprintf(cmd, sizeof(cmd), KVP_SCRIPTS_PATH "%s %s",
1306 "hv_set_ifconfig", if_file);
1307
1308
1309
1310
1311 if (str_len <= 0 || (unsigned int)str_len >= sizeof(cmd)) {
1312 syslog(LOG_ERR, "Cmd '%s' (len=%d) may be too long",
1313 cmd, str_len);
1314 return HV_E_FAIL;
1315 }
1316
1317 if (system(cmd)) {
1318 syslog(LOG_ERR, "Failed to execute cmd '%s'; error: %d %s",
1319 cmd, errno, strerror(errno));
1320 return HV_E_FAIL;
1321 }
1322 return 0;
1323
1324 setval_error:
1325 syslog(LOG_ERR, "Failed to write config file");
1326 fclose(file);
1327 return error;
1328 }
1329
1330
1331 static void
1332 kvp_get_domain_name(char *buffer, int length)
1333 {
1334 struct addrinfo hints, *info ;
1335 int error = 0;
1336
1337 gethostname(buffer, length);
1338 memset(&hints, 0, sizeof(hints));
1339 hints.ai_family = AF_INET;
1340 hints.ai_socktype = SOCK_STREAM;
1341 hints.ai_flags = AI_CANONNAME;
1342
1343 error = getaddrinfo(buffer, NULL, &hints, &info);
1344 if (error != 0) {
1345 snprintf(buffer, length, "getaddrinfo failed: 0x%x %s",
1346 error, gai_strerror(error));
1347 return;
1348 }
1349 snprintf(buffer, length, "%s", info->ai_canonname);
1350 freeaddrinfo(info);
1351 }
1352
1353 void print_usage(char *argv[])
1354 {
1355 fprintf(stderr, "Usage: %s [options]\n"
1356 "Options are:\n"
1357 " -n, --no-daemon stay in foreground, don't daemonize\n"
1358 " -h, --help print this help\n", argv[0]);
1359 }
1360
1361 int main(int argc, char *argv[])
1362 {
1363 int kvp_fd = -1, len;
1364 int error;
1365 struct pollfd pfd;
1366 char *p;
1367 struct hv_kvp_msg hv_msg[1];
1368 char *key_value;
1369 char *key_name;
1370 int op;
1371 int pool;
1372 char *if_name;
1373 struct hv_kvp_ipaddr_value *kvp_ip_val;
1374 int daemonize = 1, long_index = 0, opt;
1375
1376 static struct option long_options[] = {
1377 {"help", no_argument, 0, 'h' },
1378 {"no-daemon", no_argument, 0, 'n' },
1379 {0, 0, 0, 0 }
1380 };
1381
1382 while ((opt = getopt_long(argc, argv, "hn", long_options,
1383 &long_index)) != -1) {
1384 switch (opt) {
1385 case 'n':
1386 daemonize = 0;
1387 break;
1388 case 'h':
1389 print_usage(argv);
1390 exit(0);
1391 default:
1392 print_usage(argv);
1393 exit(EXIT_FAILURE);
1394 }
1395 }
1396
1397 if (daemonize && daemon(1, 0))
1398 return 1;
1399
1400 openlog("KVP", 0, LOG_USER);
1401 syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
1402
1403
1404
1405
1406 kvp_get_os_info();
1407
1408
1409
1410
1411 kvp_get_domain_name(full_domain_name, sizeof(full_domain_name));
1412
1413 if (kvp_file_init()) {
1414 syslog(LOG_ERR, "Failed to initialize the pools");
1415 exit(EXIT_FAILURE);
1416 }
1417
1418 reopen_kvp_fd:
1419 if (kvp_fd != -1)
1420 close(kvp_fd);
1421 in_hand_shake = 1;
1422 kvp_fd = open("/dev/vmbus/hv_kvp", O_RDWR | O_CLOEXEC);
1423
1424 if (kvp_fd < 0) {
1425 syslog(LOG_ERR, "open /dev/vmbus/hv_kvp failed; error: %d %s",
1426 errno, strerror(errno));
1427 exit(EXIT_FAILURE);
1428 }
1429
1430
1431
1432
1433 hv_msg->kvp_hdr.operation = KVP_OP_REGISTER1;
1434 len = write(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg));
1435 if (len != sizeof(struct hv_kvp_msg)) {
1436 syslog(LOG_ERR, "registration to kernel failed; error: %d %s",
1437 errno, strerror(errno));
1438 close(kvp_fd);
1439 exit(EXIT_FAILURE);
1440 }
1441
1442 pfd.fd = kvp_fd;
1443
1444 while (1) {
1445 pfd.events = POLLIN;
1446 pfd.revents = 0;
1447
1448 if (poll(&pfd, 1, -1) < 0) {
1449 syslog(LOG_ERR, "poll failed; error: %d %s", errno, strerror(errno));
1450 if (errno == EINVAL) {
1451 close(kvp_fd);
1452 exit(EXIT_FAILURE);
1453 }
1454 else
1455 continue;
1456 }
1457
1458 len = read(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg));
1459
1460 if (len != sizeof(struct hv_kvp_msg)) {
1461 syslog(LOG_ERR, "read failed; error:%d %s",
1462 errno, strerror(errno));
1463 goto reopen_kvp_fd;
1464 }
1465
1466
1467
1468
1469
1470
1471 op = hv_msg->kvp_hdr.operation;
1472 pool = hv_msg->kvp_hdr.pool;
1473 hv_msg->error = HV_S_OK;
1474
1475 if ((in_hand_shake) && (op == KVP_OP_REGISTER1)) {
1476
1477
1478
1479
1480 in_hand_shake = 0;
1481 p = (char *)hv_msg->body.kvp_register.version;
1482 lic_version = malloc(strlen(p) + 1);
1483 if (lic_version) {
1484 strcpy(lic_version, p);
1485 syslog(LOG_INFO, "KVP LIC Version: %s",
1486 lic_version);
1487 } else {
1488 syslog(LOG_ERR, "malloc failed");
1489 }
1490 continue;
1491 }
1492
1493 switch (op) {
1494 case KVP_OP_GET_IP_INFO:
1495 kvp_ip_val = &hv_msg->body.kvp_ip_val;
1496
1497 error = kvp_mac_to_ip(kvp_ip_val);
1498
1499 if (error)
1500 hv_msg->error = error;
1501
1502 break;
1503
1504 case KVP_OP_SET_IP_INFO:
1505 kvp_ip_val = &hv_msg->body.kvp_ip_val;
1506 if_name = kvp_get_if_name(
1507 (char *)kvp_ip_val->adapter_id);
1508 if (if_name == NULL) {
1509
1510
1511
1512
1513 hv_msg->error = HV_GUID_NOTFOUND;
1514 break;
1515 }
1516 error = kvp_set_ip_info(if_name, kvp_ip_val);
1517 if (error)
1518 hv_msg->error = error;
1519
1520 free(if_name);
1521 break;
1522
1523 case KVP_OP_SET:
1524 if (kvp_key_add_or_modify(pool,
1525 hv_msg->body.kvp_set.data.key,
1526 hv_msg->body.kvp_set.data.key_size,
1527 hv_msg->body.kvp_set.data.value,
1528 hv_msg->body.kvp_set.data.value_size))
1529 hv_msg->error = HV_S_CONT;
1530 break;
1531
1532 case KVP_OP_GET:
1533 if (kvp_get_value(pool,
1534 hv_msg->body.kvp_set.data.key,
1535 hv_msg->body.kvp_set.data.key_size,
1536 hv_msg->body.kvp_set.data.value,
1537 hv_msg->body.kvp_set.data.value_size))
1538 hv_msg->error = HV_S_CONT;
1539 break;
1540
1541 case KVP_OP_DELETE:
1542 if (kvp_key_delete(pool,
1543 hv_msg->body.kvp_delete.key,
1544 hv_msg->body.kvp_delete.key_size))
1545 hv_msg->error = HV_S_CONT;
1546 break;
1547
1548 default:
1549 break;
1550 }
1551
1552 if (op != KVP_OP_ENUMERATE)
1553 goto kvp_done;
1554
1555
1556
1557
1558
1559
1560 if (pool != KVP_POOL_AUTO) {
1561 if (kvp_pool_enumerate(pool,
1562 hv_msg->body.kvp_enum_data.index,
1563 hv_msg->body.kvp_enum_data.data.key,
1564 HV_KVP_EXCHANGE_MAX_KEY_SIZE,
1565 hv_msg->body.kvp_enum_data.data.value,
1566 HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
1567 hv_msg->error = HV_S_CONT;
1568 goto kvp_done;
1569 }
1570
1571 key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
1572 key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
1573
1574 switch (hv_msg->body.kvp_enum_data.index) {
1575 case FullyQualifiedDomainName:
1576 strcpy(key_value, full_domain_name);
1577 strcpy(key_name, "FullyQualifiedDomainName");
1578 break;
1579 case IntegrationServicesVersion:
1580 strcpy(key_name, "IntegrationServicesVersion");
1581 strcpy(key_value, lic_version);
1582 break;
1583 case NetworkAddressIPv4:
1584 kvp_get_ip_info(AF_INET, NULL, KVP_OP_ENUMERATE,
1585 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1586 strcpy(key_name, "NetworkAddressIPv4");
1587 break;
1588 case NetworkAddressIPv6:
1589 kvp_get_ip_info(AF_INET6, NULL, KVP_OP_ENUMERATE,
1590 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
1591 strcpy(key_name, "NetworkAddressIPv6");
1592 break;
1593 case OSBuildNumber:
1594 strcpy(key_value, os_build);
1595 strcpy(key_name, "OSBuildNumber");
1596 break;
1597 case OSName:
1598 strcpy(key_value, os_name);
1599 strcpy(key_name, "OSName");
1600 break;
1601 case OSMajorVersion:
1602 strcpy(key_value, os_major);
1603 strcpy(key_name, "OSMajorVersion");
1604 break;
1605 case OSMinorVersion:
1606 strcpy(key_value, os_minor);
1607 strcpy(key_name, "OSMinorVersion");
1608 break;
1609 case OSVersion:
1610 strcpy(key_value, os_version);
1611 strcpy(key_name, "OSVersion");
1612 break;
1613 case ProcessorArchitecture:
1614 strcpy(key_value, processor_arch);
1615 strcpy(key_name, "ProcessorArchitecture");
1616 break;
1617 default:
1618 hv_msg->error = HV_S_CONT;
1619 break;
1620 }
1621
1622
1623
1624
1625
1626
1627 kvp_done:
1628 len = write(kvp_fd, hv_msg, sizeof(struct hv_kvp_msg));
1629 if (len != sizeof(struct hv_kvp_msg)) {
1630 syslog(LOG_ERR, "write failed; error: %d %s", errno,
1631 strerror(errno));
1632 goto reopen_kvp_fd;
1633 }
1634 }
1635
1636 close(kvp_fd);
1637 exit(0);
1638 }