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 #ifndef lint
11 static const char rcsid[] =
12   "$FreeBSD$";
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>
30 extern int debug, dolog;
31 extern in_addr_t route_addr;
32 extern char *bootpfile;
33 
34 #define MAXLEN 800
35 
36 struct hostent *he;
37 static char buffer[MAXLEN];
38 static char hostname[MAX_MACHINE_NAME];
39 static char askname[MAX_MACHINE_NAME];
40 static char path[MAX_PATH_LEN];
41 static char domain_name[MAX_MACHINE_NAME];
42 
43 int getthefile(char *, char *, char *, int);
44 int checkhost(char *, char *, int);
45 
46 bp_whoami_res *
47 bootparamproc_whoami_1_svc(whoami, req)
48 bp_whoami_arg *whoami;
49 struct 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 
112 bp_getfile_res *
113   bootparamproc_getfile_1_svc(getfile, req)
114 bp_getfile_arg *getfile;
115 struct 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 
186 int
187 getthefile(askname,fileid,buffer,blen)
188 char *askname;
189 char *fileid, *buffer;
190 int 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       if (fclose(bpf))
243         warnx("could not close %s", bootpfile);
244       return(0);	/* ENOTSUP */
245 #endif
246     }
247     /* skip to next entry */
248     if ( match ) break;
249     pch = ch = getc(bpf);
250     while ( ! ( ch == '\n' && pch != '\\') && ch != EOF) {
251       pch = ch; ch = getc(bpf);
252     }
253   }
254 
255   /* if match is true we read the rest of the line to get the
256      info of the file */
257 
258   if (match) {
259     fid_len = strlen(fileid);
260 #define AS_FORMAT(d)	"%" #d "s"
261 #define REXPAND(d) AS_FORMAT(d)	/* Force another preprocessor expansion */
262     while ( ! res && (fscanf(bpf, REXPAND(INFOLEN), info)) > 0) {
263       ch = getc(bpf);                                /* and a character */
264       if ( *info != '#' ) {                          /* Comment ? */
265 	if (! strncmp(info, fileid, fid_len) && *(info + fid_len) == '=') {
266 	  where = info + fid_len + 1;
267 	  if ( isprint( *where )) {
268 	    strcpy(buffer, where);                   /* found file */
269 	    res = 1; break;
270 	  }
271 	} else {
272 	  while (isspace(ch) && ch != '\n') ch = getc(bpf);
273 	                                             /* read to end of line */
274 	  if ( ch == '\n' ) {                        /* didn't find it */
275 	    res = -1; break;                         /* but host is there */
276 	  }
277 	  if ( ch == '\\' ) {                        /* more info */
278 	    ch = getc(bpf);                          /* maybe on next line */
279 	    if (ch == '\n') continue;                /* read it in next loop */
280 	    ungetc(ch, bpf); ungetc('\\',bpf); /* push the character(s) back */
281 	  } else ungetc(ch, bpf);              /* but who know what a `\` is */
282 	}                                      /* needed for. */
283       } else break;                            /* a commented rest-of-line */
284     }
285   }
286   if (fclose(bpf)) { warnx("could not close %s", bootpfile); }
287   if ( res == -1) buffer[0] = '\0';            /* host found, file not */
288   return(match);
289 }
290 
291 /* checkhost puts the hostname found in the database file in
292    the hostname-variable and returns 1, if askname is a valid
293    name for a host in the database */
294 
295 int
296 checkhost(askname, hostname, len)
297 char *askname;
298 char *hostname;
299 int len;
300 {
301   int ch, pch;
302   FILE *bpf;
303   int res = 0;
304 #ifdef YP
305   static char *result;
306   int resultlen;
307   static char *yp_domain;
308 #endif
309 
310 /*  struct hostent *cmp_he;*/
311 
312   bpf = fopen(bootpfile, "r");
313   if ( ! bpf )
314     errx(1, "no %s", bootpfile);
315 
316   /* XXX there is no way in ISO C to specify the maximal length for a
317      conversion in a variable way */
318   while ( fscanf(bpf, "%254s", hostname) > 0 ) {
319     if ( *hostname != '#' ) { /* comment */
320       if ( ! strcmp(hostname, askname) ) {
321         /* return true for match of hostname */
322         res = 1;
323         break;
324       } else {
325         /* check the alias list */
326         he = NULL;
327         he = gethostbyname(hostname);
328         if (he && !strcmp(askname, he->h_name)) {
329   	  res = 1;
330 	  break;
331         }
332       }
333     }
334     if (*hostname == '+' ) { /* NIS */
335 #ifdef YP
336       if (yp_get_default_domain(&yp_domain)) {
337 	 if (debug) warn("NIS");
338 	 return(0);
339       }
340       if (!yp_match(yp_domain, "bootparams", askname, strlen(askname),
341 		&result, &resultlen)) {
342         /* return true for match of hostname */
343         he = NULL;
344         he = gethostbyname(askname);
345         if (he && !strcmp(askname, he->h_name)) {
346   	  res = 1;
347 	  snprintf(hostname, len, "%s", he->h_name);
348 	}
349       }
350       if (fclose(bpf))
351         warnx("could not close %s", bootpfile);
352       return(res);
353 #else
354       return(0);	/* ENOTSUP */
355 #endif
356     }
357     /* skip to next entry */
358     pch = ch = getc(bpf);
359     while ( ! ( ch == '\n' && pch != '\\') && ch != EOF) {
360       pch = ch; ch = getc(bpf);
361     }
362   }
363   if (fclose(bpf)) { warnx("could not close %s", bootpfile); }
364   return(res);
365 }
366