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