1 /* $NetBSD: bootparamd.c,v 1.14 1997/09/23 07:28:29 mrg 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.14 1997/09/23 07:28:29 mrg 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 bcopy(he->h_addr, &route_addr.s_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 bcopy((char *) &whoami->client_address.bp_address_u.ip_addr, 160 (char *) &haddr, sizeof(haddr)); 161 he = gethostbyaddr((char *) &haddr, sizeof(haddr), AF_INET); 162 if (he) { 163 strncpy(askname, he->h_name, sizeof(askname)); 164 askname[sizeof(askname)-1] = 0; 165 } else { 166 inaddr.s_addr = haddr; 167 strncpy(askname, inet_ntoa(inaddr), sizeof(askname)); 168 askname[sizeof(askname)-1] = 0; 169 } 170 171 if (debug) 172 warnx("This is host %s", askname); 173 if (dolog) 174 syslog(LOG_NOTICE, "This is host %s", askname); 175 176 if (!lookup_bootparam(askname, hostname, NULL, NULL, NULL)) { 177 res.client_name = hostname; 178 getdomainname(domain_name, MAX_MACHINE_NAME); 179 res.domain_name = domain_name; 180 181 if (res.router_address.address_type != IP_ADDR_TYPE) { 182 res.router_address.address_type = IP_ADDR_TYPE; 183 bcopy(&route_addr.s_addr, 184 &res.router_address.bp_address_u.ip_addr, 4); 185 } 186 if (debug) 187 warnx("Returning %s %s %d.%d.%d.%d", 188 res.client_name, res.domain_name, 189 255 & res.router_address.bp_address_u.ip_addr.net, 190 255 & res.router_address.bp_address_u.ip_addr.host, 191 255 & res.router_address.bp_address_u.ip_addr.lh, 192 255 &res.router_address.bp_address_u.ip_addr.impno); 193 if (dolog) 194 syslog(LOG_NOTICE, "Returning %s %s %d.%d.%d.%d", 195 res.client_name, res.domain_name, 196 255 & res.router_address.bp_address_u.ip_addr.net, 197 255 & res.router_address.bp_address_u.ip_addr.host, 198 255 & res.router_address.bp_address_u.ip_addr.lh, 199 255 &res.router_address.bp_address_u.ip_addr.impno); 200 201 return (&res); 202 } 203 if (debug) 204 warnx("whoami failed"); 205 if (dolog) 206 syslog(LOG_NOTICE, "whoami failed"); 207 return (NULL); 208 } 209 210 211 bp_getfile_res * 212 bootparamproc_getfile_1_svc(getfile, rqstp) 213 bp_getfile_arg *getfile; 214 struct svc_req *rqstp; 215 { 216 static bp_getfile_res res; 217 struct hostent *he; 218 int err; 219 220 if (debug) 221 warnx("getfile got question for \"%s\" and file \"%s\"", 222 getfile->client_name, getfile->file_id); 223 224 if (dolog) 225 syslog(LOG_NOTICE, 226 "getfile got question for \"%s\" and file \"%s\"", 227 getfile->client_name, getfile->file_id); 228 229 he = NULL; 230 he = gethostbyname(getfile->client_name); 231 if (!he) 232 goto failed; 233 234 strncpy(askname, he->h_name, sizeof(askname)); 235 askname[sizeof(askname)-1] = 0; 236 err = lookup_bootparam(askname, NULL, getfile->file_id, 237 &res.server_name, &res.server_path); 238 if (err == 0) { 239 he = gethostbyname(res.server_name); 240 if (!he) 241 goto failed; 242 bcopy(he->h_addr, &res.server_address.bp_address_u.ip_addr, 4); 243 res.server_address.address_type = IP_ADDR_TYPE; 244 } else if (err == ENOENT && !strcmp(getfile->file_id, "dump")) { 245 /* Special for dump, answer with null strings. */ 246 res.server_name[0] = '\0'; 247 res.server_path[0] = '\0'; 248 bzero(&res.server_address.bp_address_u.ip_addr, 4); 249 } else { 250 failed: 251 if (debug) 252 warnx("getfile failed for %s", 253 getfile->client_name); 254 if (dolog) 255 syslog(LOG_NOTICE, 256 "getfile failed for %s", getfile->client_name); 257 return (NULL); 258 } 259 260 if (debug) 261 warnx( 262 "returning server:%s path:%s address: %d.%d.%d.%d", 263 res.server_name, res.server_path, 264 255 & res.server_address.bp_address_u.ip_addr.net, 265 255 & res.server_address.bp_address_u.ip_addr.host, 266 255 & res.server_address.bp_address_u.ip_addr.lh, 267 255 & res.server_address.bp_address_u.ip_addr.impno); 268 if (dolog) 269 syslog(LOG_NOTICE, 270 "returning server:%s path:%s address: %d.%d.%d.%d", 271 res.server_name, res.server_path, 272 255 & res.server_address.bp_address_u.ip_addr.net, 273 255 & res.server_address.bp_address_u.ip_addr.host, 274 255 & res.server_address.bp_address_u.ip_addr.lh, 275 255 & res.server_address.bp_address_u.ip_addr.impno); 276 return (&res); 277 } 278 279 280 int 281 lookup_bootparam(client, client_canonical, id, server, path) 282 char *client; 283 char *client_canonical; 284 char *id; 285 char **server; 286 char **path; 287 { 288 FILE *f = fopen(bootpfile, "r"); 289 #ifdef YP 290 static char *ypbuf = NULL; 291 static int ypbuflen = 0; 292 #endif 293 static char buf[BUFSIZ]; 294 char *bp, *word = NULL; 295 size_t idlen = id == NULL ? 0 : strlen(id); 296 int contin = 0; 297 int found = 0; 298 299 if (f == NULL) 300 return EINVAL; /* ? */ 301 302 while (fgets(buf, sizeof buf, f)) { 303 int wascontin = contin; 304 contin = buf[strlen(buf) - 2] == '\\'; 305 bp = buf + strspn(buf, " \t\n"); 306 307 switch (wascontin) { 308 case -1: 309 /* Continuation of uninteresting line */ 310 contin *= -1; 311 continue; 312 case 0: 313 /* New line */ 314 contin *= -1; 315 if (*bp == '#') 316 continue; 317 if ((word = strsep(&bp, " \t\n")) == NULL) 318 continue; 319 #ifdef YP 320 /* A + in the file means try YP now */ 321 if (!strcmp(word, "+")) { 322 char *ypdom; 323 324 if (yp_get_default_domain(&ypdom) || 325 yp_match(ypdom, "bootparams", client, 326 strlen(client), &ypbuf, &ypbuflen)) 327 continue; 328 bp = ypbuf; 329 word = client; 330 contin *= -1; 331 break; 332 } 333 #endif 334 /* See if this line's client is the one we are 335 * looking for */ 336 if (strcasecmp(word, client) != 0) { 337 /* 338 * If it didn't match, try getting the 339 * canonical host name of the client 340 * on this line and comparing that to 341 * the client we are looking for 342 */ 343 struct hostent *hp = gethostbyname(word); 344 if (hp == NULL || 345 strcasecmp(hp->h_name, client)) 346 continue; 347 } 348 contin *= -1; 349 break; 350 case 1: 351 /* Continued line we want to parse below */ 352 break; 353 } 354 355 if (client_canonical) 356 strncpy(client_canonical, word, MAX_MACHINE_NAME); 357 358 /* We have found a line for CLIENT */ 359 if (id == NULL) { 360 (void) fclose(f); 361 return 0; 362 } 363 364 /* Look for a value for the parameter named by ID */ 365 while ((word = strsep(&bp, " \t\n")) != NULL) { 366 if (!strncmp(word, id, idlen) && word[idlen] == '=') { 367 /* We have found the entry we want */ 368 *server = &word[idlen + 1]; 369 *path = strchr(*server, ':'); 370 if (*path == NULL) 371 /* Malformed entry */ 372 continue; 373 *(*path)++ = '\0'; 374 (void) fclose(f); 375 return 0; 376 } 377 } 378 379 found = 1; 380 } 381 382 (void) fclose(f); 383 return found ? ENOENT : EPERM; 384 } 385 386 void 387 usage() 388 { 389 fprintf(stderr, 390 "usage: %s [-d] [-s] [-r router] [-f bootparmsfile]\n", __progname); 391 exit(1); 392 } 393