xref: /titanic_41/usr/src/cmd/cmd-inet/usr.sbin/in.tftpd.c (revision 70025d765b044c6d8594bb965a2247a61e991a99)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  *
22  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
28  * All Rights Reserved.
29  */
30 
31 /*
32  * University Copyright- Copyright (c) 1982, 1986, 1988
33  * The Regents of the University of California.
34  * All Rights Reserved.
35  *
36  * University Acknowledgment- Portions of this document are derived from
37  * software developed by the University of California, Berkeley, and its
38  * contributors.
39  */
40 
41 #pragma ident	"%Z%%M%	%I%	%E% SMI"
42 
43 /*
44  * Trivial file transfer protocol server.  A top level process runs in
45  * an infinite loop fielding new TFTP requests.  A child process,
46  * communicating via a pipe with the top level process, sends delayed
47  * NAKs for those that we can't handle.  A new child process is created
48  * to service each request that we can handle.  The top level process
49  * exits after a period of time during which no new requests are
50  * received.
51  */
52 
53 #include <sys/types.h>
54 #include <sys/socket.h>
55 #include <sys/wait.h>
56 #include <sys/stat.h>
57 #include <sys/time.h>
58 
59 #include <netinet/in.h>
60 
61 #include <arpa/inet.h>
62 #include <dirent.h>
63 #include <signal.h>
64 #include <stdio.h>
65 #include <stdlib.h>
66 #include <unistd.h>
67 #include <errno.h>
68 #include <ctype.h>
69 #include <netdb.h>
70 #include <setjmp.h>
71 #include <syslog.h>
72 #include <sys/param.h>
73 #include <fcntl.h>
74 #include <pwd.h>
75 #include <string.h>
76 #include <priv_utils.h>
77 #include "tftpcommon.h"
78 
79 #define	TIMEOUT		5
80 #define	DELAY_SECS	3
81 #define	DALLYSECS 60
82 
83 #define	SYSLOG_MSG(message) \
84 	(syslog((((errno == ENETUNREACH) || (errno == EHOSTUNREACH) || \
85 		(errno == ECONNREFUSED)) ? LOG_WARNING : LOG_ERR), message))
86 
87 static int			rexmtval = TIMEOUT;
88 static int			maxtimeout = 5*TIMEOUT;
89 static int			securetftp;
90 static int			debug;
91 static int			disable_pnp;
92 static int			standalone;
93 static uid_t			uid_nobody = UID_NOBODY;
94 static uid_t			gid_nobody = GID_NOBODY;
95 static int			reqsock = -1;
96 				/* file descriptor of request socket */
97 static socklen_t		fromlen;
98 static socklen_t		fromplen;
99 static struct sockaddr_storage	client;
100 static struct sockaddr_in6 	*sin6_ptr;
101 static struct sockaddr_in	*sin_ptr;
102 static struct sockaddr_in6	*from6_ptr;
103 static struct sockaddr_in	*from_ptr;
104 static int			addrfmly;
105 static int			peer;
106 static off_t			tsize;
107 static tftpbuf			ackbuf;
108 static struct sockaddr_storage	from;
109 static boolean_t		tsize_set;
110 static pid_t			child;
111 				/* pid of child handling delayed replys */
112 static int			delay_fd [2];
113 				/* pipe for communicating with child */
114 static FILE			*file;
115 static char			*filename;
116 
117 static union {
118 	struct tftphdr	hdr;
119 	char		data[SEGSIZE + 4];
120 } buf;
121 
122 static union {
123 	struct tftphdr	hdr;
124 	char		data[SEGSIZE];
125 } oackbuf;
126 
127 struct	delay_info {
128 	long	timestamp;		/* time request received */
129 	int	ecode;			/* error code to return */
130 	struct	sockaddr_storage from;	/* address of client */
131 };
132 
133 int	blocksize = SEGSIZE;	/* Number of data bytes in a DATA packet */
134 
135 /*
136  * Default directory for unqualified names
137  * Used by TFTP boot procedures
138  */
139 static char	*homedir = "/tftpboot";
140 
141 struct formats {
142 	char	*f_mode;
143 	int	(*f_validate)(int);
144 	void	(*f_send)(struct formats *, int);
145 	void	(*f_recv)(struct formats *, int);
146 	int	f_convert;
147 };
148 
149 static void	delayed_responder(void);
150 static void	tftp(struct tftphdr *, int);
151 static int	validate_filename(int);
152 static void	tftpd_sendfile(struct formats *, int);
153 static void	tftpd_recvfile(struct formats *, int);
154 static void	nak(int);
155 static char	*blksize_handler(int, char *, int *);
156 static char	*timeout_handler(int, char *, int *);
157 static char	*tsize_handler(int, char *, int *);
158 
159 static struct formats formats[] = {
160 	{ "netascii",	validate_filename, tftpd_sendfile, tftpd_recvfile, 1 },
161 	{ "octet",	validate_filename, tftpd_sendfile, tftpd_recvfile, 0 },
162 	{ NULL }
163 };
164 
165 struct options {
166 	char	*opt_name;
167 	char	*(*opt_handler)(int, char *, int *);
168 };
169 
170 static struct options options[] = {
171 	{ "blksize",	blksize_handler },
172 	{ "timeout",	timeout_handler },
173 	{ "tsize",	tsize_handler },
174 	{ NULL }
175 };
176 
177 static char		optbuf[MAX_OPTVAL_LEN];
178 static int		timeout;
179 static sigjmp_buf	timeoutbuf;
180 
181 int
182 main(int argc, char **argv)
183 {
184 	struct tftphdr *tp;
185 	int n;
186 	int c;
187 	struct	passwd *pwd;		/* for "nobody" entry */
188 	struct in_addr ipv4addr;
189 	char abuf[INET6_ADDRSTRLEN];
190 	socklen_t addrlen;
191 
192 	openlog("tftpd", LOG_PID, LOG_DAEMON);
193 
194 	pwd = getpwnam("nobody");
195 	if (pwd != NULL) {
196 		uid_nobody = pwd->pw_uid;
197 		gid_nobody = pwd->pw_gid;
198 	}
199 
200 	(void) __init_daemon_priv(
201 		PU_LIMITPRIVS,
202 		uid_nobody, gid_nobody,
203 		PRIV_PROC_FORK, PRIV_PROC_CHROOT, NULL);
204 
205 	/*
206 	 *  Limit set is still "all."  Trim it down to just what we need:
207 	 *  fork and chroot.
208 	 */
209 	(void) priv_set(PRIV_SET,
210 	    PRIV_ALLSETS, PRIV_PROC_FORK, PRIV_PROC_CHROOT, NULL);
211 	(void) priv_set(PRIV_SET, PRIV_EFFECTIVE, NULL);
212 	(void) priv_set(PRIV_SET, PRIV_INHERITABLE, NULL);
213 
214 	while ((c = getopt(argc, argv, "dspS")) != EOF)
215 		switch (c) {
216 		case 'd':		/* enable debug */
217 			debug++;
218 			continue;
219 		case 's':		/* secure daemon */
220 			securetftp = 1;
221 			continue;
222 		case 'p':		/* disable name pnp mapping */
223 			disable_pnp = 1;
224 			continue;
225 		case 'S':
226 			standalone = 1;
227 			continue;
228 		case '?':
229 		default:
230 usage:
231 			(void) fprintf(stderr,
232 			    "usage:  %s [-spd] [home-directory]\n", argv[0]);
233 			for (; optind < argc; optind++)
234 				syslog(LOG_ERR, "bad argument %s",
235 				    argv[optind]);
236 			exit(1);
237 		}
238 
239 	if (optind < argc)
240 		if (optind == argc - 1 && *argv [optind] == '/')
241 			homedir = argv [optind];
242 		else
243 			goto usage;
244 
245 	if (pipe(delay_fd) < 0) {
246 		syslog(LOG_ERR, "pipe (main): %m");
247 		exit(1);
248 	}
249 
250 	(void) sigset(SIGCHLD, SIG_IGN); /* no zombies please */
251 
252 	if (standalone) {
253 		socklen_t clientlen;
254 
255 		sin6_ptr = (struct sockaddr_in6 *)&client;
256 		clientlen = sizeof (struct sockaddr_in6);
257 		reqsock = socket(AF_INET6, SOCK_DGRAM, 0);
258 		if (reqsock == -1) {
259 			perror("socket");
260 			exit(1);
261 		}
262 		(void) memset(&client, 0, clientlen);
263 		sin6_ptr->sin6_family = AF_INET6;
264 		sin6_ptr->sin6_port = htons(IPPORT_TFTP);
265 		if (bind(reqsock, (struct sockaddr *)&client,
266 		    clientlen) == -1) {
267 			perror("bind");
268 			exit(1);
269 		}
270 		if (debug)
271 			(void) puts("running in standalone mode...");
272 	} else {
273 		/* request socket passed on fd 0 by inetd */
274 		reqsock = 0;
275 	}
276 	if (debug) {
277 		int on = 1;
278 
279 		(void) setsockopt(reqsock, SOL_SOCKET, SO_DEBUG,
280 		    (char *)&on, sizeof (on));
281 	}
282 
283 	(void) chdir(homedir);
284 
285 	(void) priv_set(PRIV_SET, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
286 	if ((child = fork()) < 0) {
287 		syslog(LOG_ERR, "fork (main): %m");
288 		exit(1);
289 	}
290 	(void) priv_set(PRIV_SET, PRIV_EFFECTIVE, NULL);
291 
292 	if (child == 0) {
293 		(void) priv_set(PRIV_SET, PRIV_ALLSETS, NULL);
294 		delayed_responder();
295 	} /* child */
296 
297 	/* close read side of pipe */
298 	(void) close(delay_fd[0]);
299 
300 
301 	/*
302 	 * Top level handling of incomming tftp requests.  Read a request
303 	 * and pass it off to be handled.  If request is valid, handling
304 	 * forks off and parent returns to this loop.  If no new requests
305 	 * are received for DALLYSECS, exit and return to inetd.
306 	 */
307 
308 	for (;;) {
309 		fd_set readfds;
310 		struct timeval dally;
311 
312 		FD_ZERO(&readfds);
313 		FD_SET(reqsock, &readfds);
314 		dally.tv_sec = DALLYSECS;
315 		dally.tv_usec = 0;
316 
317 		n = select(reqsock + 1, &readfds, NULL, NULL, &dally);
318 		if (n < 0) {
319 			if (errno == EINTR)
320 				continue;
321 			syslog(LOG_ERR, "select: %m");
322 			(void) kill(child, SIGKILL);
323 			exit(1);
324 		}
325 		if (n == 0) {
326 			/* Select timed out.  Its time to die. */
327 			if (standalone)
328 				continue;
329 			else {
330 				(void) kill(child, SIGKILL);
331 				exit(0);
332 			}
333 		}
334 		addrlen = sizeof (from);
335 		if (getsockname(reqsock, (struct sockaddr  *)&from,
336 		    &addrlen) < 0) {
337 			syslog(LOG_ERR, "getsockname: %m");
338 			exit(1);
339 		}
340 
341 		switch (from.ss_family) {
342 		case AF_INET:
343 			fromlen = (socklen_t)sizeof (struct sockaddr_in);
344 			break;
345 		case AF_INET6:
346 			fromlen = (socklen_t)sizeof (struct sockaddr_in6);
347 			break;
348 		default:
349 			syslog(LOG_ERR,
350 			    "Unknown address Family on peer connection %d",
351 			    from.ss_family);
352 			exit(1);
353 		}
354 
355 		n = recvfrom(reqsock, &buf, sizeof (buf), 0,
356 			(struct sockaddr *)&from, &fromlen);
357 		if (n < 0) {
358 			if (errno == EINTR)
359 				continue;
360 			if (standalone)
361 				perror("recvfrom");
362 			else
363 				syslog(LOG_ERR, "recvfrom: %m");
364 			(void) kill(child, SIGKILL);
365 			exit(1);
366 		}
367 
368 		(void) alarm(0);
369 
370 		switch (from.ss_family) {
371 		case AF_INET:
372 			addrfmly = AF_INET;
373 			fromplen = sizeof (struct sockaddr_in);
374 			sin_ptr = (struct sockaddr_in *)&client;
375 			(void) memset(&client, 0, fromplen);
376 			sin_ptr->sin_family = AF_INET;
377 			break;
378 		case AF_INET6:
379 			addrfmly = AF_INET6;
380 			fromplen = sizeof (struct sockaddr_in6);
381 			sin6_ptr = (struct sockaddr_in6 *)&client;
382 			(void) memset(&client, 0, fromplen);
383 			sin6_ptr->sin6_family = AF_INET6;
384 			break;
385 		default:
386 			syslog(LOG_ERR,
387 			    "Unknown address Family on peer connection");
388 			exit(1);
389 		}
390 		peer = socket(addrfmly, SOCK_DGRAM, 0);
391 		if (peer < 0) {
392 			if (standalone)
393 				perror("socket (main)");
394 			else
395 				syslog(LOG_ERR, "socket (main): %m");
396 			(void) kill(child, SIGKILL);
397 			exit(1);
398 		}
399 		if (debug) {
400 			int on = 1;
401 
402 			(void) setsockopt(peer, SOL_SOCKET, SO_DEBUG,
403 			    (char *)&on, sizeof (on));
404 		}
405 
406 		if (bind(peer, (struct sockaddr *)&client, fromplen) < 0) {
407 			if (standalone)
408 				perror("bind (main)");
409 			else
410 				syslog(LOG_ERR, "bind (main): %m");
411 			(void) kill(child, SIGKILL);
412 			exit(1);
413 		}
414 		if (standalone && debug) {
415 			sin6_ptr = (struct sockaddr_in6 *)&client;
416 			from6_ptr = (struct sockaddr_in6 *)&from;
417 			if (IN6_IS_ADDR_V4MAPPED(&from6_ptr->sin6_addr)) {
418 				IN6_V4MAPPED_TO_INADDR(&from6_ptr->sin6_addr,
419 				    &ipv4addr);
420 				(void) inet_ntop(AF_INET, &ipv4addr, abuf,
421 				    sizeof (abuf));
422 			} else {
423 				(void) inet_ntop(AF_INET6,
424 				    &from6_ptr->sin6_addr, abuf,
425 				    sizeof (abuf));
426 			}
427 			/* get local port */
428 			if (getsockname(peer, (struct sockaddr *)&client,
429 			    &fromplen) < 0)
430 				perror("getsockname (main)");
431 			(void) fprintf(stderr,
432 			    "request from %s port %d; local port %d\n",
433 			    abuf, from6_ptr->sin6_port, sin6_ptr->sin6_port);
434 		}
435 		tp = &buf.hdr;
436 		tp->th_opcode = ntohs((ushort_t)tp->th_opcode);
437 		if (tp->th_opcode == RRQ || tp->th_opcode == WRQ)
438 			tftp(tp, n);
439 
440 		(void) close(peer);
441 		(void) fclose(file);
442 	}
443 
444 	/*NOTREACHED*/
445 	return (0);
446 }
447 
448 static void
449 delayed_responder(void)
450 {
451 	struct delay_info dinfo;
452 	long now;
453 
454 	/* we don't use the descriptors passed in to the parent */
455 	(void) close(0);
456 	(void) close(1);
457 	if (standalone)
458 		(void) close(reqsock);
459 
460 	/* close write side of pipe */
461 	(void) close(delay_fd[1]);
462 
463 	for (;;) {
464 		int n;
465 
466 		if ((n = read(delay_fd[0], &dinfo,
467 		    sizeof (dinfo))) != sizeof (dinfo)) {
468 			if (n < 0) {
469 				if (errno == EINTR)
470 					continue;
471 				if (standalone)
472 					perror("read from pipe "
473 					    "(delayed responder)");
474 				else
475 					syslog(LOG_ERR, "read from pipe: %m");
476 			}
477 			exit(1);
478 		}
479 		switch (dinfo.from.ss_family) {
480 		case AF_INET:
481 			addrfmly = AF_INET;
482 			fromplen = sizeof (struct sockaddr_in);
483 			sin_ptr = (struct sockaddr_in *)&client;
484 			(void) memset(&client, 0, fromplen);
485 			sin_ptr->sin_family = AF_INET;
486 			break;
487 		case AF_INET6:
488 			addrfmly = AF_INET6;
489 			fromplen = sizeof (struct sockaddr_in6);
490 			sin6_ptr = (struct sockaddr_in6 *)&client;
491 			(void) memset(&client, 0, fromplen);
492 			sin6_ptr->sin6_family = AF_INET6;
493 			break;
494 		}
495 		peer = socket(addrfmly, SOCK_DGRAM, 0);
496 		if (peer == -1) {
497 			if (standalone)
498 				perror("socket (delayed responder)");
499 			else
500 				syslog(LOG_ERR, "socket (delay): %m");
501 			exit(1);
502 		}
503 		if (debug) {
504 			int on = 1;
505 
506 			(void) setsockopt(peer, SOL_SOCKET, SO_DEBUG,
507 			    (char *)&on, sizeof (on));
508 		}
509 
510 		if (bind(peer, (struct sockaddr *)&client, fromplen) < 0) {
511 			if (standalone)
512 				perror("bind (delayed responder)");
513 			else
514 				syslog(LOG_ERR, "bind (delay): %m");
515 			exit(1);
516 		}
517 		if (client.ss_family == AF_INET) {
518 			from_ptr = (struct sockaddr_in *)&dinfo.from;
519 			from_ptr->sin_family = AF_INET;
520 		} else {
521 			from6_ptr = (struct sockaddr_in6 *)&dinfo.from;
522 			from6_ptr->sin6_family = AF_INET6;
523 		}
524 		/*
525 		 * Since a request hasn't been received from the client
526 		 * before the delayed responder process is forked, the
527 		 * from variable is uninitialized.  So set it to contain
528 		 * the client address.
529 		 */
530 		from = dinfo.from;
531 
532 		/*
533 		 * only sleep if DELAY_SECS has not elapsed since
534 		 * original request was received.  Ensure that `now'
535 		 * is not earlier than `dinfo.timestamp'
536 		 */
537 		now = time(0);
538 		if ((uint_t)(now - dinfo.timestamp) < DELAY_SECS)
539 			(void) sleep(DELAY_SECS - (now - dinfo.timestamp));
540 		nak(dinfo.ecode);
541 		(void) close(peer);
542 	} /* for */
543 
544 	/* NOTREACHED */
545 }
546 
547 /*
548  * Handle the Blocksize option.
549  * Return the blksize option value string to include in the OACK reply.
550  */
551 /*ARGSUSED*/
552 static char *
553 blksize_handler(int opcode, char *optval, int *errcode)
554 {
555 	char *endp;
556 	int value;
557 
558 	*errcode = -1;
559 	errno = 0;
560 	value = (int)strtol(optval, &endp, 10);
561 	if (errno != 0 || value < MIN_BLKSIZE || *endp != '\0')
562 		return (NULL);
563 	/*
564 	 * As the blksize value in the OACK reply can be less than the value
565 	 * requested, to support broken clients if the value requested is larger
566 	 * than allowed in the RFC, reply with the maximum value permitted.
567 	 */
568 	if (value > MAX_BLKSIZE)
569 		value = MAX_BLKSIZE;
570 
571 	blocksize = value;
572 	(void) snprintf(optbuf, sizeof (optbuf), "%d", blocksize);
573 	return (optbuf);
574 }
575 
576 /*
577  * Handle the Timeout Interval option.
578  * Return the timeout option value string to include in the OACK reply.
579  */
580 /*ARGSUSED*/
581 static char *
582 timeout_handler(int opcode, char *optval, int *errcode)
583 {
584 	char *endp;
585 	int value;
586 
587 	*errcode = -1;
588 	errno = 0;
589 	value = (int)strtol(optval, &endp, 10);
590 	if (errno != 0 || *endp != '\0')
591 		return (NULL);
592 	/*
593 	 * The timeout value in the OACK reply must match the value specified
594 	 * by the client, so if an invalid timeout is requested don't include
595 	 * the timeout option in the OACK reply.
596 	 */
597 	if (value < MIN_TIMEOUT || value > MAX_TIMEOUT)
598 		return (NULL);
599 
600 	rexmtval = value;
601 	maxtimeout = 5 * rexmtval;
602 	(void) snprintf(optbuf, sizeof (optbuf), "%d", rexmtval);
603 	return (optbuf);
604 }
605 
606 /*
607  * Handle the Transfer Size option.
608  * Return the tsize option value string to include in the OACK reply.
609  */
610 static char *
611 tsize_handler(int opcode, char *optval, int *errcode)
612 {
613 	char *endp;
614 	longlong_t value;
615 
616 	*errcode = -1;
617 	errno = 0;
618 	value = strtoll(optval, &endp, 10);
619 	if (errno != 0 || value < 0 || *endp != '\0')
620 		return (NULL);
621 
622 	if (opcode == RRQ) {
623 		if (tsize_set == B_FALSE)
624 			return (NULL);
625 		/*
626 		 * The tsize value should be 0 for a read request, but to
627 		 * support broken clients we don't check that it is.
628 		 */
629 	} else {
630 #if _FILE_OFFSET_BITS == 32
631 		if (value > MAXOFF_T) {
632 			*errcode = ENOSPACE;
633 			return (NULL);
634 		}
635 #endif
636 		tsize = value;
637 		tsize_set = B_TRUE;
638 	}
639 	(void) snprintf(optbuf, sizeof (optbuf), OFF_T_FMT, tsize);
640 	return (optbuf);
641 }
642 
643 /*
644  * Process any options included by the client in the request packet.
645  * Return the size of the OACK reply packet built or 0 for no OACK reply.
646  */
647 static int
648 process_options(int opcode, char *opts, char *endopts)
649 {
650 	char *cp, *optname, *optval, *ostr, *oackend;
651 	struct tftphdr *oackp;
652 	int i, errcode;
653 
654 	/*
655 	 * To continue to interoperate with broken TFTP clients, ignore
656 	 * null padding appended to requests which don't include options.
657 	 */
658 	cp = opts;
659 	while ((cp < endopts) && (*cp == '\0'))
660 		cp++;
661 	if (cp == endopts)
662 		return (0);
663 
664 	/*
665 	 * Construct an Option ACKnowledgement packet if any requested option
666 	 * is recognized.
667 	 */
668 	oackp = &oackbuf.hdr;
669 	oackend = oackbuf.data + sizeof (oackbuf.data);
670 	oackp->th_opcode = htons((ushort_t)OACK);
671 	cp = (char *)&oackp->th_stuff;
672 	while (opts < endopts) {
673 		optname = opts;
674 		if ((optval = next_field(optname, endopts)) == NULL) {
675 			nak(EOPTNEG);
676 			exit(1);
677 		}
678 		if ((opts = next_field(optval, endopts)) == NULL) {
679 			nak(EOPTNEG);
680 			exit(1);
681 		}
682 		for (i = 0; options[i].opt_name != NULL; i++) {
683 			if (strcasecmp(optname, options[i].opt_name) == 0)
684 				break;
685 		}
686 		if (options[i].opt_name != NULL) {
687 			ostr = options[i].opt_handler(opcode, optval, &errcode);
688 			if (ostr != NULL) {
689 				cp += strlcpy(cp, options[i].opt_name,
690 				    oackend - cp) + 1;
691 				if (cp <= oackend)
692 					cp += strlcpy(cp, ostr, oackend - cp)
693 					    + 1;
694 
695 				if (cp > oackend) {
696 					nak(EOPTNEG);
697 					exit(1);
698 				}
699 			} else if (errcode >= 0) {
700 				nak(errcode);
701 				exit(1);
702 			}
703 		}
704 	}
705 	if (cp != (char *)&oackp->th_stuff)
706 		return (cp - oackbuf.data);
707 	return (0);
708 }
709 
710 /*
711  * Handle access errors caused by client requests.
712  */
713 
714 static void
715 delay_exit(int ecode)
716 {
717 	struct delay_info dinfo;
718 
719 	/*
720 	 * The most likely cause of an error here is that
721 	 * someone has broadcast an RRQ packet because s/he's
722 	 * trying to boot and doesn't know who the server is.
723 	 * Rather then sending an ERROR packet immediately, we
724 	 * wait a while so that the real server has a better chance
725 	 * of getting through (in case client has lousy Ethernet
726 	 * interface).  We write to a child that handles delayed
727 	 * ERROR packets to avoid delaying service to new
728 	 * requests.  Of course, we would rather just not answer
729 	 * RRQ packets that are broadcasted, but there's no way
730 	 * for a user process to determine this.
731 	 */
732 
733 	dinfo.timestamp = time(0);
734 
735 	/*
736 	 * If running in secure mode, we map all errors to EACCESS
737 	 * so that the client gets no information about which files
738 	 * or directories exist.
739 	 */
740 	if (securetftp)
741 		dinfo.ecode = EACCESS;
742 	else
743 		dinfo.ecode = ecode;
744 
745 	dinfo.from = from;
746 	if (write(delay_fd[1], &dinfo, sizeof (dinfo)) !=
747 	    sizeof (dinfo)) {
748 		syslog(LOG_ERR, "delayed write failed.");
749 		(void) kill(child, SIGKILL);
750 		exit(1);
751 	}
752 	exit(0);
753 }
754 
755 /*
756  * Handle initial connection protocol.
757  */
758 static void
759 tftp(struct tftphdr *tp, int size)
760 {
761 	char *cp;
762 	int readmode, ecode;
763 	struct formats *pf;
764 	char *mode;
765 	int fd;
766 	static boolean_t firsttime = B_TRUE;
767 	int oacklen;
768 	struct stat statb;
769 
770 	readmode = (tp->th_opcode == RRQ);
771 	filename = (char *)&tp->th_stuff;
772 	mode = next_field(filename, &buf.data[size]);
773 	cp = (mode != NULL) ? next_field(mode, &buf.data[size]) : NULL;
774 	if (cp == NULL) {
775 		nak(EBADOP);
776 		exit(1);
777 	}
778 	if (debug && standalone) {
779 		(void) fprintf(stderr, "%s for %s %s ",
780 		    readmode ? "RRQ" : "WRQ", filename, mode);
781 		print_options(stderr, cp, size + buf.data - cp);
782 		(void) putc('\n', stderr);
783 	}
784 	for (pf = formats; pf->f_mode != NULL; pf++)
785 		if (strcasecmp(pf->f_mode, mode) == 0)
786 			break;
787 	if (pf->f_mode == NULL) {
788 		nak(EBADOP);
789 		exit(1);
790 	}
791 
792 	/*
793 	 * XXX fork a new process to handle this request before
794 	 * chroot(), otherwise the parent won't be able to create a
795 	 * new socket as that requires library access to system files
796 	 * and devices.
797 	 */
798 	(void) priv_set(PRIV_SET, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
799 	switch (fork()) {
800 	case -1:
801 		syslog(LOG_ERR, "fork (tftp): %m");
802 		(void) priv_set(PRIV_SET, PRIV_EFFECTIVE, NULL);
803 		return;
804 	case 0:
805 		(void) priv_set(PRIV_SET, PRIV_EFFECTIVE, NULL);
806 		break;
807 	default:
808 		(void) priv_set(PRIV_SET, PRIV_EFFECTIVE, NULL);
809 		return;
810 	}
811 
812 	/*
813 	 * Try to see if we can access the file.  The access can still
814 	 * fail later if we are running in secure mode because of
815 	 * the chroot() call.  We only want to execute the chroot()  once.
816 	 */
817 	if (securetftp && firsttime) {
818 		(void) priv_set(
819 		    PRIV_SET, PRIV_EFFECTIVE, PRIV_PROC_CHROOT, NULL);
820 		if (chroot(homedir) == -1) {
821 			syslog(LOG_ERR,
822 			    "tftpd: cannot chroot to directory %s: %m\n",
823 			    homedir);
824 			delay_exit(EACCESS);
825 		}
826 		else
827 		{
828 			firsttime = B_FALSE;
829 		}
830 		(void) priv_set(PRIV_SET, PRIV_EFFECTIVE, NULL);
831 		(void) chdir("/");  /* cd to  new root */
832 	}
833 	(void) priv_set(PRIV_SET, PRIV_ALLSETS, NULL);
834 
835 	ecode = (*pf->f_validate)(tp->th_opcode);
836 	if (ecode != 0)
837 		delay_exit(ecode);
838 
839 	/* we don't use the descriptors passed in to the parent */
840 	(void) close(STDIN_FILENO);
841 	(void) close(STDOUT_FILENO);
842 
843 	/*
844 	 * Try to open file as low-priv setuid/setgid.  Note that
845 	 * a chroot() has already been done.
846 	 */
847 	fd = open(filename,
848 	    (readmode ? O_RDONLY : (O_WRONLY|O_TRUNC)) | O_NONBLOCK);
849 	if ((fd < 0) || (fstat(fd, &statb) < 0))
850 		delay_exit((errno == ENOENT) ? ENOTFOUND : EACCESS);
851 
852 	if (((statb.st_mode & ((readmode) ? S_IROTH : S_IWOTH)) == 0) ||
853 	    ((statb.st_mode & S_IFMT) != S_IFREG))
854 		delay_exit(EACCESS);
855 
856 	file = fdopen(fd, readmode ? "r" : "w");
857 	if (file == NULL)
858 		delay_exit(errno + 100);
859 
860 	/* Don't know the size of transfers which involve conversion */
861 	tsize_set = (readmode && (pf->f_convert == 0));
862 	if (tsize_set)
863 		tsize = statb.st_size;
864 
865 	/* Deal with any options sent by the client */
866 	oacklen = process_options(tp->th_opcode, cp, buf.data + size);
867 
868 	if (tp->th_opcode == WRQ)
869 		(*pf->f_recv)(pf, oacklen);
870 	else
871 		(*pf->f_send)(pf, oacklen);
872 
873 	exit(0);
874 }
875 
876 /*
877  *	Maybe map filename into another one.
878  *
879  *	For PNP, we get TFTP boot requests for filenames like
880  *	<Unknown Hex IP Addr>.<Architecture Name>.   We must
881  *	map these to 'pnp.<Architecture Name>'.  Note that
882  *	uppercase is mapped to lowercase in the architecture names.
883  *
884  *	For names <Hex IP Addr> there are two cases.  First,
885  *	it may be a buggy prom that omits the architecture code.
886  *	So first check if <Hex IP Addr>.<arch> is on the filesystem.
887  *	Second, this is how most Sun3s work; assume <arch> is sun3.
888  */
889 
890 static char *
891 pnp_check(char *origname)
892 {
893 	static char buf [MAXNAMLEN + 1];
894 	char *arch, *s, *bufend;
895 	in_addr_t ipaddr;
896 	int len = (origname ? strlen(origname) : 0);
897 	DIR *dir;
898 	struct dirent *dp;
899 
900 	if (securetftp || disable_pnp || len < 8 || len > 14)
901 		return (NULL);
902 
903 	/*
904 	 * XXX see if this cable allows pnp; if not, return NULL
905 	 * Requires YP support for determining this!
906 	 */
907 
908 	ipaddr = htonl(strtol(origname, &arch, 16));
909 	if ((arch == NULL) || (len > 8 && *arch != '.'))
910 		return (NULL);
911 	if (len == 8)
912 		arch = "SUN3";
913 	else
914 		arch++;
915 
916 	/*
917 	 * Allow <Hex IP Addr>* filename request to to be
918 	 * satisfied by <Hex IP Addr><Any Suffix> rather
919 	 * than enforcing this to be Sun3 systems.  Also serves
920 	 * to make case of suffix a don't-care.
921 	 */
922 	if ((dir = opendir(homedir)) == NULL)
923 		return (NULL);
924 	while ((dp = readdir(dir)) != NULL) {
925 		if (strncmp(origname, dp->d_name, 8) == 0) {
926 			(void) strlcpy(buf, dp->d_name, sizeof (buf));
927 			(void) closedir(dir);
928 			return (buf);
929 		}
930 	}
931 	(void) closedir(dir);
932 
933 	/*
934 	 * XXX maybe call YP master for most current data iff
935 	 * pnp is enabled.
936 	 */
937 
938 	/*
939 	 * only do mapping PNP boot file name for machines that
940 	 * are not in the hosts database.
941 	 */
942 	if (gethostbyaddr((char *)&ipaddr, sizeof (ipaddr), AF_INET) != NULL)
943 		return (NULL);
944 
945 	s = buf + strlcpy(buf, "pnp.", sizeof (buf));
946 	bufend = &buf[sizeof (buf) - 1];
947 	while ((*arch != '\0') && (s < bufend))
948 		*s++ = tolower (*arch++);
949 	*s = '\0';
950 	return (buf);
951 }
952 
953 
954 /*
955  * Try to validate filename. If the filename doesn't exist try PNP mapping.
956  */
957 static int
958 validate_filename(int mode)
959 {
960 	struct stat stbuf;
961 	char *origfile;
962 
963 	if (stat(filename, &stbuf) < 0) {
964 		if (errno != ENOENT)
965 			return (EACCESS);
966 		if (mode == WRQ)
967 			return (ENOTFOUND);
968 
969 		/* try to map requested filename into a pnp filename */
970 		origfile = filename;
971 		filename = pnp_check(origfile);
972 		if (filename == NULL)
973 			return (ENOTFOUND);
974 
975 		if (stat(filename, &stbuf) < 0)
976 			return (errno == ENOENT ? ENOTFOUND : EACCESS);
977 		syslog(LOG_NOTICE, "%s -> %s\n", origfile, filename);
978 	}
979 
980 	return (0);
981 }
982 
983 /* ARGSUSED */
984 static void
985 timer(int signum)
986 {
987 	timeout += rexmtval;
988 	if (timeout >= maxtimeout)
989 		exit(1);
990 	siglongjmp(timeoutbuf, 1);
991 }
992 
993 /*
994  * Send the requested file.
995  */
996 static void
997 tftpd_sendfile(struct formats *pf, int oacklen)
998 {
999 	struct tftphdr *dp;
1000 	volatile int block = 1;
1001 	int size, n, serrno;
1002 
1003 	if (oacklen != 0) {
1004 		(void) sigset(SIGALRM, timer);
1005 		timeout = 0;
1006 		(void) sigsetjmp(timeoutbuf, 1);
1007 		if (debug && standalone) {
1008 			(void) fputs("Sending OACK ", stderr);
1009 			print_options(stderr, (char *)&oackbuf.hdr.th_stuff,
1010 			    oacklen - 2);
1011 			(void) putc('\n', stderr);
1012 		}
1013 		if (sendto(peer, &oackbuf, oacklen, 0,
1014 		    (struct sockaddr *)&from, fromplen) != oacklen) {
1015 			if (debug && standalone) {
1016 				serrno = errno;
1017 				perror("sendto (oack)");
1018 				errno = serrno;
1019 			}
1020 			SYSLOG_MSG("sendto (oack): %m");
1021 			goto abort;
1022 		}
1023 		(void) alarm(rexmtval); /* read the ack */
1024 		for (;;) {
1025 			(void) sigrelse(SIGALRM);
1026 			n = recv(peer, &ackbuf, sizeof (ackbuf), 0);
1027 			(void) sighold(SIGALRM);
1028 			if (n < 0) {
1029 				if (errno == EINTR)
1030 					continue;
1031 				serrno = errno;
1032 				SYSLOG_MSG("recv (ack): %m");
1033 				if (debug && standalone) {
1034 					errno = serrno;
1035 					perror("recv (ack)");
1036 				}
1037 				goto abort;
1038 			}
1039 			ackbuf.tb_hdr.th_opcode =
1040 			    ntohs((ushort_t)ackbuf.tb_hdr.th_opcode);
1041 			ackbuf.tb_hdr.th_block =
1042 			    ntohs((ushort_t)ackbuf.tb_hdr.th_block);
1043 
1044 			if (ackbuf.tb_hdr.th_opcode == ERROR) {
1045 				if (debug && standalone) {
1046 					(void) fprintf(stderr,
1047 					    "received ERROR %d",
1048 					    ackbuf.tb_hdr.th_code);
1049 					if (n > 4)
1050 						(void) fprintf(stderr,
1051 						    " %.*s", n - 4,
1052 						    ackbuf.tb_hdr.th_msg);
1053 					(void) putc('\n', stderr);
1054 				}
1055 				goto abort;
1056 			}
1057 
1058 			if (ackbuf.tb_hdr.th_opcode == ACK) {
1059 				if (debug && standalone)
1060 					(void) fprintf(stderr,
1061 					    "received ACK for block %d\n",
1062 					    ackbuf.tb_hdr.th_block);
1063 				if (ackbuf.tb_hdr.th_block == 0)
1064 					break;
1065 				/*
1066 				 * Don't resend the OACK, avoids getting stuck
1067 				 * in an OACK/ACK loop if the client keeps
1068 				 * replying with a bad ACK. Client will either
1069 				 * send a good ACK or timeout sending bad ones.
1070 				 */
1071 			}
1072 		}
1073 		cancel_alarm();
1074 	}
1075 	dp = r_init();
1076 	do {
1077 		(void) sigset(SIGALRM, timer);
1078 		size = readit(file, &dp, pf->f_convert);
1079 		if (size < 0) {
1080 			nak(errno + 100);
1081 			goto abort;
1082 		}
1083 		dp->th_opcode = htons((ushort_t)DATA);
1084 		dp->th_block = htons((ushort_t)block);
1085 		timeout = 0;
1086 		(void) sigsetjmp(timeoutbuf, 1);
1087 		if (debug && standalone)
1088 			(void) fprintf(stderr, "Sending DATA block %d\n",
1089 			    block);
1090 		if (sendto(peer, dp, size + 4, 0,
1091 		    (struct sockaddr *)&from,  fromplen) != size + 4) {
1092 			if (debug && standalone) {
1093 				serrno = errno;
1094 				perror("sendto (data)");
1095 				errno = serrno;
1096 			}
1097 			SYSLOG_MSG("sendto (data): %m");
1098 			goto abort;
1099 		}
1100 		read_ahead(file, pf->f_convert);
1101 		(void) alarm(rexmtval); /* read the ack */
1102 		for (;;) {
1103 			(void) sigrelse(SIGALRM);
1104 			n = recv(peer, &ackbuf, sizeof (ackbuf), 0);
1105 			(void) sighold(SIGALRM);
1106 			if (n < 0) {
1107 				if (errno == EINTR)
1108 					continue;
1109 				serrno = errno;
1110 				SYSLOG_MSG("recv (ack): %m");
1111 				if (debug && standalone) {
1112 					errno = serrno;
1113 					perror("recv (ack)");
1114 				}
1115 				goto abort;
1116 			}
1117 			ackbuf.tb_hdr.th_opcode =
1118 			    ntohs((ushort_t)ackbuf.tb_hdr.th_opcode);
1119 			ackbuf.tb_hdr.th_block =
1120 			    ntohs((ushort_t)ackbuf.tb_hdr.th_block);
1121 
1122 			if (ackbuf.tb_hdr.th_opcode == ERROR) {
1123 				if (debug && standalone) {
1124 					(void) fprintf(stderr,
1125 					    "received ERROR %d",
1126 					    ackbuf.tb_hdr.th_code);
1127 					if (n > 4)
1128 						(void) fprintf(stderr,
1129 						    " %.*s", n - 4,
1130 						    ackbuf.tb_hdr.th_msg);
1131 					(void) putc('\n', stderr);
1132 				}
1133 				goto abort;
1134 			}
1135 
1136 			if (ackbuf.tb_hdr.th_opcode == ACK) {
1137 				if (debug && standalone)
1138 					(void) fprintf(stderr,
1139 						"received ACK for block %d\n",
1140 						ackbuf.tb_hdr.th_block);
1141 				if (ackbuf.tb_hdr.th_block == block) {
1142 					break;
1143 				}
1144 				/*
1145 				 * Never resend the current DATA packet on
1146 				 * receipt of a duplicate ACK, doing so would
1147 				 * cause the "Sorcerer's Apprentice Syndrome".
1148 				 */
1149 			}
1150 		}
1151 		cancel_alarm();
1152 		block++;
1153 	} while (size == blocksize);
1154 
1155 abort:
1156 	cancel_alarm();
1157 	(void) fclose(file);
1158 }
1159 
1160 /* ARGSUSED */
1161 static void
1162 justquit(int signum)
1163 {
1164 	exit(0);
1165 }
1166 
1167 /*
1168  * Receive a file.
1169  */
1170 static void
1171 tftpd_recvfile(struct formats *pf, int oacklen)
1172 {
1173 	struct tftphdr *dp;
1174 	struct tftphdr *ap;    /* ack buffer */
1175 	int block = 0, n, size, acklen, serrno;
1176 
1177 	dp = w_init();
1178 	ap = &ackbuf.tb_hdr;
1179 	do {
1180 		(void) sigset(SIGALRM, timer);
1181 		timeout = 0;
1182 		if (oacklen == 0) {
1183 			ap->th_opcode = htons((ushort_t)ACK);
1184 			ap->th_block = htons((ushort_t)block);
1185 			acklen = 4;
1186 		} else {
1187 			/* copy OACK packet to the ack buffer ready to send */
1188 			(void) memcpy(&ackbuf, &oackbuf, oacklen);
1189 			acklen = oacklen;
1190 			oacklen = 0;
1191 		}
1192 		block++;
1193 		(void) sigsetjmp(timeoutbuf, 1);
1194 send_ack:
1195 		if (debug && standalone) {
1196 			if (ap->th_opcode == htons((ushort_t)ACK)) {
1197 				(void) fprintf(stderr,
1198 				    "Sending ACK for block %d\n", block - 1);
1199 			} else {
1200 				(void) fprintf(stderr, "Sending OACK ");
1201 				print_options(stderr, (char *)&ap->th_stuff,
1202 				    acklen - 2);
1203 				(void) putc('\n', stderr);
1204 			}
1205 		}
1206 		if (sendto(peer, &ackbuf, acklen, 0, (struct sockaddr *)&from,
1207 		    fromplen) != acklen) {
1208 			if (ap->th_opcode == htons((ushort_t)ACK)) {
1209 				if (debug && standalone) {
1210 					serrno = errno;
1211 					perror("sendto (ack)");
1212 					errno = serrno;
1213 				}
1214 				syslog(LOG_ERR, "sendto (ack): %m\n");
1215 			} else {
1216 				if (debug && standalone) {
1217 					serrno = errno;
1218 					perror("sendto (oack)");
1219 					errno = serrno;
1220 				}
1221 				syslog(LOG_ERR, "sendto (oack): %m\n");
1222 			}
1223 			goto abort;
1224 		}
1225 		if (write_behind(file, pf->f_convert) < 0) {
1226 			nak(errno + 100);
1227 			goto abort;
1228 		}
1229 		(void) alarm(rexmtval);
1230 		for (;;) {
1231 			(void) sigrelse(SIGALRM);
1232 			n = recv(peer, dp, blocksize + 4, 0);
1233 			(void) sighold(SIGALRM);
1234 			if (n < 0) { /* really? */
1235 				if (errno == EINTR)
1236 					continue;
1237 				syslog(LOG_ERR, "recv (data): %m");
1238 				goto abort;
1239 			}
1240 			dp->th_opcode = ntohs((ushort_t)dp->th_opcode);
1241 			dp->th_block = ntohs((ushort_t)dp->th_block);
1242 			if (dp->th_opcode == ERROR) {
1243 				cancel_alarm();
1244 				if (debug && standalone) {
1245 					(void) fprintf(stderr,
1246 					    "received ERROR %d", dp->th_code);
1247 					if (n > 4)
1248 						(void) fprintf(stderr,
1249 						    " %.*s", n - 4, dp->th_msg);
1250 					(void) putc('\n', stderr);
1251 				}
1252 				return;
1253 			}
1254 			if (dp->th_opcode == DATA) {
1255 				if (debug && standalone)
1256 					(void) fprintf(stderr,
1257 						"Received DATA block %d\n",
1258 						dp->th_block);
1259 				if (dp->th_block == block) {
1260 					break;   /* normal */
1261 				}
1262 				/* Re-synchronize with the other side */
1263 				if (synchnet(peer) < 0) {
1264 					nak(errno + 100);
1265 					goto abort;
1266 				}
1267 				if (dp->th_block == (block-1))
1268 					goto send_ack; /* rexmit */
1269 			}
1270 		}
1271 		cancel_alarm();
1272 		/*  size = write(file, dp->th_data, n - 4); */
1273 		size = writeit(file, &dp, n - 4, pf->f_convert);
1274 		if (size != (n - 4)) {
1275 			nak((size < 0) ? (errno + 100) : ENOSPACE);
1276 			goto abort;
1277 		}
1278 	} while (size == blocksize);
1279 	if (write_behind(file, pf->f_convert) < 0) {
1280 		nak(errno + 100);
1281 		goto abort;
1282 	}
1283 	n = fclose(file);	/* close data file */
1284 	file = NULL;
1285 	if (n == EOF) {
1286 		nak(errno + 100);
1287 		goto abort;
1288 	}
1289 
1290 	ap->th_opcode = htons((ushort_t)ACK);    /* send the "final" ack */
1291 	ap->th_block = htons((ushort_t)(block));
1292 	if (debug && standalone)
1293 		(void) fprintf(stderr, "Sending ACK for block %d\n", block);
1294 	if (sendto(peer, &ackbuf, 4, 0, (struct sockaddr *)&from,
1295 	    fromplen) == -1) {
1296 		if (debug && standalone)
1297 			perror("sendto (ack)");
1298 	}
1299 	(void) sigset(SIGALRM, justquit); /* just quit on timeout */
1300 	(void) alarm(rexmtval);
1301 	/* normally times out and quits */
1302 	n = recv(peer, dp, blocksize + 4, 0);
1303 	(void) alarm(0);
1304 	dp->th_opcode = ntohs((ushort_t)dp->th_opcode);
1305 	dp->th_block = ntohs((ushort_t)dp->th_block);
1306 	if (n >= 4 &&		/* if read some data */
1307 	    dp->th_opcode == DATA && /* and got a data block */
1308 	    block == dp->th_block) {	/* then my last ack was lost */
1309 		if (debug && standalone) {
1310 			(void) fprintf(stderr, "Sending ACK for block %d\n",
1311 			    block);
1312 		}
1313 		/* resend final ack */
1314 		if (sendto(peer, &ackbuf, 4, 0, (struct sockaddr *)&from,
1315 		    fromplen) == -1) {
1316 			if (debug && standalone)
1317 				perror("sendto (last ack)");
1318 		}
1319 	}
1320 
1321 abort:
1322 	cancel_alarm();
1323 	if (file != NULL)
1324 		(void) fclose(file);
1325 }
1326 
1327 /*
1328  * Send a nak packet (error message).
1329  * Error code passed in is one of the
1330  * standard TFTP codes, or a UNIX errno
1331  * offset by 100.
1332  * Handles connected as well as unconnected peer.
1333  */
1334 static void
1335 nak(int error)
1336 {
1337 	struct tftphdr *tp;
1338 	int length;
1339 	struct errmsg *pe;
1340 	int ret;
1341 
1342 	tp = &buf.hdr;
1343 	tp->th_opcode = htons((ushort_t)ERROR);
1344 	tp->th_code = htons((ushort_t)error);
1345 	for (pe = errmsgs; pe->e_code >= 0; pe++)
1346 		if (pe->e_code == error)
1347 			break;
1348 	if (pe->e_code < 0) {
1349 		pe->e_msg = strerror(error - 100);
1350 		tp->th_code = EUNDEF;   /* set 'undef' errorcode */
1351 	}
1352 	(void) strlcpy(tp->th_msg, (pe->e_msg != NULL) ? pe->e_msg : "UNKNOWN",
1353 	    sizeof (buf) - sizeof (struct tftphdr));
1354 	length = strlen(tp->th_msg);
1355 	length += sizeof (struct tftphdr);
1356 	if (debug && standalone)
1357 		(void) fprintf(stderr, "Sending NAK: %s\n", tp->th_msg);
1358 
1359 	ret = sendto(peer, &buf, length, 0, (struct sockaddr *)&from,
1360 	    fromplen);
1361 	if (ret == -1 && errno == EISCONN) {
1362 		/* Try without an address */
1363 		ret = send(peer, &buf, length, 0);
1364 	}
1365 	if (ret == -1) {
1366 		if (standalone)
1367 			perror("sendto (nak)");
1368 		else
1369 			syslog(LOG_ERR, "tftpd: nak: %m\n");
1370 	} else if (ret != length) {
1371 		if (standalone)
1372 			perror("sendto (nak) lost data");
1373 		else
1374 			syslog(LOG_ERR, "tftpd: nak: %d lost\n", length - ret);
1375 	}
1376 }
1377