00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <string.h>
00023 #include <unistd.h>
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include <sys/socket.h>
00027 #include <netinet/in.h>
00028 #include <arpa/inet.h>
00029 #include <sys/types.h>
00030 #include <sys/wait.h>
00031 #include <errno.h>
00032
00033 #include "options.h"
00034 #include "dhcpd.h"
00035 #include "dhcpc.h"
00036 #include "packet.h"
00037 #include "options.h"
00038 #include "debug.h"
00039
00040
00041 static int max_option_length[] = {
00042 [OPTION_IP] = sizeof("255.255.255.255 "),
00043 [OPTION_IP_PAIR] = sizeof("255.255.255.255 ") * 2,
00044 [OPTION_STRING] = 1,
00045 [OPTION_BOOLEAN] = sizeof("yes "),
00046 [OPTION_U8] = sizeof("255 "),
00047 [OPTION_U16] = sizeof("65535 "),
00048 [OPTION_S16] = sizeof("-32768 "),
00049 [OPTION_U32] = sizeof("4294967295 "),
00050 [OPTION_S32] = sizeof("-2147483684 "),
00051 };
00052
00053
00054 static int upper_length(int length, struct dhcp_option *option)
00055 {
00056 return max_option_length[option->flags & TYPE_MASK] *
00057 (length / option_lengths[option->flags & TYPE_MASK]);
00058 }
00059
00060
00061 static int sprintip(char *dest, char *pre, unsigned char *ip) {
00062 return sprintf(dest, "%s%d.%d.%d.%d ", pre, ip[0], ip[1], ip[2], ip[3]);
00063 }
00064
00065
00066
00067 static void fill_options(char *dest, unsigned char *option, struct dhcp_option *type_p)
00068 {
00069 int type, optlen;
00070 u_int16_t val_u16;
00071 int16_t val_s16;
00072 u_int32_t val_u32;
00073 int32_t val_s32;
00074 int len = option[OPT_LEN - 2];
00075
00076 dest += sprintf(dest, "%s=", type_p->name);
00077
00078 type = type_p->flags & TYPE_MASK;
00079 optlen = option_lengths[type];
00080 for(;;) {
00081 switch (type) {
00082 case OPTION_IP_PAIR:
00083 dest += sprintip(dest, "", option);
00084 *(dest++) = '/';
00085 option += 4;
00086 optlen = 4;
00087 case OPTION_IP:
00088 dest += sprintip(dest, "", option);
00089 break;
00090 case OPTION_BOOLEAN:
00091 dest += sprintf(dest, *option ? "yes " : "no ");
00092 break;
00093 case OPTION_U8:
00094 dest += sprintf(dest, "%u ", *option);
00095 break;
00096 case OPTION_U16:
00097 memcpy(&val_u16, option, 2);
00098 dest += sprintf(dest, "%u ", ntohs(val_u16));
00099 break;
00100 case OPTION_S16:
00101 memcpy(&val_s16, option, 2);
00102 dest += sprintf(dest, "%d ", ntohs(val_s16));
00103 break;
00104 case OPTION_U32:
00105 memcpy(&val_u32, option, 4);
00106 dest += sprintf(dest, "%lu ", (unsigned long) ntohl(val_u32));
00107 break;
00108 case OPTION_S32:
00109 memcpy(&val_s32, option, 4);
00110 dest += sprintf(dest, "%ld ", (long) ntohl(val_s32));
00111 break;
00112 case OPTION_STRING:
00113 memcpy(dest, option, len);
00114 dest[len] = '\0';
00115 return;
00116 }
00117 option += optlen;
00118 len -= optlen;
00119 if (len <= 0) break;
00120 }
00121 }
00122
00123
00124 static char *find_env(const char *prefix, char *defaultstr)
00125 {
00126 extern char **environ;
00127 char **ptr;
00128 const int len = strlen(prefix);
00129
00130 for (ptr = environ; *ptr != NULL; ptr++) {
00131 if (strncmp(prefix, *ptr, len) == 0)
00132 return *ptr;
00133 }
00134 return defaultstr;
00135 }
00136
00137
00138
00139 static char **fill_envp(struct dhcpMessage *packet)
00140 {
00141 int num_options = 0;
00142 int i, j;
00143 char **envp;
00144 unsigned char *temp;
00145 char over = 0;
00146
00147 if (packet == NULL)
00148 num_options = 0;
00149 else {
00150 for (i = 0; options[i].code; i++)
00151 if (get_option(packet, options[i].code))
00152 num_options++;
00153 if (packet->siaddr) num_options++;
00154 if ((temp = get_option(packet, DHCP_OPTION_OVER)))
00155 over = *temp;
00156 if (!(over & FILE_FIELD) && packet->file[0]) num_options++;
00157 if (!(over & SNAME_FIELD) && packet->sname[0]) num_options++;
00158 }
00159
00160 envp = xmalloc((num_options + 5) * sizeof(char *));
00161 envp[0] = xmalloc(sizeof("interface=") + strlen(client_config.interface));
00162 sprintf(envp[0], "interface=%s", client_config.interface);
00163 envp[1] = find_env("PATH", "PATH=/bin:/usr/bin:/sbin:/usr/sbin");
00164 envp[2] = find_env("HOME", "HOME=/");
00165
00166 if (packet == NULL) {
00167 envp[3] = NULL;
00168 return envp;
00169 }
00170
00171 envp[3] = xmalloc(sizeof("ip=255.255.255.255"));
00172 sprintip(envp[3], "ip=", (unsigned char *) &packet->yiaddr);
00173 for (i = 0, j = 4; options[i].code; i++) {
00174 if ((temp = get_option(packet, options[i].code))) {
00175 envp[j] = xmalloc(upper_length(temp[OPT_LEN - 2], &options[i]) + strlen(options[i].name) + 2);
00176 fill_options(envp[j], temp, &options[i]);
00177 j++;
00178 }
00179 }
00180 if (packet->siaddr) {
00181 envp[j] = xmalloc(sizeof("siaddr=255.255.255.255"));
00182 sprintip(envp[j++], "siaddr=", (unsigned char *) &packet->siaddr);
00183 }
00184 if (!(over & FILE_FIELD) && packet->file[0]) {
00185
00186 packet->file[sizeof(packet->file) - 1] = '\0';
00187 envp[j] = xmalloc(sizeof("boot_file=") + strlen(packet->file));
00188 sprintf(envp[j++], "boot_file=%s", packet->file);
00189 }
00190 if (!(over & SNAME_FIELD) && packet->sname[0]) {
00191
00192 packet->sname[sizeof(packet->sname) - 1] = '\0';
00193 envp[j] = xmalloc(sizeof("sname=") + strlen(packet->sname));
00194 sprintf(envp[j++], "sname=%s", packet->sname);
00195 }
00196 envp[j] = NULL;
00197 return envp;
00198 }
00199
00200
00201
00202 void run_script(struct dhcpMessage *packet, const char *name)
00203 {
00204 int pid;
00205 char **envp;
00206
00207 if (client_config.script == NULL)
00208 return;
00209
00210
00211 pid = fork();
00212 if (pid) {
00213 waitpid(pid, NULL, 0);
00214 return;
00215 } else if (pid == 0) {
00216 envp = fill_envp(packet);
00217
00218
00219
00220
00221 DEBUG(LOG_INFO, "execle'ing %s", client_config.script);
00222 execle(client_config.script, client_config.script,
00223 name, NULL, envp);
00224 LOG(LOG_ERR, "script %s failed: %s",
00225 client_config.script, strerror(errno));
00226 exit(1);
00227 }
00228 }