xref: /netbsd-src/usr.sbin/rbootd/utils.c (revision 21e37cc72a480a47828990a439cde7ac9ffaf0c6)
1 /*	$NetBSD: utils.c,v 1.14 2003/08/07 11:25:41 agc Exp $	*/
2 
3 /*
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. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  *	from: @(#)utils.c	8.1 (Berkeley) 6/4/93
38  *
39  * From: Utah Hdr: utils.c 3.1 92/07/06
40  * Author: Jeff Forys, University of Utah CSS
41  */
42 
43 /*
44  * Copyright (c) 1988, 1992 The University of Utah and the Center
45  *	for Software Science (CSS).
46  *
47  * This code is derived from software contributed to Berkeley by
48  * the Center for Software Science of the University of Utah Computer
49  * Science Department.  CSS requests users of this software to return
50  * to css-dist@cs.utah.edu any improvements that they make and grant
51  * CSS redistribution rights.
52  *
53  * Redistribution and use in source and binary forms, with or without
54  * modification, are permitted provided that the following conditions
55  * are met:
56  * 1. Redistributions of source code must retain the above copyright
57  *    notice, this list of conditions and the following disclaimer.
58  * 2. Redistributions in binary form must reproduce the above copyright
59  *    notice, this list of conditions and the following disclaimer in the
60  *    documentation and/or other materials provided with the distribution.
61  * 3. All advertising materials mentioning features or use of this software
62  *    must display the following acknowledgement:
63  *	This product includes software developed by the University of
64  *	California, Berkeley and its contributors.
65  * 4. Neither the name of the University nor the names of its contributors
66  *    may be used to endorse or promote products derived from this software
67  *    without specific prior written permission.
68  *
69  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
70  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
71  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
72  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
73  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
74  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
75  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
76  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
77  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
78  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
79  * SUCH DAMAGE.
80  *
81  *	from: @(#)utils.c	8.1 (Berkeley) 6/4/93
82  *
83  * From: Utah Hdr: utils.c 3.1 92/07/06
84  * Author: Jeff Forys, University of Utah CSS
85  */
86 
87 #include <sys/cdefs.h>
88 #ifndef lint
89 #if 0
90 static char sccsid[] = "@(#)utils.c	8.1 (Berkeley) 6/4/93";
91 #else
92 __RCSID("$NetBSD: utils.c,v 1.14 2003/08/07 11:25:41 agc Exp $");
93 #endif
94 #endif /* not lint */
95 
96 #include <sys/param.h>
97 
98 #include <fcntl.h>
99 #include <signal.h>
100 #include <stdio.h>
101 #include <stdlib.h>
102 #include <string.h>
103 #include <syslog.h>
104 #include <time.h>
105 #include <unistd.h>
106 #include "defs.h"
107 
108 /*
109 **  DispPkt -- Display the contents of an RMPCONN packet.
110 **
111 **	Parameters:
112 **		rconn - packet to be displayed.
113 **		direct - direction packet is going (DIR_*).
114 **
115 **	Returns:
116 **		Nothing.
117 **
118 **	Side Effects:
119 **		None.
120 */
121 void
122 DispPkt(rconn, direct)
123 	RMPCONN *rconn;
124 	int direct;
125 {
126 	static const char BootFmt[] = "\t\tRetCode:%u SeqNo:%lx SessID:%x Vers:%u";
127 	static const char ReadFmt[] = "\t\tRetCode:%u Offset:%lx SessID:%x\n";
128 
129 	struct tm *tmp;
130 	struct rmp_packet *rmp;
131 	int i, omask;
132 	u_int32_t t;
133 
134 	/*
135 	 *  Since we will be working with RmpConns as well as DbgFp, we
136 	 *  must block signals that can affect either.
137 	 */
138 	omask = sigblock(sigmask(SIGHUP)|sigmask(SIGUSR1)|sigmask(SIGUSR2));
139 
140 	if (DbgFp == NULL) {			/* sanity */
141 		(void) sigsetmask(omask);
142 		return;
143 	}
144 
145 	/* display direction packet is going using '>>>' or '<<<' */
146 	fputs((direct==DIR_RCVD)?"<<< ":(direct==DIR_SENT)?">>> ":"", DbgFp);
147 
148 	/* display packet timestamp */
149 	tmp = localtime((time_t *)&rconn->tstamp.tv_sec);
150 	fprintf(DbgFp, "%02d:%02d:%02d.%06ld   ", tmp->tm_hour, tmp->tm_min,
151 	        tmp->tm_sec, (long int)rconn->tstamp.tv_usec);
152 
153 	/* display src or dst addr and information about network interface */
154 	fprintf(DbgFp, "Addr: %s   Intf: %s\n", EnetStr(rconn), IntfName);
155 
156 	rmp = &rconn->rmp;
157 
158 	/* display IEEE 802.2 Logical Link Control header */
159 	(void) fprintf(DbgFp, "\t802.2 LLC: DSAP:%x SSAP:%x CTRL:%x\n",
160                rmp->hp_llc.dsap, rmp->hp_llc.ssap, ntohs(rmp->hp_llc.cntrl));
161 
162 	/* display HP extensions to 802.2 Logical Link Control header */
163 	(void) fprintf(DbgFp, "\tHP Ext:    DXSAP:%x SXSAP:%x\n",
164 	               ntohs(rmp->hp_llc.dxsap), ntohs(rmp->hp_llc.sxsap));
165 
166 	/*
167 	 *  Display information about RMP packet using type field to
168 	 *  determine what kind of packet this is.
169 	 */
170 	switch(rmp->r_type) {
171 		case RMP_BOOT_REQ:		/* boot request */
172 			(void) fprintf(DbgFp, "\tBoot Request:");
173 			GETWORD(rmp->r_brq.rmp_seqno, t);
174 			if (ntohs(rmp->r_brq.rmp_session) == RMP_PROBESID) {
175 				if (WORDZE(rmp->r_brq.rmp_seqno))
176 					fputs(" (Send Server ID)", DbgFp);
177 				else
178 					fprintf(DbgFp," (Send Filename #%u)",t);
179 			}
180 			(void) fputc('\n', DbgFp);
181 			(void) fprintf(DbgFp, BootFmt, rmp->r_brq.rmp_retcode,
182 			        (unsigned long)t, ntohs(rmp->r_brq.rmp_session),
183 			        ntohs(rmp->r_brq.rmp_version));
184 			(void) fprintf(DbgFp, "\n\t\tMachine Type: ");
185 			for (i = 0; i < RMP_MACHLEN; i++)
186 				(void) fputc(rmp->r_brq.rmp_machtype[i], DbgFp);
187 			DspFlnm(rmp->r_brq.rmp_flnmsize, &rmp->r_brq.rmp_flnm);
188 			break;
189 		case RMP_BOOT_REPL:		/* boot reply */
190 			fprintf(DbgFp, "\tBoot Reply:\n");
191 			GETWORD(rmp->r_brpl.rmp_seqno, t);
192 			(void) fprintf(DbgFp, BootFmt, rmp->r_brpl.rmp_retcode,
193 			        (unsigned long)t, ntohs(rmp->r_brpl.rmp_session),
194 			        ntohs(rmp->r_brpl.rmp_version));
195 			DspFlnm(rmp->r_brpl.rmp_flnmsize,&rmp->r_brpl.rmp_flnm);
196 			break;
197 		case RMP_READ_REQ:		/* read request */
198 			(void) fprintf(DbgFp, "\tRead Request:\n");
199 			GETWORD(rmp->r_rrq.rmp_offset, t);
200 			(void) fprintf(DbgFp, ReadFmt, rmp->r_rrq.rmp_retcode,
201 			        (unsigned long)t, ntohs(rmp->r_rrq.rmp_session));
202 			(void) fprintf(DbgFp, "\t\tNoOfBytes: %u\n",
203 			        ntohs(rmp->r_rrq.rmp_size));
204 			break;
205 		case RMP_READ_REPL:		/* read reply */
206 			(void) fprintf(DbgFp, "\tRead Reply:\n");
207 			GETWORD(rmp->r_rrpl.rmp_offset, t);
208 			(void) fprintf(DbgFp, ReadFmt, rmp->r_rrpl.rmp_retcode,
209 			        (unsigned long)t, ntohs(rmp->r_rrpl.rmp_session));
210 			(void) fprintf(DbgFp, "\t\tNoOfBytesSent: %ld\n",
211 			        (long)(rconn->rmplen - RMPREADSIZE(0)));
212 			break;
213 		case RMP_BOOT_DONE:		/* boot complete */
214 			(void) fprintf(DbgFp, "\tBoot Complete:\n");
215 			(void) fprintf(DbgFp, "\t\tRetCode:%u SessID:%x\n",
216 			        rmp->r_done.rmp_retcode,
217 			        ntohs(rmp->r_done.rmp_session));
218 			break;
219 		default:			/* ??? */
220 			(void) fprintf(DbgFp, "\tUnknown Type:(%d)\n",
221 				rmp->r_type);
222 	}
223 	(void) fputc('\n', DbgFp);
224 	(void) fflush(DbgFp);
225 
226 	(void) sigsetmask(omask);		/* reset old signal mask */
227 }
228 
229 
230 /*
231 **  GetEtherAddr -- convert an RMP (Ethernet) address into a string.
232 **
233 **	An RMP BOOT packet has been received.  Look at the type field
234 **	and process Boot Requests, Read Requests, and Boot Complete
235 **	packets.  Any other type will be dropped with a warning msg.
236 **
237 **	Parameters:
238 **		addr - array of RMP_ADDRLEN bytes.
239 **
240 **	Returns:
241 **		Pointer to static string representation of `addr'.
242 **
243 **	Side Effects:
244 **		None.
245 **
246 **	Warnings:
247 **		- The return value points to a static buffer; it must
248 **		  be copied if it's to be saved.
249 */
250 char *
251 GetEtherAddr(addr)
252 	u_int8_t *addr;
253 {
254 	static char Hex[] = "0123456789abcdef";
255 	static char etherstr[RMP_ADDRLEN*3];
256 	int i;
257 	char *cp;
258 
259 	/*
260 	 *  For each byte in `addr', convert it to "<hexchar><hexchar>:".
261 	 *  The last byte does not get a trailing `:' appended.
262 	 */
263 	i = 0;
264 	cp = etherstr;
265 	for(;;) {
266 		*cp++ = Hex[*addr >> 4 & 0xf];
267 		*cp++ = Hex[*addr++ & 0xf];
268 		if (++i == RMP_ADDRLEN)
269 			break;
270 		*cp++ = ':';
271 	}
272 	*cp = '\0';
273 
274 	return(etherstr);
275 }
276 
277 
278 /*
279 **  DispFlnm -- Print a string of bytes to DbgFp (often, a file name).
280 **
281 **	Parameters:
282 **		size - number of bytes to print.
283 **		flnm - address of first byte.
284 **
285 **	Returns:
286 **		Nothing.
287 **
288 **	Side Effects:
289 **		- Characters are sent to `DbgFp'.
290 */
291 void
292 DspFlnm(size, flnm)
293 	u_int size;
294 	char *flnm;
295 {
296 	int i;
297 
298 	(void) fprintf(DbgFp, "\n\t\tFile Name (%u): <", size);
299 	for (i = 0; i < size; i++)
300 		(void) fputc(*flnm++, DbgFp);
301 	(void) fputs(">\n", DbgFp);
302 }
303 
304 
305 /*
306 **  NewClient -- allocate memory for a new CLIENT.
307 **
308 **	Parameters:
309 **		addr - RMP (Ethernet) address of new client.
310 **
311 **	Returns:
312 **		Ptr to new CLIENT or NULL if we ran out of memory.
313 **
314 **	Side Effects:
315 **		- Memory will be malloc'd for the new CLIENT.
316 **		- If malloc() fails, a log message will be generated.
317 */
318 CLIENT *
319 NewClient(addr)
320 	u_int8_t *addr;
321 {
322 	CLIENT *ctmp;
323 
324 	if ((ctmp = (CLIENT *) malloc(sizeof(CLIENT))) == NULL) {
325 		syslog(LOG_ERR, "NewClient: out of memory (%s)",
326 		       GetEtherAddr(addr));
327 		return(NULL);
328 	}
329 
330 	memset(ctmp, 0, sizeof(CLIENT));
331 	memmove(&ctmp->addr[0], addr, RMP_ADDRLEN);
332 	return(ctmp);
333 }
334 
335 /*
336 **  FreeClients -- free linked list of Clients.
337 **
338 **	Parameters:
339 **		None.
340 **
341 **	Returns:
342 **		Nothing.
343 **
344 **	Side Effects:
345 **		- All malloc'd memory associated with the linked list of
346 **		  CLIENTS will be free'd; `Clients' will be set to NULL.
347 **
348 **	Warnings:
349 **		- This routine must be called with SIGHUP blocked.
350 */
351 void
352 FreeClients()
353 {
354 	CLIENT *ctmp;
355 
356 	while (Clients != NULL) {
357 		ctmp = Clients;
358 		Clients = Clients->next;
359 		FreeClient(ctmp);
360 	}
361 }
362 
363 /*
364 **  NewStr -- allocate memory for a character array.
365 **
366 **	Parameters:
367 **		str - null terminated character array.
368 **
369 **	Returns:
370 **		Ptr to new character array or NULL if we ran out of memory.
371 **
372 **	Side Effects:
373 **		- Memory will be malloc'd for the new character array.
374 **		- If malloc() fails, a log message will be generated.
375 */
376 char *
377 NewStr(str)
378 	char *str;
379 {
380 	char *stmp;
381 
382 	if ((stmp = strdup(str)) == NULL) {
383 		syslog(LOG_ERR, "NewStr: out of memory (%s)", str);
384 		return(NULL);
385 	}
386 
387 	return(stmp);
388 }
389 
390 /*
391 **  To save time, NewConn and FreeConn maintain a cache of one RMPCONN
392 **  in `LastFree' (defined below).
393 */
394 
395 static RMPCONN *LastFree = NULL;
396 
397 /*
398 **  NewConn -- allocate memory for a new RMPCONN connection.
399 **
400 **	Parameters:
401 **		rconn - initialization template for new connection.
402 **
403 **	Returns:
404 **		Ptr to new RMPCONN or NULL if we ran out of memory.
405 **
406 **	Side Effects:
407 **		- Memory may be malloc'd for the new RMPCONN (if not cached).
408 **		- If malloc() fails, a log message will be generated.
409 */
410 RMPCONN *
411 NewConn(rconn)
412 	RMPCONN *rconn;
413 {
414 	RMPCONN *rtmp;
415 
416 	if (LastFree == NULL) {		/* nothing cached; make a new one */
417 		if ((rtmp = (RMPCONN *) malloc(sizeof(RMPCONN))) == NULL) {
418 			syslog(LOG_ERR, "NewConn: out of memory (%s)",
419 			       EnetStr(rconn));
420 			return(NULL);
421 		}
422 	} else {			/* use the cached RMPCONN */
423 		rtmp = LastFree;
424 		LastFree = NULL;
425 	}
426 
427 	/*
428 	 *  Copy template into `rtmp', init file descriptor to `-1' and
429 	 *  set ptr to next elem NULL.
430 	 */
431 	memmove((char *)rtmp, (char *)rconn, sizeof(RMPCONN));
432 	rtmp->bootfd = -1;
433 	rtmp->next = NULL;
434 
435 	return(rtmp);
436 }
437 
438 /*
439 **  FreeConn -- Free memory associated with an RMPCONN connection.
440 **
441 **	Parameters:
442 **		rtmp - ptr to RMPCONN to be free'd.
443 **
444 **	Returns:
445 **		Nothing.
446 **
447 **	Side Effects:
448 **		- Memory associated with `rtmp' may be free'd (or cached).
449 **		- File desc associated with `rtmp->bootfd' will be closed.
450 */
451 void
452 FreeConn(rtmp)
453 	RMPCONN *rtmp;
454 {
455 	/*
456 	 *  If the file descriptor is in use, close the file.
457 	 */
458 	if (rtmp->bootfd >= 0) {
459 		(void) close(rtmp->bootfd);
460 		rtmp->bootfd = -1;
461 	}
462 
463 	if (LastFree == NULL)		/* cache for next time */
464 		LastFree = rtmp;
465 	else				/* already one cached; free this one */
466 		free((char *)rtmp);
467 }
468 
469 /*
470 **  FreeConns -- free linked list of RMPCONN connections.
471 **
472 **	Parameters:
473 **		None.
474 **
475 **	Returns:
476 **		Nothing.
477 **
478 **	Side Effects:
479 **		- All malloc'd memory associated with the linked list of
480 **		  connections will be free'd; `RmpConns' will be set to NULL.
481 **		- If LastFree is != NULL, it too will be free'd & NULL'd.
482 **
483 **	Warnings:
484 **		- This routine must be called with SIGHUP blocked.
485 */
486 void
487 FreeConns()
488 {
489 	RMPCONN *rtmp;
490 
491 	while (RmpConns != NULL) {
492 		rtmp = RmpConns;
493 		RmpConns = RmpConns->next;
494 		FreeConn(rtmp);
495 	}
496 
497 	if (LastFree != NULL) {
498 		free((char *)LastFree);
499 		LastFree = NULL;
500 	}
501 }
502 
503 /*
504 **  AddConn -- Add a connection to the linked list of connections.
505 **
506 **	Parameters:
507 **		rconn - connection to be added.
508 **
509 **	Returns:
510 **		Nothing.
511 **
512 **	Side Effects:
513 **		- RmpConn will point to new connection.
514 **
515 **	Warnings:
516 **		- This routine must be called with SIGHUP blocked.
517 */
518 void
519 AddConn(rconn)
520 	RMPCONN *rconn;
521 {
522 	if (RmpConns != NULL)
523 		rconn->next = RmpConns;
524 	RmpConns = rconn;
525 }
526 
527 /*
528 **  FindConn -- Find a connection in the linked list of connections.
529 **
530 **	We use the RMP (Ethernet) address as the basis for determining
531 **	if this is the same connection.  According to the Remote Maint
532 **	Protocol, we can only have one connection with any machine.
533 **
534 **	Parameters:
535 **		rconn - connection to be found.
536 **
537 **	Returns:
538 **		Matching connection from linked list or NULL if not found.
539 **
540 **	Side Effects:
541 **		None.
542 **
543 **	Warnings:
544 **		- This routine must be called with SIGHUP blocked.
545 */
546 RMPCONN *
547 FindConn(rconn)
548 	RMPCONN *rconn;
549 {
550 	RMPCONN *rtmp;
551 
552 	for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next)
553 		if (memcmp((char *)&rconn->rmp.hp_hdr.saddr[0],
554 		         (char *)&rtmp->rmp.hp_hdr.saddr[0], RMP_ADDRLEN) == 0)
555 			break;
556 
557 	return(rtmp);
558 }
559 
560 /*
561 **  RemoveConn -- Remove a connection from the linked list of connections.
562 **
563 **	Parameters:
564 **		rconn - connection to be removed.
565 **
566 **	Returns:
567 **		Nothing.
568 **
569 **	Side Effects:
570 **		- If found, an RMPCONN will cease to exist and it will
571 **		  be removed from the linked list.
572 **
573 **	Warnings:
574 **		- This routine must be called with SIGHUP blocked.
575 */
576 void
577 RemoveConn(rconn)
578 	RMPCONN *rconn;
579 {
580 	RMPCONN *thisrconn, *lastrconn;
581 
582 	if (RmpConns == rconn) {		/* easy case */
583 		RmpConns = RmpConns->next;
584 		FreeConn(rconn);
585 	} else {				/* must traverse linked list */
586 		lastrconn = RmpConns;			/* set back ptr */
587 		thisrconn = lastrconn->next;		/* set current ptr */
588 		while (thisrconn != NULL) {
589 			if (rconn == thisrconn) {		/* found it */
590 				lastrconn->next = thisrconn->next;
591 				FreeConn(thisrconn);
592 				break;
593 			}
594 			lastrconn = thisrconn;
595 			thisrconn = thisrconn->next;
596 		}
597 	}
598 }
599