script.c

Go to the documentation of this file.
00001 /* script.c
00002  *
00003  * Functions to call the DHCP client notification scripts 
00004  *
00005  * Russ Dill <Russ.Dill@asu.edu> July 2001
00006  *
00007  * This program is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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 /* get a rough idea of how long an option will be (rounding up...) */
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 /* Fill dest with the text of option 'option'. */
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: /* Works regardless of host byte order. */
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;  /* Short circuit this case */
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 /* put all the paramaters into an environment */
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                 /* watch out for invalid packets */
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                 /* watch out for invalid packets */
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 /* Call a script with a par file and env vars */
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         /* call script */
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                 /* close fd's? */
00219                 
00220                 /* exec script */
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 }

Generated on Tue Jan 15 12:24:45 2008 for Dynamics 0.8.1.Dynamo.1 by  doxygen 1.5.1