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: src/usr.sbin/bootparamd/bootparamd/bootparamd.c,v 1.10 1999/08/28 01:15:39 peter Exp $";
13 #endif /* not lint */
14 
15 #include <rpc/rpc.h>
16 #include <rpcsvc/yp_prot.h>
17 #include <rpcsvc/ypclnt.h>
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 extern int debug, dolog;
29 extern unsigned long route_addr;
30 extern char *bootpfile;
31 
32 #define MAXLEN 800
33 
34 struct hostent *he;
35 static char buffer[MAXLEN];
36 static char hostname[MAX_MACHINE_NAME];
37 static char askname[MAX_MACHINE_NAME];
38 static char path[MAX_PATH_LEN];
39 static char domain_name[MAX_MACHINE_NAME];
40 
41 int getthefile __P((char *, char *, char *, int));
42 int checkhost __P((char *, char *, int));
43 
44 bp_whoami_res *
45 bootparamproc_whoami_1(whoami)
46 bp_whoami_arg *whoami;
47 {
48   long 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, 4);
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(getfile)
111 bp_getfile_arg *getfile;
112 {
113   char *where, *index();
114   static bp_getfile_res res;
115 
116   if (debug)
117     warnx("getfile got question for \"%s\" and file \"%s\"",
118 	    getfile->client_name, getfile->file_id);
119 
120   if (dolog)
121     syslog(LOG_NOTICE,"getfile got question for \"%s\" and file \"%s\"\n",
122 	    getfile->client_name, getfile->file_id);
123 
124   he = NULL;
125   he = gethostbyname(getfile->client_name);
126   if (! he ) goto failed;
127 
128   strncpy(askname, he->h_name, sizeof(askname));
129   askname[sizeof(askname)-1] = 0;
130 
131   if (getthefile(askname, getfile->file_id,buffer,sizeof(buffer))) {
132     if ( (where = index(buffer,':')) ) {
133       /* buffer is re-written to contain the name of the info of file */
134       strncpy(hostname, buffer, where - buffer);
135       hostname[where - buffer] = '\0';
136       where++;
137       strcpy(path, where);
138       he = gethostbyname(hostname);
139       if ( !he ) goto failed;
140       bcopy( he->h_addr, &res.server_address.bp_address_u.ip_addr, 4);
141       res.server_name = hostname;
142       res.server_path = path;
143       res.server_address.address_type = IP_ADDR_TYPE;
144     }
145     else { /* special for dump, answer with null strings */
146       if (!strcmp(getfile->file_id, "dump")) {
147 	res.server_name = "";
148 	res.server_path = "";
149         res.server_address.address_type = IP_ADDR_TYPE;
150 	bzero(&res.server_address.bp_address_u.ip_addr,4);
151       } else goto failed;
152     }
153     if (debug)
154       fprintf(stderr, "returning server:%s path:%s address: %d.%d.%d.%d\n",
155 	     res.server_name, res.server_path,
156 	     255 &  res.server_address.bp_address_u.ip_addr.net,
157 	     255 & res.server_address.bp_address_u.ip_addr.host,
158 	     255 &  res.server_address.bp_address_u.ip_addr.lh,
159 	     255 & res.server_address.bp_address_u.ip_addr.impno);
160     if (dolog)
161       syslog(LOG_NOTICE, "returning server:%s path:%s address: %d.%d.%d.%d\n",
162 	     res.server_name, res.server_path,
163 	     255 &  res.server_address.bp_address_u.ip_addr.net,
164 	     255 & res.server_address.bp_address_u.ip_addr.host,
165 	     255 &  res.server_address.bp_address_u.ip_addr.lh,
166 	     255 & res.server_address.bp_address_u.ip_addr.impno);
167     return(&res);
168   }
169   failed:
170   if (debug) warnx("getfile failed for %s", getfile->client_name);
171   if (dolog) syslog(LOG_NOTICE,
172 		    "getfile failed for %s\n", getfile->client_name);
173   return(NULL);
174 }
175 
176 /*    getthefile return 1 and fills the buffer with the information
177       of the file, e g "host:/export/root/client" if it can be found.
178       If the host is in the database, but the file is not, the buffer
179       will be empty. (This makes it possible to give the special
180       empty answer for the file "dump")   */
181 
182 int
183 getthefile(askname,fileid,buffer,blen)
184 char *askname;
185 char *fileid, *buffer;
186 int blen;
187 {
188   FILE *bpf;
189   char  *where;
190   static char *result;
191   int resultlen;
192   static char *yp_domain;
193 
194   int ch, pch, fid_len, res = 0;
195   int match = 0;
196   char info[MAX_FILEID + MAX_PATH_LEN+MAX_MACHINE_NAME + 3];
197 
198   bpf = fopen(bootpfile, "r");
199   if ( ! bpf )
200     errx(1, "no %s", bootpfile);
201 
202   /* XXX see comment below */
203   while ( fscanf(bpf, "%255s", hostname) > 0  && !match ) {
204     if ( *hostname != '#' ) { /* comment */
205       if ( ! strcmp(hostname, askname) ) {
206 	match = 1;
207       } else {
208 	he = gethostbyname(hostname);
209 	if (he && !strcmp(he->h_name, askname)) match = 1;
210       }
211     }
212     if (*hostname == '+' ) { /* NIS */
213       if (yp_get_default_domain(&yp_domain)) {
214 	 if (debug) warn("NIS");
215 	 return(0);
216       }
217       if (yp_match(yp_domain, "bootparams", askname, strlen(askname),
218 		&result, &resultlen))
219 	return (0);
220       if (strstr(result, fileid) == NULL) {
221 	buffer[0] = '\0';
222       } else {
223 	snprintf(buffer, blen,
224 		"%s",strchr(strstr(result,fileid), '=') + 1);
225 	if (strchr(buffer, ' ') != NULL)
226 	  *(char *)(strchr(buffer, ' ')) = '\0';
227       }
228       if (fclose(bpf))
229         warnx("could not close %s", bootpfile);
230       return(1);
231     }
232     /* skip to next entry */
233     if ( match ) break;
234     pch = ch = getc(bpf);
235     while ( ! ( ch == '\n' && pch != '\\') && ch != EOF) {
236       pch = ch; ch = getc(bpf);
237     }
238   }
239 
240   /* if match is true we read the rest of the line to get the
241      info of the file */
242 
243   if (match) {
244     fid_len = strlen(fileid);
245     while ( ! res && (fscanf(bpf,"%s", info)) > 0) { /* read a string */
246       ch = getc(bpf);                                /* and a character */
247       if ( *info != '#' ) {                          /* Comment ? */
248 	if (! strncmp(info, fileid, fid_len) && *(info + fid_len) == '=') {
249 	  where = info + fid_len + 1;
250 	  if ( isprint( *where )) {
251 	    strcpy(buffer, where);                   /* found file */
252 	    res = 1; break;
253 	  }
254 	} else {
255 	  while (isspace(ch) && ch != '\n') ch = getc(bpf);
256 	                                             /* read to end of line */
257 	  if ( ch == '\n' ) {                        /* didn't find it */
258 	    res = -1; break;                         /* but host is there */
259 	  }
260 	  if ( ch == '\\' ) {                        /* more info */
261 	    ch = getc(bpf);                          /* maybe on next line */
262 	    if (ch == '\n') continue;                /* read it in next loop */
263 	    ungetc(ch, bpf); ungetc('\\',bpf); /* push the character(s) back */
264 	  } else ungetc(ch, bpf);              /* but who know what a `\` is */
265 	}                                      /* needed for. */
266       } else break;                            /* a commented rest-of-line */
267     }
268   }
269   if (fclose(bpf)) { warnx("could not close %s", bootpfile); }
270   if ( res == -1) buffer[0] = '\0';            /* host found, file not */
271   return(match);
272 }
273 
274 /* checkhost puts the hostname found in the database file in
275    the hostname-variable and returns 1, if askname is a valid
276    name for a host in the database */
277 
278 int
279 checkhost(askname, hostname, len)
280 char *askname;
281 char *hostname;
282 int len;
283 {
284   int ch, pch;
285   FILE *bpf;
286   int res = 0;
287   static char *result;
288   int resultlen;
289   static char *yp_domain;
290 
291 /*  struct hostent *cmp_he;*/
292 
293   bpf = fopen(bootpfile, "r");
294   if ( ! bpf )
295     errx(1, "no %s", bootpfile);
296 
297   /* XXX there is no way in ISO C to specify the maximal length for a
298      conversion in a variable way */
299   while ( fscanf(bpf, "%254s", hostname) > 0 ) {
300     if ( *hostname != '#' ) { /* comment */
301       if ( ! strcmp(hostname, askname) ) {
302         /* return true for match of hostname */
303         res = 1;
304         break;
305       } else {
306         /* check the alias list */
307         he = NULL;
308         he = gethostbyname(hostname);
309         if (he && !strcmp(askname, he->h_name)) {
310   	  res = 1;
311 	  break;
312         }
313       }
314     }
315     if (*hostname == '+' ) { /* NIS */
316       if (yp_get_default_domain(&yp_domain)) {
317 	 if (debug) warn("NIS");
318 	 return(0);
319       }
320       if (!yp_match(yp_domain, "bootparams", askname, strlen(askname),
321 		&result, &resultlen)) {
322         /* return true for match of hostname */
323         he = NULL;
324         he = gethostbyname(askname);
325         if (he && !strcmp(askname, he->h_name)) {
326   	  res = 1;
327 	  snprintf(hostname, len, "%s", he->h_name);
328 	}
329       }
330       if (fclose(bpf))
331         warnx("could not close %s", bootpfile);
332       return(res);
333     }
334     /* skip to next entry */
335     pch = ch = getc(bpf);
336     while ( ! ( ch == '\n' && pch != '\\') && ch != EOF) {
337       pch = ch; ch = getc(bpf);
338     }
339   }
340   if (fclose(bpf)) { warnx("could not close %s", bootpfile); }
341   return(res);
342 }
343