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