Initial import from FreeBSD RELENG_4:
[dragonfly.git] / usr.sbin / bootparamd / bootparamd / bootparamd.c
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 #ifndef lint
11 static const char rcsid[] =
12   "$FreeBSD: src/usr.sbin/bootparamd/bootparamd/bootparamd.c,v 1.10 1999/08/28 01:15:39 peter 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>
28 extern int debug, dolog;
29 extern unsigned long route_addr;
30 extern char *bootpfile;
31
32 #define MAXLEN 800
33
34 struct hostent *he;
35 static char buffer[MAXLEN];
36 static char hostname[MAX_MACHINE_NAME];
37 static char askname[MAX_MACHINE_NAME];
38 static char path[MAX_PATH_LEN];
39 static char domain_name[MAX_MACHINE_NAME];
40
41 int getthefile __P((char *, char *, char *, int));
42 int checkhost __P((char *, char *, int));
43
44 bp_whoami_res *
45 bootparamproc_whoami_1(whoami)
46 bp_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
109 bp_getfile_res *
110   bootparamproc_getfile_1(getfile)
111 bp_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
182 int
183 getthefile(askname,fileid,buffer,blen)
184 char *askname;
185 char *fileid, *buffer;
186 int 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
278 int
279 checkhost(askname, hostname, len)
280 char *askname;
281 char *hostname;
282 int 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 }