script.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  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 len_of_option_as_string[] = {
  15. [OPTION_IP] = sizeof("255.255.255.255 "),
  16. [OPTION_IP_PAIR] = sizeof("255.255.255.255 ") * 2,
  17. [OPTION_STATIC_ROUTES]= sizeof("255.255.255.255/32 255.255.255.255 "),
  18. [OPTION_STRING] = 1,
  19. #if ENABLE_FEATURE_UDHCP_RFC3397
  20. [OPTION_STR1035] = 1,
  21. #endif
  22. [OPTION_BOOLEAN] = sizeof("yes "),
  23. [OPTION_U8] = sizeof("255 "),
  24. [OPTION_U16] = sizeof("65535 "),
  25. [OPTION_S16] = sizeof("-32768 "),
  26. [OPTION_U32] = sizeof("4294967295 "),
  27. [OPTION_S32] = sizeof("-2147483684 "),
  28. };
  29. /* note: ip is a pointer to an IP in network order, possibly misaliged */
  30. static int sprint_nip(char *dest, const char *pre, const uint8_t *ip)
  31. {
  32. return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]);
  33. }
  34. /* really simple implementation, just count the bits */
  35. static int mton(uint32_t mask)
  36. {
  37. int i = 0;
  38. mask = ntohl(mask); /* 111110000-like bit pattern */
  39. while (mask) {
  40. i++;
  41. mask <<= 1;
  42. }
  43. return i;
  44. }
  45. /* Create "opt_name=opt_value" string */
  46. static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_option *type_p, const char *opt_name)
  47. {
  48. unsigned upper_length;
  49. int len, type, optlen;
  50. uint16_t val_u16;
  51. int16_t val_s16;
  52. uint32_t val_u32;
  53. int32_t val_s32;
  54. char *dest, *ret;
  55. /* option points to OPT_DATA, need to go back and get OPT_LEN */
  56. len = option[OPT_LEN - OPT_DATA];
  57. type = type_p->flags & TYPE_MASK;
  58. optlen = dhcp_option_lengths[type];
  59. upper_length = len_of_option_as_string[type] * (len / optlen);
  60. dest = ret = xmalloc(upper_length + strlen(opt_name) + 2);
  61. dest += sprintf(ret, "%s=", opt_name);
  62. while (len >= optlen) {
  63. switch (type) {
  64. case OPTION_IP_PAIR:
  65. dest += sprint_nip(dest, "", option);
  66. *dest++ = '/';
  67. option += 4;
  68. optlen = 4;
  69. case OPTION_IP: /* Works regardless of host byte order. */
  70. dest += sprint_nip(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. move_from_unaligned16(val_u16, option);
  80. dest += sprintf(dest, "%u", ntohs(val_u16));
  81. break;
  82. case OPTION_S16:
  83. move_from_unaligned16(val_s16, option);
  84. dest += sprintf(dest, "%d", ntohs(val_s16));
  85. break;
  86. case OPTION_U32:
  87. move_from_unaligned32(val_u32, option);
  88. dest += sprintf(dest, "%lu", (unsigned long) ntohl(val_u32));
  89. break;
  90. case OPTION_S32:
  91. move_from_unaligned32(val_s32, option);
  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. case OPTION_STATIC_ROUTES: {
  99. /* Option binary format:
  100. * mask [one byte, 0..32]
  101. * ip [big endian, 0..4 bytes depending on mask]
  102. * router [big endian, 4 bytes]
  103. * may be repeated
  104. *
  105. * We convert it to a string "IP/MASK ROUTER IP2/MASK2 ROUTER2"
  106. */
  107. const char *pfx = "";
  108. while (len >= 1 + 4) { /* mask + 0-byte ip + router */
  109. uint32_t nip;
  110. uint8_t *p;
  111. unsigned mask;
  112. int bytes;
  113. mask = *option++;
  114. if (mask > 32)
  115. break;
  116. len--;
  117. nip = 0;
  118. p = (void*) &nip;
  119. bytes = (mask + 7) / 8; /* 0 -> 0, 1..8 -> 1, 9..16 -> 2 etc */
  120. while (--bytes >= 0) {
  121. *p++ = *option++;
  122. len--;
  123. }
  124. if (len < 4)
  125. break;
  126. /* print ip/mask */
  127. dest += sprint_nip(dest, pfx, (void*) &nip);
  128. pfx = " ";
  129. dest += sprintf(dest, "/%u ", mask);
  130. /* print router */
  131. dest += sprint_nip(dest, "", option);
  132. option += 4;
  133. len -= 4;
  134. }
  135. return ret;
  136. }
  137. #if ENABLE_FEATURE_UDHCP_RFC3397
  138. case OPTION_STR1035:
  139. /* unpack option into dest; use ret for prefix (i.e., "optname=") */
  140. dest = dname_dec(option, len, ret);
  141. if (dest) {
  142. free(ret);
  143. return dest;
  144. }
  145. /* error. return "optname=" string */
  146. return ret;
  147. #endif
  148. }
  149. option += optlen;
  150. len -= optlen;
  151. if (len <= 0)
  152. break;
  153. *dest++ = ' ';
  154. *dest = '\0';
  155. }
  156. return ret;
  157. }
  158. /* put all the parameters into an environment */
  159. static char **fill_envp(struct dhcp_packet *packet)
  160. {
  161. int num_options = 0;
  162. int i;
  163. char **envp, **curr;
  164. const char *opt_name;
  165. uint8_t *temp;
  166. uint8_t over = 0;
  167. if (packet) {
  168. for (i = 0; dhcp_options[i].code; i++) {
  169. if (get_option(packet, dhcp_options[i].code)) {
  170. num_options++;
  171. if (dhcp_options[i].code == DHCP_SUBNET)
  172. num_options++; /* for mton */
  173. }
  174. }
  175. if (packet->siaddr_nip)
  176. num_options++;
  177. temp = get_option(packet, DHCP_OPTION_OVERLOAD);
  178. if (temp)
  179. over = *temp;
  180. if (!(over & FILE_FIELD) && packet->file[0])
  181. num_options++;
  182. if (!(over & SNAME_FIELD) && packet->sname[0])
  183. num_options++;
  184. }
  185. curr = envp = xzalloc(sizeof(char *) * (num_options + 3));
  186. *curr = xasprintf("interface=%s", client_config.interface);
  187. putenv(*curr++);
  188. if (packet == NULL)
  189. return envp;
  190. *curr = xmalloc(sizeof("ip=255.255.255.255"));
  191. sprint_nip(*curr, "ip=", (uint8_t *) &packet->yiaddr);
  192. putenv(*curr++);
  193. opt_name = dhcp_option_strings;
  194. i = 0;
  195. while (*opt_name) {
  196. temp = get_option(packet, dhcp_options[i].code);
  197. if (!temp)
  198. goto next;
  199. *curr = xmalloc_optname_optval(temp, &dhcp_options[i], opt_name);
  200. putenv(*curr++);
  201. /* Fill in a subnet bits option for things like /24 */
  202. if (dhcp_options[i].code == DHCP_SUBNET) {
  203. uint32_t subnet;
  204. move_from_unaligned32(subnet, temp);
  205. *curr = xasprintf("mask=%d", mton(subnet));
  206. putenv(*curr++);
  207. }
  208. next:
  209. opt_name += strlen(opt_name) + 1;
  210. i++;
  211. }
  212. if (packet->siaddr_nip) {
  213. *curr = xmalloc(sizeof("siaddr=255.255.255.255"));
  214. sprint_nip(*curr, "siaddr=", (uint8_t *) &packet->siaddr_nip);
  215. putenv(*curr++);
  216. }
  217. if (!(over & FILE_FIELD) && packet->file[0]) {
  218. /* watch out for invalid packets */
  219. packet->file[sizeof(packet->file) - 1] = '\0';
  220. *curr = xasprintf("boot_file=%s", packet->file);
  221. putenv(*curr++);
  222. }
  223. if (!(over & SNAME_FIELD) && packet->sname[0]) {
  224. /* watch out for invalid packets */
  225. packet->sname[sizeof(packet->sname) - 1] = '\0';
  226. *curr = xasprintf("sname=%s", packet->sname);
  227. putenv(*curr++);
  228. }
  229. return envp;
  230. }
  231. /* Call a script with a par file and env vars */
  232. void FAST_FUNC udhcp_run_script(struct dhcp_packet *packet, const char *name)
  233. {
  234. char **envp, **curr;
  235. char *argv[3];
  236. if (client_config.script == NULL)
  237. return;
  238. envp = fill_envp(packet);
  239. /* call script */
  240. log1("Executing %s", client_config.script);
  241. argv[0] = (char*) client_config.script;
  242. argv[1] = (char*) name;
  243. argv[2] = NULL;
  244. wait4pid(spawn(argv));
  245. for (curr = envp; *curr; curr++) {
  246. log2(" %s", *curr);
  247. bb_unsetenv(*curr);
  248. free(*curr);
  249. }
  250. free(envp);
  251. }