]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - usr.sbin/bootparamd/bootparamd/bootparamd.c
MFC r318790, r319336
[FreeBSD/stable/10.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       return(0);        /* ENOTSUP */
243 #endif
244     }
245     /* skip to next entry */
246     if ( match ) break;
247     pch = ch = getc(bpf);
248     while ( ! ( ch == '\n' && pch != '\\') && ch != EOF) {
249       pch = ch; ch = getc(bpf);
250     }
251   }
252
253   /* if match is true we read the rest of the line to get the
254      info of the file */
255
256   if (match) {
257     fid_len = strlen(fileid);
258 #define AS_FORMAT(d)    "%" #d "s"
259 #define REXPAND(d) AS_FORMAT(d) /* Force another preprocessor expansion */
260     while ( ! res && (fscanf(bpf, REXPAND(INFOLEN), info)) > 0) {
261       ch = getc(bpf);                                /* and a character */
262       if ( *info != '#' ) {                          /* Comment ? */
263         if (! strncmp(info, fileid, fid_len) && *(info + fid_len) == '=') {
264           where = info + fid_len + 1;
265           if ( isprint( *where )) {
266             strcpy(buffer, where);                   /* found file */
267             res = 1; break;
268           }
269         } else {
270           while (isspace(ch) && ch != '\n') ch = getc(bpf);
271                                                      /* read to end of line */
272           if ( ch == '\n' ) {                        /* didn't find it */
273             res = -1; break;                         /* but host is there */
274           }
275           if ( ch == '\\' ) {                        /* more info */
276             ch = getc(bpf);                          /* maybe on next line */
277             if (ch == '\n') continue;                /* read it in next loop */
278             ungetc(ch, bpf); ungetc('\\',bpf); /* push the character(s) back */
279           } else ungetc(ch, bpf);              /* but who know what a `\` is */
280         }                                      /* needed for. */
281       } else break;                            /* a commented rest-of-line */
282     }
283   }
284   if (fclose(bpf)) { warnx("could not close %s", bootpfile); }
285   if ( res == -1) buffer[0] = '\0';            /* host found, file not */
286   return(match);
287 }
288
289 /* checkhost puts the hostname found in the database file in
290    the hostname-variable and returns 1, if askname is a valid
291    name for a host in the database */
292
293 int
294 checkhost(askname, hostname, len)
295 char *askname;
296 char *hostname;
297 int len;
298 {
299   int ch, pch;
300   FILE *bpf;
301   int res = 0;
302 #ifdef YP
303   static char *result;
304   int resultlen;
305   static char *yp_domain;
306 #endif
307
308 /*  struct hostent *cmp_he;*/
309
310   bpf = fopen(bootpfile, "r");
311   if ( ! bpf )
312     errx(1, "no %s", bootpfile);
313
314   /* XXX there is no way in ISO C to specify the maximal length for a
315      conversion in a variable way */
316   while ( fscanf(bpf, "%254s", hostname) > 0 ) {
317     if ( *hostname != '#' ) { /* comment */
318       if ( ! strcmp(hostname, askname) ) {
319         /* return true for match of hostname */
320         res = 1;
321         break;
322       } else {
323         /* check the alias list */
324         he = NULL;
325         he = gethostbyname(hostname);
326         if (he && !strcmp(askname, he->h_name)) {
327           res = 1;
328           break;
329         }
330       }
331     }
332     if (*hostname == '+' ) { /* NIS */
333 #ifdef YP
334       if (yp_get_default_domain(&yp_domain)) {
335          if (debug) warn("NIS");
336          return(0);
337       }
338       if (!yp_match(yp_domain, "bootparams", askname, strlen(askname),
339                 &result, &resultlen)) {
340         /* return true for match of hostname */
341         he = NULL;
342         he = gethostbyname(askname);
343         if (he && !strcmp(askname, he->h_name)) {
344           res = 1;
345           snprintf(hostname, len, "%s", he->h_name);
346         }
347       }
348       if (fclose(bpf))
349         warnx("could not close %s", bootpfile);
350       return(res);
351 #else
352       return(0);        /* ENOTSUP */
353 #endif
354     }
355     /* skip to next entry */
356     pch = ch = getc(bpf);
357     while ( ! ( ch == '\n' && pch != '\\') && ch != EOF) {
358       pch = ch; ch = getc(bpf);
359     }
360   }
361   if (fclose(bpf)) { warnx("could not close %s", bootpfile); }
362   return(res);
363 }