1/*
2
3This code is not copyright, and is placed in the public domain. Feel free to
4use 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
11static 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>
30extern int debug, dolog;
31extern in_addr_t route_addr;
32extern char *bootpfile;
33
34#define MAXLEN 800
35
36struct hostent *he;
37static char buffer[MAXLEN];
38static char hostname[MAX_MACHINE_NAME];
39static char askname[MAX_MACHINE_NAME];
40static char path[MAX_PATH_LEN];
41static char domain_name[MAX_MACHINE_NAME];
42
43int getthefile(char *, char *, char *, int);
44int checkhost(char *, char *, int);
45
46bp_whoami_res *
47bootparamproc_whoami_1_svc(whoami, req)
48bp_whoami_arg *whoami;
49struct 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
112bp_getfile_res *
113  bootparamproc_getfile_1_svc(getfile, req)
114bp_getfile_arg *getfile;
115struct svc_req *req;
116{
117  char *where, *index();
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 = index(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
186int
187getthefile(askname,fileid,buffer,blen)
188char *askname;
189char *fileid, *buffer;
190int 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
288int
289checkhost(askname, hostname, len)
290char *askname;
291char *hostname;
292int 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