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