16751Swpaul/* 26751Swpaul 38857SrgrimesThis code is not copyright, and is placed in the public domain. Feel free to 46751Swpauluse and modify. Please send modifications and/or suggestions + bug fixes to 56751Swpaul 66751Swpaul Klas Heggemann <klas@nada.kth.se> 76751Swpaul 86751Swpaul*/ 96751Swpaul 1029102Scharnier#ifndef lint 1129102Scharnierstatic const char rcsid[] = 1250479Speter "$FreeBSD: stable/10/usr.sbin/bootparamd/bootparamd/bootparamd.c 320780 2017-07-07 15:09:08Z asomers $"; 1329102Scharnier#endif /* not lint */ 146751Swpaul 15137675Sbz#ifdef YP 166751Swpaul#include <rpc/rpc.h> 179718Swpaul#include <rpcsvc/yp_prot.h> 189718Swpaul#include <rpcsvc/ypclnt.h> 19137675Sbz#endif 206751Swpaul#include "bootparam_prot.h" 2129102Scharnier#include <ctype.h> 2229102Scharnier#include <err.h> 2329102Scharnier#include <netdb.h> 246751Swpaul#include <stdio.h> 2522954Smpp#include <string.h> 2629102Scharnier#include <syslog.h> 2729102Scharnier#include <unistd.h> 286751Swpaul#include <sys/types.h> 296751Swpaul#include <sys/socket.h> 306751Swpaulextern int debug, dolog; 31175823Srinkextern in_addr_t route_addr; 326751Swpaulextern char *bootpfile; 336751Swpaul 346751Swpaul#define MAXLEN 800 356751Swpaul 366751Swpaulstruct hostent *he; 376751Swpaulstatic char buffer[MAXLEN]; 386751Swpaulstatic char hostname[MAX_MACHINE_NAME]; 396751Swpaulstatic char askname[MAX_MACHINE_NAME]; 406751Swpaulstatic char path[MAX_PATH_LEN]; 416751Swpaulstatic char domain_name[MAX_MACHINE_NAME]; 426751Swpaul 43173412Skevloint getthefile(char *, char *, char *, int); 44173412Skevloint checkhost(char *, char *, int); 458857Srgrimes 466751Swpaulbp_whoami_res * 47121554Speterbootparamproc_whoami_1_svc(whoami, req) 486751Swpaulbp_whoami_arg *whoami; 49121554Speterstruct svc_req *req; 506751Swpaul{ 51175823Srink in_addr_t haddr; 526751Swpaul static bp_whoami_res res; 538857Srgrimes if (debug) 548857Srgrimes fprintf(stderr,"whoami got question for %d.%d.%d.%d\n", 556751Swpaul 255 & whoami->client_address.bp_address_u.ip_addr.net, 566751Swpaul 255 & whoami->client_address.bp_address_u.ip_addr.host, 576751Swpaul 255 & whoami->client_address.bp_address_u.ip_addr.lh, 586751Swpaul 255 & whoami->client_address.bp_address_u.ip_addr.impno); 598857Srgrimes if (dolog) 608857Srgrimes syslog(LOG_NOTICE, "whoami got question for %d.%d.%d.%d\n", 616751Swpaul 255 & whoami->client_address.bp_address_u.ip_addr.net, 626751Swpaul 255 & whoami->client_address.bp_address_u.ip_addr.host, 636751Swpaul 255 & whoami->client_address.bp_address_u.ip_addr.lh, 646751Swpaul 255 & whoami->client_address.bp_address_u.ip_addr.impno); 656751Swpaul 668857Srgrimes bcopy((char *)&whoami->client_address.bp_address_u.ip_addr, (char *)&haddr, 676751Swpaul sizeof(haddr)); 686751Swpaul he = gethostbyaddr((char *)&haddr,sizeof(haddr),AF_INET); 696751Swpaul if ( ! he ) goto failed; 706751Swpaul 7129102Scharnier if (debug) warnx("this is host %s", he->h_name); 726751Swpaul if (dolog) syslog(LOG_NOTICE,"This is host %s\n", he->h_name); 738857Srgrimes 7430570Sjoerg strncpy(askname, he->h_name, sizeof(askname)); 7530570Sjoerg askname[sizeof(askname)-1] = 0; 7630570Sjoerg 7730570Sjoerg if (checkhost(askname, hostname, sizeof hostname) ) { 786751Swpaul res.client_name = hostname; 796751Swpaul getdomainname(domain_name, MAX_MACHINE_NAME); 806751Swpaul res.domain_name = domain_name; 816751Swpaul 826751Swpaul if ( res.router_address.address_type != IP_ADDR_TYPE ) { 836751Swpaul res.router_address.address_type = IP_ADDR_TYPE; 84175823Srink bcopy( &route_addr, &res.router_address.bp_address_u.ip_addr, sizeof(in_addr_t)); 856751Swpaul } 866751Swpaul if (debug) fprintf(stderr, 878857Srgrimes "Returning %s %s %d.%d.%d.%d\n", 886751Swpaul res.client_name, 896751Swpaul res.domain_name, 906751Swpaul 255 & res.router_address.bp_address_u.ip_addr.net, 916751Swpaul 255 & res.router_address.bp_address_u.ip_addr.host, 926751Swpaul 255 & res.router_address.bp_address_u.ip_addr.lh, 936751Swpaul 255 & res.router_address.bp_address_u.ip_addr.impno); 946751Swpaul if (dolog) syslog(LOG_NOTICE, 958857Srgrimes "Returning %s %s %d.%d.%d.%d\n", 966751Swpaul res.client_name, 976751Swpaul res.domain_name, 986751Swpaul 255 & res.router_address.bp_address_u.ip_addr.net, 996751Swpaul 255 & res.router_address.bp_address_u.ip_addr.host, 1006751Swpaul 255 & res.router_address.bp_address_u.ip_addr.lh, 1016751Swpaul 255 & res.router_address.bp_address_u.ip_addr.impno); 1026751Swpaul 1036751Swpaul return(&res); 1046751Swpaul } 1056751Swpaul failed: 10629102Scharnier if (debug) warnx("whoami failed"); 1076751Swpaul if (dolog) syslog(LOG_NOTICE,"whoami failed\n"); 1086751Swpaul return(NULL); 1096751Swpaul} 1106751Swpaul 1116751Swpaul 1126751Swpaulbp_getfile_res * 113121554Speter bootparamproc_getfile_1_svc(getfile, req) 1146751Swpaulbp_getfile_arg *getfile; 115121554Speterstruct svc_req *req; 1166751Swpaul{ 117229403Sed char *where; 1186751Swpaul static bp_getfile_res res; 1196751Swpaul 1208857Srgrimes if (debug) 12129102Scharnier warnx("getfile got question for \"%s\" and file \"%s\"", 1226751Swpaul getfile->client_name, getfile->file_id); 1236751Swpaul 1248857Srgrimes if (dolog) 1256751Swpaul syslog(LOG_NOTICE,"getfile got question for \"%s\" and file \"%s\"\n", 1266751Swpaul getfile->client_name, getfile->file_id); 1276751Swpaul 1286751Swpaul he = NULL; 1296751Swpaul he = gethostbyname(getfile->client_name); 1306751Swpaul if (! he ) goto failed; 1316751Swpaul 13230570Sjoerg strncpy(askname, he->h_name, sizeof(askname)); 13330570Sjoerg askname[sizeof(askname)-1] = 0; 13430570Sjoerg 13536794Simp if (getthefile(askname, getfile->file_id,buffer,sizeof(buffer))) { 136229403Sed if ( (where = strchr(buffer,':')) ) { 1376751Swpaul /* buffer is re-written to contain the name of the info of file */ 1386751Swpaul strncpy(hostname, buffer, where - buffer); 1396751Swpaul hostname[where - buffer] = '\0'; 1406751Swpaul where++; 1416751Swpaul strcpy(path, where); 1426751Swpaul he = gethostbyname(hostname); 1436751Swpaul if ( !he ) goto failed; 1446751Swpaul bcopy( he->h_addr, &res.server_address.bp_address_u.ip_addr, 4); 1456751Swpaul res.server_name = hostname; 1466751Swpaul res.server_path = path; 1476751Swpaul res.server_address.address_type = IP_ADDR_TYPE; 1486751Swpaul } 1496751Swpaul else { /* special for dump, answer with null strings */ 1506751Swpaul if (!strcmp(getfile->file_id, "dump")) { 1516751Swpaul res.server_name = ""; 1526751Swpaul res.server_path = ""; 1536751Swpaul res.server_address.address_type = IP_ADDR_TYPE; 1546751Swpaul bzero(&res.server_address.bp_address_u.ip_addr,4); 1556751Swpaul } else goto failed; 1566751Swpaul } 1578857Srgrimes if (debug) 1586751Swpaul fprintf(stderr, "returning server:%s path:%s address: %d.%d.%d.%d\n", 1596751Swpaul res.server_name, res.server_path, 1606751Swpaul 255 & res.server_address.bp_address_u.ip_addr.net, 1616751Swpaul 255 & res.server_address.bp_address_u.ip_addr.host, 1626751Swpaul 255 & res.server_address.bp_address_u.ip_addr.lh, 1636751Swpaul 255 & res.server_address.bp_address_u.ip_addr.impno); 1648857Srgrimes if (dolog) 1656751Swpaul syslog(LOG_NOTICE, "returning server:%s path:%s address: %d.%d.%d.%d\n", 1666751Swpaul res.server_name, res.server_path, 1676751Swpaul 255 & res.server_address.bp_address_u.ip_addr.net, 1686751Swpaul 255 & res.server_address.bp_address_u.ip_addr.host, 1696751Swpaul 255 & res.server_address.bp_address_u.ip_addr.lh, 1706751Swpaul 255 & res.server_address.bp_address_u.ip_addr.impno); 1716751Swpaul return(&res); 1726751Swpaul } 1736751Swpaul failed: 17429102Scharnier if (debug) warnx("getfile failed for %s", getfile->client_name); 1758857Srgrimes if (dolog) syslog(LOG_NOTICE, 1766751Swpaul "getfile failed for %s\n", getfile->client_name); 1776751Swpaul return(NULL); 1786751Swpaul} 1796751Swpaul 1806751Swpaul/* getthefile return 1 and fills the buffer with the information 1816751Swpaul of the file, e g "host:/export/root/client" if it can be found. 1828857Srgrimes If the host is in the database, but the file is not, the buffer 1836751Swpaul will be empty. (This makes it possible to give the special 1846751Swpaul empty answer for the file "dump") */ 1856751Swpaul 18629102Scharnierint 18736794Simpgetthefile(askname,fileid,buffer,blen) 1886751Swpaulchar *askname; 1896751Swpaulchar *fileid, *buffer; 19036794Simpint blen; 1916751Swpaul{ 1926751Swpaul FILE *bpf; 1936751Swpaul char *where; 194201521Sed#ifdef YP 1956751Swpaul static char *result; 1966751Swpaul int resultlen; 1976751Swpaul static char *yp_domain; 198137675Sbz#endif 1996751Swpaul 2006751Swpaul int ch, pch, fid_len, res = 0; 2016751Swpaul int match = 0; 202320780Sasomers#define INFOLEN 1343 203320780Sasomers _Static_assert(INFOLEN >= MAX_FILEID + MAX_PATH_LEN+MAX_MACHINE_NAME + 3, 204320780Sasomers "INFOLEN isn't large enough"); 205320780Sasomers char info[INFOLEN + 1]; 2066751Swpaul 2076751Swpaul bpf = fopen(bootpfile, "r"); 20829102Scharnier if ( ! bpf ) 20929102Scharnier errx(1, "no %s", bootpfile); 2106751Swpaul 21130570Sjoerg /* XXX see comment below */ 21230570Sjoerg while ( fscanf(bpf, "%255s", hostname) > 0 && !match ) { 2136751Swpaul if ( *hostname != '#' ) { /* comment */ 2146751Swpaul if ( ! strcmp(hostname, askname) ) { 2156751Swpaul match = 1; 2166751Swpaul } else { 2176751Swpaul he = gethostbyname(hostname); 2186751Swpaul if (he && !strcmp(he->h_name, askname)) match = 1; 2196751Swpaul } 2206751Swpaul } 2216751Swpaul if (*hostname == '+' ) { /* NIS */ 222137675Sbz#ifdef YP 2236751Swpaul if (yp_get_default_domain(&yp_domain)) { 22429102Scharnier if (debug) warn("NIS"); 2256751Swpaul return(0); 2266751Swpaul } 2276751Swpaul if (yp_match(yp_domain, "bootparams", askname, strlen(askname), 2286751Swpaul &result, &resultlen)) 2296751Swpaul return (0); 2306751Swpaul if (strstr(result, fileid) == NULL) { 2316751Swpaul buffer[0] = '\0'; 2326751Swpaul } else { 23336794Simp snprintf(buffer, blen, 23436794Simp "%s",strchr(strstr(result,fileid), '=') + 1); 2356751Swpaul if (strchr(buffer, ' ') != NULL) 2366751Swpaul *(char *)(strchr(buffer, ' ')) = '\0'; 2376751Swpaul } 2386751Swpaul if (fclose(bpf)) 23929102Scharnier warnx("could not close %s", bootpfile); 2406751Swpaul return(1); 241137675Sbz#else 242137675Sbz return(0); /* ENOTSUP */ 243137675Sbz#endif 2446751Swpaul } 2456751Swpaul /* skip to next entry */ 2466751Swpaul if ( match ) break; 2478857Srgrimes pch = ch = getc(bpf); 2486751Swpaul while ( ! ( ch == '\n' && pch != '\\') && ch != EOF) { 2496751Swpaul pch = ch; ch = getc(bpf); 2506751Swpaul } 2516751Swpaul } 2526751Swpaul 2536751Swpaul /* if match is true we read the rest of the line to get the 2546751Swpaul info of the file */ 2556751Swpaul 2566751Swpaul if (match) { 2576751Swpaul fid_len = strlen(fileid); 258320780Sasomers#define AS_FORMAT(d) "%" #d "s" 259320780Sasomers#define REXPAND(d) AS_FORMAT(d) /* Force another preprocessor expansion */ 260320780Sasomers while ( ! res && (fscanf(bpf, REXPAND(INFOLEN), info)) > 0) { 2616751Swpaul ch = getc(bpf); /* and a character */ 2626751Swpaul if ( *info != '#' ) { /* Comment ? */ 2636751Swpaul if (! strncmp(info, fileid, fid_len) && *(info + fid_len) == '=') { 2646751Swpaul where = info + fid_len + 1; 2656751Swpaul if ( isprint( *where )) { 2666751Swpaul strcpy(buffer, where); /* found file */ 2676751Swpaul res = 1; break; 2686751Swpaul } 2698857Srgrimes } else { 2708857Srgrimes while (isspace(ch) && ch != '\n') ch = getc(bpf); 2716751Swpaul /* read to end of line */ 2726751Swpaul if ( ch == '\n' ) { /* didn't find it */ 2736751Swpaul res = -1; break; /* but host is there */ 2746751Swpaul } 2756751Swpaul if ( ch == '\\' ) { /* more info */ 2766751Swpaul ch = getc(bpf); /* maybe on next line */ 2776751Swpaul if (ch == '\n') continue; /* read it in next loop */ 2786751Swpaul ungetc(ch, bpf); ungetc('\\',bpf); /* push the character(s) back */ 2796751Swpaul } else ungetc(ch, bpf); /* but who know what a `\` is */ 2806751Swpaul } /* needed for. */ 2816751Swpaul } else break; /* a commented rest-of-line */ 2826751Swpaul } 2836751Swpaul } 28429102Scharnier if (fclose(bpf)) { warnx("could not close %s", bootpfile); } 2856751Swpaul if ( res == -1) buffer[0] = '\0'; /* host found, file not */ 2866751Swpaul return(match); 2876751Swpaul} 2886751Swpaul 2896751Swpaul/* checkhost puts the hostname found in the database file in 2906751Swpaul the hostname-variable and returns 1, if askname is a valid 2916751Swpaul name for a host in the database */ 2926751Swpaul 29329102Scharnierint 29430570Sjoergcheckhost(askname, hostname, len) 2956751Swpaulchar *askname; 2966751Swpaulchar *hostname; 29730570Sjoergint len; 2986751Swpaul{ 2996751Swpaul int ch, pch; 3006751Swpaul FILE *bpf; 3016751Swpaul int res = 0; 302201521Sed#ifdef YP 3036751Swpaul static char *result; 3046751Swpaul int resultlen; 3056751Swpaul static char *yp_domain; 306137675Sbz#endif 3076751Swpaul 3086751Swpaul/* struct hostent *cmp_he;*/ 3096751Swpaul 3106751Swpaul bpf = fopen(bootpfile, "r"); 31129102Scharnier if ( ! bpf ) 31229102Scharnier errx(1, "no %s", bootpfile); 3136751Swpaul 31430570Sjoerg /* XXX there is no way in ISO C to specify the maximal length for a 31530570Sjoerg conversion in a variable way */ 31630570Sjoerg while ( fscanf(bpf, "%254s", hostname) > 0 ) { 3176751Swpaul if ( *hostname != '#' ) { /* comment */ 3186751Swpaul if ( ! strcmp(hostname, askname) ) { 3196751Swpaul /* return true for match of hostname */ 3206751Swpaul res = 1; 3216751Swpaul break; 3226751Swpaul } else { 3236751Swpaul /* check the alias list */ 3246751Swpaul he = NULL; 3256751Swpaul he = gethostbyname(hostname); 3266751Swpaul if (he && !strcmp(askname, he->h_name)) { 3276751Swpaul res = 1; 3286751Swpaul break; 3296751Swpaul } 3306751Swpaul } 3316751Swpaul } 3326751Swpaul if (*hostname == '+' ) { /* NIS */ 333137675Sbz#ifdef YP 3346751Swpaul if (yp_get_default_domain(&yp_domain)) { 33529102Scharnier if (debug) warn("NIS"); 3366751Swpaul return(0); 3376751Swpaul } 3386751Swpaul if (!yp_match(yp_domain, "bootparams", askname, strlen(askname), 3396751Swpaul &result, &resultlen)) { 3406751Swpaul /* return true for match of hostname */ 3416751Swpaul he = NULL; 3426751Swpaul he = gethostbyname(askname); 3436751Swpaul if (he && !strcmp(askname, he->h_name)) { 3446751Swpaul res = 1; 34530570Sjoerg snprintf(hostname, len, "%s", he->h_name); 3466751Swpaul } 3476751Swpaul } 3486751Swpaul if (fclose(bpf)) 34929102Scharnier warnx("could not close %s", bootpfile); 3506751Swpaul return(res); 351137675Sbz#else 352137675Sbz return(0); /* ENOTSUP */ 353137675Sbz#endif 3546751Swpaul } 3556751Swpaul /* skip to next entry */ 3568857Srgrimes pch = ch = getc(bpf); 3576751Swpaul while ( ! ( ch == '\n' && pch != '\\') && ch != EOF) { 3586751Swpaul pch = ch; ch = getc(bpf); 3596751Swpaul } 3606751Swpaul } 36129102Scharnier if (fclose(bpf)) { warnx("could not close %s", bootpfile); } 3626751Swpaul return(res); 3636751Swpaul} 364