bootparamd.c revision 36794
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	"$Id: bootparamd.c,v 1.8 1997/10/19 10:42:39 joerg 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>
28extern int debug, dolog;
29extern unsigned long route_addr;
30extern char *bootpfile;
31
32#define MAXLEN 800
33
34struct hostent *he;
35static char buffer[MAXLEN];
36static char hostname[MAX_MACHINE_NAME];
37static char askname[MAX_MACHINE_NAME];
38static char path[MAX_PATH_LEN];
39static char domain_name[MAX_MACHINE_NAME];
40
41int getthefile __P((char *, char *, char *, int));
42int checkhost __P((char *, char *, int));
43
44bp_whoami_res *
45bootparamproc_whoami_1(whoami)
46bp_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
109bp_getfile_res *
110  bootparamproc_getfile_1(getfile)
111bp_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
182int
183getthefile(askname,fileid,buffer,blen)
184char *askname;
185char *fileid, *buffer;
186int 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
278int
279checkhost(askname, hostname, len)
280char *askname;
281char *hostname;
282int 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