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 /*
11  * $FreeBSD: src/usr.sbin/bootparamd/bootparamd/bootparamd.c,v 1.10 1999/08/28 01:15:39 peter Exp $
12  * $DragonFly: src/usr.sbin/bootparamd/bootparamd/bootparamd.c,v 1.4 2003/11/15 23:33:35 eirikn Exp $
13  */
14 #include <rpc/rpc.h>
15 #include <rpcsvc/yp_prot.h>
16 #include <rpcsvc/ypclnt.h>
17 #include "bootparam_prot.h"
18 #include <ctype.h>
19 #include <err.h>
20 #include <netdb.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <syslog.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 extern int debug, dolog;
28 extern unsigned long route_addr;
29 extern char *bootpfile;
30 
31 #define MAXLEN 800
32 
33 struct hostent *he;
34 static char buffer[MAXLEN];
35 static char hostname[MAX_MACHINE_NAME];
36 static char askname[MAX_MACHINE_NAME];
37 static char path[MAX_PATH_LEN];
38 static char domain_name[MAX_MACHINE_NAME];
39 
40 int getthefile(char *, char *, char *, int);
41 int checkhost(char *, char *, int);
42 
43 bp_whoami_res *
44 bootparamproc_whoami_1(bp_whoami_arg *whoami)
45 {
46   long 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, 4);
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(bp_getfile_arg *getfile)
109 {
110   char *where, *index();
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 = index(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 buffer 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 buffer
176       will be empty. (This makes it possible to give the special
177       empty answer for the file "dump")   */
178 
179 int
180 getthefile(char *askname, char *fileid, char *buffer, int blen)
181 {
182   FILE *bpf;
183   char  *where;
184   static char *result;
185   int resultlen;
186   static char *yp_domain;
187 
188   int ch, pch, fid_len, res = 0;
189   int match = 0;
190   char info[MAX_FILEID + MAX_PATH_LEN+MAX_MACHINE_NAME + 3];
191 
192   bpf = fopen(bootpfile, "r");
193   if ( ! bpf )
194     errx(1, "no %s", bootpfile);
195 
196   /* XXX see comment below */
197   while ( fscanf(bpf, "%255s", hostname) > 0  && !match ) {
198     if ( *hostname != '#' ) { /* comment */
199       if ( ! strcmp(hostname, askname) ) {
200 	match = 1;
201       } else {
202 	he = gethostbyname(hostname);
203 	if (he && !strcmp(he->h_name, askname)) match = 1;
204       }
205     }
206     if (*hostname == '+' ) { /* NIS */
207       if (yp_get_default_domain(&yp_domain)) {
208 	 if (debug) warn("NIS");
209 	 return(0);
210       }
211       if (yp_match(yp_domain, "bootparams", askname, strlen(askname),
212 		&result, &resultlen))
213 	return (0);
214       if (strstr(result, fileid) == NULL) {
215 	buffer[0] = '\0';
216       } else {
217 	snprintf(buffer, blen,
218 		"%s",strchr(strstr(result,fileid), '=') + 1);
219 	if (strchr(buffer, ' ') != NULL)
220 	  *(char *)(strchr(buffer, ' ')) = '\0';
221       }
222       if (fclose(bpf))
223         warnx("could not close %s", bootpfile);
224       return(1);
225     }
226     /* skip to next entry */
227     if ( match ) break;
228     pch = ch = getc(bpf);
229     while ( ! ( ch == '\n' && pch != '\\') && ch != EOF) {
230       pch = ch; ch = getc(bpf);
231     }
232   }
233 
234   /* if match is true we read the rest of the line to get the
235      info of the file */
236 
237   if (match) {
238     fid_len = strlen(fileid);
239     while ( ! res && (fscanf(bpf,"%s", info)) > 0) { /* read a string */
240       ch = getc(bpf);                                /* and a character */
241       if ( *info != '#' ) {                          /* Comment ? */
242 	if (! strncmp(info, fileid, fid_len) && *(info + fid_len) == '=') {
243 	  where = info + fid_len + 1;
244 	  if ( isprint( *where )) {
245 	    strcpy(buffer, where);                   /* found file */
246 	    res = 1; break;
247 	  }
248 	} else {
249 	  while (isspace(ch) && ch != '\n') ch = getc(bpf);
250 	                                             /* read to end of line */
251 	  if ( ch == '\n' ) {                        /* didn't find it */
252 	    res = -1; break;                         /* but host is there */
253 	  }
254 	  if ( ch == '\\' ) {                        /* more info */
255 	    ch = getc(bpf);                          /* maybe on next line */
256 	    if (ch == '\n') continue;                /* read it in next loop */
257 	    ungetc(ch, bpf); ungetc('\\',bpf); /* push the character(s) back */
258 	  } else ungetc(ch, bpf);              /* but who know what a `\` is */
259 	}                                      /* needed for. */
260       } else break;                            /* a commented rest-of-line */
261     }
262   }
263   if (fclose(bpf)) { warnx("could not close %s", bootpfile); }
264   if ( res == -1) buffer[0] = '\0';            /* host found, file not */
265   return(match);
266 }
267 
268 /* checkhost puts the hostname found in the database file in
269    the hostname-variable and returns 1, if askname is a valid
270    name for a host in the database */
271 
272 int
273 checkhost(char *askname, char *hostname, int len)
274 {
275   int ch, pch;
276   FILE *bpf;
277   int res = 0;
278   static char *result;
279   int resultlen;
280   static char *yp_domain;
281 
282 /*  struct hostent *cmp_he;*/
283 
284   bpf = fopen(bootpfile, "r");
285   if ( ! bpf )
286     errx(1, "no %s", bootpfile);
287 
288   /* XXX there is no way in ISO C to specify the maximal length for a
289      conversion in a variable way */
290   while ( fscanf(bpf, "%254s", hostname) > 0 ) {
291     if ( *hostname != '#' ) { /* comment */
292       if ( ! strcmp(hostname, askname) ) {
293         /* return true for match of hostname */
294         res = 1;
295         break;
296       } else {
297         /* check the alias list */
298         he = NULL;
299         he = gethostbyname(hostname);
300         if (he && !strcmp(askname, he->h_name)) {
301   	  res = 1;
302 	  break;
303         }
304       }
305     }
306     if (*hostname == '+' ) { /* NIS */
307       if (yp_get_default_domain(&yp_domain)) {
308 	 if (debug) warn("NIS");
309 	 return(0);
310       }
311       if (!yp_match(yp_domain, "bootparams", askname, strlen(askname),
312 		&result, &resultlen)) {
313         /* return true for match of hostname */
314         he = NULL;
315         he = gethostbyname(askname);
316         if (he && !strcmp(askname, he->h_name)) {
317   	  res = 1;
318 	  snprintf(hostname, len, "%s", he->h_name);
319 	}
320       }
321       if (fclose(bpf))
322         warnx("could not close %s", bootpfile);
323       return(res);
324     }
325     /* skip to next entry */
326     pch = ch = getc(bpf);
327     while ( ! ( ch == '\n' && pch != '\\') && ch != EOF) {
328       pch = ch; ch = getc(bpf);
329     }
330   }
331   if (fclose(bpf)) { warnx("could not close %s", bootpfile); }
332   return(res);
333 }
334