1 /* $NetBSD: bootparamd.c,v 1.7 1996/08/30 20:10:26 thorpej 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 "pathnames.h" 24 25 #define MAXLEN 800 26 27 struct hostent *he; 28 static char buffer[MAXLEN]; 29 static char hostname[MAX_MACHINE_NAME]; 30 static char askname[MAX_MACHINE_NAME]; 31 static char path[MAX_PATH_LEN]; 32 static char domain_name[MAX_MACHINE_NAME]; 33 34 extern void bootparamprog_1 __P((struct svc_req *, SVCXPRT *)); 35 36 int _rpcsvcdirty = 0; 37 int _rpcpmstart = 0; 38 int debug = 0; 39 int dolog = 0; 40 unsigned long route_addr, inet_addr(); 41 struct sockaddr_in my_addr; 42 char *progname; 43 char *bootpfile = _PATH_BOOTPARAMS; 44 45 extern char *optarg; 46 extern int optind; 47 48 void 49 usage() 50 { 51 fprintf(stderr, 52 "usage: rpc.bootparamd [-d] [-s] [-r router] [-f bootparmsfile]\n"); 53 } 54 55 56 /* 57 * ever familiar 58 */ 59 int 60 main(argc, argv) 61 int argc; 62 char **argv; 63 { 64 SVCXPRT *transp; 65 int i, s, pid; 66 char *rindex(); 67 struct hostent *he; 68 struct stat buf; 69 char *optstring; 70 int c; 71 72 progname = rindex(argv[0], '/'); 73 if (progname) 74 progname++; 75 else 76 progname = argv[0]; 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 route_addr = inet_addr(optarg); 86 break; 87 } 88 he = gethostbyname(optarg); 89 if (!he) { 90 fprintf(stderr, "%s: No such host %s\n", 91 progname, optarg); 92 usage(); 93 exit(1); 94 } 95 bcopy(he->h_addr, (char *) &route_addr, sizeof(route_addr)); 96 break; 97 case 'f': 98 bootpfile = optarg; 99 break; 100 case 's': 101 dolog = 1; 102 #ifndef LOG_DAEMON 103 openlog(progname, 0, 0); 104 #else 105 openlog(progname, 0, LOG_DAEMON); 106 setlogmask(LOG_UPTO(LOG_NOTICE)); 107 #endif 108 break; 109 default: 110 usage(); 111 exit(1); 112 } 113 114 if (stat(bootpfile, &buf)) { 115 fprintf(stderr, "%s: ", progname); 116 perror(bootpfile); 117 exit(1); 118 } 119 if (!route_addr) { 120 get_myaddress(&my_addr); 121 bcopy(&my_addr.sin_addr.s_addr, &route_addr, sizeof(route_addr)); 122 } 123 if (!debug) 124 daemon(); 125 126 (void) pmap_unset(BOOTPARAMPROG, BOOTPARAMVERS); 127 128 transp = svcudp_create(RPC_ANYSOCK); 129 if (transp == NULL) { 130 fprintf(stderr, "cannot create udp service.\n"); 131 exit(1); 132 } 133 if (!svc_register(transp, BOOTPARAMPROG, BOOTPARAMVERS, 134 bootparamprog_1, IPPROTO_UDP)) { 135 fprintf(stderr, 136 "bootparamd: unable to register BOOTPARAMPROG version %d, udp)\n", 137 BOOTPARAMVERS); 138 exit(1); 139 } 140 svc_run(); 141 fprintf(stderr, "svc_run returned\n"); 142 exit(1); 143 } 144 145 bp_whoami_res * 146 bootparamproc_whoami_1_svc(whoami, rqstp) 147 bp_whoami_arg *whoami; 148 struct svc_req *rqstp; 149 { 150 long haddr; 151 static bp_whoami_res res; 152 153 if (debug) 154 fprintf(stderr, "whoami got question for %d.%d.%d.%d\n", 155 255 & whoami->client_address.bp_address_u.ip_addr.net, 156 255 & whoami->client_address.bp_address_u.ip_addr.host, 157 255 & whoami->client_address.bp_address_u.ip_addr.lh, 158 255 & whoami->client_address.bp_address_u.ip_addr.impno); 159 if (dolog) 160 syslog(LOG_NOTICE, "whoami got question for %d.%d.%d.%d\n", 161 255 & whoami->client_address.bp_address_u.ip_addr.net, 162 255 & whoami->client_address.bp_address_u.ip_addr.host, 163 255 & whoami->client_address.bp_address_u.ip_addr.lh, 164 255 & whoami->client_address.bp_address_u.ip_addr.impno); 165 166 bcopy((char *) &whoami->client_address.bp_address_u.ip_addr, (char *) &haddr, 167 sizeof(haddr)); 168 he = gethostbyaddr((char *) &haddr, sizeof(haddr), AF_INET); 169 if (!he) 170 goto failed; 171 172 if (debug) 173 fprintf(stderr, "This is host %s\n", he->h_name); 174 if (dolog) 175 syslog(LOG_NOTICE, "This is host %s\n", he->h_name); 176 177 strcpy(askname, he->h_name); 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 failed: 205 if (debug) 206 fprintf(stderr, "whoami failed\n"); 207 if (dolog) 208 syslog(LOG_NOTICE, "whoami failed\n"); 209 return (NULL); 210 } 211 212 213 bp_getfile_res * 214 bootparamproc_getfile_1_svc(getfile, rqstp) 215 bp_getfile_arg *getfile; 216 struct svc_req *rqstp; 217 { 218 char *where, *index(); 219 static bp_getfile_res res; 220 int err; 221 222 if (debug) 223 fprintf(stderr, "getfile got question for \"%s\" and file \"%s\"\n", 224 getfile->client_name, getfile->file_id); 225 226 if (dolog) 227 syslog(LOG_NOTICE, "getfile got question for \"%s\" and file \"%s\"\n", 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 strcpy(askname, he->h_name); 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 fprintf(stderr, "getfile failed for %s\n", 253 getfile->client_name); 254 if (dolog) 255 syslog(LOG_NOTICE, 256 "getfile failed for %s\n", getfile->client_name); 257 return (NULL); 258 } 259 260 if (debug) 261 fprintf(stderr, 262 "returning server:%s path:%s address: %d.%d.%d.%d\n", 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\n", 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; 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 (strcmp(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 || strcmp(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