script.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /* vi: set sw=4 ts=4: */
  2. /* script.c
  3. *
  4. * Functions to call the DHCP client notification scripts
  5. *
  6. * Russ Dill <Russ.Dill@asu.edu> July 2001
  7. *
  8. * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  9. */
  10. #include "common.h"
  11. #include "dhcpd.h"
  12. #include "dhcpc.h"
  13. #include "options.h"
  14. /* get a rough idea of how long an option will be (rounding up...) */
  15. static const int max_option_length[] = {
  16. [OPTION_IP] = sizeof("255.255.255.255 "),
  17. [OPTION_IP_PAIR] = sizeof("255.255.255.255 ") * 2,
  18. [OPTION_STRING] = 1,
  19. [OPTION_BOOLEAN] = sizeof("yes "),
  20. [OPTION_U8] = sizeof("255 "),
  21. [OPTION_U16] = sizeof("65535 "),
  22. [OPTION_S16] = sizeof("-32768 "),
  23. [OPTION_U32] = sizeof("4294967295 "),
  24. [OPTION_S32] = sizeof("-2147483684 "),
  25. };
  26. static inline int upper_length(int length, int opt_index)
  27. {
  28. return max_option_length[opt_index] *
  29. (length / option_lengths[opt_index]);
  30. }
  31. static int sprintip(char *dest, char *pre, uint8_t *ip)
  32. {
  33. return sprintf(dest, "%s%d.%d.%d.%d", pre, ip[0], ip[1], ip[2], ip[3]);
  34. }
  35. /* really simple implementation, just count the bits */
  36. static int mton(struct in_addr *mask)
  37. {
  38. int i;
  39. unsigned long bits = ntohl(mask->s_addr);
  40. /* too bad one can't check the carry bit, etc in c bit
  41. * shifting */
  42. for (i = 0; i < 32 && !((bits >> i) & 1); i++);
  43. return 32 - i;
  44. }
  45. /* Fill dest with the text of option 'option'. */
  46. static void fill_options(char *dest, uint8_t *option,
  47. const struct dhcp_option *type_p)
  48. {
  49. int type, optlen;
  50. uint16_t val_u16;
  51. int16_t val_s16;
  52. uint32_t val_u32;
  53. int32_t val_s32;
  54. int len = option[OPT_LEN - 2];
  55. dest += sprintf(dest, "%s=", type_p->name);
  56. type = type_p->flags & TYPE_MASK;
  57. optlen = option_lengths[type];
  58. for (;;) {
  59. switch (type) {
  60. case OPTION_IP_PAIR:
  61. dest += sprintip(dest, "", option);
  62. *(dest++) = '/';
  63. option += 4;
  64. optlen = 4;
  65. case OPTION_IP: /* Works regardless of host byte order. */
  66. dest += sprintip(dest, "", option);
  67. break;
  68. case OPTION_BOOLEAN:
  69. dest += sprintf(dest, *option ? "yes" : "no");
  70. break;
  71. case OPTION_U8:
  72. dest += sprintf(dest, "%u", *option);
  73. break;
  74. case OPTION_U16:
  75. memcpy(&val_u16, option, 2);
  76. dest += sprintf(dest, "%u", ntohs(val_u16));
  77. break;
  78. case OPTION_S16:
  79. memcpy(&val_s16, option, 2);
  80. dest += sprintf(dest, "%d", ntohs(val_s16));
  81. break;
  82. case OPTION_U32:
  83. memcpy(&val_u32, option, 4);
  84. dest += sprintf(dest, "%lu", (unsigned long) ntohl(val_u32));
  85. break;
  86. case OPTION_S32:
  87. memcpy(&val_s32, option, 4);
  88. dest += sprintf(dest, "%ld", (long) ntohl(val_s32));
  89. break;
  90. case OPTION_STRING:
  91. memcpy(dest, option, len);
  92. dest[len] = '\0';
  93. return; /* Short circuit this case */
  94. }
  95. option += optlen;
  96. len -= optlen;
  97. if (len <= 0) break;
  98. dest += sprintf(dest, " ");
  99. }
  100. }
  101. /* put all the parameters into an environment */
  102. static char **fill_envp(struct dhcpMessage *packet)
  103. {
  104. int num_options = 0;
  105. int i, j;
  106. char **envp;
  107. uint8_t *temp;
  108. struct in_addr subnet;
  109. char over = 0;
  110. if (packet == NULL)
  111. num_options = 0;
  112. else {
  113. for (i = 0; dhcp_options[i].code; i++)
  114. if (get_option(packet, dhcp_options[i].code)) {
  115. num_options++;
  116. if (dhcp_options[i].code == DHCP_SUBNET)
  117. num_options++; /* for mton */
  118. }
  119. if (packet->siaddr) num_options++;
  120. if ((temp = get_option(packet, DHCP_OPTION_OVER)))
  121. over = *temp;
  122. if (!(over & FILE_FIELD) && packet->file[0]) num_options++;
  123. if (!(over & SNAME_FIELD) && packet->sname[0]) num_options++;
  124. }
  125. envp = xzalloc(sizeof(char *) * (num_options + 5));
  126. j = 0;
  127. envp[j++] = xasprintf("interface=%s", client_config.interface);
  128. envp[j++] = xasprintf("PATH=%s",
  129. getenv("PATH") ? : "/bin:/usr/bin:/sbin:/usr/sbin");
  130. envp[j++] = xasprintf("HOME=%s", getenv("HOME") ? : "/");
  131. if (packet == NULL) return envp;
  132. envp[j] = xmalloc(sizeof("ip=255.255.255.255"));
  133. sprintip(envp[j++], "ip=", (uint8_t *) &packet->yiaddr);
  134. for (i = 0; dhcp_options[i].code; i++) {
  135. temp = get_option(packet, dhcp_options[i].code);
  136. if (!temp)
  137. continue;
  138. envp[j] = xmalloc(upper_length(temp[OPT_LEN - 2],
  139. dhcp_options[i].flags & TYPE_MASK) + strlen(dhcp_options[i].name) + 2);
  140. fill_options(envp[j++], temp, &dhcp_options[i]);
  141. /* Fill in a subnet bits option for things like /24 */
  142. if (dhcp_options[i].code == DHCP_SUBNET) {
  143. memcpy(&subnet, temp, 4);
  144. envp[j++] = xasprintf("mask=%d", mton(&subnet));
  145. }
  146. }
  147. if (packet->siaddr) {
  148. envp[j] = xmalloc(sizeof("siaddr=255.255.255.255"));
  149. sprintip(envp[j++], "siaddr=", (uint8_t *) &packet->siaddr);
  150. }
  151. if (!(over & FILE_FIELD) && packet->file[0]) {
  152. /* watch out for invalid packets */
  153. packet->file[sizeof(packet->file) - 1] = '\0';
  154. envp[j++] = xasprintf("boot_file=%s", packet->file);
  155. }
  156. if (!(over & SNAME_FIELD) && packet->sname[0]) {
  157. /* watch out for invalid packets */
  158. packet->sname[sizeof(packet->sname) - 1] = '\0';
  159. envp[j++] = xasprintf("sname=%s", packet->sname);
  160. }
  161. return envp;
  162. }
  163. /* Call a script with a par file and env vars */
  164. void udhcp_run_script(struct dhcpMessage *packet, const char *name)
  165. {
  166. int pid;
  167. char **envp, **curr;
  168. if (client_config.script == NULL)
  169. return;
  170. DEBUG("vfork'ing and execle'ing %s", client_config.script);
  171. envp = fill_envp(packet);
  172. /* call script */
  173. pid = vfork();
  174. if (pid) {
  175. waitpid(pid, NULL, 0);
  176. for (curr = envp; *curr; curr++) free(*curr);
  177. free(envp);
  178. return;
  179. } else if (pid == 0) {
  180. /* close fd's? */
  181. /* exec script */
  182. execle(client_config.script, client_config.script,
  183. name, NULL, envp);
  184. bb_perror_msg("script %s failed", client_config.script);
  185. exit(1);
  186. }
  187. }