1*b7dcf10eScgd /* $NetBSD: bootparamd.c,v 1.9 1996/10/14 19:28:09 cgd Exp $ */ 252110e02Sthorpej 3ae99bc57Sderaadt /* 4ae99bc57Sderaadt * This code is not copyright, and is placed in the public domain. 5ae99bc57Sderaadt * Feel free to use and modify. Please send modifications and/or 6ae99bc57Sderaadt * suggestions + bug fixes to Klas Heggemann <klas@nada.kth.se> 7ae99bc57Sderaadt * 8ae99bc57Sderaadt * Various small changes by Theo de Raadt <deraadt@fsa.ca> 90d8ec8d0Sderaadt * Parser rewritten (adding YP support) by Roland McGrath <roland@frob.com> 10ae99bc57Sderaadt */ 11ae99bc57Sderaadt 12ae99bc57Sderaadt #include <sys/types.h> 13ae99bc57Sderaadt #include <sys/ioctl.h> 14ae99bc57Sderaadt #include <sys/stat.h> 15ae99bc57Sderaadt #include <sys/socket.h> 16ae99bc57Sderaadt #include <rpc/rpc.h> 17ae99bc57Sderaadt #include <rpcsvc/bootparam_prot.h> 18ae99bc57Sderaadt #include <stdio.h> 19ae99bc57Sderaadt #include <netdb.h> 20ae99bc57Sderaadt #include <ctype.h> 21ae99bc57Sderaadt #include <syslog.h> 220d8ec8d0Sderaadt #include <string.h> 23*b7dcf10eScgd #include <arpa/inet.h> 240d8ec8d0Sderaadt #include "pathnames.h" 25ae99bc57Sderaadt 26ae99bc57Sderaadt #define MAXLEN 800 27ae99bc57Sderaadt 28ae99bc57Sderaadt static char hostname[MAX_MACHINE_NAME]; 29ae99bc57Sderaadt static char askname[MAX_MACHINE_NAME]; 30ae99bc57Sderaadt static char domain_name[MAX_MACHINE_NAME]; 31ae99bc57Sderaadt 32d8f00aa3Spk extern void bootparamprog_1 __P((struct svc_req *, SVCXPRT *)); 33ae99bc57Sderaadt 34d8f00aa3Spk int _rpcsvcdirty = 0; 35d8f00aa3Spk int _rpcpmstart = 0; 36ae99bc57Sderaadt int debug = 0; 37ae99bc57Sderaadt int dolog = 0; 38ae99bc57Sderaadt unsigned long route_addr, inet_addr(); 39ae99bc57Sderaadt struct sockaddr_in my_addr; 40ae99bc57Sderaadt char *progname; 410d8ec8d0Sderaadt char *bootpfile = _PATH_BOOTPARAMS; 42ae99bc57Sderaadt 43ae99bc57Sderaadt extern char *optarg; 44ae99bc57Sderaadt extern int optind; 45ae99bc57Sderaadt 46ae99bc57Sderaadt void 47ae99bc57Sderaadt usage() 48ae99bc57Sderaadt { 49ae99bc57Sderaadt fprintf(stderr, 50ae99bc57Sderaadt "usage: rpc.bootparamd [-d] [-s] [-r router] [-f bootparmsfile]\n"); 51ae99bc57Sderaadt } 52ae99bc57Sderaadt 53ae99bc57Sderaadt 54ae99bc57Sderaadt /* 55ae99bc57Sderaadt * ever familiar 56ae99bc57Sderaadt */ 57ae99bc57Sderaadt int 58ae99bc57Sderaadt main(argc, argv) 59ae99bc57Sderaadt int argc; 60ae99bc57Sderaadt char **argv; 61ae99bc57Sderaadt { 62ae99bc57Sderaadt SVCXPRT *transp; 63ae99bc57Sderaadt struct hostent *he; 64ae99bc57Sderaadt struct stat buf; 65d907c076Smark int c; 66ae99bc57Sderaadt 67ae99bc57Sderaadt progname = rindex(argv[0], '/'); 68ae99bc57Sderaadt if (progname) 69ae99bc57Sderaadt progname++; 70ae99bc57Sderaadt else 71ae99bc57Sderaadt progname = argv[0]; 72ae99bc57Sderaadt 73d907c076Smark while ((c = getopt(argc, argv, "dsr:f:")) != -1) 74ae99bc57Sderaadt switch (c) { 75ae99bc57Sderaadt case 'd': 76ae99bc57Sderaadt debug = 1; 77ae99bc57Sderaadt break; 78ae99bc57Sderaadt case 'r': 79ae99bc57Sderaadt if (isdigit(*optarg)) { 80ae99bc57Sderaadt route_addr = inet_addr(optarg); 81ae99bc57Sderaadt break; 82ae99bc57Sderaadt } 83ae99bc57Sderaadt he = gethostbyname(optarg); 84ae99bc57Sderaadt if (!he) { 85ae99bc57Sderaadt fprintf(stderr, "%s: No such host %s\n", 86ae99bc57Sderaadt progname, optarg); 87ae99bc57Sderaadt usage(); 88ae99bc57Sderaadt exit(1); 89ae99bc57Sderaadt } 90ae99bc57Sderaadt bcopy(he->h_addr, (char *) &route_addr, sizeof(route_addr)); 91ae99bc57Sderaadt break; 92ae99bc57Sderaadt case 'f': 93ae99bc57Sderaadt bootpfile = optarg; 94ae99bc57Sderaadt break; 95ae99bc57Sderaadt case 's': 96ae99bc57Sderaadt dolog = 1; 97ae99bc57Sderaadt #ifndef LOG_DAEMON 98ae99bc57Sderaadt openlog(progname, 0, 0); 99ae99bc57Sderaadt #else 100ae99bc57Sderaadt openlog(progname, 0, LOG_DAEMON); 101ae99bc57Sderaadt setlogmask(LOG_UPTO(LOG_NOTICE)); 102ae99bc57Sderaadt #endif 103ae99bc57Sderaadt break; 104ae99bc57Sderaadt default: 105ae99bc57Sderaadt usage(); 106ae99bc57Sderaadt exit(1); 107ae99bc57Sderaadt } 108ae99bc57Sderaadt 109ae99bc57Sderaadt if (stat(bootpfile, &buf)) { 110ae99bc57Sderaadt fprintf(stderr, "%s: ", progname); 111ae99bc57Sderaadt perror(bootpfile); 112ae99bc57Sderaadt exit(1); 113ae99bc57Sderaadt } 114ae99bc57Sderaadt if (!route_addr) { 115ae99bc57Sderaadt get_myaddress(&my_addr); 116ae99bc57Sderaadt bcopy(&my_addr.sin_addr.s_addr, &route_addr, sizeof(route_addr)); 117ae99bc57Sderaadt } 118ae99bc57Sderaadt if (!debug) 119ae99bc57Sderaadt daemon(); 120ae99bc57Sderaadt 121ae99bc57Sderaadt (void) pmap_unset(BOOTPARAMPROG, BOOTPARAMVERS); 122ae99bc57Sderaadt 123ae99bc57Sderaadt transp = svcudp_create(RPC_ANYSOCK); 124ae99bc57Sderaadt if (transp == NULL) { 125ae99bc57Sderaadt fprintf(stderr, "cannot create udp service.\n"); 126ae99bc57Sderaadt exit(1); 127ae99bc57Sderaadt } 128ae99bc57Sderaadt if (!svc_register(transp, BOOTPARAMPROG, BOOTPARAMVERS, 129ae99bc57Sderaadt bootparamprog_1, IPPROTO_UDP)) { 130ae99bc57Sderaadt fprintf(stderr, 131ae99bc57Sderaadt "bootparamd: unable to register BOOTPARAMPROG version %d, udp)\n", 132ae99bc57Sderaadt BOOTPARAMVERS); 133ae99bc57Sderaadt exit(1); 134ae99bc57Sderaadt } 135ae99bc57Sderaadt svc_run(); 136ae99bc57Sderaadt fprintf(stderr, "svc_run returned\n"); 137ae99bc57Sderaadt exit(1); 138ae99bc57Sderaadt } 139ae99bc57Sderaadt 140ae99bc57Sderaadt bp_whoami_res * 141d8f00aa3Spk bootparamproc_whoami_1_svc(whoami, rqstp) 142ae99bc57Sderaadt bp_whoami_arg *whoami; 143d8f00aa3Spk struct svc_req *rqstp; 144ae99bc57Sderaadt { 145ae99bc57Sderaadt static bp_whoami_res res; 146*b7dcf10eScgd struct hostent *he; 147*b7dcf10eScgd struct in_addr inaddr; 148*b7dcf10eScgd long haddr; 1490d8ec8d0Sderaadt 150ae99bc57Sderaadt if (debug) 151ae99bc57Sderaadt fprintf(stderr, "whoami got question for %d.%d.%d.%d\n", 152ae99bc57Sderaadt 255 & whoami->client_address.bp_address_u.ip_addr.net, 153ae99bc57Sderaadt 255 & whoami->client_address.bp_address_u.ip_addr.host, 154ae99bc57Sderaadt 255 & whoami->client_address.bp_address_u.ip_addr.lh, 155ae99bc57Sderaadt 255 & whoami->client_address.bp_address_u.ip_addr.impno); 156ae99bc57Sderaadt if (dolog) 157ae99bc57Sderaadt syslog(LOG_NOTICE, "whoami got question for %d.%d.%d.%d\n", 158ae99bc57Sderaadt 255 & whoami->client_address.bp_address_u.ip_addr.net, 159ae99bc57Sderaadt 255 & whoami->client_address.bp_address_u.ip_addr.host, 160ae99bc57Sderaadt 255 & whoami->client_address.bp_address_u.ip_addr.lh, 161ae99bc57Sderaadt 255 & whoami->client_address.bp_address_u.ip_addr.impno); 162ae99bc57Sderaadt 163ae99bc57Sderaadt bcopy((char *) &whoami->client_address.bp_address_u.ip_addr, (char *) &haddr, 164ae99bc57Sderaadt sizeof(haddr)); 165ae99bc57Sderaadt he = gethostbyaddr((char *) &haddr, sizeof(haddr), AF_INET); 166*b7dcf10eScgd if (he) 167*b7dcf10eScgd strcpy(askname, he->h_name); 168*b7dcf10eScgd else { 169*b7dcf10eScgd inaddr.s_addr = haddr; 170*b7dcf10eScgd strcpy(askname, inet_ntoa(inaddr)); 171*b7dcf10eScgd } 172ae99bc57Sderaadt 173ae99bc57Sderaadt if (debug) 174*b7dcf10eScgd fprintf(stderr, "This is host %s\n", askname); 175ae99bc57Sderaadt if (dolog) 176*b7dcf10eScgd syslog(LOG_NOTICE, "This is host %s\n", askname); 177ae99bc57Sderaadt 1780d8ec8d0Sderaadt if (!lookup_bootparam(askname, hostname, NULL, NULL, NULL)) { 179ae99bc57Sderaadt res.client_name = hostname; 180ae99bc57Sderaadt getdomainname(domain_name, MAX_MACHINE_NAME); 181ae99bc57Sderaadt res.domain_name = domain_name; 182ae99bc57Sderaadt 183ae99bc57Sderaadt if (res.router_address.address_type != IP_ADDR_TYPE) { 184ae99bc57Sderaadt res.router_address.address_type = IP_ADDR_TYPE; 185ae99bc57Sderaadt bcopy(&route_addr, &res.router_address.bp_address_u.ip_addr, 4); 186ae99bc57Sderaadt } 187ae99bc57Sderaadt if (debug) 188ae99bc57Sderaadt fprintf(stderr, "Returning %s %s %d.%d.%d.%d\n", 189ae99bc57Sderaadt res.client_name, res.domain_name, 190ae99bc57Sderaadt 255 & res.router_address.bp_address_u.ip_addr.net, 191ae99bc57Sderaadt 255 & res.router_address.bp_address_u.ip_addr.host, 192ae99bc57Sderaadt 255 & res.router_address.bp_address_u.ip_addr.lh, 193ae99bc57Sderaadt 255 & res.router_address.bp_address_u.ip_addr.impno); 194ae99bc57Sderaadt if (dolog) 195ae99bc57Sderaadt syslog(LOG_NOTICE, "Returning %s %s %d.%d.%d.%d\n", 196ae99bc57Sderaadt res.client_name, res.domain_name, 197ae99bc57Sderaadt 255 & res.router_address.bp_address_u.ip_addr.net, 198ae99bc57Sderaadt 255 & res.router_address.bp_address_u.ip_addr.host, 199ae99bc57Sderaadt 255 & res.router_address.bp_address_u.ip_addr.lh, 200ae99bc57Sderaadt 255 & res.router_address.bp_address_u.ip_addr.impno); 201ae99bc57Sderaadt 202ae99bc57Sderaadt return (&res); 203ae99bc57Sderaadt } 204ae99bc57Sderaadt if (debug) 205ae99bc57Sderaadt fprintf(stderr, "whoami failed\n"); 206ae99bc57Sderaadt if (dolog) 207ae99bc57Sderaadt syslog(LOG_NOTICE, "whoami failed\n"); 208ae99bc57Sderaadt return (NULL); 209ae99bc57Sderaadt } 210ae99bc57Sderaadt 211ae99bc57Sderaadt 212ae99bc57Sderaadt bp_getfile_res * 213d8f00aa3Spk bootparamproc_getfile_1_svc(getfile, rqstp) 214ae99bc57Sderaadt bp_getfile_arg *getfile; 215d8f00aa3Spk struct svc_req *rqstp; 216ae99bc57Sderaadt { 217ae99bc57Sderaadt static bp_getfile_res res; 218*b7dcf10eScgd struct hostent *he; 2190d8ec8d0Sderaadt int err; 220ae99bc57Sderaadt 221ae99bc57Sderaadt if (debug) 222ae99bc57Sderaadt fprintf(stderr, "getfile got question for \"%s\" and file \"%s\"\n", 223ae99bc57Sderaadt getfile->client_name, getfile->file_id); 224ae99bc57Sderaadt 225ae99bc57Sderaadt if (dolog) 226ae99bc57Sderaadt syslog(LOG_NOTICE, "getfile got question for \"%s\" and file \"%s\"\n", 227ae99bc57Sderaadt getfile->client_name, getfile->file_id); 228ae99bc57Sderaadt 229ae99bc57Sderaadt he = NULL; 230ae99bc57Sderaadt he = gethostbyname(getfile->client_name); 231ae99bc57Sderaadt if (!he) 232ae99bc57Sderaadt goto failed; 233ae99bc57Sderaadt 234ae99bc57Sderaadt strcpy(askname, he->h_name); 2350d8ec8d0Sderaadt err = lookup_bootparam(askname, NULL, getfile->file_id, 2360d8ec8d0Sderaadt &res.server_name, &res.server_path); 2370d8ec8d0Sderaadt if (err == 0) { 2380d8ec8d0Sderaadt he = gethostbyname(res.server_name); 239ae99bc57Sderaadt if (!he) 240ae99bc57Sderaadt goto failed; 241ae99bc57Sderaadt bcopy(he->h_addr, &res.server_address.bp_address_u.ip_addr, 4); 242ae99bc57Sderaadt res.server_address.address_type = IP_ADDR_TYPE; 2430d8ec8d0Sderaadt } else if (err == ENOENT && !strcmp(getfile->file_id, "dump")) { 2440d8ec8d0Sderaadt /* Special for dump, answer with null strings. */ 245ae99bc57Sderaadt res.server_name[0] = '\0'; 246ae99bc57Sderaadt res.server_path[0] = '\0'; 247ae99bc57Sderaadt bzero(&res.server_address.bp_address_u.ip_addr, 4); 2480d8ec8d0Sderaadt } else { 2490d8ec8d0Sderaadt failed: 2500d8ec8d0Sderaadt if (debug) 2510d8ec8d0Sderaadt fprintf(stderr, "getfile failed for %s\n", 2520d8ec8d0Sderaadt getfile->client_name); 2530d8ec8d0Sderaadt if (dolog) 2540d8ec8d0Sderaadt syslog(LOG_NOTICE, 2550d8ec8d0Sderaadt "getfile failed for %s\n", getfile->client_name); 2560d8ec8d0Sderaadt return (NULL); 257ae99bc57Sderaadt } 2580d8ec8d0Sderaadt 259ae99bc57Sderaadt if (debug) 260ae99bc57Sderaadt fprintf(stderr, 261ae99bc57Sderaadt "returning server:%s path:%s address: %d.%d.%d.%d\n", 262ae99bc57Sderaadt res.server_name, res.server_path, 263ae99bc57Sderaadt 255 & res.server_address.bp_address_u.ip_addr.net, 264ae99bc57Sderaadt 255 & res.server_address.bp_address_u.ip_addr.host, 265ae99bc57Sderaadt 255 & res.server_address.bp_address_u.ip_addr.lh, 266ae99bc57Sderaadt 255 & res.server_address.bp_address_u.ip_addr.impno); 267ae99bc57Sderaadt if (dolog) 268ae99bc57Sderaadt syslog(LOG_NOTICE, 269ae99bc57Sderaadt "returning server:%s path:%s address: %d.%d.%d.%d\n", 270ae99bc57Sderaadt res.server_name, res.server_path, 271ae99bc57Sderaadt 255 & res.server_address.bp_address_u.ip_addr.net, 272ae99bc57Sderaadt 255 & res.server_address.bp_address_u.ip_addr.host, 273ae99bc57Sderaadt 255 & res.server_address.bp_address_u.ip_addr.lh, 274ae99bc57Sderaadt 255 & res.server_address.bp_address_u.ip_addr.impno); 275ae99bc57Sderaadt return (&res); 276ae99bc57Sderaadt } 277ae99bc57Sderaadt 278ae99bc57Sderaadt 2790d8ec8d0Sderaadt int 2800d8ec8d0Sderaadt lookup_bootparam(client, client_canonical, id, server, path) 2810d8ec8d0Sderaadt char *client; 2820d8ec8d0Sderaadt char *client_canonical; 2830d8ec8d0Sderaadt char *id; 2840d8ec8d0Sderaadt char **server; 2850d8ec8d0Sderaadt char **path; 286ae99bc57Sderaadt { 2870d8ec8d0Sderaadt FILE *f = fopen(bootpfile, "r"); 2880d8ec8d0Sderaadt #ifdef YP 2890d8ec8d0Sderaadt static char *ypbuf = NULL; 2900d8ec8d0Sderaadt static int ypbuflen = 0; 2910d8ec8d0Sderaadt #endif 2920d8ec8d0Sderaadt static char buf[BUFSIZ]; 2930d8ec8d0Sderaadt char *bp, *word; 2940d8ec8d0Sderaadt size_t idlen = id == NULL ? 0 : strlen(id); 2950d8ec8d0Sderaadt int contin = 0; 2960d8ec8d0Sderaadt int found = 0; 297ae99bc57Sderaadt 2980d8ec8d0Sderaadt if (f == NULL) 2990d8ec8d0Sderaadt return EINVAL; /* ? */ 300ae99bc57Sderaadt 3010d8ec8d0Sderaadt while (fgets(buf, sizeof buf, f)) { 3020d8ec8d0Sderaadt int wascontin = contin; 3030d8ec8d0Sderaadt contin = buf[strlen(buf) - 2] == '\\'; 3040d8ec8d0Sderaadt bp = buf + strspn(buf, " \t\n"); 305ae99bc57Sderaadt 3060d8ec8d0Sderaadt switch (wascontin) { 3070d8ec8d0Sderaadt case -1: 3080d8ec8d0Sderaadt /* Continuation of uninteresting line */ 3090d8ec8d0Sderaadt contin *= -1; 310ae99bc57Sderaadt continue; 3110d8ec8d0Sderaadt case 0: 3120d8ec8d0Sderaadt /* New line */ 3130d8ec8d0Sderaadt contin *= -1; 3140d8ec8d0Sderaadt if (*bp == '#') 3150d8ec8d0Sderaadt continue; 3160d8ec8d0Sderaadt if ((word = strsep(&bp, " \t\n")) == NULL) 3170d8ec8d0Sderaadt continue; 3180d8ec8d0Sderaadt #ifdef YP 3190d8ec8d0Sderaadt /* A + in the file means try YP now */ 3200d8ec8d0Sderaadt if (!strcmp(word, "+")) { 3210d8ec8d0Sderaadt char *ypdom; 3220d8ec8d0Sderaadt 3230d8ec8d0Sderaadt if (yp_get_default_domain(&ypdom) || 3240d8ec8d0Sderaadt yp_match(ypdom, "bootparams", client, 3250d8ec8d0Sderaadt strlen(client), &ypbuf, &ypbuflen)) 3260d8ec8d0Sderaadt continue; 3270d8ec8d0Sderaadt bp = ypbuf; 3280d8ec8d0Sderaadt word = client; 3290d8ec8d0Sderaadt contin *= -1; 330ae99bc57Sderaadt break; 331ae99bc57Sderaadt } 3320d8ec8d0Sderaadt #endif 3330d8ec8d0Sderaadt /* See if this line's client is the one we are 3340d8ec8d0Sderaadt * looking for */ 335010a229cScgd if (strcasecmp(word, client) != 0) { 336ae99bc57Sderaadt /* 3370d8ec8d0Sderaadt * If it didn't match, try getting the 3380d8ec8d0Sderaadt * canonical host name of the client 3390d8ec8d0Sderaadt * on this line and comparing that to 3400d8ec8d0Sderaadt * the client we are looking for 341ae99bc57Sderaadt */ 3420d8ec8d0Sderaadt struct hostent *hp = gethostbyname(word); 343010a229cScgd if (hp == NULL || 344010a229cScgd strcasecmp(hp->h_name, client)) 3450d8ec8d0Sderaadt continue; 3460d8ec8d0Sderaadt } 3470d8ec8d0Sderaadt contin *= -1; 3480d8ec8d0Sderaadt break; 3490d8ec8d0Sderaadt case 1: 3500d8ec8d0Sderaadt /* Continued line we want to parse below */ 3510d8ec8d0Sderaadt break; 3520d8ec8d0Sderaadt } 353ae99bc57Sderaadt 3540d8ec8d0Sderaadt if (client_canonical) 3550d8ec8d0Sderaadt strncpy(client_canonical, word, MAX_MACHINE_NAME); 3560d8ec8d0Sderaadt 3570d8ec8d0Sderaadt /* We have found a line for CLIENT */ 358f392a261Sglass if (id == NULL) { 359f392a261Sglass (void) fclose(f); 3600d8ec8d0Sderaadt return 0; 361f392a261Sglass } 3620d8ec8d0Sderaadt 3630d8ec8d0Sderaadt /* Look for a value for the parameter named by ID */ 3640d8ec8d0Sderaadt while ((word = strsep(&bp, " \t\n")) != NULL) { 3650d8ec8d0Sderaadt if (!strncmp(word, id, idlen) && word[idlen] == '=') { 3660d8ec8d0Sderaadt /* We have found the entry we want */ 3670d8ec8d0Sderaadt *server = &word[idlen + 1]; 3680d8ec8d0Sderaadt *path = strchr(*server, ':'); 3690d8ec8d0Sderaadt if (*path == NULL) 3700d8ec8d0Sderaadt /* Malformed entry */ 3710d8ec8d0Sderaadt continue; 3720d8ec8d0Sderaadt *(*path)++ = '\0'; 3730d8ec8d0Sderaadt (void) fclose(f); 3740d8ec8d0Sderaadt return 0; 375ae99bc57Sderaadt } 376ae99bc57Sderaadt } 3770d8ec8d0Sderaadt 3780d8ec8d0Sderaadt found = 1; 379ae99bc57Sderaadt } 3800d8ec8d0Sderaadt 3810d8ec8d0Sderaadt (void) fclose(f); 3820d8ec8d0Sderaadt return found ? ENOENT : EPERM; 383ae99bc57Sderaadt } 384