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

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