bootparamd.c revision 320780
1/* 2 3This code is not copyright, and is placed in the public domain. Feel free to 4use and modify. Please send modifications and/or suggestions + bug fixes to 5 6 Klas Heggemann <klas@nada.kth.se> 7 8*/ 9 10#ifndef lint 11static const char rcsid[] = 12 "$FreeBSD: stable/10/usr.sbin/bootparamd/bootparamd/bootparamd.c 320780 2017-07-07 15:09:08Z asomers $"; 13#endif /* not lint */ 14 15#ifdef YP 16#include <rpc/rpc.h> 17#include <rpcsvc/yp_prot.h> 18#include <rpcsvc/ypclnt.h> 19#endif 20#include "bootparam_prot.h" 21#include <ctype.h> 22#include <err.h> 23#include <netdb.h> 24#include <stdio.h> 25#include <string.h> 26#include <syslog.h> 27#include <unistd.h> 28#include <sys/types.h> 29#include <sys/socket.h> 30extern int debug, dolog; 31extern in_addr_t route_addr; 32extern char *bootpfile; 33 34#define MAXLEN 800 35 36struct hostent *he; 37static char buffer[MAXLEN]; 38static char hostname[MAX_MACHINE_NAME]; 39static char askname[MAX_MACHINE_NAME]; 40static char path[MAX_PATH_LEN]; 41static char domain_name[MAX_MACHINE_NAME]; 42 43int getthefile(char *, char *, char *, int); 44int checkhost(char *, char *, int); 45 46bp_whoami_res * 47bootparamproc_whoami_1_svc(whoami, req) 48bp_whoami_arg *whoami; 49struct svc_req *req; 50{ 51 in_addr_t haddr; 52 static bp_whoami_res res; 53 if (debug) 54 fprintf(stderr,"whoami got question for %d.%d.%d.%d\n", 55 255 & whoami->client_address.bp_address_u.ip_addr.net, 56 255 & whoami->client_address.bp_address_u.ip_addr.host, 57 255 & whoami->client_address.bp_address_u.ip_addr.lh, 58 255 & whoami->client_address.bp_address_u.ip_addr.impno); 59 if (dolog) 60 syslog(LOG_NOTICE, "whoami got question for %d.%d.%d.%d\n", 61 255 & whoami->client_address.bp_address_u.ip_addr.net, 62 255 & whoami->client_address.bp_address_u.ip_addr.host, 63 255 & whoami->client_address.bp_address_u.ip_addr.lh, 64 255 & whoami->client_address.bp_address_u.ip_addr.impno); 65 66 bcopy((char *)&whoami->client_address.bp_address_u.ip_addr, (char *)&haddr, 67 sizeof(haddr)); 68 he = gethostbyaddr((char *)&haddr,sizeof(haddr),AF_INET); 69 if ( ! he ) goto failed; 70 71 if (debug) warnx("this is host %s", he->h_name); 72 if (dolog) syslog(LOG_NOTICE,"This is host %s\n", he->h_name); 73 74 strncpy(askname, he->h_name, sizeof(askname)); 75 askname[sizeof(askname)-1] = 0; 76 77 if (checkhost(askname, hostname, sizeof hostname) ) { 78 res.client_name = hostname; 79 getdomainname(domain_name, MAX_MACHINE_NAME); 80 res.domain_name = domain_name; 81 82 if ( res.router_address.address_type != IP_ADDR_TYPE ) { 83 res.router_address.address_type = IP_ADDR_TYPE; 84 bcopy( &route_addr, &res.router_address.bp_address_u.ip_addr, sizeof(in_addr_t)); 85 } 86 if (debug) fprintf(stderr, 87 "Returning %s %s %d.%d.%d.%d\n", 88 res.client_name, 89 res.domain_name, 90 255 & res.router_address.bp_address_u.ip_addr.net, 91 255 & res.router_address.bp_address_u.ip_addr.host, 92 255 & res.router_address.bp_address_u.ip_addr.lh, 93 255 & res.router_address.bp_address_u.ip_addr.impno); 94 if (dolog) syslog(LOG_NOTICE, 95 "Returning %s %s %d.%d.%d.%d\n", 96 res.client_name, 97 res.domain_name, 98 255 & res.router_address.bp_address_u.ip_addr.net, 99 255 & res.router_address.bp_address_u.ip_addr.host, 100 255 & res.router_address.bp_address_u.ip_addr.lh, 101 255 & res.router_address.bp_address_u.ip_addr.impno); 102 103 return(&res); 104 } 105 failed: 106 if (debug) warnx("whoami failed"); 107 if (dolog) syslog(LOG_NOTICE,"whoami failed\n"); 108 return(NULL); 109} 110 111 112bp_getfile_res * 113 bootparamproc_getfile_1_svc(getfile, req) 114bp_getfile_arg *getfile; 115struct svc_req *req; 116{ 117 char *where; 118 static bp_getfile_res res; 119 120 if (debug) 121 warnx("getfile got question for \"%s\" and file \"%s\"", 122 getfile->client_name, getfile->file_id); 123 124 if (dolog) 125 syslog(LOG_NOTICE,"getfile got question for \"%s\" and file \"%s\"\n", 126 getfile->client_name, getfile->file_id); 127 128 he = NULL; 129 he = gethostbyname(getfile->client_name); 130 if (! he ) goto failed; 131 132 strncpy(askname, he->h_name, sizeof(askname)); 133 askname[sizeof(askname)-1] = 0; 134 135 if (getthefile(askname, getfile->file_id,buffer,sizeof(buffer))) { 136 if ( (where = strchr(buffer,':')) ) { 137 /* buffer is re-written to contain the name of the info of file */ 138 strncpy(hostname, buffer, where - buffer); 139 hostname[where - buffer] = '\0'; 140 where++; 141 strcpy(path, where); 142 he = gethostbyname(hostname); 143 if ( !he ) goto failed; 144 bcopy( he->h_addr, &res.server_address.bp_address_u.ip_addr, 4); 145 res.server_name = hostname; 146 res.server_path = path; 147 res.server_address.address_type = IP_ADDR_TYPE; 148 } 149 else { /* special for dump, answer with null strings */ 150 if (!strcmp(getfile->file_id, "dump")) { 151 res.server_name = ""; 152 res.server_path = ""; 153 res.server_address.address_type = IP_ADDR_TYPE; 154 bzero(&res.server_address.bp_address_u.ip_addr,4); 155 } else goto failed; 156 } 157 if (debug) 158 fprintf(stderr, "returning server:%s path:%s address: %d.%d.%d.%d\n", 159 res.server_name, res.server_path, 160 255 & res.server_address.bp_address_u.ip_addr.net, 161 255 & res.server_address.bp_address_u.ip_addr.host, 162 255 & res.server_address.bp_address_u.ip_addr.lh, 163 255 & res.server_address.bp_address_u.ip_addr.impno); 164 if (dolog) 165 syslog(LOG_NOTICE, "returning server:%s path:%s address: %d.%d.%d.%d\n", 166 res.server_name, res.server_path, 167 255 & res.server_address.bp_address_u.ip_addr.net, 168 255 & res.server_address.bp_address_u.ip_addr.host, 169 255 & res.server_address.bp_address_u.ip_addr.lh, 170 255 & res.server_address.bp_address_u.ip_addr.impno); 171 return(&res); 172 } 173 failed: 174 if (debug) warnx("getfile failed for %s", getfile->client_name); 175 if (dolog) syslog(LOG_NOTICE, 176 "getfile failed for %s\n", getfile->client_name); 177 return(NULL); 178} 179 180/* getthefile return 1 and fills the buffer with the information 181 of the file, e g "host:/export/root/client" if it can be found. 182 If the host is in the database, but the file is not, the buffer 183 will be empty. (This makes it possible to give the special 184 empty answer for the file "dump") */ 185 186int 187getthefile(askname,fileid,buffer,blen) 188char *askname; 189char *fileid, *buffer; 190int blen; 191{ 192 FILE *bpf; 193 char *where; 194#ifdef YP 195 static char *result; 196 int resultlen; 197 static char *yp_domain; 198#endif 199 200 int ch, pch, fid_len, res = 0; 201 int match = 0; 202#define INFOLEN 1343 203 _Static_assert(INFOLEN >= MAX_FILEID + MAX_PATH_LEN+MAX_MACHINE_NAME + 3, 204 "INFOLEN isn't large enough"); 205 char info[INFOLEN + 1]; 206 207 bpf = fopen(bootpfile, "r"); 208 if ( ! bpf ) 209 errx(1, "no %s", bootpfile); 210 211 /* XXX see comment below */ 212 while ( fscanf(bpf, "%255s", hostname) > 0 && !match ) { 213 if ( *hostname != '#' ) { /* comment */ 214 if ( ! strcmp(hostname, askname) ) { 215 match = 1; 216 } else { 217 he = gethostbyname(hostname); 218 if (he && !strcmp(he->h_name, askname)) match = 1; 219 } 220 } 221 if (*hostname == '+' ) { /* NIS */ 222#ifdef YP 223 if (yp_get_default_domain(&yp_domain)) { 224 if (debug) warn("NIS"); 225 return(0); 226 } 227 if (yp_match(yp_domain, "bootparams", askname, strlen(askname), 228 &result, &resultlen)) 229 return (0); 230 if (strstr(result, fileid) == NULL) { 231 buffer[0] = '\0'; 232 } else { 233 snprintf(buffer, blen, 234 "%s",strchr(strstr(result,fileid), '=') + 1); 235 if (strchr(buffer, ' ') != NULL) 236 *(char *)(strchr(buffer, ' ')) = '\0'; 237 } 238 if (fclose(bpf)) 239 warnx("could not close %s", bootpfile); 240 return(1); 241#else 242 return(0); /* ENOTSUP */ 243#endif 244 } 245 /* skip to next entry */ 246 if ( match ) break; 247 pch = ch = getc(bpf); 248 while ( ! ( ch == '\n' && pch != '\\') && ch != EOF) { 249 pch = ch; ch = getc(bpf); 250 } 251 } 252 253 /* if match is true we read the rest of the line to get the 254 info of the file */ 255 256 if (match) { 257 fid_len = strlen(fileid); 258#define AS_FORMAT(d) "%" #d "s" 259#define REXPAND(d) AS_FORMAT(d) /* Force another preprocessor expansion */ 260 while ( ! res && (fscanf(bpf, REXPAND(INFOLEN), info)) > 0) { 261 ch = getc(bpf); /* and a character */ 262 if ( *info != '#' ) { /* Comment ? */ 263 if (! strncmp(info, fileid, fid_len) && *(info + fid_len) == '=') { 264 where = info + fid_len + 1; 265 if ( isprint( *where )) { 266 strcpy(buffer, where); /* found file */ 267 res = 1; break; 268 } 269 } else { 270 while (isspace(ch) && ch != '\n') ch = getc(bpf); 271 /* read to end of line */ 272 if ( ch == '\n' ) { /* didn't find it */ 273 res = -1; break; /* but host is there */ 274 } 275 if ( ch == '\\' ) { /* more info */ 276 ch = getc(bpf); /* maybe on next line */ 277 if (ch == '\n') continue; /* read it in next loop */ 278 ungetc(ch, bpf); ungetc('\\',bpf); /* push the character(s) back */ 279 } else ungetc(ch, bpf); /* but who know what a `\` is */ 280 } /* needed for. */ 281 } else break; /* a commented rest-of-line */ 282 } 283 } 284 if (fclose(bpf)) { warnx("could not close %s", bootpfile); } 285 if ( res == -1) buffer[0] = '\0'; /* host found, file not */ 286 return(match); 287} 288 289/* checkhost puts the hostname found in the database file in 290 the hostname-variable and returns 1, if askname is a valid 291 name for a host in the database */ 292 293int 294checkhost(askname, hostname, len) 295char *askname; 296char *hostname; 297int len; 298{ 299 int ch, pch; 300 FILE *bpf; 301 int res = 0; 302#ifdef YP 303 static char *result; 304 int resultlen; 305 static char *yp_domain; 306#endif 307 308/* struct hostent *cmp_he;*/ 309 310 bpf = fopen(bootpfile, "r"); 311 if ( ! bpf ) 312 errx(1, "no %s", bootpfile); 313 314 /* XXX there is no way in ISO C to specify the maximal length for a 315 conversion in a variable way */ 316 while ( fscanf(bpf, "%254s", hostname) > 0 ) { 317 if ( *hostname != '#' ) { /* comment */ 318 if ( ! strcmp(hostname, askname) ) { 319 /* return true for match of hostname */ 320 res = 1; 321 break; 322 } else { 323 /* check the alias list */ 324 he = NULL; 325 he = gethostbyname(hostname); 326 if (he && !strcmp(askname, he->h_name)) { 327 res = 1; 328 break; 329 } 330 } 331 } 332 if (*hostname == '+' ) { /* NIS */ 333#ifdef YP 334 if (yp_get_default_domain(&yp_domain)) { 335 if (debug) warn("NIS"); 336 return(0); 337 } 338 if (!yp_match(yp_domain, "bootparams", askname, strlen(askname), 339 &result, &resultlen)) { 340 /* return true for match of hostname */ 341 he = NULL; 342 he = gethostbyname(askname); 343 if (he && !strcmp(askname, he->h_name)) { 344 res = 1; 345 snprintf(hostname, len, "%s", he->h_name); 346 } 347 } 348 if (fclose(bpf)) 349 warnx("could not close %s", bootpfile); 350 return(res); 351#else 352 return(0); /* ENOTSUP */ 353#endif 354 } 355 /* skip to next entry */ 356 pch = ch = getc(bpf); 357 while ( ! ( ch == '\n' && pch != '\\') && ch != EOF) { 358 pch = ch; ch = getc(bpf); 359 } 360 } 361 if (fclose(bpf)) { warnx("could not close %s", bootpfile); } 362 return(res); 363} 364