1 /* $NetBSD: bootparamd.c,v 1.15 1997/10/18 11:27:49 lukem Exp $ */ 2 3 /* 4 * This code is not copyright, and is placed in the public domain. 5 * Feel free to use and modify. Please send modifications and/or 6 * suggestions + bug fixes to Klas Heggemann <klas@nada.kth.se> 7 * 8 * Various small changes by Theo de Raadt <deraadt@fsa.ca> 9 * Parser rewritten (adding YP support) by Roland McGrath <roland@frob.com> 10 */ 11 12 #include <sys/cdefs.h> 13 #ifndef lint 14 __RCSID("$NetBSD: bootparamd.c,v 1.15 1997/10/18 11:27:49 lukem Exp $"); 15 #endif 16 17 #include <sys/types.h> 18 #include <sys/ioctl.h> 19 #include <sys/stat.h> 20 #include <sys/socket.h> 21 22 #include <ctype.h> 23 #include <err.h> 24 #include <netdb.h> 25 #include <stdlib.h> 26 #include <stdio.h> 27 #include <string.h> 28 #include <syslog.h> 29 #include <unistd.h> 30 31 #include <netinet/in.h> 32 #include <arpa/inet.h> 33 34 #include <rpc/rpc.h> 35 #include <rpc/pmap_clnt.h> 36 #include <rpcsvc/bootparam_prot.h> 37 #include <rpcsvc/ypclnt.h> 38 39 #include "pathnames.h" 40 41 #define MAXLEN 800 42 43 static char hostname[MAX_MACHINE_NAME]; 44 static char askname[MAX_MACHINE_NAME]; 45 static char domain_name[MAX_MACHINE_NAME]; 46 47 extern void bootparamprog_1 __P((struct svc_req *, SVCXPRT *)); 48 49 int _rpcsvcdirty = 0; 50 int _rpcpmstart = 0; 51 int debug = 0; 52 int dolog = 0; 53 struct in_addr route_addr; 54 struct sockaddr_in my_addr; 55 extern char *__progname; 56 char *bootpfile = _PATH_BOOTPARAMS; 57 58 int main __P((int, char *[])); 59 int lookup_bootparam __P((char *, char *, char *, char **, char **)); 60 void usage __P((void)); 61 62 63 /* 64 * ever familiar 65 */ 66 int 67 main(argc, argv) 68 int argc; 69 char *argv[]; 70 { 71 SVCXPRT *transp; 72 struct hostent *he; 73 struct stat buf; 74 int c; 75 76 while ((c = getopt(argc, argv, "dsr:f:")) != -1) 77 switch (c) { 78 case 'd': 79 debug = 1; 80 break; 81 case 'r': 82 if (isdigit(*optarg)) { 83 if (inet_aton(optarg, &route_addr) != 0) 84 break; 85 } 86 he = gethostbyname(optarg); 87 if (he == 0) { 88 warnx("no such host: %s", optarg); 89 usage(); 90 } 91 memmove(&route_addr.s_addr, he->h_addr, he->h_length); 92 break; 93 case 'f': 94 bootpfile = optarg; 95 break; 96 case 's': 97 dolog = 1; 98 #ifndef LOG_DAEMON 99 openlog(__progname, 0, 0); 100 #else 101 openlog(__progname, 0, LOG_DAEMON); 102 setlogmask(LOG_UPTO(LOG_NOTICE)); 103 #endif 104 break; 105 default: 106 usage(); 107 } 108 109 if (stat(bootpfile, &buf)) 110 err(1, "%s", bootpfile); 111 112 if (route_addr.s_addr == 0) { 113 get_myaddress(&my_addr); 114 route_addr.s_addr = my_addr.sin_addr.s_addr; 115 } 116 if (!debug) { 117 if (daemon(0, 0)) 118 err(1, "can't detach from terminal"); 119 } 120 121 (void) pmap_unset(BOOTPARAMPROG, BOOTPARAMVERS); 122 123 transp = svcudp_create(RPC_ANYSOCK); 124 if (transp == NULL) 125 errx(1, "can't create udp service"); 126 127 if (!svc_register(transp, BOOTPARAMPROG, BOOTPARAMVERS, bootparamprog_1, 128 IPPROTO_UDP)) 129 errx(1, "unable to register BOOTPARAMPROG version %ld, udp", 130 BOOTPARAMVERS); 131 132 svc_run(); 133 errx(1, "svc_run returned"); 134 } 135 136 bp_whoami_res * 137 bootparamproc_whoami_1_svc(whoami, rqstp) 138 bp_whoami_arg *whoami; 139 struct svc_req *rqstp; 140 { 141 static bp_whoami_res res; 142 struct hostent *he; 143 struct in_addr inaddr; 144 long haddr; 145 146 if (debug) 147 warnx("whoami got question for %d.%d.%d.%d", 148 255 & whoami->client_address.bp_address_u.ip_addr.net, 149 255 & whoami->client_address.bp_address_u.ip_addr.host, 150 255 & whoami->client_address.bp_address_u.ip_addr.lh, 151 255 & whoami->client_address.bp_address_u.ip_addr.impno); 152 if (dolog) 153 syslog(LOG_NOTICE, "whoami got question for %d.%d.%d.%d", 154 255 & whoami->client_address.bp_address_u.ip_addr.net, 155 255 & whoami->client_address.bp_address_u.ip_addr.host, 156 255 & whoami->client_address.bp_address_u.ip_addr.lh, 157 255 & whoami->client_address.bp_address_u.ip_addr.impno); 158 159 memmove((char *) &haddr, 160 (char *) &whoami->client_address.bp_address_u.ip_addr, 161 sizeof(haddr)); 162 he = gethostbyaddr((char *) &haddr, sizeof(haddr), AF_INET); 163 if (he) { 164 strncpy(askname, he->h_name, sizeof(askname)); 165 askname[sizeof(askname)-1] = 0; 166 } else { 167 inaddr.s_addr = haddr; 168 strncpy(askname, inet_ntoa(inaddr), sizeof(askname)); 169 askname[sizeof(askname)-1] = 0; 170 } 171 172 if (debug) 173 warnx("This is host %s", askname); 174 if (dolog) 175 syslog(LOG_NOTICE, "This is host %s", askname); 176 177 if (!lookup_bootparam(askname, hostname, NULL, NULL, NULL)) { 178 res.client_name = hostname; 179 getdomainname(domain_name, MAX_MACHINE_NAME); 180 res.domain_name = domain_name; 181 182 if (res.router_address.address_type != IP_ADDR_TYPE) { 183 res.router_address.address_type = IP_ADDR_TYPE; 184 memmove(&res.router_address.bp_address_u.ip_addr, 185 &route_addr.s_addr,4); 186 } 187 if (debug) 188 warnx("Returning %s %s %d.%d.%d.%d", 189 res.client_name, res.domain_name, 190 255 & res.router_address.bp_address_u.ip_addr.net, 191 255 & res.router_address.bp_address_u.ip_addr.host, 192 255 & res.router_address.bp_address_u.ip_addr.lh, 193 255 &res.router_address.bp_address_u.ip_addr.impno); 194 if (dolog) 195 syslog(LOG_NOTICE, "Returning %s %s %d.%d.%d.%d", 196 res.client_name, res.domain_name, 197 255 & res.router_address.bp_address_u.ip_addr.net, 198 255 & res.router_address.bp_address_u.ip_addr.host, 199 255 & res.router_address.bp_address_u.ip_addr.lh, 200 255 &res.router_address.bp_address_u.ip_addr.impno); 201 202 return (&res); 203 } 204 if (debug) 205 warnx("whoami failed"); 206 if (dolog) 207 syslog(LOG_NOTICE, "whoami failed"); 208 return (NULL); 209 } 210 211 212 bp_getfile_res * 213 bootparamproc_getfile_1_svc(getfile, rqstp) 214 bp_getfile_arg *getfile; 215 struct svc_req *rqstp; 216 { 217 static bp_getfile_res res; 218 struct hostent *he; 219 int err; 220 221 if (debug) 222 warnx("getfile got question for \"%s\" and file \"%s\"", 223 getfile->client_name, getfile->file_id); 224 225 if (dolog) 226 syslog(LOG_NOTICE, 227 "getfile got question for \"%s\" and file \"%s\"", 228 getfile->client_name, getfile->file_id); 229 230 he = NULL; 231 he = gethostbyname(getfile->client_name); 232 if (!he) 233 goto failed; 234 235 strncpy(askname, he->h_name, sizeof(askname)); 236 askname[sizeof(askname)-1] = 0; 237 err = lookup_bootparam(askname, NULL, getfile->file_id, 238 &res.server_name, &res.server_path); 239 if (err == 0) { 240 he = gethostbyname(res.server_name); 241 if (!he) 242 goto failed; 243 memmove(&res.server_address.bp_address_u.ip_addr, 244 he->h_addr, 4); 245 res.server_address.address_type = IP_ADDR_TYPE; 246 } else if (err == ENOENT && !strcmp(getfile->file_id, "dump")) { 247 /* Special for dump, answer with null strings. */ 248 res.server_name[0] = '\0'; 249 res.server_path[0] = '\0'; 250 memset(&res.server_address.bp_address_u.ip_addr, 0, 4); 251 } else { 252 failed: 253 if (debug) 254 warnx("getfile failed for %s", 255 getfile->client_name); 256 if (dolog) 257 syslog(LOG_NOTICE, 258 "getfile failed for %s", getfile->client_name); 259 return (NULL); 260 } 261 262 if (debug) 263 warnx( 264 "returning server:%s path:%s address: %d.%d.%d.%d", 265 res.server_name, res.server_path, 266 255 & res.server_address.bp_address_u.ip_addr.net, 267 255 & res.server_address.bp_address_u.ip_addr.host, 268 255 & res.server_address.bp_address_u.ip_addr.lh, 269 255 & res.server_address.bp_address_u.ip_addr.impno); 270 if (dolog) 271 syslog(LOG_NOTICE, 272 "returning server:%s path:%s address: %d.%d.%d.%d", 273 res.server_name, res.server_path, 274 255 & res.server_address.bp_address_u.ip_addr.net, 275 255 & res.server_address.bp_address_u.ip_addr.host, 276 255 & res.server_address.bp_address_u.ip_addr.lh, 277 255 & res.server_address.bp_address_u.ip_addr.impno); 278 return (&res); 279 } 280 281 282 int 283 lookup_bootparam(client, client_canonical, id, server, path) 284 char *client; 285 char *client_canonical; 286 char *id; 287 char **server; 288 char **path; 289 { 290 FILE *f = fopen(bootpfile, "r"); 291 #ifdef YP 292 static char *ypbuf = NULL; 293 static int ypbuflen = 0; 294 #endif 295 static char buf[BUFSIZ]; 296 char *bp, *word = NULL; 297 size_t idlen = id == NULL ? 0 : strlen(id); 298 int contin = 0; 299 int found = 0; 300 301 if (f == NULL) 302 return EINVAL; /* ? */ 303 304 while (fgets(buf, sizeof buf, f)) { 305 int wascontin = contin; 306 contin = buf[strlen(buf) - 2] == '\\'; 307 bp = buf + strspn(buf, " \t\n"); 308 309 switch (wascontin) { 310 case -1: 311 /* Continuation of uninteresting line */ 312 contin *= -1; 313 continue; 314 case 0: 315 /* New line */ 316 contin *= -1; 317 if (*bp == '#') 318 continue; 319 if ((word = strsep(&bp, " \t\n")) == NULL) 320 continue; 321 #ifdef YP 322 /* A + in the file means try YP now */ 323 if (!strcmp(word, "+")) { 324 char *ypdom; 325 326 if (yp_get_default_domain(&ypdom) || 327 yp_match(ypdom, "bootparams", client, 328 strlen(client), &ypbuf, &ypbuflen)) 329 continue; 330 bp = ypbuf; 331 word = client; 332 contin *= -1; 333 break; 334 } 335 #endif 336 /* See if this line's client is the one we are 337 * looking for */ 338 if (strcasecmp(word, client) != 0) { 339 /* 340 * If it didn't match, try getting the 341 * canonical host name of the client 342 * on this line and comparing that to 343 * the client we are looking for 344 */ 345 struct hostent *hp = gethostbyname(word); 346 if (hp == NULL || 347 strcasecmp(hp->h_name, client)) 348 continue; 349 } 350 contin *= -1; 351 break; 352 case 1: 353 /* Continued line we want to parse below */ 354 break; 355 } 356 357 if (client_canonical) 358 strncpy(client_canonical, word, MAX_MACHINE_NAME); 359 360 /* We have found a line for CLIENT */ 361 if (id == NULL) { 362 (void) fclose(f); 363 return 0; 364 } 365 366 /* Look for a value for the parameter named by ID */ 367 while ((word = strsep(&bp, " \t\n")) != NULL) { 368 if (!strncmp(word, id, idlen) && word[idlen] == '=') { 369 /* We have found the entry we want */ 370 *server = &word[idlen + 1]; 371 *path = strchr(*server, ':'); 372 if (*path == NULL) 373 /* Malformed entry */ 374 continue; 375 *(*path)++ = '\0'; 376 (void) fclose(f); 377 return 0; 378 } 379 } 380 381 found = 1; 382 } 383 384 (void) fclose(f); 385 return found ? ENOENT : EPERM; 386 } 387 388 void 389 usage() 390 { 391 fprintf(stderr, 392 "usage: %s [-d] [-s] [-r router] [-f bootparmsfile]\n", __progname); 393 exit(1); 394 } 395