script.c 5.8 KB

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