Date: Fri, 13 Oct 2000 09:17:42 +0200 From: Danny Braniss <danny@cs.huji.ac.il> To: freebsd-hackers@freebsd.org Subject: bootp/diskless/kenv Message-ID: <E13jz66-0001aJ-00@sexta.cs.huji.ac.il>
next in thread | raw e-mail | index | archive | help
Im including a modified lib/libstand/bootp.c for evaluation. It has: o- fixes for evaluation of netmask - only if not supplied. o- puts in the environment the dhcp stuff it does not - yet -: do any good check for string overflow. check for environment buffer overflow - haven't found out how to do it yet since kenv can now be used early on the diskless boot process, i think it should be placed in /bin and staticaly linked. danny --------- cut here -------- /* $NetBSD: bootp.c,v 1.14 1998/02/16 11:10:54 drochner Exp $ */ /* * Copyright (c) 1992 Regents of the University of California. * All rights reserved. * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and * contributed to Berkeley. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Lawrence Berkeley Laboratory and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) Header: bootp.c,v 1.4 93/09/11 03:13:51 leres Exp (LBL) * $FreeBSD: src/lib/libstand/bootp.c,v 1.1.1.1.6.1 2000/09/10 02:52:19 ps Exp $ */ #include <sys/types.h> #include <netinet/in.h> #include <netinet/in_systm.h> #include <string.h> /* #define BOOTP_DEBUGxx */ #define SUPPORT_DHCP /*#define BOOTP_DEBUG /* danny */ #if defined(BOOTP_DEBUG) || defined(BOOTP_DEBUGxx) int debug=1; #endif #include "stand.h" #include "net.h" #include "netif.h" #include "bootp.h" struct in_addr servip; static n_long smask; static time_t bot; static char vm_rfc1048[4] = VM_RFC1048; #ifdef BOOTP_VEND_CMU static char vm_cmu[4] = VM_CMU; #endif /* Local forwards */ static ssize_t bootpsend(struct iodesc *, void *, size_t); static ssize_t bootprecv(struct iodesc *, void *, size_t, time_t); static int vend_rfc1048(u_char *, u_int); #ifdef BOOTP_VEND_CMU static void vend_cmu(u_char *); #endif #ifdef SUPPORT_DHCP static char expected_dhcpmsgtype = -1, dhcp_ok; struct in_addr dhcp_serverip; #endif static void setenv_dhcp(u_char *cp, u_int len); /* Fetch required bootp infomation */ void bootp(sock, flag) int sock; int flag; { struct iodesc *d; register struct bootp *bp; struct { u_char header[HEADER_SIZE]; struct bootp wbootp; } wbuf; struct { u_char header[HEADER_SIZE]; struct bootp rbootp; } rbuf; int j; #ifdef BOOTP_DEBUGxx if (debug) printf("bootp: socket=%d\n", sock); #endif if (!bot) bot = getsecs(); if (!(d = socktodesc(sock))) { printf("bootp: bad socket. %d\n", sock); return; } #ifdef BOOTP_DEBUGxx if (debug) printf("bootp: d=%lx\n", (long)d); #endif bp = &wbuf.wbootp; bzero(bp, sizeof(*bp)); bp->bp_op = BOOTREQUEST; bp->bp_htype = 1; /* 10Mb Ethernet (48 bits) */ bp->bp_hlen = 6; bp->bp_xid = htonl(d->xid); MACPY(d->myea, bp->bp_chaddr); strncpy(bp->bp_file, bootfile, sizeof(bp->bp_file)); bcopy(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)); j = sizeof(vm_rfc1048); #ifdef SUPPORT_DHCP bp->bp_vend[j++] = TAG_DHCP_MSGTYPE; bp->bp_vend[j++] = 1; bp->bp_vend[j++] = DHCPDISCOVER; #if 0 /* * We send an RFC 1533 "Maximum DHCP Message Size" option, saying we * can do 1200 bytes. If we don't ISC DHCPD will limit the answer to * 64 bytes and root/swap and similar will be dropped. */ bp->bp_vend[j++] = TAG_MAXSIZE; bp->bp_vend[j++] = 2; bp->bp_vend[j++] = 1200 / 256; bp->bp_vend[j++] = 1200 % 256; #endif /* * If we are booting from PXE, we want to send the string * 'PXEClient' to the DHCP server so you have the option of * only responding to PXE aware dhcp requests. */ if (flag & BOOTP_PXE) { char *classid; int len; bp->bp_vend[j++] = TAG_CLASSID; #if 0 bp->bp_vend[j++] = 9; bcopy("PXEClient", &bp->bp_vend[j], 9); j += 9; #else classid = "FreeBSDc"; bp->bp_vend[j++] = len = strlen(classid); bcopy(classid, &bp->bp_vend[j], len); j += len; #endif } expected_dhcpmsgtype = DHCPOFFER; dhcp_ok = 0; #endif bp->bp_vend[j++] = TAG_END; d->myip.s_addr = INADDR_ANY; d->myport = htons(IPPORT_BOOTPC); d->destip.s_addr = INADDR_BROADCAST; d->destport = htons(IPPORT_BOOTPS); if(sendrecv(d, bootpsend, bp, sizeof(*bp), bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp)) == -1) { printf("bootp: no reply\n"); return; } #ifdef SUPPORT_DHCP if(dhcp_ok) { u_int32_t leasetime; int j; j = 6; bp->bp_vend[j++] = DHCPREQUEST; bp->bp_vend[j++] = TAG_REQ_ADDR; bp->bp_vend[j++] = 4; bcopy(&rbuf.rbootp.bp_yiaddr, &bp->bp_vend[j], 4); j += 4; bp->bp_vend[j++] = TAG_SERVERID; bp->bp_vend[j++] = 4; bcopy(&dhcp_serverip.s_addr, &bp->bp_vend[j], 4); j += 4; bp->bp_vend[j++] = TAG_LEASETIME; bp->bp_vend[j++] = 4; leasetime = htonl(300); bcopy(&leasetime, &bp->bp_vend[j], 4); j += 4; if (flag & BOOTP_PXE) { #if 0 bp->bp_vend[j++] = TAG_CLASSID; bp->bp_vend[j++] = 9; bcopy("PXEClient", &bp->bp_vend[j], 9); j += 9; #else char *classid; int len; classid = "FreeBSDc"; bp->bp_vend[j++] = len = strlen(classid); bcopy(classid, &bp->bp_vend[j], len); j += len; #endif } bp->bp_vend[j++] = TAG_END; expected_dhcpmsgtype = DHCPACK; if(sendrecv(d, bootpsend, bp, sizeof(*bp), bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp)) == -1) { printf("DHCPREQUEST failed\n"); return; } } #endif /* SUPPORT_DHCP */ myip = d->myip = rbuf.rbootp.bp_yiaddr; servip = rbuf.rbootp.bp_siaddr; if(rootip.s_addr == INADDR_ANY) rootip = servip; bcopy(rbuf.rbootp.bp_file, bootfile, sizeof(bootfile)); bootfile[sizeof(bootfile) - 1] = '\0'; if(smask == 0) { if(IN_CLASSA(ntohl(myip.s_addr))) smask = htonl(IN_CLASSA_NET); else if(IN_CLASSB(ntohl(myip.s_addr))) smask = htonl(IN_CLASSB_NET); else smask = htonl(IN_CLASSC_NET); } /* Get subnet (or natural net) mask */ netmask = smask; /* We need a gateway if root is on a different net */ if (!SAMENET(myip, rootip, netmask)) { #ifdef BOOTP_DEBUG if (debug) printf("need gateway for root ip\n"); #endif } /* Toss gateway if on a different net */ if (!SAMENET(myip, gateip, netmask)) { printf("gateway ip (%s) is bad!\n", inet_ntoa(gateip)); gateip.s_addr = 0; } /* Bump xid so next request will be unique. */ ++d->xid; } /* Transmit a bootp request */ static ssize_t bootpsend(d, pkt, len) register struct iodesc *d; register void *pkt; register size_t len; { register struct bootp *bp; #ifdef BOOTP_DEBUGxx if (debug) printf("bootpsend: d=%lx called.\n", (long)d); #endif bp = pkt; bp->bp_secs = htons((u_short)(getsecs() - bot)); #ifdef BOOTP_DEBUGxx if (debug) printf("bootpsend: calling sendudp\n"); #endif return (sendudp(d, pkt, len)); } static ssize_t bootprecv(d, pkt, len, tleft) register struct iodesc *d; register void *pkt; register size_t len; time_t tleft; { register ssize_t n; register struct bootp *bp; #ifdef BOOTP_DEBUGxx if (debug) printf("bootp_recvoffer: called\n"); #endif n = readudp(d, pkt, len, tleft); if (n == -1 || n < sizeof(struct bootp) - BOOTP_VENDSIZE) goto bad; bp = (struct bootp *)pkt; #ifdef BOOTP_DEBUGxx if (debug) printf("bootprecv: checked. bp = 0x%lx, n = %d\n", (long)bp, (int)n); #endif if (bp->bp_xid != htonl(d->xid)) { #ifdef BOOTP_DEBUG if (debug) { printf("bootprecv: expected xid 0x%lx, got 0x%x\n", d->xid, ntohl(bp->bp_xid)); } #endif goto bad; } #ifdef BOOTP_DEBUGxx if (debug) printf("bootprecv: got one!\n"); #endif /* Suck out vendor info */ if (bcmp(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)) == 0) { if(vend_rfc1048(bp->bp_vend, sizeof(bp->bp_vend)) != 0) goto bad; } #ifdef BOOTP_VEND_CMU else if (bcmp(vm_cmu, bp->bp_vend, sizeof(vm_cmu)) == 0) vend_cmu(bp->bp_vend); #endif else printf("bootprecv: unknown vendor 0x%lx\n", (long)bp->bp_vend); return(n); bad: errno = 0; return (-1); } static int vend_rfc1048(cp, len) register u_char *cp; u_int len; { register u_char *ep; register int size; register u_char tag; setenv_dhcp(cp, len); #ifdef BOOTP_DEBUG if (debug) printf("vend_rfc1048 bootp info. len=%d\n", len); #endif ep = cp + len; /* Step over magic cookie */ cp += sizeof(int); while (cp < ep) { tag = *cp++; size = *cp++; switch(tag) { case 0: continue; case TAG_END: break; case TAG_SUBNET_MASK: bcopy(cp, &smask, sizeof(smask)); break; case TAG_GATEWAY: bcopy(cp, &gateip.s_addr, sizeof(gateip.s_addr)); break; case TAG_SWAPSERVER: /* let it override bp_siaddr */ bcopy(cp, &rootip.s_addr, sizeof(swapip.s_addr)); break; case TAG_ROOTPATH: strncpy(rootpath, (char *)cp, sizeof(rootpath)); rootpath[size] = '\0'; break; case TAG_HOSTNAME: strncpy(hostname, (char *)cp, sizeof(hostname)); hostname[size] = '\0'; break; #ifdef SUPPORT_DHCP case TAG_DHCP_MSGTYPE: if(*cp != expected_dhcpmsgtype) return(-1); dhcp_ok = 1; break; case TAG_SERVERID: bcopy(cp, &dhcp_serverip.s_addr, sizeof(dhcp_serverip.s_addr)); break; #endif #ifdef BOOTP_DEBUG default: if (debug) printf("unknown tag:%d size=%d\n", tag, size); #endif } cp += size; } return(0); } #ifdef BOOTP_VEND_CMU static void vend_cmu(cp) u_char *cp; { register struct cmu_vend *vp; #ifdef BOOTP_DEBUGxx if (debug) printf("vend_cmu bootp info.\n"); #endif vp = (struct cmu_vend *)cp; if (vp->v_smask.s_addr != 0) { smask = vp->v_smask.s_addr; } if (vp->v_dgate.s_addr != 0) { gateip = vp->v_dgate; } } #endif /* | DHCP Option names, formats and codes, from RFC1533. */ #define __IP 1 #define __TXT 2 #define __8 3 #define __16 4 #define __32 5 #define __VE 6 struct dhcp_opt { int tag; int fmt; char *desc; } dhcp_opt[] = { #define _DHCP(num, fmt, dsc) {num, fmt, dsc} _DHCP(1, __IP, "subnet-mask"), _DHCP(2, __32, "time-offset"), _DHCP(3, __IP, "routers"), _DHCP(4, __IP, "time-servers"), _DHCP(5, __IP, "ien116-name-servers"), _DHCP(6, __IP, "domain-name-servers"), _DHCP(7, __IP, "log-servers"), _DHCP(8, __IP, "cookie-servers"), _DHCP(9, __IP, "lpr-servers"), _DHCP(10, __IP, "impress-servers"), _DHCP(11, __IP, "resource-location-servers"), _DHCP(12, __TXT, "host-name"), _DHCP(13, __16, "boot-size"), _DHCP(14, __TXT, "merit-dump"), _DHCP(15, __TXT, "domain-name"), _DHCP(16, __IP, "swap-server"), _DHCP(17, __TXT, "root-path"), _DHCP(18, __TXT, "extensions-path"), _DHCP(19, __8, "ip-forwarding"), _DHCP(20, __8, "non-local-source-routing"), _DHCP(21, __IP, "policy-filter"), _DHCP(22, __16, "max-dgram-reassembly"), _DHCP(23, __8, "default-ip-ttl"), _DHCP(24, __32, "path-mtu-aging-timeout"), _DHCP(25, __16, "path-mtu-plateau-table"), _DHCP(26, __16, "interface-mtu"), _DHCP(27, __8, "all-subnets-local"), _DHCP(28, __IP, "broadcast-address"), _DHCP(29, __8, "perform-mask-discovery"), _DHCP(30, __8, "mask-supplier"), _DHCP(31, __8, "router-discovery"), _DHCP(32, __IP, "router-solicitation-address"), _DHCP(33, __IP, "static-routes"), _DHCP(34, __8, "trailer-encapsulation"), _DHCP(35, __32, "arp-cache-timeout"), _DHCP(36, __8, "ieee802-3-encapsulation"), _DHCP(37, __8, "default-tcp-ttl"), _DHCP(38, __32, "tcp-keepalive-interval"), _DHCP(39, __8, "tcp-keepalive-garbage"), _DHCP(40, __TXT, "nis-domain"), _DHCP(41, __IP, "nis-servers"), _DHCP(42, __IP, "ntp-servers"), _DHCP(43, __VE, "vendor-encapsulated-options"), _DHCP(44, __IP, "netbios-name-servers"), _DHCP(45, __IP, "netbios-dd-server"), _DHCP(46, __8, "netbios-node-type"), _DHCP(47, __TXT, "netbios-scope"), _DHCP(48, __IP, "font-servers"), _DHCP(49, __IP, "x-display-manager"), _DHCP(50, __IP, "dhcp-requested-address"), _DHCP(51, __32, "dhcp-lease-time"), _DHCP(52, __8, "dhcp-option-overload"), _DHCP(53, __8, "dhcp-message-type"), _DHCP(54, __IP, "dhcp-server-identifier"), _DHCP(55, __8, "dhcp-parameter-request-list"), _DHCP(56, __TXT, "dhcp-message"), _DHCP(57, __16, "dhcp-max-message-size"), _DHCP(58, __32, "dhcp-renewal-time"), _DHCP(59, __32, "dhcp-rebinding-time"), _DHCP(60, __TXT, "vendor-class-identifier"), _DHCP(61, __TXT, "dhcp-client-identifier"), _DHCP(64, __TXT, "nisplus-domain"), _DHCP(65, __IP, "nisplus-servers"), _DHCP(66, __TXT, "tftp-server-name"), _DHCP(67, __TXT, "bootfile-name"), _DHCP(68, __IP, "mobile-ip-home-agent"), _DHCP(69, __IP, "smtp-server"), _DHCP(70, __IP, "pop-server"), _DHCP(71, __IP, "nntp-server"), _DHCP(72, __IP, "www-server"), _DHCP(73, __IP, "finger-server"), _DHCP(74, __IP, "irc-server"), _DHCP(75, __IP, "streettalk-server"), _DHCP(76, __IP, "streettalk-directory-assistance-server"), _DHCP(77, __TXT, "user-class"), _DHCP(85, __IP, "nds-servers"), _DHCP(86, __TXT, "nds-tree-name"), _DHCP(87, __TXT, "nds-context"), _DHCP(210, __TXT, "authenticate"), {0} }; struct dhcp_opt optdef = _DHCP(0, __TXT, "option-%d"); #undef _DHCP static void setenv_dhcp(u_char *cp, u_int len) { u_char *ep; int size; u_char tag; char env[128], val[512], *vp, tags[512], *tp; struct in_addr in_ip; ep = cp + len; cp += sizeof(vm_rfc1048); /* hopefully this was checked? */ tp = tags; while(cp < ep) { struct dhcp_opt *op; tag = *cp++; size = *cp++; if(tag == TAG_END) break; if(tag == 0) continue; for(op = dhcp_opt; op->tag; op++) if(op->tag >= tag) break; if(op->tag != tag) op = &optdef; vp = val; switch(op->fmt) { case __VE: /* vendor specific */ while(size-- > 0) { sprintf(vp, "%02x", *cp++); vp += 2; } break; case __IP: /* ip address */ while(size > 0) { if(vp != val) *vp++ = ','; bcopy(cp, &in_ip.s_addr, sizeof(in_ip.s_addr)); sprintf(vp, "%s", inet_ntoa(in_ip)); vp += strlen(vp); size -= 4; cp += 4; } break; case __TXT: bcopy(cp, val, size); val[size] = 0; cp += size; break; case __8: case __16: case __32: while(size > 0) { int n = 0; if(vp != val) *vp++ = ','; switch(op->fmt) { case __8: sprintf(vp, "%02x", cp[0]); n = 1; break; case __16: sprintf(vp, "%02x%02x", cp[0], cp[1]); n = 2; break; case __32: sprintf(vp, "%02x%02x%02x%02x", cp[0], cp[1], cp[2], cp[3]); n = 4; break; } cp += n; size -= n; vp += strlen(vp); } break; } sprintf(tp, "%03d:", tag); tp += strlen(tp); if(op == &optdef) sprintf(env, "dhcp.option-%d", tag); else sprintf(env, "dhcp.%s", op->desc); #ifdef BOOTP_DEBUG if(debug) printf("%s %s\n", env, val); #endif setenv(env, val, 1); } if(tp != tags) { #ifdef BOOTP_DEBUG if(debug) printf("%s %s\n", "dhcp.tags", tags); #endif setenv("dhcp.tags", tags, 1); } } To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-hackers" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?E13jz66-0001aJ-00>