1 /* vi: set sw=4 ts=4: */
4 * Functions to call the DHCP client notification scripts
6 * Russ Dill <Russ.Dill@asu.edu> July 2001
8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
16 /* get a rough idea of how long an option will be (rounding up...) */
17 static const uint8_t max_option_length
[] = {
18 [OPTION_IP
] = sizeof("255.255.255.255 "),
19 [OPTION_IP_PAIR
] = sizeof("255.255.255.255 ") * 2,
21 #if ENABLE_FEATURE_UDHCP_RFC3397
24 [OPTION_BOOLEAN
] = sizeof("yes "),
25 [OPTION_U8
] = sizeof("255 "),
26 [OPTION_U16
] = sizeof("65535 "),
27 [OPTION_S16
] = sizeof("-32768 "),
28 [OPTION_U32
] = sizeof("4294967295 "),
29 [OPTION_S32
] = sizeof("-2147483684 "),
33 static inline int upper_length(int length
, int opt_index
)
35 return max_option_length
[opt_index
] *
36 (length
/ dhcp_option_lengths
[opt_index
]);
40 static int sprintip(char *dest
, const char *pre
, const uint8_t *ip
)
42 return sprintf(dest
, "%s%d.%d.%d.%d", pre
, ip
[0], ip
[1], ip
[2], ip
[3]);
46 /* really simple implementation, just count the bits */
47 static int mton(uint32_t mask
)
50 mask
= ntohl(mask
); /* 111110000-like bit pattern */
59 /* Allocate and fill with the text of option 'option'. */
60 static char *alloc_fill_opts(uint8_t *option
, const struct dhcp_option
*type_p
, const char *opt_name
)
62 int len
, type
, optlen
;
69 len
= option
[OPT_LEN
- 2];
70 type
= type_p
->flags
& TYPE_MASK
;
71 optlen
= dhcp_option_lengths
[type
];
73 dest
= ret
= xmalloc(upper_length(len
, type
) + strlen(opt_name
) + 2);
74 dest
+= sprintf(ret
, "%s=", opt_name
);
79 dest
+= sprintip(dest
, "", option
);
83 case OPTION_IP
: /* Works regardless of host byte order. */
84 dest
+= sprintip(dest
, "", option
);
87 dest
+= sprintf(dest
, *option
? "yes" : "no");
90 dest
+= sprintf(dest
, "%u", *option
);
93 move_from_unaligned16(val_u16
, option
);
94 dest
+= sprintf(dest
, "%u", ntohs(val_u16
));
97 move_from_unaligned16(val_s16
, option
);
98 dest
+= sprintf(dest
, "%d", ntohs(val_s16
));
101 move_from_unaligned32(val_u32
, option
);
102 dest
+= sprintf(dest
, "%lu", (unsigned long) ntohl(val_u32
));
105 move_from_unaligned32(val_s32
, option
);
106 dest
+= sprintf(dest
, "%ld", (long) ntohl(val_s32
));
109 memcpy(dest
, option
, len
);
111 return ret
; /* Short circuit this case */
112 #if ENABLE_FEATURE_UDHCP_RFC3397
114 /* unpack option into dest; use ret for prefix (i.e., "optname=") */
115 dest
= dname_dec(option
, len
, ret
);
124 dest
+= sprintf(dest
, " ");
130 /* put all the parameters into an environment */
131 static char **fill_envp(struct dhcpMessage
*packet
)
136 const char *opt_name
;
141 for (i
= 0; dhcp_options
[i
].code
; i
++) {
142 if (get_option(packet
, dhcp_options
[i
].code
)) {
144 if (dhcp_options
[i
].code
== DHCP_SUBNET
)
145 num_options
++; /* for mton */
150 temp
= get_option(packet
, DHCP_OPTION_OVERLOAD
);
153 if (!(over
& FILE_FIELD
) && packet
->file
[0])
155 if (!(over
& SNAME_FIELD
) && packet
->sname
[0])
159 curr
= envp
= xzalloc(sizeof(char *) * (num_options
+ 3));
160 *curr
= xasprintf("interface=%s", client_config
.interface
);
166 *curr
= xmalloc(sizeof("ip=255.255.255.255"));
167 sprintip(*curr
, "ip=", (uint8_t *) &packet
->yiaddr
);
170 opt_name
= dhcp_option_strings
;
173 temp
= get_option(packet
, dhcp_options
[i
].code
);
176 *curr
= alloc_fill_opts(temp
, &dhcp_options
[i
], opt_name
);
179 /* Fill in a subnet bits option for things like /24 */
180 if (dhcp_options
[i
].code
== DHCP_SUBNET
) {
182 move_from_unaligned32(subnet
, temp
);
183 *curr
= xasprintf("mask=%d", mton(subnet
));
187 opt_name
+= strlen(opt_name
) + 1;
190 if (packet
->siaddr
) {
191 *curr
= xmalloc(sizeof("siaddr=255.255.255.255"));
192 sprintip(*curr
, "siaddr=", (uint8_t *) &packet
->siaddr
);
195 if (!(over
& FILE_FIELD
) && packet
->file
[0]) {
196 /* watch out for invalid packets */
197 packet
->file
[sizeof(packet
->file
) - 1] = '\0';
198 *curr
= xasprintf("boot_file=%s", packet
->file
);
201 if (!(over
& SNAME_FIELD
) && packet
->sname
[0]) {
202 /* watch out for invalid packets */
203 packet
->sname
[sizeof(packet
->sname
) - 1] = '\0';
204 *curr
= xasprintf("sname=%s", packet
->sname
);
211 /* Call a script with a par file and env vars */
212 void FAST_FUNC
udhcp_run_script(struct dhcpMessage
*packet
, const char *name
)
217 if (client_config
.script
== NULL
)
220 DEBUG("vfork'ing and exec'ing %s", client_config
.script
);
222 envp
= fill_envp(packet
);
225 argv
[0] = (char*) client_config
.script
;
226 argv
[1] = (char*) name
;
228 wait4pid(spawn(argv
));
230 for (curr
= envp
; *curr
; curr
++) {