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.14 2008/01/30 13:48:37 rink Exp $
12  * $DragonFly: src/usr.sbin/bootparamd/bootparamd/bootparamd.c,v 1.4 2003/11/15 23:33:35 eirikn Exp $
13  */
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>
30 extern int debug, dolog;
31 extern in_addr_t route_addr;
32 extern char *bootpfile;
33 
34 #define MAXLEN 800
35 
36 struct hostent *he;
37 static char buffer[MAXLEN];
38 static char hostname[MAX_MACHINE_NAME];
39 static char askname[MAX_MACHINE_NAME];
40 static char path[MAX_PATH_LEN];
41 static char domain_name[MAX_MACHINE_NAME];
42 
43 int getthefile(char *, char *, char *, int);
44 int checkhost(char *, char *, int);
45 
46 bp_whoami_res *
47 bootparamproc_whoami_1_svc(bp_whoami_arg *whoami, struct svc_req *req)
48 {
49   in_addr_t haddr;
50   static bp_whoami_res res;
51   if (debug)
52     fprintf(stderr,"whoami got question for %d.%d.%d.%d\n",
53 	    255 &  whoami->client_address.bp_address_u.ip_addr.net,
54 	    255 & whoami->client_address.bp_address_u.ip_addr.host,
55 	    255 &  whoami->client_address.bp_address_u.ip_addr.lh,
56 	    255 &  whoami->client_address.bp_address_u.ip_addr.impno);
57   if (dolog)
58     syslog(LOG_NOTICE, "whoami got question for %d.%d.%d.%d\n",
59 	    255 &  whoami->client_address.bp_address_u.ip_addr.net,
60 	    255 & whoami->client_address.bp_address_u.ip_addr.host,
61 	    255 &  whoami->client_address.bp_address_u.ip_addr.lh,
62 	    255 &  whoami->client_address.bp_address_u.ip_addr.impno);
63 
64   bcopy((char *)&whoami->client_address.bp_address_u.ip_addr, (char *)&haddr,
65 	sizeof(haddr));
66   he = gethostbyaddr(&haddr,sizeof(haddr),AF_INET);
67   if ( ! he ) goto failed;
68 
69   if (debug) warnx("this is host %s", he->h_name);
70   if (dolog) syslog(LOG_NOTICE,"This is host %s\n", he->h_name);
71 
72   strncpy(askname, he->h_name, sizeof(askname));
73   askname[sizeof(askname)-1] = 0;
74 
75   if (checkhost(askname, hostname, sizeof hostname) ) {
76     res.client_name = hostname;
77     getdomainname(domain_name, MAX_MACHINE_NAME);
78     res.domain_name = domain_name;
79 
80     if (  res.router_address.address_type != IP_ADDR_TYPE ) {
81       res.router_address.address_type = IP_ADDR_TYPE;
82       bcopy( &route_addr, &res.router_address.bp_address_u.ip_addr, sizeof(in_addr_t));
83     }
84     if (debug) fprintf(stderr,
85 		       "Returning %s   %s    %d.%d.%d.%d\n",
86 		       res.client_name,
87 		       res.domain_name,
88 		       255 &  res.router_address.bp_address_u.ip_addr.net,
89 		       255 & res.router_address.bp_address_u.ip_addr.host,
90 		       255 &  res.router_address.bp_address_u.ip_addr.lh,
91 		       255 & res.router_address.bp_address_u.ip_addr.impno);
92     if (dolog) syslog(LOG_NOTICE,
93 		       "Returning %s   %s    %d.%d.%d.%d\n",
94 		       res.client_name,
95 		       res.domain_name,
96 		       255 &  res.router_address.bp_address_u.ip_addr.net,
97 		       255 & res.router_address.bp_address_u.ip_addr.host,
98 		       255 &  res.router_address.bp_address_u.ip_addr.lh,
99 		       255 & res.router_address.bp_address_u.ip_addr.impno);
100 
101     return(&res);
102   }
103  failed:
104   if (debug) warnx("whoami failed");
105   if (dolog) syslog(LOG_NOTICE,"whoami failed\n");
106   return(NULL);
107 }
108 
109 
110 bp_getfile_res *
111 bootparamproc_getfile_1_svc(bp_getfile_arg *getfile, struct svc_req *req)
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(char *askname, char *fileid, char *buffer, int blen)
184 {
185   FILE *bpf;
186   char  *where;
187   static char *result;
188   int resultlen;
189 #ifdef YP
190   static char *yp_domain;
191 #endif
192 
193   int ch, pch, fid_len, res = 0;
194   int match = 0;
195   char info[MAX_FILEID + MAX_PATH_LEN+MAX_MACHINE_NAME + 3];
196 
197   bpf = fopen(bootpfile, "r");
198   if ( ! bpf )
199     errx(1, "no %s", bootpfile);
200 
201   /* XXX see comment below */
202   while ( fscanf(bpf, "%255s", hostname) > 0  && !match ) {
203     if ( *hostname != '#' ) { /* comment */
204       if ( ! strcmp(hostname, askname) ) {
205 	match = 1;
206       } else {
207 	he = gethostbyname(hostname);
208 	if (he && !strcmp(he->h_name, askname)) match = 1;
209       }
210     }
211     if (*hostname == '+' ) { /* NIS */
212 #ifdef YP
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 #else
232       return(0);	/* ENOTSUP */
233 #endif
234     }
235     /* skip to next entry */
236     if ( match ) break;
237     pch = ch = getc(bpf);
238     while ( ! ( ch == '\n' && pch != '\\') && ch != EOF) {
239       pch = ch; ch = getc(bpf);
240     }
241   }
242 
243   /* if match is true we read the rest of the line to get the
244      info of the file */
245 
246   if (match) {
247     fid_len = strlen(fileid);
248     while ( ! res && (fscanf(bpf,"%s", info)) > 0) { /* read a string */
249       ch = getc(bpf);                                /* and a character */
250       if ( *info != '#' ) {                          /* Comment ? */
251 	if (! strncmp(info, fileid, fid_len) && *(info + fid_len) == '=') {
252 	  where = info + fid_len + 1;
253 	  if ( isprint( *where )) {
254 	    strcpy(buffer, where);                   /* found file */
255 	    res = 1; break;
256 	  }
257 	} else {
258 	  while (isspace(ch) && ch != '\n') ch = getc(bpf);
259 	                                             /* read to end of line */
260 	  if ( ch == '\n' ) {                        /* didn't find it */
261 	    res = -1; break;                         /* but host is there */
262 	  }
263 	  if ( ch == '\\' ) {                        /* more info */
264 	    ch = getc(bpf);                          /* maybe on next line */
265 	    if (ch == '\n') continue;                /* read it in next loop */
266 	    ungetc(ch, bpf); ungetc('\\',bpf); /* push the character(s) back */
267 	  } else ungetc(ch, bpf);              /* but who know what a `\` is */
268 	}                                      /* needed for. */
269       } else break;                            /* a commented rest-of-line */
270     }
271   }
272   if (fclose(bpf)) { warnx("could not close %s", bootpfile); }
273   if ( res == -1) buffer[0] = '\0';            /* host found, file not */
274   return(match);
275 }
276 
277 /* checkhost puts the hostname found in the database file in
278    the hostname-variable and returns 1, if askname is a valid
279    name for a host in the database */
280 
281 int
282 checkhost(char *askname, char *hostname, int len)
283 {
284   int ch, pch;
285   FILE *bpf;
286   int res = 0;
287   static char *result;
288   int resultlen;
289 #ifdef YP
290   static char *yp_domain;
291 #endif
292 
293 /*  struct hostent *cmp_he;*/
294 
295   bpf = fopen(bootpfile, "r");
296   if ( ! bpf )
297     errx(1, "no %s", bootpfile);
298 
299   /* XXX there is no way in ISO C to specify the maximal length for a
300      conversion in a variable way */
301   while ( fscanf(bpf, "%254s", hostname) > 0 ) {
302     if ( *hostname != '#' ) { /* comment */
303       if ( ! strcmp(hostname, askname) ) {
304         /* return true for match of hostname */
305         res = 1;
306         break;
307       } else {
308         /* check the alias list */
309         he = NULL;
310         he = gethostbyname(hostname);
311         if (he && !strcmp(askname, he->h_name)) {
312   	  res = 1;
313 	  break;
314         }
315       }
316     }
317     if (*hostname == '+' ) { /* NIS */
318 #ifdef YP
319       if (yp_get_default_domain(&yp_domain)) {
320 	 if (debug) warn("NIS");
321 	 return(0);
322       }
323       if (!yp_match(yp_domain, "bootparams", askname, strlen(askname),
324 		&result, &resultlen)) {
325         /* return true for match of hostname */
326         he = NULL;
327         he = gethostbyname(askname);
328         if (he && !strcmp(askname, he->h_name)) {
329   	  res = 1;
330 	  snprintf(hostname, len, "%s", he->h_name);
331 	}
332       }
333       if (fclose(bpf))
334         warnx("could not close %s", bootpfile);
335       return(res);
336 #else
337       return(0);	/* ENOTSUP */
338 #endif
339     }
340     /* skip to next entry */
341     pch = ch = getc(bpf);
342     while ( ! ( ch == '\n' && pch != '\\') && ch != EOF) {
343       pch = ch; ch = getc(bpf);
344     }
345   }
346   if (fclose(bpf)) { warnx("could not close %s", bootpfile); }
347   return(res);
348 }
349