Ansify some function definitions that were previously overlooked.
[dragonfly.git] / libexec / rbootd / rmpproto.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 1988, 1992 The University of Utah and the Center
3 * for Software Science (CSS).
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * the Center for Software Science of the University of Utah Computer
9 * Science Department. CSS requests users of this software to return
10 * to css-dist@cs.utah.edu any improvements that they make and grant
11 * CSS redistribution rights.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement:
23 * This product includes software developed by the University of
24 * California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
40 *
41 * from: @(#)rmpproto.c 8.1 (Berkeley) 6/4/93
42 *
43 * From: Utah Hdr: rmpproto.c 3.1 92/07/06
44 * Author: Jeff Forys, University of Utah CSS
1de703da
MD
45 *
46 * @(#)rmpproto.c 8.1 (Berkeley) 6/4/93
47 * $FreeBSD: src/libexec/rbootd/rmpproto.c,v 1.6.2.1 2001/02/18 02:54:11 kris Exp $
984263bc
MD
48 */
49
984263bc
MD
50#include <sys/param.h>
51#include <sys/time.h>
52
53#include <errno.h>
54#include <fcntl.h>
55#include <stdio.h>
56#include <string.h>
57#include <syslog.h>
58#include <unistd.h>
59#include "defs.h"
60
61/*
62** ProcessPacket -- determine packet type and do what's required.
63**
64** An RMP BOOT packet has been received. Look at the type field
65** and process Boot Requests, Read Requests, and Boot Complete
66** packets. Any other type will be dropped with a warning msg.
67**
68** Parameters:
69** rconn - the new connection
70** client - list of files available to this host
71**
72** Returns:
73** Nothing.
74**
75** Side Effects:
76** - If this is a valid boot request, it will be added to
77** the linked list of outstanding requests (RmpConns).
78** - If this is a valid boot complete, its associated
79** entry in RmpConns will be deleted.
80** - Also, unless we run out of memory, a reply will be
81** sent to the host that sent the packet.
82*/
83void
89a89091 84ProcessPacket(RMPCONN *rconn, CLIENT *client)
984263bc
MD
85{
86 struct rmp_packet *rmp;
87 RMPCONN *rconnout;
88
89 rmp = &rconn->rmp; /* cache pointer to RMP packet */
90
91 switch(rmp->r_type) { /* do what we came here to do */
92 case RMP_BOOT_REQ: /* boot request */
93 if ((rconnout = NewConn(rconn)) == NULL)
94 return;
95
96 /*
97 * If the Session ID is 0xffff, this is a "probe"
98 * packet and we do not want to add the connection
99 * to the linked list of active connections. There
100 * are two types of probe packets, if the Sequence
101 * Number is 0 they want to know our host name, o/w
102 * they want the name of the file associated with
103 * the number spec'd by the Sequence Number.
104 *
105 * If this is an actual boot request, open the file
106 * and send a reply. If SendBootRepl() does not
107 * return 0, add the connection to the linked list
108 * of active connections, otherwise delete it since
109 * an error was encountered.
110 */
111 if (ntohs(rmp->r_brq.rmp_session) == RMP_PROBESID) {
112 if (WORDZE(rmp->r_brq.rmp_seqno))
113 (void) SendServerID(rconnout);
114 else
115 (void) SendFileNo(rmp, rconnout,
116 client? client->files:
117 BootFiles);
118 FreeConn(rconnout);
119 } else {
120 if (SendBootRepl(rmp, rconnout,
121 client? client->files: BootFiles))
122 AddConn(rconnout);
123 else
124 FreeConn(rconnout);
125 }
126 break;
127
128 case RMP_BOOT_REPL: /* boot reply (not valid) */
129 syslog(LOG_WARNING, "%s: sent a boot reply",
130 EnetStr(rconn));
131 break;
132
133 case RMP_READ_REQ: /* read request */
134 /*
135 * Send a portion of the boot file.
136 */
137 (void) SendReadRepl(rconn);
138 break;
139
140 case RMP_READ_REPL: /* read reply (not valid) */
141 syslog(LOG_WARNING, "%s: sent a read reply",
142 EnetStr(rconn));
143 break;
144
145 case RMP_BOOT_DONE: /* boot complete */
146 /*
147 * Remove the entry from the linked list of active
148 * connections.
149 */
150 (void) BootDone(rconn);
151 break;
152
153 default: /* unknown RMP packet type */
154 syslog(LOG_WARNING, "%s: unknown packet type (%u)",
155 EnetStr(rconn), rmp->r_type);
156 }
157}
158
159/*
160** SendServerID -- send our host name to who ever requested it.
161**
162** Parameters:
163** rconn - the reply packet to be formatted.
164**
165** Returns:
166** 1 on success, 0 on failure.
167**
168** Side Effects:
169** none.
170*/
171int
89a89091 172SendServerID(RMPCONN *rconn)
984263bc
MD
173{
174 struct rmp_packet *rpl;
175 char *src, *dst;
176 u_int8_t *size;
177
178 rpl = &rconn->rmp; /* cache ptr to RMP packet */
179
180 /*
181 * Set up assorted fields in reply packet.
182 */
183 rpl->r_brpl.rmp_type = RMP_BOOT_REPL;
184 rpl->r_brpl.rmp_retcode = RMP_E_OKAY;
185 ZEROWORD(rpl->r_brpl.rmp_seqno);
186 rpl->r_brpl.rmp_session = 0;
187 rpl->r_brpl.rmp_version = htons(RMP_VERSION);
188
189 size = &rpl->r_brpl.rmp_flnmsize; /* ptr to length of host name */
190
191 /*
192 * Copy our host name into the reply packet incrementing the
193 * length as we go. Stop at RMP_HOSTLEN or the first dot.
194 */
195 src = MyHost;
196 dst = (char *) &rpl->r_brpl.rmp_flnm;
197 for (*size = 0; *size < RMP_HOSTLEN; (*size)++) {
198 if (*src == '.' || *src == '\0')
199 break;
200 *dst++ = *src++;
201 }
202
203 rconn->rmplen = RMPBOOTSIZE(*size); /* set packet length */
204
205 return(SendPacket(rconn)); /* send packet */
206}
207
208/*
209** SendFileNo -- send the name of a bootable file to the requester.
210**
211** Parameters:
212** req - RMP BOOT packet containing the request.
213** rconn - the reply packet to be formatted.
214** filelist - list of files available to the requester.
215**
216** Returns:
217** 1 on success, 0 on failure.
218**
219** Side Effects:
220** none.
221*/
222int
89a89091 223SendFileNo(struct rmp_packet *req, RMPCONN *rconn, char *filelist[])
984263bc
MD
224{
225 struct rmp_packet *rpl;
226 char *src, *dst;
227 u_int8_t *size;
228 int i;
229
230 GETWORD(req->r_brpl.rmp_seqno, i); /* SeqNo is really FileNo */
231 rpl = &rconn->rmp; /* cache ptr to RMP packet */
232
233 /*
234 * Set up assorted fields in reply packet.
235 */
236 rpl->r_brpl.rmp_type = RMP_BOOT_REPL;
237 PUTWORD(i, rpl->r_brpl.rmp_seqno);
238 i--;
239 rpl->r_brpl.rmp_session = 0;
240 rpl->r_brpl.rmp_version = htons(RMP_VERSION);
241
242 size = &rpl->r_brpl.rmp_flnmsize; /* ptr to length of filename */
243 *size = 0; /* init length to zero */
244
245 /*
246 * Copy the file name into the reply packet incrementing the
247 * length as we go. Stop at end of string or when RMPBOOTDATA
248 * characters have been copied. Also, set return code to
249 * indicate success or "no more files".
250 */
251 if (i < C_MAXFILE && filelist[i] != NULL) {
252 src = filelist[i];
253 dst = (char *)&rpl->r_brpl.rmp_flnm;
254 for (; *src && *size < RMPBOOTDATA; (*size)++) {
255 if (*src == '\0')
256 break;
257 *dst++ = *src++;
258 }
259 rpl->r_brpl.rmp_retcode = RMP_E_OKAY;
260 } else
261 rpl->r_brpl.rmp_retcode = RMP_E_NODFLT;
262
263 rconn->rmplen = RMPBOOTSIZE(*size); /* set packet length */
264
265 return(SendPacket(rconn)); /* send packet */
266}
267
268/*
269** SendBootRepl -- open boot file and respond to boot request.
270**
271** Parameters:
272** req - RMP BOOT packet containing the request.
273** rconn - the reply packet to be formatted.
274** filelist - list of files available to the requester.
275**
276** Returns:
277** 1 on success, 0 on failure.
278**
279** Side Effects:
280** none.
281*/
282int
89a89091 283SendBootRepl(struct rmp_packet *req, RMPCONN *rconn, char *filelist[])
984263bc
MD
284{
285 int retval;
286 char *filename, filepath[RMPBOOTDATA+1];
287 RMPCONN *oldconn;
288 struct rmp_packet *rpl;
289 char *src, *dst1, *dst2;
290 u_int8_t i;
291
292 /*
293 * If another connection already exists, delete it since we
294 * are obviously starting again.
295 */
296 if ((oldconn = FindConn(rconn)) != NULL) {
297 syslog(LOG_WARNING, "%s: dropping existing connection",
298 EnetStr(oldconn));
299 RemoveConn(oldconn);
300 }
301
302 rpl = &rconn->rmp; /* cache ptr to RMP packet */
303
304 /*
305 * Set up assorted fields in reply packet.
306 */
307 rpl->r_brpl.rmp_type = RMP_BOOT_REPL;
308 COPYWORD(req->r_brq.rmp_seqno, rpl->r_brpl.rmp_seqno);
309 rpl->r_brpl.rmp_session = htons(GenSessID());
310 rpl->r_brpl.rmp_version = htons(RMP_VERSION);
311 rpl->r_brpl.rmp_flnmsize = req->r_brq.rmp_flnmsize;
312
313 /*
314 * Copy file name to `filepath' string, and into reply packet.
315 */
316 src = &req->r_brq.rmp_flnm;
317 dst1 = filepath;
318 dst2 = &rpl->r_brpl.rmp_flnm;
319 for (i = 0; i < req->r_brq.rmp_flnmsize; i++)
320 *dst1++ = *dst2++ = *src++;
321 *dst1 = '\0';
322
323 /*
324 * If we are booting HP-UX machines, their secondary loader will
325 * ask for files like "/hp-ux". As a security measure, we do not
326 * allow boot files to lay outside the boot directory (unless they
327 * are purposely link'd out. So, make `filename' become the path-
328 * stripped file name and spoof the client into thinking that it
329 * really got what it wanted.
330 */
8f5c3d2a
SW
331 if ((filename = strrchr(filepath, '/')) != NULL)
332 filename++;
333 else
334 filename = filepath;
984263bc
MD
335
336 /*
337 * Check that this is a valid boot file name.
338 */
339 for (i = 0; i < C_MAXFILE && filelist[i] != NULL; i++)
340 if (STREQN(filename, filelist[i]))
341 goto match;
342
343 /*
344 * Invalid boot file name, set error and send reply packet.
345 */
346 rpl->r_brpl.rmp_retcode = RMP_E_NOFILE;
347 retval = 0;
348 goto sendpkt;
349
350match:
351 /*
352 * This is a valid boot file. Open the file and save the file
353 * descriptor associated with this connection and set success
354 * indication. If the file couldnt be opened, set error:
355 * "no such file or dir" - RMP_E_NOFILE
356 * "file table overflow" - RMP_E_BUSY
357 * "too many open files" - RMP_E_BUSY
358 * anything else - RMP_E_OPENFILE
359 */
360 if ((rconn->bootfd = open(filename, O_RDONLY, 0600)) < 0) {
361 rpl->r_brpl.rmp_retcode = (errno == ENOENT)? RMP_E_NOFILE:
362 (errno == EMFILE || errno == ENFILE)? RMP_E_BUSY:
363 RMP_E_OPENFILE;
364 retval = 0;
365 } else {
366 rpl->r_brpl.rmp_retcode = RMP_E_OKAY;
367 retval = 1;
368 }
369
370sendpkt:
371 syslog(LOG_INFO, "%s: request to boot %s (%s)",
372 EnetStr(rconn), filename, retval? "granted": "denied");
373
374 rconn->rmplen = RMPBOOTSIZE(rpl->r_brpl.rmp_flnmsize);
375
376 return (retval & SendPacket(rconn));
377}
378
379/*
380** SendReadRepl -- send a portion of the boot file to the requester.
381**
382** Parameters:
383** rconn - the reply packet to be formatted.
384**
385** Returns:
386** 1 on success, 0 on failure.
387**
388** Side Effects:
389** none.
390*/
391int
89a89091 392SendReadRepl(RMPCONN *rconn)
984263bc
MD
393{
394 int retval = 0;
395 RMPCONN *oldconn;
396 struct rmp_packet *rpl, *req;
397 int size = 0;
398 int madeconn = 0;
399
400 /*
401 * Find the old connection. If one doesnt exist, create one only
402 * to return the error code.
403 */
404 if ((oldconn = FindConn(rconn)) == NULL) {
405 if ((oldconn = NewConn(rconn)) == NULL)
406 return(0);
407 syslog(LOG_ERR, "SendReadRepl: no active connection (%s)",
408 EnetStr(rconn));
409 madeconn++;
410 }
411
412 req = &rconn->rmp; /* cache ptr to request packet */
413 rpl = &oldconn->rmp; /* cache ptr to reply packet */
414
415 if (madeconn) { /* no active connection above; abort */
416 rpl->r_rrpl.rmp_retcode = RMP_E_ABORT;
417 retval = 1;
418 goto sendpkt;
419 }
420
421 /*
422 * Make sure Session ID's match.
423 */
424 if (ntohs(req->r_rrq.rmp_session) !=
425 ((rpl->r_type == RMP_BOOT_REPL)? ntohs(rpl->r_brpl.rmp_session):
426 ntohs(rpl->r_rrpl.rmp_session))) {
427 syslog(LOG_ERR, "SendReadRepl: bad session id (%s)",
428 EnetStr(rconn));
429 rpl->r_rrpl.rmp_retcode = RMP_E_BADSID;
430 retval = 1;
431 goto sendpkt;
432 }
433
434 /*
435 * If the requester asks for more data than we can fit,
436 * silently clamp the request size down to RMPREADDATA.
437 *
438 * N.B. I do not know if this is "legal", however it seems
439 * to work. This is necessary for bpfwrite() on machines
440 * with MCLBYTES less than 1514.
441 */
442 if (ntohs(req->r_rrq.rmp_size) > RMPREADDATA)
443 req->r_rrq.rmp_size = htons(RMPREADDATA);
444
445 /*
446 * Position read head on file according to info in request packet.
447 */
448 GETWORD(req->r_rrq.rmp_offset, size);
449 if (lseek(oldconn->bootfd, (off_t)size, SEEK_SET) < 0) {
450 syslog(LOG_ERR, "SendReadRepl: lseek: %m (%s)",
451 EnetStr(rconn));
452 rpl->r_rrpl.rmp_retcode = RMP_E_ABORT;
453 retval = 1;
454 goto sendpkt;
455 }
456
457 /*
458 * Read data directly into reply packet.
459 */
460 if ((size = read(oldconn->bootfd, &rpl->r_rrpl.rmp_data,
461 (int) ntohs(req->r_rrq.rmp_size))) <= 0) {
462 if (size < 0) {
463 syslog(LOG_ERR, "SendReadRepl: read: %m (%s)",
464 EnetStr(rconn));
465 rpl->r_rrpl.rmp_retcode = RMP_E_ABORT;
466 } else {
467 rpl->r_rrpl.rmp_retcode = RMP_E_EOF;
468 }
469 retval = 1;
470 goto sendpkt;
471 }
472
473 /*
474 * Set success indication.
475 */
476 rpl->r_rrpl.rmp_retcode = RMP_E_OKAY;
477
478sendpkt:
479 /*
480 * Set up assorted fields in reply packet.
481 */
482 rpl->r_rrpl.rmp_type = RMP_READ_REPL;
483 COPYWORD(req->r_rrq.rmp_offset, rpl->r_rrpl.rmp_offset);
484 rpl->r_rrpl.rmp_session = req->r_rrq.rmp_session;
485
486 oldconn->rmplen = RMPREADSIZE(size); /* set size of packet */
487
488 retval &= SendPacket(oldconn); /* send packet */
489
490 if (madeconn) /* clean up after ourself */
491 FreeConn(oldconn);
492
493 return (retval);
494}
495
496/*
497** BootDone -- free up memory allocated for a connection.
498**
499** Parameters:
500** rconn - incoming boot complete packet.
501**
502** Returns:
503** 1 on success, 0 on failure.
504**
505** Side Effects:
506** none.
507*/
508int
89a89091 509BootDone(RMPCONN *rconn)
984263bc
MD
510{
511 RMPCONN *oldconn;
512 struct rmp_packet *rpl;
513
514 /*
515 * If we cant find the connection, ignore the request.
516 */
517 if ((oldconn = FindConn(rconn)) == NULL) {
518 syslog(LOG_ERR, "BootDone: no existing connection (%s)",
519 EnetStr(rconn));
520 return(0);
521 }
522
523 rpl = &oldconn->rmp; /* cache ptr to RMP packet */
524
525 /*
526 * Make sure Session ID's match.
527 */
528 if (ntohs(rconn->rmp.r_rrq.rmp_session) !=
529 ((rpl->r_type == RMP_BOOT_REPL)? ntohs(rpl->r_brpl.rmp_session):
530 ntohs(rpl->r_rrpl.rmp_session))) {
531 syslog(LOG_ERR, "BootDone: bad session id (%s)",
532 EnetStr(rconn));
533 return(0);
534 }
535
536 RemoveConn(oldconn); /* remove connection */
537
538 syslog(LOG_INFO, "%s: boot complete", EnetStr(rconn));
539
540 return(1);
541}
542
543/*
544** SendPacket -- send an RMP packet to a remote host.
545**
546** Parameters:
547** rconn - packet to be sent.
548**
549** Returns:
550** 1 on success, 0 on failure.
551**
552** Side Effects:
553** none.
554*/
555int
89a89091 556SendPacket(RMPCONN *rconn)
984263bc
MD
557{
558 /*
559 * Set Ethernet Destination address to Source (BPF and the enet
560 * driver will take care of getting our source address set).
561 */
562 memmove((char *)&rconn->rmp.hp_hdr.daddr[0],
563 (char *)&rconn->rmp.hp_hdr.saddr[0], RMP_ADDRLEN);
564 rconn->rmp.hp_hdr.len = htons(rconn->rmplen - sizeof(struct hp_hdr));
565
566 /*
567 * Reverse 802.2/HP Extended Source & Destination Access Pts.
568 */
569 rconn->rmp.hp_llc.dxsap = htons(HPEXT_SXSAP);
570 rconn->rmp.hp_llc.sxsap = htons(HPEXT_DXSAP);
571
572 /*
573 * Last time this connection was active.
574 */
60233e58 575 (void) gettimeofday(&rconn->tstamp, NULL);
984263bc
MD
576
577 if (DbgFp != NULL) /* display packet */
578 DispPkt(rconn,DIR_SENT);
579
580 /*
581 * Send RMP packet to remote host.
582 */
583 return(BpfWrite(rconn));
584}