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