3
0

script.c 5.7 KB

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