tftpdLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:29k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* tftpdLib.c - Trivial File Transfer Protocol server library */
  2. /* Copyright 1992 - 2001 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01l,07may02,kbw  man page edits
  8. 01k,15oct01,rae  merge from truestack ver 01n, base 01i (SPR #69222 etc.)
  9. 01j,09jan01,dgr  Adding to comment-header-block of tftpdInit as per SPR #63337
  10. 01i,09oct97,nbs  modified tftpd to use filename from TFTP_DESC, spr # 9413
  11. 01h,01aug96,sgv  added trunc flag for open call SPR #6839
  12. 01g,21jul95,vin  applied ntohs for the opcode field. SPR4124.
  13. 01f,11aug93,jmm  Changed ioctl.h and socket.h to sys/ioctl.h and sys/socket.h
  14. 01e,21sep92,jdi  documentation cleanup. 
  15. 01d,18jul92,smb  Changed errno.h to errnoLib.h.
  16. 01c,04jun92,ajm  shut up warnings on mips compiler
  17. 01b,26may92,rrr  the tree shuffle
  18.   -changed includes to have absolute path from h/
  19. 01a,29Jan92,jmm written.
  20. */
  21. /*
  22. DESCRIPTION
  23. This library implements the VxWorks Trivial File Transfer Protocol
  24. (TFTP) server module.  The server can respond to both read and write
  25. requests.  It is started by a call to tftpdInit().
  26. The server has access to a list of directories that can either be
  27. provided in the initial call to tftpdInit() or changed dynamically
  28. using the tftpdDirectoryAdd() and tftpDirectoryRemove() calls.
  29. Requests for files not in the directory trees specified in the access
  30. list will be rejected, unless the list is empty, in which case all
  31. requests will be allowed.  By default, the access list contains the
  32. directory given in the global variable `tftpdDirectory'.  It is possible
  33. to remove the default by calling tftpdDirectoryRemove().
  34. For specific information about the TFTP protocol, see RFC 783, "TFTP
  35. Protocol."
  36. VXWORKS AE PROTECTION DOMAINS
  37. Under VxWorks AE, you can run the tftp server in the kernel protection 
  38. domain only.  This restriction does not apply under non-AE versions of 
  39. VxWorks.  
  40. INTERNAL
  41. The server library uses the TFTP client routines tftpPut() and
  42. tftpGet() to do the actual file transfer.  When the server receives a
  43. request, it does one of three things:
  44.     Read request (RRQ): spawns tftpFileRead task, which will call
  45.                         tftpPut().
  46.     Write request (WRQ): spawns tftpFileWrite task, which will call
  47.                          tftpGet().
  48.     All others: sends back error packet
  49. To use this feature, include the following component:
  50. INCLUDE_TFTP_SERVER
  51. INCLUDE FILES: tftpdLib.h, tftpLib.h
  52. SEE ALSO:
  53. tftpLib, RFC 783 "TFTP Protocol"
  54. */
  55. #include "vxWorks.h"
  56. #include "tftpdLib.h"
  57. #include "netinet/in.h"
  58. #include "sockLib.h"
  59. #include "sys/socket.h"
  60. #include "tftpLib.h"
  61. #include "errnoLib.h"
  62. #include "fcntl.h"
  63. #include "ioLib.h"
  64. #include "stdio.h"
  65. #include "stdlib.h"
  66. #include "string.h"
  67. #include "sys/types.h"
  68. #include "unistd.h"
  69. #include "usrLib.h"
  70. #include "iosLib.h"
  71. #include "msgQLib.h"
  72. #include "semLib.h"
  73. #include "inetLib.h"
  74. #include "memPartLib.h"
  75. /* EXTERNALS */
  76. extern int sysClkRateGet (void);
  77. /* GLOBALS */
  78. BOOL tftpdDebug = FALSE; /* TRUE: debugging messages */
  79. int tftpdTaskPriority = 55;
  80. int tftpdTaskStackSize = 12000;
  81. int tftpdTaskId = NONE;
  82. int tftpdErrorSendTries = 3;
  83. int tftpdMaxConnections = 10;
  84. char *tftpdDirectoryDefault = "/tftpboot";
  85. int tftpdResponsePriority = 100;
  86. /* XXX Hack for Genus */
  87. FUNCPTR tftpdNameMunge = NULL;
  88. /* LOCALS */
  89. LOCAL SEM_ID tftpdDirectorySem; /* protection for the semaphore list */
  90. LOCAL LIST     tftpdDirectoryList; /* access list, elements  TFTPD_DIR  */
  91. LOCAL MSG_Q_ID tftpdDescriptorQueue; /* msg queue of available connection */
  92. LOCAL TFTP_DESC *tftpdDescriptorPool;
  93. LOCAL char tftpdErrStr [] = "TFTP server";
  94. /* PROTOTYPES */
  95. static STATUS tftpdRequestVerify (TFTP_DESC *pReplyDesc, int opCode,
  96.   char *fileName);
  97. static STATUS tftpdRequestDecode (TFTP_MSG *pTftpMsg, int *opCode,
  98.   char *fileName, char *mode);
  99. static STATUS tftpdFileRead (char *fileName, TFTP_DESC *pReplyDesc);
  100. static STATUS tftpdFileWrite (char *fileName, TFTP_DESC *pReplyDesc);
  101. static STATUS tftpdDescriptorQueueInit (int nEntries);
  102. static STATUS tftpdDescriptorQueueDelete (void);
  103. static TFTP_DESC *tftpdDescriptorCreate (char *mode, BOOL connected,
  104.  int sock, u_short clientPort,
  105.  struct sockaddr_in *pClientAddr);
  106. static STATUS tftpdDescriptorDelete (TFTP_DESC *descriptor);
  107. static STATUS tftpdDirectoryValidate (char *fileName);
  108. static STATUS tftpdErrorSend (TFTP_DESC *pReplyDesc, int errorNum);
  109. /******************************************************************************
  110. *
  111. * tftpdInit - initialize the TFTP server task
  112. *
  113. * This routine will spawn a new TFTP server task, if one does not already
  114. * exist.  If a TFTP server task is running already, tftpdInit() will simply
  115. * return an ERROR value without creating a new task.
  116. *
  117. * To change the default stack size for the TFTP server task, use the
  118. * <stackSize> parameter.  The task stack size should be set to a large enough
  119. * value for the needs of your application - use checkStack() to evaluate your
  120. * stack usage.  The default size is set in the global variable
  121. * `tftpdTaskStackSize'.  Setting <stackSize> to zero will result in the stack
  122. * size being set to this default.
  123. *
  124. * To set the maximum number of simultaneous TFTP connections (each with its
  125. * own transfer identifier or TID), set the <maxConnections> parameter.  More
  126. * information on this is found in RFC 1350 ("The TFTP Protocol (Revision 2)").
  127. * Setting <maxConnections> to zero will result in the maximum number of
  128. * connections being set to the default, which is 10.
  129. *
  130. * If <noControl> is TRUE, the server will be set up to transfer any
  131. * file in any location.  Otherwise, it will only transfer files in the
  132. * directories in '/tftpboot' or the <nDirectories> directories in the
  133. * <directoryNames> list, and will send an
  134. * access violation error to clients that attempt to access files outside of
  135. * these directories.
  136. *
  137. * By default, <noControl> is FALSE, <directoryNames> is empty, <nDirectories>
  138. * is zero, and access is restricted to the '/tftpboot' directory.
  139. *
  140. * Directories can be added to the access list after initialization by using
  141. * the tftpdDirectoryAdd() routine.
  142. *
  143. * VXWORKS AE PROTECTION DOMAINS
  144. * Under VxWorks AE, you can call this function from within the kernel 
  145. * protection domain only.  In addition, all arguments to this function can  
  146. * reference only that data which is valid in the kernel protection domain. 
  147. * This restriction does not apply under non-AE versions of VxWorks.  
  148. *
  149. * RETURNS:
  150. * OK, or ERROR if a new TFTP task cannot be created.
  151. */
  152. STATUS tftpdInit
  153.     (
  154.     int  stackSize, /* stack size for the tftpdTask */
  155.     int  nDirectories, /* number of directories allowed read */
  156.     char **directoryNames, /* array of dir names */
  157.     BOOL noControl, /* TRUE if no access control required */
  158.     int  maxConnections
  159.     )
  160.     {
  161.     /*
  162.      * Make sure there isn't a TFTP server task running already
  163.      */
  164.     if (tftpdTaskId != NONE)
  165. {
  166. return (ERROR);
  167. }
  168.     /*
  169.      * Initialize the access list, add the default directory,
  170.      * and give the semaphore that protects the list
  171.      */
  172.     lstInit (&tftpdDirectoryList);
  173.     tftpdDirectorySem = semMCreate(SEM_Q_FIFO);
  174.     /*
  175.      * If access control isn't turned off, add the default directory
  176.      * to the list
  177.      */
  178.     if (noControl != TRUE)
  179.         tftpdDirectoryAdd (tftpdDirectoryDefault);
  180.     /*
  181.      * Add the first set of directories to the list
  182.      */
  183.     while (--nDirectories >= 0)
  184. {
  185. tftpdDirectoryAdd (directoryNames [nDirectories]);
  186. }
  187.     /* create a TFTP server task */
  188.     tftpdTaskId = taskSpawn ("tTftpdTask", tftpdTaskPriority, 0,
  189.      stackSize == 0 ? tftpdTaskStackSize : stackSize,
  190.      tftpdTask, nDirectories, (int) directoryNames,
  191.      maxConnections, 0, 0, 0, 0, 0, 0, 0);
  192.     if (tftpdTaskId == ERROR)
  193. {
  194.         printErr ("%s: tftpdTask cannot be createdn", tftpdErrStr);
  195. return (ERROR);
  196. }
  197.     return (OK);
  198.     }
  199. /******************************************************************************
  200. *
  201. * tftpdTask - TFTP server daemon task
  202. *
  203. * This routine processes incoming TFTP client requests by spawning a new
  204. * task for each connection that is set up.  This routine is called by 
  205. * tftpdInit().
  206. *
  207. * VXWORKS AE PROTECTION DOMAINS
  208. * Under VxWorks AE, you can call this function from within the kernel 
  209. * protection domain only.  In addition, all arguments to this function can  
  210. * reference only that data which is valid in the kernel protection domain. 
  211. * This restriction does not apply under non-AE versions of VxWorks.  
  212. *
  213. * RETURNS:
  214. * OK, or ERROR if the task returns unexpectedly.
  215. */
  216. STATUS tftpdTask
  217.     (
  218.     int nDirectories, /* number of dirs allowed access    */
  219.     char **directoryNames, /* array of directory names         */
  220.     int maxConnections /* max number of simultan. connects */
  221.     )
  222.     {
  223.     int serverSocket; /* socket to use to communicate with
  224.  * the remote process */
  225.     struct sockaddr_in clientAddr; /* process requesting TFTP
  226.  * connection */
  227.     struct sockaddr_in serverAddr;
  228.     int clientAddrLength = sizeof (struct sockaddr_in);
  229.     TFTP_MSG  requestBuffer;
  230.     int value;
  231.     int opCode;
  232.     char *fileName;
  233.     char mode [TFTP_SEGSIZE];
  234.     TFTP_DESC *pReplyDesc;
  235.     int replySocket;
  236.     serverSocket = socket (AF_INET, SOCK_DGRAM, 0);
  237.     bzero ((char *) &serverAddr, sizeof (struct sockaddr_in));
  238.     bzero ((char *) &clientAddr, sizeof (struct sockaddr_in));
  239.     serverAddr.sin_family = AF_INET;
  240.     serverAddr.sin_port = htons((u_short) TFTP_PORT);
  241.     serverAddr.sin_addr.s_addr = INADDR_ANY;
  242.     if (bind (serverSocket, (SOCKADDR *) &serverAddr,
  243.       sizeof (struct sockaddr_in)) == ERROR)
  244. {
  245. printErr ("%s: could not bind to TFTP portn", tftpdErrStr);
  246. return (ERROR);
  247. }
  248.     if (tftpdDescriptorQueueInit (maxConnections) == ERROR)
  249. {
  250. printErr ("%s: could not create descriptor queuen", tftpdErrStr);
  251. return (ERROR);
  252. }
  253.     /*
  254.      * Clean out any outstanding data on the TFTP port.
  255.      */
  256.     FOREVER
  257. {
  258. if (ioctl (serverSocket, FIONREAD, (int) &value) == ERROR)
  259.     return (ERROR);
  260. if (value == 0)                /* done - socket cleaned out */
  261.     break;
  262. recvfrom (serverSocket, (caddr_t) &requestBuffer,
  263.   sizeof (TFTP_MSG), 0, (SOCKADDR *) NULL,
  264.   (int *) NULL);
  265. }
  266.     /*
  267.      * The main loop.  Receive requests on the TFTP port, parse the request,
  268.      * and spawn tasks to handle it.
  269.      */
  270.     FOREVER
  271. {
  272. /*
  273.  * Read a message from the TFTP port
  274.  */
  275. value = recvfrom (serverSocket, (char *) &requestBuffer, TFTP_SEGSIZE,
  276.   0, (struct sockaddr *) &clientAddr,
  277.   &clientAddrLength);
  278. /*
  279.  * If there's an error reading on the port, abort the server.
  280.  */
  281. if (value == ERROR)
  282.     {
  283.     printErr ("%s:  could not read on TFTP portn", tftpdErrStr);
  284.     close (serverSocket);
  285.     tftpdDescriptorQueueDelete ();
  286.     break;
  287.     }
  288. /*
  289.  * Set up a socket to use for a reply, and get a port number for it.
  290.  */
  291. replySocket = socket (AF_INET, SOCK_DGRAM, 0);
  292. if (replySocket == ERROR)
  293.     {
  294.     /*
  295.      * XXX How should we deal with an error here?
  296.      */
  297.     continue;
  298.     }
  299. serverAddr.sin_port = htons((u_short) 0);
  300. if (bind (replySocket, (SOCKADDR *) &serverAddr,
  301.   sizeof (struct sockaddr_in)) == ERROR)
  302.     {
  303.     /*
  304.      * XXX How should we deal with an error here?
  305.      */
  306.     continue;
  307.     }
  308. if (tftpdRequestDecode (&requestBuffer, &opCode, NULL,
  309. (char *) mode) == ERROR)
  310.     {
  311.     /*
  312.      * We received something that doesn't look like a TFTP request.
  313.      * Ignore it.
  314.      */
  315.     close (replySocket);
  316.     continue;
  317.     }
  318. /*
  319.  * Get a reply descriptor.  This will pend until one is available.
  320.  */
  321. pReplyDesc = tftpdDescriptorCreate (mode, TRUE, replySocket,
  322.     clientAddr.sin_port, &clientAddr);
  323. if (pReplyDesc == NULL)
  324.     {
  325.     /*
  326.      * Couldn't create a reply descriptor.
  327.      */
  328.     close (replySocket);
  329.     continue;
  330.     }
  331. /*
  332.  * Copy the name of the requested file into the TFTP_DESC
  333.  */
  334. fileName = pReplyDesc->fileName;
  335.         if (tftpdRequestDecode (&requestBuffer, NULL, (char *) fileName,
  336.                                 NULL) == ERROR)
  337.             {
  338.             /*
  339.              * We received something that doesn't look like a TFTP request.
  340.              * Ignore it.
  341.              */
  342.             close (replySocket);
  343.             continue;
  344.             }
  345. if (tftpdRequestVerify (pReplyDesc, opCode, fileName) != OK)
  346.     {
  347.     /*
  348.      * Invalid request, error packet already sent by tftpdRequestVerify
  349.      */
  350.     tftpdDescriptorDelete (pReplyDesc);
  351.     close (replySocket);
  352.     continue;
  353.     }
  354. if (tftpdDebug)
  355.     {
  356.     printf ("%s: Request: Opcode = %d, file = %s, client = %sn",
  357.     tftpdErrStr, opCode, fileName, pReplyDesc->serverName);
  358.     }
  359. switch (opCode)
  360.     {
  361.     case TFTP_RRQ:
  362. /*
  363.  * We've received a read request.  Spawn a tftpdFileRead
  364.  * task to process it.
  365.  */
  366.         taskSpawn ("tTftpRRQ", tftpdResponsePriority, 0, 10000,
  367.    tftpdFileRead, (int) fileName, (int) pReplyDesc,
  368.    0, 0, 0, 0, 0, 0, 0, 0);
  369. break;
  370.     case TFTP_WRQ:
  371. /*
  372.  * We've received a write request.  Spawn a tftpdFileWrite
  373.  * task to process it.
  374.  */
  375.         taskSpawn ("tTftpWRQ", tftpdResponsePriority, 0, 10000,
  376.    tftpdFileWrite, (int) fileName, (int) pReplyDesc,
  377.    0, 0, 0, 0, 0, 0, 0, 0);
  378. break;
  379.     }
  380. } /* end FOREVER */
  381.     printErr ("%s:  aborting TFTP servern", tftpdErrStr);
  382.     tftpdDescriptorQueueDelete ();
  383.     close (serverSocket);
  384.     return (ERROR);
  385.     }
  386. /******************************************************************************
  387. *
  388. * tftpdRequestVerify - ensure that an incoming TFTP request is valid
  389. *
  390. * Checks a TFTP request to make sure that the opcode is either
  391. * a read or write request, and then checks to see if the file requested
  392. * is in the access list.
  393. *
  394. * If there is an error, it sends an error packet to the offending client.
  395. *
  396. * RETURNS: OK, or ERROR if any of the conditions aren't met.
  397. */
  398. LOCAL STATUS tftpdRequestVerify
  399.     (
  400.     TFTP_DESC *pReplyDesc,
  401.     int opCode,
  402.     char *fileName
  403.     )
  404.     {
  405.     int dirIsValid;
  406.     /*
  407.      * Need to check two things:
  408.      *
  409.      * 1.  The request itself needs to be valid, either a write request (WRQ)
  410.      *     or a read request (RRQ).
  411.      *
  412.      * 2.  It needs to be to a valid directory.
  413.      */
  414.     if ((opCode != TFTP_RRQ) && (opCode != TFTP_WRQ))
  415. {
  416. /*
  417.  * Bad opCode sent to the server.
  418.  */
  419. tftpdErrorSend (pReplyDesc, EBADOP);
  420. return (ERROR);
  421. }
  422.     dirIsValid = tftpdDirectoryValidate (fileName);
  423.     if (dirIsValid != OK)
  424. {
  425. /*
  426.  * Access was denied to the file that the client
  427.  * requested.
  428.  */
  429. tftpdErrorSend (pReplyDesc, errnoGet());
  430. return (ERROR);
  431. }
  432.     return (OK);
  433.     }
  434. /******************************************************************************
  435. *
  436. * tftpdRequestDecode - break down a TFTP request
  437. *
  438. * Given a pointer to a TFTP message, this routine decodes the message
  439. * and returns the message's opcode, file name, and mode.
  440. *
  441. * RETURNS:
  442. * OK or ERROR.
  443. */
  444. LOCAL STATUS tftpdRequestDecode
  445.     (
  446.     TFTP_MSG *pTftpMsg,
  447.     int * opCode, /* pointer to the opCode to return */
  448.     char *fileName, /* where to return filename */
  449.     char *mode /* where to return mode */
  450.     )
  451.     {
  452.     char *strIndex; /* index into pTftpMsg to get mode string */
  453.     if (pTftpMsg == NULL)
  454. return (ERROR);
  455.     if (opCode != NULL)
  456. *opCode = ntohs(pTftpMsg->th_opcode);
  457.     if (fileName != NULL)
  458. {
  459. strncpy (fileName, pTftpMsg->th.request, 128);
  460. fileName [127] = EOS;
  461. }
  462.     if (mode != NULL)
  463. {
  464. /*
  465.  * Need to get the next string in the struct. Use the for loop to
  466.  * find the end of the first string.
  467.  */
  468. for (strIndex = pTftpMsg->th.request;
  469.      *strIndex != EOS;
  470.      strIndex++)
  471.     ;
  472. strncpy(mode, ++strIndex, 32);
  473. mode [31] = EOS;
  474. }
  475.     return (OK);
  476.     }
  477. /******************************************************************************
  478. *
  479. * tftpdFileRead - handle a read request
  480. *
  481. * This routine constructs and executes the tftpPut() command to put the file
  482. * to the remote system.  Normally this routine is the entry point for a task
  483. * created by tftpdTask() in response to a read request.
  484. *
  485. * RETURNS: OK, or ERROR if the file requested could not be opened.
  486. */
  487. LOCAL STATUS tftpdFileRead
  488.     (
  489.     char *fileName, /* file to be sent */
  490.     TFTP_DESC *pReplyDesc  /* where to send the file */
  491.     )
  492.     {
  493.     int requestFd;
  494.     int returnValue = OK;
  495.     /*
  496.      * XXX - X windows needs files that don't work with DOS - they have
  497.      * more than three chars after a dot (as in fonts.alias).  If the
  498.      * funcpointer is non-null, call the routine with a pointer to
  499.      * filename, and the called routine should change the name to something
  500.      * DOS understands.
  501.      */
  502.     if (tftpdNameMunge != NULL)
  503.         (*tftpdNameMunge) (fileName);
  504.     requestFd = open (fileName, O_RDONLY, 0);
  505.     if (requestFd == ERROR)
  506. {
  507. if (tftpdDebug)
  508.     {
  509.     printErr ("%s: Could not open file %sn", tftpdErrStr, fileName);
  510.     }
  511. tftpdErrorSend (pReplyDesc, errnoGet());
  512. }
  513.     else
  514. {
  515. /*
  516.  * We call tftpPut from the server on a read request because the
  517.  * server is putting the file to the client
  518.  */
  519. returnValue = tftpPut (pReplyDesc, fileName, requestFd,
  520.        TFTP_SERVER);
  521. close (requestFd);
  522. }
  523.     /*
  524.      * Close the socket, and delete the
  525.      * tftpd descriptor.
  526.      */
  527.     if (returnValue == ERROR)
  528. {
  529. printErr ("%s:  could not send client file "%s"n", tftpdErrStr,
  530.   fileName);
  531. }
  532.     tftpdDescriptorDelete (pReplyDesc);
  533.     return (returnValue);
  534.     }
  535. /******************************************************************************
  536. *
  537. * tftpdFileWrite - handle a write request
  538. *
  539. * This routine constructs and executes the tftpGet() command to get the file
  540. * from the remote system.  Normally this routine is the entry point for a
  541. * task created by tftpdTask() in response to a write request.
  542. *
  543. * RETURNS: OK, or ERROR if the file requested could not be opened.
  544. */
  545. LOCAL STATUS tftpdFileWrite
  546.     (
  547.     char *fileName, /* file to be sent */
  548.     TFTP_DESC *pReplyDesc  /* where to send the file */
  549.     )
  550.     {
  551.     int requestFd;
  552.     int returnValue = OK;
  553.     requestFd = open (fileName, O_WRONLY | O_CREAT | O_TRUNC, 0);
  554.     if (requestFd == ERROR)
  555. {
  556. if (tftpdDebug)
  557.     {
  558.     printErr ("%s: Could not open file %sn", tftpdErrStr, fileName);
  559.     }
  560. tftpdErrorSend (pReplyDesc, errnoGet());
  561. }
  562.     else
  563. {
  564. /*
  565.  * We call tftpGet from the server on a read request because the
  566.  * server is putting the file to the client
  567.  */
  568. returnValue = tftpGet (pReplyDesc, fileName, requestFd,
  569.        TFTP_SERVER);
  570. close (requestFd);
  571. }
  572.     /*
  573.      * Close the socket, and delete the
  574.      * tftpd descriptor.
  575.      */
  576.     if (returnValue == ERROR)
  577. {
  578. printErr ("%s:  could not send "%s" to clientn", tftpdErrStr);
  579. }
  580.     tftpdDescriptorDelete (pReplyDesc);
  581.     return (returnValue);
  582.     }
  583. /******************************************************************************
  584. *
  585. * tftpdDescriptorQueueInit - set up pool of available descriptors
  586. *
  587. * This routine sets up the system for managing a pool of available reply
  588. * descriptors.  A piece of contiguous memory, large enough to hold an
  589. * array of <nEntries> descriptors, is allocated (with malloc()).
  590. * Pointers to each element in the array are written into a message
  591. * queue.  The routine tftpdDescriptorCreate() reads pointers out of this
  592. * queue, and tftpdDescriptorDelete() writes them back in when the
  593. * descriptor space is no longer needed.
  594. *
  595. * RETURNS: OK, or ERROR if either out of memory or the queue could not
  596. * be allocated.
  597. */
  598. LOCAL STATUS tftpdDescriptorQueueInit
  599.     (
  600.     int nEntries /* maximum number of descriptors in
  601.  * use at any time */
  602.     )
  603.     {
  604.     TFTP_DESC *theAddress;
  605.     /*
  606.      * If nEntries is 0, set it to the default number of connections
  607.      */
  608.     if (nEntries == 0)
  609.         nEntries = tftpdMaxConnections;
  610.     /*
  611.      * Create the message queue
  612.      */
  613.     if ((tftpdDescriptorQueue = (MSG_Q_ID) msgQCreate (nEntries,
  614.        sizeof (TFTP_DESC *),
  615.        MSG_Q_FIFO)) == NULL)
  616.         {
  617. return (ERROR);
  618. }
  619.     /*
  620.      * Allocate space for the descriptors.
  621.      */
  622.     tftpdDescriptorPool = (TFTP_DESC *) KHEAP_ALLOC(sizeof (TFTP_DESC) * nEntries);
  623.     if (tftpdDescriptorPool == NULL)
  624. {
  625. msgQDelete (tftpdDescriptorQueue);
  626.         return (ERROR);
  627. }
  628.     while (nEntries--)
  629. {
  630. theAddress = &(tftpdDescriptorPool [nEntries]);
  631. msgQSend (tftpdDescriptorQueue, (char *) &theAddress,
  632.   sizeof (TFTP_DESC *), WAIT_FOREVER, MSG_PRI_NORMAL);
  633. }
  634.     return (OK);
  635.     }
  636. /******************************************************************************
  637. *
  638. * tftpdDescriptorQueueDelete - delete pool of available descriptors
  639. *
  640. * This routine deletes the memory and message queues allocated by
  641. * tftpdDescriptorQueueInit.
  642. *
  643. * RETURNS: OK, or ERROR if either memory could not be freed or if the
  644. * message queue could not be deleted.
  645. */
  646. LOCAL STATUS tftpdDescriptorQueueDelete
  647.     (
  648.     void
  649.     )
  650.     {
  651.     STATUS returnValue = OK;
  652.     if (msgQDelete (tftpdDescriptorQueue) == ERROR)
  653. {
  654. printErr ("%s:  could not delete message queuen", tftpdErrStr);
  655. returnValue = ERROR;
  656. }
  657.     /*
  658.      * free() is now void according to ANSI, so can't check the return value
  659.      */
  660.     KHEAP_FREE((char *)tftpdDescriptorPool);
  661.     return (returnValue);
  662.     }
  663. /******************************************************************************
  664. *
  665. * tftpdDescriptorCreate - build a tftp descriptor to use with tftpLib
  666. *
  667. * The routines in tftpLib, tftpPut() and tftpGet() in particular, expect to
  668. * be passed a pointer to a struct of type TFTP_DESC that contains the
  669. * information about the connection to the host.  This is a convenience
  670. * routine to allocate space for a TFTP_DESC struct, fill in the elements,
  671. * and return a pointer to it.
  672. *
  673. * This routine pends until a descriptor is available.
  674. *
  675. * RETURNS:
  676. * A pointer to a newly allocated TFTP_DESC struct, or NULL on failure.
  677. */
  678. LOCAL TFTP_DESC *tftpdDescriptorCreate
  679.     (
  680.     char *mode, /* mode  */
  681.     BOOL connected, /* state */
  682.     int sock, /* socket number */
  683.     u_short clientPort, /* client port number */
  684.     struct sockaddr_in *pClientAddr  /* client address */
  685.     )
  686.     {
  687.     TFTP_DESC *pTftpDesc; /* pointer to the struct to return */
  688.     char clientName [INET_ADDR_LEN];
  689.     if (msgQReceive (tftpdDescriptorQueue, (char *) &pTftpDesc,
  690.      sizeof (pTftpDesc), WAIT_FOREVER) == ERROR)
  691. {
  692. /*
  693.  * Couldn't get a descriptor from the queue, return an error
  694.  */
  695. return (NULL);
  696. }
  697.     /*
  698.      * Copy the arguments into the appropriate elements of the struct
  699.      */
  700.     strncpy (pTftpDesc->mode, mode, 31);
  701.     pTftpDesc->mode [31] = EOS;
  702.     pTftpDesc->connected = connected;
  703.     /*
  704.      * clientName and serverName are reversed, because the routines
  705.      * that use this descriptor are expecting to look at the universe
  706.      * from the client side.
  707.      */
  708.     inet_ntoa_b (pClientAddr->sin_addr, clientName);
  709.     strncpy (pTftpDesc->serverName, clientName, 128);
  710.     pTftpDesc->serverName [127] = EOS;
  711.     bcopy ((char *) pClientAddr, (char *) &pTftpDesc->serverAddr,
  712.    sizeof (struct sockaddr_in));
  713.     pTftpDesc->sock = sock;
  714.     pTftpDesc->serverPort = clientPort;
  715.     /*
  716.      * We've filled the struct, now return a pointer to it
  717.      */
  718.     return (pTftpDesc);
  719.     }
  720. /******************************************************************************
  721. *
  722. * tftpdDescriptorDelete - delete a reply descriptor
  723. *
  724. * This routine returns the space for a reply descriptor back to the
  725. * descriptor pool.
  726. *
  727. * RETURNS: OK or ERROR.
  728. */
  729. LOCAL STATUS tftpdDescriptorDelete
  730.     (
  731.     TFTP_DESC *descriptor
  732.     )
  733.     {
  734.     close (descriptor->sock);
  735.     return (msgQSend (tftpdDescriptorQueue, (char *) &descriptor,
  736.       sizeof (TFTP_DESC *), WAIT_FOREVER, MSG_PRI_NORMAL));
  737.     }
  738. /******************************************************************************
  739. *
  740. * tftpdDirectoryAdd - add a directory to the access list
  741. *
  742. * This routine adds the specified directory name to the access list 
  743. * for the TFTP server.
  744. *
  745. * RETURNS: N/A
  746. */
  747. STATUS tftpdDirectoryAdd
  748.     (
  749.     char *fileName /* name of directory to add to access list */
  750.     )
  751.     {
  752.     TFTPD_DIR *newNode;
  753.     /*
  754.      * Allocate memory for the node
  755.      */
  756.     newNode = (TFTPD_DIR *) KHEAP_ALLOC(sizeof (TFTPD_DIR));
  757.     if (newNode == NULL)
  758. {
  759. return (ERROR);
  760. }
  761.     /*
  762.      * Copy the filename into the node
  763.      */
  764.     strncpy (newNode->dirName, fileName, MAX_FILENAME_LENGTH);
  765.     newNode->dirName [MAX_FILENAME_LENGTH - 1] = EOS;
  766.     /*
  767.      * Add the node to the list
  768.      */
  769.     semTake (tftpdDirectorySem, WAIT_FOREVER);
  770.     lstAdd (&tftpdDirectoryList, (NODE *) newNode);
  771.     semGive (tftpdDirectorySem);
  772.     return (OK);
  773.     }
  774. /******************************************************************************
  775. *
  776. * tftpdDirectoryRemove - delete a directory from the access list
  777. *
  778. * This routine deletes the specified directory name from the access list 
  779. * for the TFTP server.
  780. *
  781. * RETURNS: N/A
  782. */
  783. STATUS tftpdDirectoryRemove
  784.     (
  785.     char *fileName /* name of directory to add to access list */
  786.     )
  787.     {
  788.     TFTPD_DIR *dirNode;
  789.     for (dirNode = (TFTPD_DIR *) lstFirst (&tftpdDirectoryList);
  790.  dirNode != NULL;
  791.  dirNode = (TFTPD_DIR *) lstNext ((NODE *) dirNode))
  792. {
  793. /*
  794.  * if the name of the file matches the name in the current
  795.  * element, delete the element
  796.  */
  797. if (strcmp (dirNode->dirName, fileName) == 0)
  798.     {
  799.     semTake (tftpdDirectorySem, WAIT_FOREVER);
  800.     lstDelete (&tftpdDirectoryList, (NODE *) dirNode);
  801.     semGive (tftpdDirectorySem);
  802.     /*
  803.      * Also need to free the memory
  804.      */
  805.     KHEAP_FREE((char *)dirNode);
  806.     return (OK);
  807.     }
  808. }
  809.     /*
  810.      * If we got to this point, then there was no match.  Return error.
  811.      */
  812.     return (ERROR);
  813.     }
  814. /******************************************************************************
  815. *
  816. * tftpdDirectoryValidate - confirm that file requested is in valid directory
  817. *
  818. * This routine checks that the file requested is in a directory that
  819. * matches an entry in the directory access list.  The validation
  820. * procedure is:
  821. *
  822. *     1.  If the requested file matches the directory exactly,
  823. *         deny access.  This prevents opening devices rather
  824. *    than files.
  825. *
  826. *     2.  If the directory and the first part of the file
  827. *         are equal, permission is granted.
  828. *
  829. *     Examples:
  830. *
  831. *  File Directory Result
  832. *  /mem /mem rejected by #1
  833. *  /mem/foo /mem granted
  834. *  /stuff/foo /mem rejected by #2
  835. *  (first four chars of file
  836. *  don't match "/mem")
  837. *
  838. * RETURNS: OK, or ERROR if access is not allowed.
  839. */
  840. LOCAL STATUS tftpdDirectoryValidate
  841.     (
  842.     char *fileName
  843.     )
  844.     {
  845.     DEV_HDR *deviceHdr;
  846.     char  fullPathName [MAX_FILENAME_LENGTH];
  847.     char  tmpString [MAX_FILENAME_LENGTH];
  848.     TFTPD_DIR *dirNode;
  849.     STATUS  returnValue = ERROR;
  850.     /*
  851.      * Use ioFullFileNameGet to get the complete name, including
  852.      * the device, of the requested file.
  853.      */
  854.     ioFullFileNameGet (fileName, &deviceHdr, fullPathName);
  855.     strcpy (tmpString, deviceHdr->name);
  856.     strcat (tmpString, fullPathName);
  857.     strcpy (fullPathName, tmpString);
  858.     /*
  859.      * If the access list is empty, there are no restrictions.  Return OK.
  860.      */
  861.     if (lstCount (&tftpdDirectoryList) == 0)
  862. return (OK);
  863.     semTake (tftpdDirectorySem, WAIT_FOREVER);
  864.     for (dirNode = (TFTPD_DIR *) lstFirst (&tftpdDirectoryList);
  865.  dirNode != NULL;
  866.  dirNode = (TFTPD_DIR *) lstNext ((NODE *) dirNode))
  867. {
  868. /*
  869.  * If the filename is exactly the same as the directory, break the loop
  870.  * and return an error (rejected by #1)
  871.  */
  872. if (strcmp (fullPathName, dirNode->dirName) == 0)
  873.     {
  874.     returnValue = ERROR;
  875.     break;
  876.     }
  877. /*
  878.  * If the first part of the filename is exactly equal
  879.  * to the directory name, return OK (#2).
  880.  */
  881. if (strncmp (dirNode->dirName, fullPathName,
  882.      strlen (dirNode->dirName)) == 0)
  883.     {
  884.     returnValue = OK;
  885.     break;
  886.     }
  887. }
  888.     semGive (tftpdDirectorySem);
  889.     if (returnValue == ERROR)
  890. errnoSet (EACCESS);
  891.     return (returnValue);
  892.     }
  893. /******************************************************************************
  894. *
  895. * tftpdErrorSend - send an error to a client
  896. *
  897. * Given a client connection and an error number, this routine builds an error
  898. * packet and sends it to the client.
  899. *
  900. * RETURNS:
  901. * OK, or ERROR if tftpSend() fails.  Note that no further action is required if
  902. * tftpSend() fails.
  903. */
  904. LOCAL STATUS tftpdErrorSend
  905.     (
  906.     TFTP_DESC *pReplyDesc, /* client to send to */
  907.     int errorNum /* error to send */
  908.     )
  909.     {
  910.     TFTP_MSG errMsg;
  911.     int errSize;
  912.     int repeatCount = tftpdErrorSendTries;
  913.     STATUS returnValue = OK;
  914.     errSize = tftpErrorCreate (&errMsg, errorNum);
  915.     /*
  916.      * Try to send the error message a few times.
  917.      */
  918.     while (repeatCount--)
  919. {
  920. returnValue = tftpSend (pReplyDesc, &errMsg, errSize,
  921. (TFTP_MSG *) 0, 0, 0, (int *) 0);
  922. /*
  923.  * If we didn't get an error, break out of the loop.  Otherwise,
  924.  * wait one second and retry
  925.  */
  926. if (returnValue != ERROR)
  927.     {
  928.     break;
  929.     }
  930. else
  931.     {
  932.     taskDelay (sysClkRateGet ());
  933.     }
  934. }
  935.     return (returnValue);
  936.     }
  937.     /* XXX
  938.      * everything below here doesn't go into final product
  939.      */
  940. char *dirs[] = { "/mem", "/tftpboot", "/folk/james/zap", "/xt" };
  941. void tftpTst (void)
  942.     {
  943.     tftpdTask (sizeof (dirs) / sizeof (char *), dirs, 3);
  944.     }