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