hv_kvp_daemon.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. /*
  2. * An implementation of key value pair (KVP) functionality for Linux.
  3. *
  4. *
  5. * Copyright (C) 2010, Novell, Inc.
  6. * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
  7. *
  8. * This program is free software; you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public License version 2 as published
  10. * by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  15. * NON INFRINGEMENT. See the GNU General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  21. *
  22. */
  23. #include <sys/types.h>
  24. #include <sys/socket.h>
  25. #include <sys/poll.h>
  26. #include <sys/utsname.h>
  27. #include <linux/types.h>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <unistd.h>
  31. #include <string.h>
  32. #include <errno.h>
  33. #include <arpa/inet.h>
  34. #include <linux/connector.h>
  35. #include <linux/netlink.h>
  36. #include <ifaddrs.h>
  37. #include <netdb.h>
  38. #include <syslog.h>
  39. /*
  40. * KYS: TODO. Need to register these in the kernel.
  41. *
  42. * The following definitions are shared with the in-kernel component; do not
  43. * change any of this without making the corresponding changes in
  44. * the KVP kernel component.
  45. */
  46. #define CN_KVP_IDX 0x9 /* MSFT KVP functionality */
  47. #define CN_KVP_VAL 0x1 /* This supports queries from the kernel */
  48. #define CN_KVP_USER_VAL 0x2 /* This supports queries from the user */
  49. /*
  50. * KVP protocol: The user mode component first registers with the
  51. * the kernel component. Subsequently, the kernel component requests, data
  52. * for the specified keys. In response to this message the user mode component
  53. * fills in the value corresponding to the specified key. We overload the
  54. * sequence field in the cn_msg header to define our KVP message types.
  55. *
  56. * We use this infrastructure for also supporting queries from user mode
  57. * application for state that may be maintained in the KVP kernel component.
  58. *
  59. * XXXKYS: Have a shared header file between the user and kernel (TODO)
  60. */
  61. enum kvp_op {
  62. KVP_REGISTER = 0, /* Register the user mode component*/
  63. KVP_KERNEL_GET, /*Kernel is requesting the value for the specified key*/
  64. KVP_KERNEL_SET, /*Kernel is providing the value for the specified key*/
  65. KVP_USER_GET, /*User is requesting the value for the specified key*/
  66. KVP_USER_SET /*User is providing the value for the specified key*/
  67. };
  68. #define HV_KVP_EXCHANGE_MAX_KEY_SIZE 512
  69. #define HV_KVP_EXCHANGE_MAX_VALUE_SIZE 2048
  70. struct hv_ku_msg {
  71. __u32 kvp_index;
  72. __u8 kvp_key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; /* Key name */
  73. __u8 kvp_value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; /* Key value */
  74. };
  75. enum key_index {
  76. FullyQualifiedDomainName = 0,
  77. IntegrationServicesVersion, /*This key is serviced in the kernel*/
  78. NetworkAddressIPv4,
  79. NetworkAddressIPv6,
  80. OSBuildNumber,
  81. OSName,
  82. OSMajorVersion,
  83. OSMinorVersion,
  84. OSVersion,
  85. ProcessorArchitecture
  86. };
  87. /*
  88. * End of shared definitions.
  89. */
  90. static char kvp_send_buffer[4096];
  91. static char kvp_recv_buffer[4096];
  92. static struct sockaddr_nl addr;
  93. static char *os_name = "";
  94. static char *os_major = "";
  95. static char *os_minor = "";
  96. static char *processor_arch;
  97. static char *os_build;
  98. static char *lic_version;
  99. static struct utsname uts_buf;
  100. void kvp_get_os_info(void)
  101. {
  102. FILE *file;
  103. char *p, buf[512];
  104. uname(&uts_buf);
  105. os_build = uts_buf.release;
  106. processor_arch = uts_buf.machine;
  107. /*
  108. * The current windows host (win7) expects the build
  109. * string to be of the form: x.y.z
  110. * Strip additional information we may have.
  111. */
  112. p = strchr(os_build, '-');
  113. if (p)
  114. *p = '\0';
  115. file = fopen("/etc/SuSE-release", "r");
  116. if (file != NULL)
  117. goto kvp_osinfo_found;
  118. file = fopen("/etc/redhat-release", "r");
  119. if (file != NULL)
  120. goto kvp_osinfo_found;
  121. /*
  122. * Add code for other supported platforms.
  123. */
  124. /*
  125. * We don't have information about the os.
  126. */
  127. os_name = uts_buf.sysname;
  128. return;
  129. kvp_osinfo_found:
  130. /* up to three lines */
  131. p = fgets(buf, sizeof(buf), file);
  132. if (p) {
  133. p = strchr(buf, '\n');
  134. if (p)
  135. *p = '\0';
  136. p = strdup(buf);
  137. if (!p)
  138. goto done;
  139. os_name = p;
  140. /* second line */
  141. p = fgets(buf, sizeof(buf), file);
  142. if (p) {
  143. p = strchr(buf, '\n');
  144. if (p)
  145. *p = '\0';
  146. p = strdup(buf);
  147. if (!p)
  148. goto done;
  149. os_major = p;
  150. /* third line */
  151. p = fgets(buf, sizeof(buf), file);
  152. if (p) {
  153. p = strchr(buf, '\n');
  154. if (p)
  155. *p = '\0';
  156. p = strdup(buf);
  157. if (p)
  158. os_minor = p;
  159. }
  160. }
  161. }
  162. done:
  163. fclose(file);
  164. return;
  165. }
  166. static int
  167. kvp_get_ip_address(int family, char *buffer, int length)
  168. {
  169. struct ifaddrs *ifap;
  170. struct ifaddrs *curp;
  171. int ipv4_len = strlen("255.255.255.255") + 1;
  172. int ipv6_len = strlen("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")+1;
  173. int offset = 0;
  174. const char *str;
  175. char tmp[50];
  176. int error = 0;
  177. /*
  178. * On entry into this function, the buffer is capable of holding the
  179. * maximum key value (2048 bytes).
  180. */
  181. if (getifaddrs(&ifap)) {
  182. strcpy(buffer, "getifaddrs failed\n");
  183. return 1;
  184. }
  185. curp = ifap;
  186. while (curp != NULL) {
  187. if ((curp->ifa_addr != NULL) &&
  188. (curp->ifa_addr->sa_family == family)) {
  189. if (family == AF_INET) {
  190. struct sockaddr_in *addr =
  191. (struct sockaddr_in *) curp->ifa_addr;
  192. str = inet_ntop(family, &addr->sin_addr,
  193. tmp, 50);
  194. if (str == NULL) {
  195. strcpy(buffer, "inet_ntop failed\n");
  196. error = 1;
  197. goto getaddr_done;
  198. }
  199. if (offset == 0)
  200. strcpy(buffer, tmp);
  201. else
  202. strcat(buffer, tmp);
  203. strcat(buffer, ";");
  204. offset += strlen(str) + 1;
  205. if ((length - offset) < (ipv4_len + 1))
  206. goto getaddr_done;
  207. } else {
  208. /*
  209. * We only support AF_INET and AF_INET6
  210. * and the list of addresses is separated by a ";".
  211. */
  212. struct sockaddr_in6 *addr =
  213. (struct sockaddr_in6 *) curp->ifa_addr;
  214. str = inet_ntop(family,
  215. &addr->sin6_addr.s6_addr,
  216. tmp, 50);
  217. if (str == NULL) {
  218. strcpy(buffer, "inet_ntop failed\n");
  219. error = 1;
  220. goto getaddr_done;
  221. }
  222. if (offset == 0)
  223. strcpy(buffer, tmp);
  224. else
  225. strcat(buffer, tmp);
  226. strcat(buffer, ";");
  227. offset += strlen(str) + 1;
  228. if ((length - offset) < (ipv6_len + 1))
  229. goto getaddr_done;
  230. }
  231. }
  232. curp = curp->ifa_next;
  233. }
  234. getaddr_done:
  235. freeifaddrs(ifap);
  236. return error;
  237. }
  238. static int
  239. kvp_get_domain_name(char *buffer, int length)
  240. {
  241. struct addrinfo hints, *info ;
  242. int error = 0;
  243. gethostname(buffer, length);
  244. memset(&hints, 0, sizeof(hints));
  245. hints.ai_family = AF_INET; /*Get only ipv4 addrinfo. */
  246. hints.ai_socktype = SOCK_STREAM;
  247. hints.ai_flags = AI_CANONNAME;
  248. error = getaddrinfo(buffer, NULL, &hints, &info);
  249. if (error != 0) {
  250. strcpy(buffer, "getaddrinfo failed\n");
  251. return error;
  252. }
  253. strcpy(buffer, info->ai_canonname);
  254. freeaddrinfo(info);
  255. return error;
  256. }
  257. static int
  258. netlink_send(int fd, struct cn_msg *msg)
  259. {
  260. struct nlmsghdr *nlh;
  261. unsigned int size;
  262. struct msghdr message;
  263. char buffer[64];
  264. struct iovec iov[2];
  265. size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
  266. nlh = (struct nlmsghdr *)buffer;
  267. nlh->nlmsg_seq = 0;
  268. nlh->nlmsg_pid = getpid();
  269. nlh->nlmsg_type = NLMSG_DONE;
  270. nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
  271. nlh->nlmsg_flags = 0;
  272. iov[0].iov_base = nlh;
  273. iov[0].iov_len = sizeof(*nlh);
  274. iov[1].iov_base = msg;
  275. iov[1].iov_len = size;
  276. memset(&message, 0, sizeof(message));
  277. message.msg_name = &addr;
  278. message.msg_namelen = sizeof(addr);
  279. message.msg_iov = iov;
  280. message.msg_iovlen = 2;
  281. return sendmsg(fd, &message, 0);
  282. }
  283. int main(void)
  284. {
  285. int fd, len, sock_opt;
  286. int error;
  287. struct cn_msg *message;
  288. struct pollfd pfd;
  289. struct nlmsghdr *incoming_msg;
  290. struct cn_msg *incoming_cn_msg;
  291. struct hv_ku_msg *hv_msg;
  292. char *p;
  293. char *key_value;
  294. char *key_name;
  295. daemon(1, 0);
  296. openlog("KVP", 0, LOG_USER);
  297. syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
  298. /*
  299. * Retrieve OS release information.
  300. */
  301. kvp_get_os_info();
  302. fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
  303. if (fd < 0) {
  304. syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
  305. exit(-1);
  306. }
  307. addr.nl_family = AF_NETLINK;
  308. addr.nl_pad = 0;
  309. addr.nl_pid = 0;
  310. addr.nl_groups = CN_KVP_IDX;
  311. error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
  312. if (error < 0) {
  313. syslog(LOG_ERR, "bind failed; error:%d", error);
  314. close(fd);
  315. exit(-1);
  316. }
  317. sock_opt = addr.nl_groups;
  318. setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt));
  319. /*
  320. * Register ourselves with the kernel.
  321. */
  322. message = (struct cn_msg *)kvp_send_buffer;
  323. message->id.idx = CN_KVP_IDX;
  324. message->id.val = CN_KVP_VAL;
  325. message->seq = KVP_REGISTER;
  326. message->ack = 0;
  327. message->len = 0;
  328. len = netlink_send(fd, message);
  329. if (len < 0) {
  330. syslog(LOG_ERR, "netlink_send failed; error:%d", len);
  331. close(fd);
  332. exit(-1);
  333. }
  334. pfd.fd = fd;
  335. while (1) {
  336. pfd.events = POLLIN;
  337. pfd.revents = 0;
  338. poll(&pfd, 1, -1);
  339. len = recv(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0);
  340. if (len < 0) {
  341. syslog(LOG_ERR, "recv failed; error:%d", len);
  342. close(fd);
  343. return -1;
  344. }
  345. incoming_msg = (struct nlmsghdr *)kvp_recv_buffer;
  346. incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
  347. switch (incoming_cn_msg->seq) {
  348. case KVP_REGISTER:
  349. /*
  350. * Driver is registering with us; stash away the version
  351. * information.
  352. */
  353. p = (char *)incoming_cn_msg->data;
  354. lic_version = malloc(strlen(p) + 1);
  355. if (lic_version) {
  356. strcpy(lic_version, p);
  357. syslog(LOG_INFO, "KVP LIC Version: %s",
  358. lic_version);
  359. } else {
  360. syslog(LOG_ERR, "malloc failed");
  361. }
  362. continue;
  363. case KVP_KERNEL_GET:
  364. break;
  365. default:
  366. continue;
  367. }
  368. hv_msg = (struct hv_ku_msg *)incoming_cn_msg->data;
  369. key_name = (char *)hv_msg->kvp_key;
  370. key_value = (char *)hv_msg->kvp_value;
  371. switch (hv_msg->kvp_index) {
  372. case FullyQualifiedDomainName:
  373. kvp_get_domain_name(key_value,
  374. HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
  375. strcpy(key_name, "FullyQualifiedDomainName");
  376. break;
  377. case IntegrationServicesVersion:
  378. strcpy(key_name, "IntegrationServicesVersion");
  379. strcpy(key_value, lic_version);
  380. break;
  381. case NetworkAddressIPv4:
  382. kvp_get_ip_address(AF_INET, key_value,
  383. HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
  384. strcpy(key_name, "NetworkAddressIPv4");
  385. break;
  386. case NetworkAddressIPv6:
  387. kvp_get_ip_address(AF_INET6, key_value,
  388. HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
  389. strcpy(key_name, "NetworkAddressIPv6");
  390. break;
  391. case OSBuildNumber:
  392. strcpy(key_value, os_build);
  393. strcpy(key_name, "OSBuildNumber");
  394. break;
  395. case OSName:
  396. strcpy(key_value, os_name);
  397. strcpy(key_name, "OSName");
  398. break;
  399. case OSMajorVersion:
  400. strcpy(key_value, os_major);
  401. strcpy(key_name, "OSMajorVersion");
  402. break;
  403. case OSMinorVersion:
  404. strcpy(key_value, os_minor);
  405. strcpy(key_name, "OSMinorVersion");
  406. break;
  407. case OSVersion:
  408. strcpy(key_value, os_build);
  409. strcpy(key_name, "OSVersion");
  410. break;
  411. case ProcessorArchitecture:
  412. strcpy(key_value, processor_arch);
  413. strcpy(key_name, "ProcessorArchitecture");
  414. break;
  415. default:
  416. strcpy(key_value, "Unknown Key");
  417. /*
  418. * We use a null key name to terminate enumeration.
  419. */
  420. strcpy(key_name, "");
  421. break;
  422. }
  423. /*
  424. * Send the value back to the kernel. The response is
  425. * already in the receive buffer. Update the cn_msg header to
  426. * reflect the key value that has been added to the message
  427. */
  428. incoming_cn_msg->id.idx = CN_KVP_IDX;
  429. incoming_cn_msg->id.val = CN_KVP_VAL;
  430. incoming_cn_msg->seq = KVP_USER_SET;
  431. incoming_cn_msg->ack = 0;
  432. incoming_cn_msg->len = sizeof(struct hv_ku_msg);
  433. len = netlink_send(fd, incoming_cn_msg);
  434. if (len < 0) {
  435. syslog(LOG_ERR, "net_link send failed; error:%d", len);
  436. exit(-1);
  437. }
  438. }
  439. }