hv_kvp_daemon.c 11 KB

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