Bring in a transport-independent RPC (TI-RPC).
[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.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 }