Merge from vendor branch FILE:
[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 /*
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 }