bootparamd.c revision 320780
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: stable/10/usr.sbin/bootparamd/bootparamd/bootparamd.c 320780 2017-07-07 15:09:08Z asomers $";
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;
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
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#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      return(0);	/* ENOTSUP */
243#endif
244    }
245    /* skip to next entry */
246    if ( match ) break;
247    pch = ch = getc(bpf);
248    while ( ! ( ch == '\n' && pch != '\\') && ch != EOF) {
249      pch = ch; ch = getc(bpf);
250    }
251  }
252
253  /* if match is true we read the rest of the line to get the
254     info of the file */
255
256  if (match) {
257    fid_len = strlen(fileid);
258#define AS_FORMAT(d)	"%" #d "s"
259#define REXPAND(d) AS_FORMAT(d)	/* Force another preprocessor expansion */
260    while ( ! res && (fscanf(bpf, REXPAND(INFOLEN), info)) > 0) {
261      ch = getc(bpf);                                /* and a character */
262      if ( *info != '#' ) {                          /* Comment ? */
263	if (! strncmp(info, fileid, fid_len) && *(info + fid_len) == '=') {
264	  where = info + fid_len + 1;
265	  if ( isprint( *where )) {
266	    strcpy(buffer, where);                   /* found file */
267	    res = 1; break;
268	  }
269	} else {
270	  while (isspace(ch) && ch != '\n') ch = getc(bpf);
271	                                             /* read to end of line */
272	  if ( ch == '\n' ) {                        /* didn't find it */
273	    res = -1; break;                         /* but host is there */
274	  }
275	  if ( ch == '\\' ) {                        /* more info */
276	    ch = getc(bpf);                          /* maybe on next line */
277	    if (ch == '\n') continue;                /* read it in next loop */
278	    ungetc(ch, bpf); ungetc('\\',bpf); /* push the character(s) back */
279	  } else ungetc(ch, bpf);              /* but who know what a `\` is */
280	}                                      /* needed for. */
281      } else break;                            /* a commented rest-of-line */
282    }
283  }
284  if (fclose(bpf)) { warnx("could not close %s", bootpfile); }
285  if ( res == -1) buffer[0] = '\0';            /* host found, file not */
286  return(match);
287}
288
289/* checkhost puts the hostname found in the database file in
290   the hostname-variable and returns 1, if askname is a valid
291   name for a host in the database */
292
293int
294checkhost(askname, hostname, len)
295char *askname;
296char *hostname;
297int len;
298{
299  int ch, pch;
300  FILE *bpf;
301  int res = 0;
302#ifdef YP
303  static char *result;
304  int resultlen;
305  static char *yp_domain;
306#endif
307
308/*  struct hostent *cmp_he;*/
309
310  bpf = fopen(bootpfile, "r");
311  if ( ! bpf )
312    errx(1, "no %s", bootpfile);
313
314  /* XXX there is no way in ISO C to specify the maximal length for a
315     conversion in a variable way */
316  while ( fscanf(bpf, "%254s", hostname) > 0 ) {
317    if ( *hostname != '#' ) { /* comment */
318      if ( ! strcmp(hostname, askname) ) {
319        /* return true for match of hostname */
320        res = 1;
321        break;
322      } else {
323        /* check the alias list */
324        he = NULL;
325        he = gethostbyname(hostname);
326        if (he && !strcmp(askname, he->h_name)) {
327  	  res = 1;
328	  break;
329        }
330      }
331    }
332    if (*hostname == '+' ) { /* NIS */
333#ifdef YP
334      if (yp_get_default_domain(&yp_domain)) {
335	 if (debug) warn("NIS");
336	 return(0);
337      }
338      if (!yp_match(yp_domain, "bootparams", askname, strlen(askname),
339		&result, &resultlen)) {
340        /* return true for match of hostname */
341        he = NULL;
342        he = gethostbyname(askname);
343        if (he && !strcmp(askname, he->h_name)) {
344  	  res = 1;
345	  snprintf(hostname, len, "%s", he->h_name);
346	}
347      }
348      if (fclose(bpf))
349        warnx("could not close %s", bootpfile);
350      return(res);
351#else
352      return(0);	/* ENOTSUP */
353#endif
354    }
355    /* skip to next entry */
356    pch = ch = getc(bpf);
357    while ( ! ( ch == '\n' && pch != '\\') && ch != EOF) {
358      pch = ch; ch = getc(bpf);
359    }
360  }
361  if (fclose(bpf)) { warnx("could not close %s", bootpfile); }
362  return(res);
363}
364