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