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