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