home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume26 / port-lpr / part01 / vms-win-tcp.c < prev   
C/C++ Source or Header  |  1993-04-09  |  9KB  |  358 lines

  1. /*
  2.  * lpr interface for Wollengong's WIN/TCP for VAX/VMS
  3.  */
  4.  
  5. #include "common.h"
  6. #include "config.h"
  7. #include <stdio.h>
  8. #include <ctype.h>
  9. /*
  10.  * Our (old) version of WIN/TCP has definitions in its include files that
  11.  * conflict with the definitions in the VMS system library include files.
  12.  * So I have pulled out only those definitions I need for this module.
  13.  */
  14. /* #include "twg$tcp:[netdist.include.sys]types.h" */
  15. typedef unsigned short u_short;
  16. typedef unsigned long u_long;
  17. typedef char * caddr_t;
  18. /* #include "twg$tcp:[netdist.include.sys]stat.h" */
  19. #include "twg$tcp:[netdist.include]netdb.h"
  20. #include "twg$tcp:[netdist.include.sys]socket.h"
  21. /*
  22.  * WIN/TCP's errno.h puts errno in a different program segment than
  23.  * the one in sys$library.  The only define we use here is EACCES
  24.  * which is the same in both places.  If you are running an old
  25.  * version of VMS, you might have to change this a bit.
  26.  */
  27. /* #include "twg$tcp:[netdist.include]errno.h" */
  28. #include <errno.h>
  29. #include "twg$tcp:[netdist.include.netinet]in.h"
  30. #include <prvdef.h>
  31. #include <jpidef.h>
  32. #include <ssdef.h>
  33. #include <lnmdef.h>
  34.  
  35. struct item_list {
  36.     unsigned short buffer_length;
  37.     unsigned short item_code;
  38.     char *buffer_address;
  39.     char *length_address;
  40. };
  41.  
  42. struct descrip {
  43.     int length;
  44.     char *ptr;
  45. };
  46.  
  47. /*
  48.  * Translate a VAX/VMS logical name, given the name we want to translate
  49.  * and the table name we want to search with.
  50.  */
  51.  
  52. int
  53. translate_logical_name (table, name, buf, size)
  54. char *table; char *name; char *buf; int size;
  55. {
  56.     struct descrip table_d;
  57.     struct descrip name_d;
  58.     struct item_list item_list[2];
  59.     int foo;
  60.     int status;
  61.  
  62.     table_d.length = strlen (table);
  63.     table_d.ptr = table;
  64.     name_d.length = strlen (name);
  65.     name_d.ptr = name;
  66.     item_list[0].buffer_length = size - 1;
  67.     item_list[0].item_code = LNM$_STRING;
  68.     item_list[0].buffer_address = buf;
  69.     item_list[0].length_address = &foo;
  70.     item_list[1].buffer_length = 0;
  71.     item_list[1].item_code = 0;
  72.     item_list[1].buffer_address = 0;
  73.     item_list[1].length_address = 0;
  74.     status = SYS$TRNLNM (0, &table_d, &name_d, 0, item_list);
  75.     if ((status & 01) != 01)
  76.     lib$signal (status);
  77.     if (foo >= 0 && foo < size)
  78.     buf[foo] = '\0';
  79.     return ((status & 01) ? 0 : EOF);
  80. }
  81.  
  82. /*
  83.  * Determine the DECnet node name by translating the system logical name
  84.  * SYS$NODE.  We use this function rather than the getenv() function,
  85.  * just to make sure the user doesn't define his/her own SYS$NODE variable
  86.  * and pretend he/she is submitting the print job from somewhere else.
  87.  */
  88.  
  89. int
  90. get_decnet_node_name (buf, size)
  91. char *buf; int size;
  92. {
  93.     
  94.     if (!translate_logical_name ("LNM$SYSTEM_TABLE", "SYS$NODE", buf, size)) {
  95.     char *p;
  96.     while ((p = strrchr (buf, ':')))
  97.         *p = '\0';
  98.     return 0;
  99.     }
  100.     return EOF;
  101. }
  102.  
  103. #ifndef MAKE_EMAIL_ADDRESS
  104. #define MAKE_EMAIL_ADDRESS(buf,user,dom) sprintf (buf, "%s@%s", user, dom)
  105. #endif
  106.  
  107. struct hostent *
  108. gethostbynameoraddr (hostname)
  109. char *hostname;
  110. {
  111.     if (isdigit (*hostname)) {
  112.     static struct hostent x;
  113.     static char *alias_list[1];
  114.     static unsigned long *addr_list[2];
  115.     static unsigned long ip_address;
  116.  
  117.     ip_address = inet_addr (hostname);
  118.  
  119.     addr_list[0] = &ip_address;
  120.     addr_list[1] = NULL;
  121.     alias_list[0] = NULL;
  122.  
  123.     x.h_name = hostname;
  124.     x.h_aliases = alias_list;
  125.     x.h_addrtype = AF_INET;
  126.     x.h_length = sizeof (unsigned long);
  127.     x.h_addr_list = (char **) addr_list;
  128.     return &x;
  129.     }
  130.     return gethostbyname (hostname);
  131. }
  132.  
  133.  
  134. void sysdep()
  135. {
  136.     struct passwd *pwd;
  137.     char *p;
  138.     struct hostent *hp;
  139.     char *getenv ();
  140.     char nodename[100];
  141.  
  142.     get_decnet_node_name (nodename, sizeof(nodename));
  143.     gethostname (hostname, sizeof hostname);
  144.  
  145.     /* get user name (will be in ALL CAPS - yikes!) */
  146.     cuserid (username);
  147.  
  148.     hp = gethostbyname (hostname);
  149.     MAKE_EMAIL_ADDRESS(email_address, username, hp ? hp->h_name : hostname);
  150.  
  151.     /* lower case host name and user name */
  152.     for (p = hostname; *p; ++p)
  153.     if (isupper (*p))
  154.         *p = tolower (*p);
  155.  
  156.     for (p = username; *p; ++p)
  157.     if (isupper (*p))
  158.         *p = tolower (*p);
  159. }
  160.  
  161.  
  162. /*
  163.  * Allocate a socket and bind it to a local privileged port
  164.  * We have to be running set-uid to root to do this.
  165.  */
  166.  
  167. int
  168. get_priv_tcp_socket ()
  169. {
  170.     int fd;
  171.     int port;
  172.     struct sockaddr_in s;
  173.  
  174.     if ((fd = socket (AF_INET, SOCK_STREAM, 0)) == EOF) {
  175.     perror ("socket");
  176.     return EOF;
  177.     }
  178.     for (port = IPPORT_RESERVED-1; port > IPPORT_RESERVED / 2; port--) {
  179.     extern int errno;
  180.     s.sin_family = AF_INET;
  181.     s.sin_addr.s_addr = INADDR_ANY;
  182.     s.sin_port = htons (port);
  183.     if (bind (fd, (struct sockaddr *) &s, sizeof (s)) == 0)
  184.         return fd;
  185.     if (errno == EACCES) {
  186.         fprintf (stderr, "lpr warning: bind: cannot bind to privileged port\n");
  187.         return fd;
  188.     }
  189.     }
  190.     close (fd);
  191.     return EOF;
  192. }
  193.  
  194. /*
  195.  * Open a TCP connection to an lpd-server.
  196.  * This requires that this program be run set-uid to root in order to be able
  197.  * to bind a socket to a privileged port.
  198.  */
  199.  
  200. int
  201. open_lpd (server)
  202. char *server;
  203. {
  204.     int fd;
  205.     int i;
  206.     int last_connect_failed;
  207.     struct hostent *hp;
  208.     struct servent *sp;
  209.     struct sockaddr_in s;
  210.     void bcopy ();
  211.  
  212.     if (server == NULL || *server == '\0') {
  213.     fprintf (stderr, "lpr: no server host was specified.\n");
  214.     fprintf (stderr, "     Supply one with the -S option, or\n");
  215.     fprintf (stderr, "     by defining the LPD_SERVER logical name\n");
  216.     return EOF;
  217.     }
  218.     if ((hp = gethostbynameoraddr (server)) == NULL) {
  219.     fprintf (stderr, "lpr: can't find network address for %s\n",
  220.          server);
  221.     fflush (stderr);
  222.     return EOF;
  223.     }
  224.  
  225.     s.sin_family = AF_INET;
  226. #if 1
  227.     /* some bug in the VMS C optimizer seems to require this */
  228.     s.sin_port = htons (515);
  229. #else
  230.     if ((sp = getservbyname ("printer", "tcp")) == NULL)
  231.     s.sin_port = htons (515);
  232.     else
  233.     s.sin_port = sp->s_port;
  234. #endif
  235.  
  236.     /*
  237.      * On some systems h_addr is a macro that is defined to be h_addr_list[0]
  238.      * On other (ancient) systems, h_addr is a member of the hostent structure.
  239.      * So if h_addr is defined as a macro, then we must have the list...
  240.      */
  241.  
  242. #ifdef h_addr
  243.     for (i = 0; hp->h_addr_list[i] ; ++i) {
  244.     fd = get_priv_tcp_socket ();
  245.     disable_special_privileges ();
  246.     if (fd < 0)
  247.         return EOF;
  248.     bcopy ((char *) hp->h_addr_list[i], (char *) &s.sin_addr,
  249.            sizeof (s.sin_addr));
  250.     if (debug)
  251.         fprintf (stderr, "Trying %s...", inet_ntoa (s.sin_addr));
  252.     last_connect_failed = 0; /* "I'm ashamed of this." - SMK */
  253.     if (connect (fd, &s, sizeof s) == 0) {
  254.         if (debug)
  255.         fprintf (stderr, "open\n");
  256.         break;
  257.     }
  258.     else {
  259.         close (fd);        /* reuse fd */
  260.         if (debug)
  261.         perror ("");
  262.         last_connect_failed = 1;
  263.     }
  264.     }
  265.     if (last_connect_failed) {
  266.     perror ("connect");
  267.     return EOF;
  268.     }
  269. #else
  270.     fd = get_priv_tcp_socket ();
  271.     disable_special_privileges ();
  272.     if (fd < 0)
  273.     return EOF;
  274.     bcopy ((char *) hp->h_addr, (char *) &s.sin_addr, sizeof(s.sin_addr));
  275.     if (connect (fd, &s, sizeof s) < 0) {
  276.     perror ("connect");
  277.     close (fd);
  278.     return EOF;
  279.     }
  280. #endif
  281.  
  282.     max_net_read = max_net_write = 32767;
  283.     return fd;
  284. }
  285.  
  286. /*
  287.  * initialized data structures for disable_special_privileges (), below
  288.  */
  289.  
  290. int curr_proc_privs[2] = { 0, 0 }; /* current (image+perm) proc privs */
  291. int perm_proc_privs[2] = { 0, 0 }; /* permanent process privileges */
  292. int privs_length = 2;
  293.  
  294. struct item_list jpi_item_list[] = {
  295.     { sizeof curr_proc_privs, JPI$_CURPRIV,  curr_proc_privs, &privs_length },
  296.     { sizeof perm_proc_privs, JPI$_PROCPRIV, perm_proc_privs, &privs_length },
  297.     { 0 },
  298. };
  299.  
  300. /*
  301.  * Turn off set-uid privileges.
  302.  * We have to have either SYSPRV or BYPASS privilege to bind to a privileged
  303.  * port.  In order to minimize the security risk, we want to turn off these
  304.  * privileges as soon as we acquire the binding.  This function turns off
  305.  * all privileges that are specific to this image.
  306.  */
  307.  
  308. int
  309. disable_special_privileges ()
  310. {
  311.     int status;
  312.     int privs_to_disable[2];
  313.  
  314.     /* get current privileges */
  315.     if ((status = sys$getjpiw (0, 0, 0, jpi_item_list, 0, 0, 0)) != SS$_NORMAL)
  316.     exit (status);
  317.     /*
  318.      * Turn off any privileges that aren't in the permanent process priv mask.
  319.      */
  320.     privs_to_disable[0] = curr_proc_privs[0] & ~perm_proc_privs[0];
  321.     privs_to_disable[1] = curr_proc_privs[1] & ~perm_proc_privs[1];
  322.  
  323.     if ((status = sys$setprv (0, privs_to_disable, 0, 0)) != SS$_NORMAL)
  324.     exit (status);
  325. }
  326.  
  327. /*
  328.  * bcopy() is not provided by the VMS C library
  329.  * This version is not particularly efficient, but we don't use it enough
  330.  * here to write a better version.
  331.  */
  332.  
  333. void
  334. bcopy (src, dest, length)
  335. register char *src, *dest;
  336. unsigned int length;
  337. {
  338.     if (length == 0)
  339.     return;
  340.     do {
  341.     *dest++ = *src++;
  342.     } while (--length);
  343. }
  344.  
  345. /*
  346.  * unlink() is not provided by the VMS C library (for reasons which have
  347.  * always eluded me).  delete() does essentially the same thing, but
  348.  * doesn't return the same error codes as unlink.  It is, however, sufficient 
  349.  * for our purposes.
  350.  */
  351.  
  352. int
  353. unlink (filename)
  354. char *filename;
  355. {
  356.     return delete (filename);
  357. }
  358.