]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bootparamd/bootparamd/bootparamd.c
Merge llvm trunk r366426, resolve conflicts, and update FREEBSD-Xlist.
[FreeBSD/FreeBSD.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$";
13 #endif /* not lint */
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(whoami, req)
48 bp_whoami_arg *whoami;
49 struct svc_req *req;
50 {
51   in_addr_t haddr;
52   static bp_whoami_res res;
53   if (debug)
54     fprintf(stderr,"whoami got question for %d.%d.%d.%d\n",
55             255 &  whoami->client_address.bp_address_u.ip_addr.net,
56             255 & whoami->client_address.bp_address_u.ip_addr.host,
57             255 &  whoami->client_address.bp_address_u.ip_addr.lh,
58             255 &  whoami->client_address.bp_address_u.ip_addr.impno);
59   if (dolog)
60     syslog(LOG_NOTICE, "whoami got question for %d.%d.%d.%d\n",
61             255 &  whoami->client_address.bp_address_u.ip_addr.net,
62             255 & whoami->client_address.bp_address_u.ip_addr.host,
63             255 &  whoami->client_address.bp_address_u.ip_addr.lh,
64             255 &  whoami->client_address.bp_address_u.ip_addr.impno);
65
66   bcopy((char *)&whoami->client_address.bp_address_u.ip_addr, (char *)&haddr,
67         sizeof(haddr));
68   he = gethostbyaddr((char *)&haddr,sizeof(haddr),AF_INET);
69   if ( ! he ) goto failed;
70
71   if (debug) warnx("this is host %s", he->h_name);
72   if (dolog) syslog(LOG_NOTICE,"This is host %s\n", he->h_name);
73
74   strncpy(askname, he->h_name, sizeof(askname));
75   askname[sizeof(askname)-1] = 0;
76
77   if (checkhost(askname, hostname, sizeof hostname) ) {
78     res.client_name = hostname;
79     getdomainname(domain_name, MAX_MACHINE_NAME);
80     res.domain_name = domain_name;
81
82     if (  res.router_address.address_type != IP_ADDR_TYPE ) {
83       res.router_address.address_type = IP_ADDR_TYPE;
84       bcopy( &route_addr, &res.router_address.bp_address_u.ip_addr, sizeof(in_addr_t));
85     }
86     if (debug) fprintf(stderr,
87                        "Returning %s   %s    %d.%d.%d.%d\n",
88                        res.client_name,
89                        res.domain_name,
90                        255 &  res.router_address.bp_address_u.ip_addr.net,
91                        255 & res.router_address.bp_address_u.ip_addr.host,
92                        255 &  res.router_address.bp_address_u.ip_addr.lh,
93                        255 & res.router_address.bp_address_u.ip_addr.impno);
94     if (dolog) syslog(LOG_NOTICE,
95                        "Returning %s   %s    %d.%d.%d.%d\n",
96                        res.client_name,
97                        res.domain_name,
98                        255 &  res.router_address.bp_address_u.ip_addr.net,
99                        255 & res.router_address.bp_address_u.ip_addr.host,
100                        255 &  res.router_address.bp_address_u.ip_addr.lh,
101                        255 & res.router_address.bp_address_u.ip_addr.impno);
102
103     return(&res);
104   }
105  failed:
106   if (debug) warnx("whoami failed");
107   if (dolog) syslog(LOG_NOTICE,"whoami failed\n");
108   return(NULL);
109 }
110
111
112 bp_getfile_res *
113   bootparamproc_getfile_1_svc(getfile, req)
114 bp_getfile_arg *getfile;
115 struct svc_req *req;
116 {
117   char *where;
118   static bp_getfile_res res;
119
120   if (debug)
121     warnx("getfile got question for \"%s\" and file \"%s\"",
122             getfile->client_name, getfile->file_id);
123
124   if (dolog)
125     syslog(LOG_NOTICE,"getfile got question for \"%s\" and file \"%s\"\n",
126             getfile->client_name, getfile->file_id);
127
128   he = NULL;
129   he = gethostbyname(getfile->client_name);
130   if (! he ) goto failed;
131
132   strncpy(askname, he->h_name, sizeof(askname));
133   askname[sizeof(askname)-1] = 0;
134
135   if (getthefile(askname, getfile->file_id,buffer,sizeof(buffer))) {
136     if ( (where = strchr(buffer,':')) ) {
137       /* buffer is re-written to contain the name of the info of file */
138       strncpy(hostname, buffer, where - buffer);
139       hostname[where - buffer] = '\0';
140       where++;
141       strcpy(path, where);
142       he = gethostbyname(hostname);
143       if ( !he ) goto failed;
144       bcopy( he->h_addr, &res.server_address.bp_address_u.ip_addr, 4);
145       res.server_name = hostname;
146       res.server_path = path;
147       res.server_address.address_type = IP_ADDR_TYPE;
148     }
149     else { /* special for dump, answer with null strings */
150       if (!strcmp(getfile->file_id, "dump")) {
151         res.server_name = "";
152         res.server_path = "";
153         res.server_address.address_type = IP_ADDR_TYPE;
154         bzero(&res.server_address.bp_address_u.ip_addr,4);
155       } else goto failed;
156     }
157     if (debug)
158       fprintf(stderr, "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     if (dolog)
165       syslog(LOG_NOTICE, "returning server:%s path:%s address: %d.%d.%d.%d\n",
166              res.server_name, res.server_path,
167              255 &  res.server_address.bp_address_u.ip_addr.net,
168              255 & res.server_address.bp_address_u.ip_addr.host,
169              255 &  res.server_address.bp_address_u.ip_addr.lh,
170              255 & res.server_address.bp_address_u.ip_addr.impno);
171     return(&res);
172   }
173   failed:
174   if (debug) warnx("getfile failed for %s", getfile->client_name);
175   if (dolog) syslog(LOG_NOTICE,
176                     "getfile failed for %s\n", getfile->client_name);
177   return(NULL);
178 }
179
180 /*    getthefile return 1 and fills the buffer with the information
181       of the file, e g "host:/export/root/client" if it can be found.
182       If the host is in the database, but the file is not, the buffer
183       will be empty. (This makes it possible to give the special
184       empty answer for the file "dump")   */
185
186 int
187 getthefile(askname,fileid,buffer,blen)
188 char *askname;
189 char *fileid, *buffer;
190 int blen;
191 {
192   FILE *bpf;
193   char  *where;
194 #ifdef YP
195   static char *result;
196   int resultlen;
197   static char *yp_domain;
198 #endif
199
200   int ch, pch, fid_len, res = 0;
201   int match = 0;
202 #define INFOLEN 1343
203   _Static_assert(INFOLEN >= MAX_FILEID + MAX_PATH_LEN+MAX_MACHINE_NAME + 3,
204                   "INFOLEN isn't large enough");
205   char info[INFOLEN + 1];
206
207   bpf = fopen(bootpfile, "r");
208   if ( ! bpf )
209     errx(1, "no %s", bootpfile);
210
211   /* XXX see comment below */
212   while ( fscanf(bpf, "%255s", hostname) > 0  && !match ) {
213     if ( *hostname != '#' ) { /* comment */
214       if ( ! strcmp(hostname, askname) ) {
215         match = 1;
216       } else {
217         he = gethostbyname(hostname);
218         if (he && !strcmp(he->h_name, askname)) match = 1;
219       }
220     }
221     if (*hostname == '+' ) { /* NIS */
222 #ifdef YP
223       if (yp_get_default_domain(&yp_domain)) {
224          if (debug) warn("NIS");
225          return(0);
226       }
227       if (yp_match(yp_domain, "bootparams", askname, strlen(askname),
228                 &result, &resultlen))
229         return (0);
230       if (strstr(result, fileid) == NULL) {
231         buffer[0] = '\0';
232       } else {
233         snprintf(buffer, blen,
234                 "%s",strchr(strstr(result,fileid), '=') + 1);
235         if (strchr(buffer, ' ') != NULL)
236           *(char *)(strchr(buffer, ' ')) = '\0';
237       }
238       if (fclose(bpf))
239         warnx("could not close %s", bootpfile);
240       return(1);
241 #else
242       if (fclose(bpf))
243         warnx("could not close %s", bootpfile);
244       return(0);        /* ENOTSUP */
245 #endif
246     }
247     /* skip to next entry */
248     if ( match ) break;
249     pch = ch = getc(bpf);
250     while ( ! ( ch == '\n' && pch != '\\') && ch != EOF) {
251       pch = ch; ch = getc(bpf);
252     }
253   }
254
255   /* if match is true we read the rest of the line to get the
256      info of the file */
257
258   if (match) {
259     fid_len = strlen(fileid);
260 #define AS_FORMAT(d)    "%" #d "s"
261 #define REXPAND(d) AS_FORMAT(d) /* Force another preprocessor expansion */
262     while ( ! res && (fscanf(bpf, REXPAND(INFOLEN), info)) > 0) {
263       ch = getc(bpf);                                /* and a character */
264       if ( *info != '#' ) {                          /* Comment ? */
265         if (! strncmp(info, fileid, fid_len) && *(info + fid_len) == '=') {
266           where = info + fid_len + 1;
267           if ( isprint( *where )) {
268             strcpy(buffer, where);                   /* found file */
269             res = 1; break;
270           }
271         } else {
272           while (isspace(ch) && ch != '\n') ch = getc(bpf);
273                                                      /* read to end of line */
274           if ( ch == '\n' ) {                        /* didn't find it */
275             res = -1; break;                         /* but host is there */
276           }
277           if ( ch == '\\' ) {                        /* more info */
278             ch = getc(bpf);                          /* maybe on next line */
279             if (ch == '\n') continue;                /* read it in next loop */
280             ungetc(ch, bpf); ungetc('\\',bpf); /* push the character(s) back */
281           } else ungetc(ch, bpf);              /* but who know what a `\` is */
282         }                                      /* needed for. */
283       } else break;                            /* a commented rest-of-line */
284     }
285   }
286   if (fclose(bpf)) { warnx("could not close %s", bootpfile); }
287   if ( res == -1) buffer[0] = '\0';            /* host found, file not */
288   return(match);
289 }
290
291 /* checkhost puts the hostname found in the database file in
292    the hostname-variable and returns 1, if askname is a valid
293    name for a host in the database */
294
295 int
296 checkhost(askname, hostname, len)
297 char *askname;
298 char *hostname;
299 int len;
300 {
301   int ch, pch;
302   FILE *bpf;
303   int res = 0;
304 #ifdef YP
305   static char *result;
306   int resultlen;
307   static char *yp_domain;
308 #endif
309
310 /*  struct hostent *cmp_he;*/
311
312   bpf = fopen(bootpfile, "r");
313   if ( ! bpf )
314     errx(1, "no %s", bootpfile);
315
316   /* XXX there is no way in ISO C to specify the maximal length for a
317      conversion in a variable way */
318   while ( fscanf(bpf, "%254s", hostname) > 0 ) {
319     if ( *hostname != '#' ) { /* comment */
320       if ( ! strcmp(hostname, askname) ) {
321         /* return true for match of hostname */
322         res = 1;
323         break;
324       } else {
325         /* check the alias list */
326         he = NULL;
327         he = gethostbyname(hostname);
328         if (he && !strcmp(askname, he->h_name)) {
329           res = 1;
330           break;
331         }
332       }
333     }
334     if (*hostname == '+' ) { /* NIS */
335 #ifdef YP
336       if (yp_get_default_domain(&yp_domain)) {
337          if (debug) warn("NIS");
338          return(0);
339       }
340       if (!yp_match(yp_domain, "bootparams", askname, strlen(askname),
341                 &result, &resultlen)) {
342         /* return true for match of hostname */
343         he = NULL;
344         he = gethostbyname(askname);
345         if (he && !strcmp(askname, he->h_name)) {
346           res = 1;
347           snprintf(hostname, len, "%s", he->h_name);
348         }
349       }
350       if (fclose(bpf))
351         warnx("could not close %s", bootpfile);
352       return(res);
353 #else
354       return(0);        /* ENOTSUP */
355 #endif
356     }
357     /* skip to next entry */
358     pch = ch = getc(bpf);
359     while ( ! ( ch == '\n' && pch != '\\') && ch != EOF) {
360       pch = ch; ch = getc(bpf);
361     }
362   }
363   if (fclose(bpf)) { warnx("could not close %s", bootpfile); }
364   return(res);
365 }