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   char info[MAX_FILEID + MAX_PATH_LEN+MAX_MACHINE_NAME + 3];
203 
204   bpf = fopen(bootpfile, "r");
205   if ( ! bpf )
206     errx(1, "no %s", bootpfile);
207 
208   /* XXX see comment below */
209   while ( fscanf(bpf, "%255s", hostname) > 0  && !match ) {
210     if ( *hostname != '#' ) { /* comment */
211       if ( ! strcmp(hostname, askname) ) {
212 	match = 1;
213       } else {
214 	he = gethostbyname(hostname);
215 	if (he && !strcmp(he->h_name, askname)) match = 1;
216       }
217     }
218     if (*hostname == '+' ) { /* NIS */
219 #ifdef YP
220       if (yp_get_default_domain(&yp_domain)) {
221 	 if (debug) warn("NIS");
222 	 return(0);
223       }
224       if (yp_match(yp_domain, "bootparams", askname, strlen(askname),
225 		&result, &resultlen))
226 	return (0);
227       if (strstr(result, fileid) == NULL) {
228 	buffer[0] = '\0';
229       } else {
230 	snprintf(buffer, blen,
231 		"%s",strchr(strstr(result,fileid), '=') + 1);
232 	if (strchr(buffer, ' ') != NULL)
233 	  *(char *)(strchr(buffer, ' ')) = '\0';
234       }
235       if (fclose(bpf))
236         warnx("could not close %s", bootpfile);
237       return(1);
238 #else
239       return(0);	/* ENOTSUP */
240 #endif
241     }
242     /* skip to next entry */
243     if ( match ) break;
244     pch = ch = getc(bpf);
245     while ( ! ( ch == '\n' && pch != '\\') && ch != EOF) {
246       pch = ch; ch = getc(bpf);
247     }
248   }
249 
250   /* if match is true we read the rest of the line to get the
251      info of the file */
252 
253   if (match) {
254     fid_len = strlen(fileid);
255     while ( ! res && (fscanf(bpf,"%s", info)) > 0) { /* read a string */
256       ch = getc(bpf);                                /* and a character */
257       if ( *info != '#' ) {                          /* Comment ? */
258 	if (! strncmp(info, fileid, fid_len) && *(info + fid_len) == '=') {
259 	  where = info + fid_len + 1;
260 	  if ( isprint( *where )) {
261 	    strcpy(buffer, where);                   /* found file */
262 	    res = 1; break;
263 	  }
264 	} else {
265 	  while (isspace(ch) && ch != '\n') ch = getc(bpf);
266 	                                             /* read to end of line */
267 	  if ( ch == '\n' ) {                        /* didn't find it */
268 	    res = -1; break;                         /* but host is there */
269 	  }
270 	  if ( ch == '\\' ) {                        /* more info */
271 	    ch = getc(bpf);                          /* maybe on next line */
272 	    if (ch == '\n') continue;                /* read it in next loop */
273 	    ungetc(ch, bpf); ungetc('\\',bpf); /* push the character(s) back */
274 	  } else ungetc(ch, bpf);              /* but who know what a `\` is */
275 	}                                      /* needed for. */
276       } else break;                            /* a commented rest-of-line */
277     }
278   }
279   if (fclose(bpf)) { warnx("could not close %s", bootpfile); }
280   if ( res == -1) buffer[0] = '\0';            /* host found, file not */
281   return(match);
282 }
283 
284 /* checkhost puts the hostname found in the database file in
285    the hostname-variable and returns 1, if askname is a valid
286    name for a host in the database */
287 
288 int
289 checkhost(askname, hostname, len)
290 char *askname;
291 char *hostname;
292 int len;
293 {
294   int ch, pch;
295   FILE *bpf;
296   int res = 0;
297 #ifdef YP
298   static char *result;
299   int resultlen;
300   static char *yp_domain;
301 #endif
302 
303 /*  struct hostent *cmp_he;*/
304 
305   bpf = fopen(bootpfile, "r");
306   if ( ! bpf )
307     errx(1, "no %s", bootpfile);
308 
309   /* XXX there is no way in ISO C to specify the maximal length for a
310      conversion in a variable way */
311   while ( fscanf(bpf, "%254s", hostname) > 0 ) {
312     if ( *hostname != '#' ) { /* comment */
313       if ( ! strcmp(hostname, askname) ) {
314         /* return true for match of hostname */
315         res = 1;
316         break;
317       } else {
318         /* check the alias list */
319         he = NULL;
320         he = gethostbyname(hostname);
321         if (he && !strcmp(askname, he->h_name)) {
322   	  res = 1;
323 	  break;
324         }
325       }
326     }
327     if (*hostname == '+' ) { /* NIS */
328 #ifdef YP
329       if (yp_get_default_domain(&yp_domain)) {
330 	 if (debug) warn("NIS");
331 	 return(0);
332       }
333       if (!yp_match(yp_domain, "bootparams", askname, strlen(askname),
334 		&result, &resultlen)) {
335         /* return true for match of hostname */
336         he = NULL;
337         he = gethostbyname(askname);
338         if (he && !strcmp(askname, he->h_name)) {
339   	  res = 1;
340 	  snprintf(hostname, len, "%s", he->h_name);
341 	}
342       }
343       if (fclose(bpf))
344         warnx("could not close %s", bootpfile);
345       return(res);
346 #else
347       return(0);	/* ENOTSUP */
348 #endif
349     }
350     /* skip to next entry */
351     pch = ch = getc(bpf);
352     while ( ! ( ch == '\n' && pch != '\\') && ch != EOF) {
353       pch = ch; ch = getc(bpf);
354     }
355   }
356   if (fclose(bpf)) { warnx("could not close %s", bootpfile); }
357   return(res);
358 }
359