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