1 /* 2 * This code is not copyright, and is placed in the public domain. 3 * Feel free to use and modify. Please send modifications and/or 4 * suggestions + bug fixes to Klas Heggemann <klas@nada.kth.se> 5 * 6 * Various small changes by Theo de Raadt <deraadt@fsa.ca> 7 * Parser rewritten (adding YP support) by Roland McGrath <roland@frob.com> 8 * 9 * $Id: bootparamd.c,v 1.3 1994/01/23 21:55:56 deraadt Exp $ 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(); 35 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 int i, s, pid; 64 char *rindex(); 65 struct hostent *he; 66 struct stat buf; 67 char *optstring; 68 char c; 69 70 progname = rindex(argv[0], '/'); 71 if (progname) 72 progname++; 73 else 74 progname = argv[0]; 75 76 while ((c = getopt(argc, argv, "dsr:f:")) != EOF) 77 switch (c) { 78 case 'd': 79 debug = 1; 80 break; 81 case 'r': 82 if (isdigit(*optarg)) { 83 route_addr = inet_addr(optarg); 84 break; 85 } 86 he = gethostbyname(optarg); 87 if (!he) { 88 fprintf(stderr, "%s: No such host %s\n", 89 progname, optarg); 90 usage(); 91 exit(1); 92 } 93 bcopy(he->h_addr, (char *) &route_addr, sizeof(route_addr)); 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 exit(1); 110 } 111 112 if (stat(bootpfile, &buf)) { 113 fprintf(stderr, "%s: ", progname); 114 perror(bootpfile); 115 exit(1); 116 } 117 if (!route_addr) { 118 get_myaddress(&my_addr); 119 bcopy(&my_addr.sin_addr.s_addr, &route_addr, sizeof(route_addr)); 120 } 121 if (!debug) 122 daemon(); 123 124 (void) pmap_unset(BOOTPARAMPROG, BOOTPARAMVERS); 125 126 transp = svcudp_create(RPC_ANYSOCK); 127 if (transp == NULL) { 128 fprintf(stderr, "cannot create udp service.\n"); 129 exit(1); 130 } 131 if (!svc_register(transp, BOOTPARAMPROG, BOOTPARAMVERS, 132 bootparamprog_1, IPPROTO_UDP)) { 133 fprintf(stderr, 134 "bootparamd: unable to register BOOTPARAMPROG version %d, udp)\n", 135 BOOTPARAMVERS); 136 exit(1); 137 } 138 svc_run(); 139 fprintf(stderr, "svc_run returned\n"); 140 exit(1); 141 } 142 143 bp_whoami_res * 144 bootparamproc_whoami_1(whoami) 145 bp_whoami_arg *whoami; 146 { 147 long haddr; 148 static bp_whoami_res res; 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 goto failed; 168 169 if (debug) 170 fprintf(stderr, "This is host %s\n", he->h_name); 171 if (dolog) 172 syslog(LOG_NOTICE, "This is host %s\n", he->h_name); 173 174 strcpy(askname, he->h_name); 175 if (!lookup_bootparam(askname, hostname, NULL, NULL, NULL)) { 176 res.client_name = hostname; 177 getdomainname(domain_name, MAX_MACHINE_NAME); 178 res.domain_name = domain_name; 179 180 if (res.router_address.address_type != IP_ADDR_TYPE) { 181 res.router_address.address_type = IP_ADDR_TYPE; 182 bcopy(&route_addr, &res.router_address.bp_address_u.ip_addr, 4); 183 } 184 if (debug) 185 fprintf(stderr, "Returning %s %s %d.%d.%d.%d\n", 186 res.client_name, res.domain_name, 187 255 & res.router_address.bp_address_u.ip_addr.net, 188 255 & res.router_address.bp_address_u.ip_addr.host, 189 255 & res.router_address.bp_address_u.ip_addr.lh, 190 255 & res.router_address.bp_address_u.ip_addr.impno); 191 if (dolog) 192 syslog(LOG_NOTICE, "Returning %s %s %d.%d.%d.%d\n", 193 res.client_name, res.domain_name, 194 255 & res.router_address.bp_address_u.ip_addr.net, 195 255 & res.router_address.bp_address_u.ip_addr.host, 196 255 & res.router_address.bp_address_u.ip_addr.lh, 197 255 & res.router_address.bp_address_u.ip_addr.impno); 198 199 return (&res); 200 } 201 failed: 202 if (debug) 203 fprintf(stderr, "whoami failed\n"); 204 if (dolog) 205 syslog(LOG_NOTICE, "whoami failed\n"); 206 return (NULL); 207 } 208 209 210 bp_getfile_res * 211 bootparamproc_getfile_1(getfile) 212 bp_getfile_arg *getfile; 213 { 214 char *where, *index(); 215 static bp_getfile_res res; 216 int err; 217 218 if (debug) 219 fprintf(stderr, "getfile got question for \"%s\" and file \"%s\"\n", 220 getfile->client_name, getfile->file_id); 221 222 if (dolog) 223 syslog(LOG_NOTICE, "getfile got question for \"%s\" and file \"%s\"\n", 224 getfile->client_name, getfile->file_id); 225 226 he = NULL; 227 he = gethostbyname(getfile->client_name); 228 if (!he) 229 goto failed; 230 231 strcpy(askname, he->h_name); 232 err = lookup_bootparam(askname, NULL, getfile->file_id, 233 &res.server_name, &res.server_path); 234 if (err == 0) { 235 he = gethostbyname(res.server_name); 236 if (!he) 237 goto failed; 238 bcopy(he->h_addr, &res.server_address.bp_address_u.ip_addr, 4); 239 res.server_address.address_type = IP_ADDR_TYPE; 240 } else if (err == ENOENT && !strcmp(getfile->file_id, "dump")) { 241 /* Special for dump, answer with null strings. */ 242 res.server_name[0] = '\0'; 243 res.server_path[0] = '\0'; 244 bzero(&res.server_address.bp_address_u.ip_addr, 4); 245 } else { 246 failed: 247 if (debug) 248 fprintf(stderr, "getfile failed for %s\n", 249 getfile->client_name); 250 if (dolog) 251 syslog(LOG_NOTICE, 252 "getfile failed for %s\n", getfile->client_name); 253 return (NULL); 254 } 255 256 if (debug) 257 fprintf(stderr, 258 "returning server:%s path:%s address: %d.%d.%d.%d\n", 259 res.server_name, res.server_path, 260 255 & res.server_address.bp_address_u.ip_addr.net, 261 255 & res.server_address.bp_address_u.ip_addr.host, 262 255 & res.server_address.bp_address_u.ip_addr.lh, 263 255 & res.server_address.bp_address_u.ip_addr.impno); 264 if (dolog) 265 syslog(LOG_NOTICE, 266 "returning server:%s path:%s address: %d.%d.%d.%d\n", 267 res.server_name, res.server_path, 268 255 & res.server_address.bp_address_u.ip_addr.net, 269 255 & res.server_address.bp_address_u.ip_addr.host, 270 255 & res.server_address.bp_address_u.ip_addr.lh, 271 255 & res.server_address.bp_address_u.ip_addr.impno); 272 return (&res); 273 } 274 275 276 int 277 lookup_bootparam(client, client_canonical, id, server, path) 278 char *client; 279 char *client_canonical; 280 char *id; 281 char **server; 282 char **path; 283 { 284 FILE *f = fopen(bootpfile, "r"); 285 #ifdef YP 286 static char *ypbuf = NULL; 287 static int ypbuflen = 0; 288 #endif 289 static char buf[BUFSIZ]; 290 char *bp, *word; 291 size_t idlen = id == NULL ? 0 : strlen(id); 292 int contin = 0; 293 int found = 0; 294 295 if (f == NULL) 296 return EINVAL; /* ? */ 297 298 while (fgets(buf, sizeof buf, f)) { 299 int wascontin = contin; 300 contin = buf[strlen(buf) - 2] == '\\'; 301 bp = buf + strspn(buf, " \t\n"); 302 303 switch (wascontin) { 304 case -1: 305 /* Continuation of uninteresting line */ 306 contin *= -1; 307 continue; 308 case 0: 309 /* New line */ 310 contin *= -1; 311 if (*bp == '#') 312 continue; 313 if ((word = strsep(&bp, " \t\n")) == NULL) 314 continue; 315 #ifdef YP 316 /* A + in the file means try YP now */ 317 if (!strcmp(word, "+")) { 318 char *ypdom; 319 320 if (yp_get_default_domain(&ypdom) || 321 yp_match(ypdom, "bootparams", client, 322 strlen(client), &ypbuf, &ypbuflen)) 323 continue; 324 bp = ypbuf; 325 word = client; 326 contin *= -1; 327 break; 328 } 329 #endif 330 /* See if this line's client is the one we are 331 * looking for */ 332 if (strcmp(word, client) != 0) { 333 /* 334 * If it didn't match, try getting the 335 * canonical host name of the client 336 * on this line and comparing that to 337 * the client we are looking for 338 */ 339 struct hostent *hp = gethostbyname(word); 340 if (hp == NULL || strcmp(hp->h_name, client)) 341 continue; 342 } 343 contin *= -1; 344 break; 345 case 1: 346 /* Continued line we want to parse below */ 347 break; 348 } 349 350 if (client_canonical) 351 strncpy(client_canonical, word, MAX_MACHINE_NAME); 352 353 /* We have found a line for CLIENT */ 354 if (id == NULL) 355 return 0; 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