home *** CD-ROM | disk | FTP | other *** search
- /*
- * lpr interface for VAX/VMS UCX TCP
- */
-
- #include "common.h"
- #include "config.h"
- #include <stdio.h>
- #include <ctype.h>
- #include <types.h>
- #include <stat.h>
- #include <netdb.h>
- #include <socket.h>
- #include <errno.h>
- #include <in.h>
- #include <prvdef.h>
- #include <jpidef.h>
- #include <ssdef.h>
- #include <lnmdef.h>
-
- struct item_list {
- unsigned short buffer_length;
- unsigned short item_code;
- char *buffer_address;
- char *length_address;
- };
-
- struct descrip {
- int length;
- char *ptr;
- };
-
- /*
- * Translate a VAX/VMS logical name, given the name we want to translate
- * and the table name we want to search with.
- */
-
- int
- translate_logical_name (table, name, buf, size)
- char *table; char *name; char *buf; int size;
- {
- struct descrip table_d;
- struct descrip name_d;
- struct item_list item_list[2];
- int foo;
- int status;
-
- table_d.length = strlen (table);
- table_d.ptr = table;
- name_d.length = strlen (name);
- name_d.ptr = name;
- item_list[0].buffer_length = size - 1;
- item_list[0].item_code = LNM$_STRING;
- item_list[0].buffer_address = buf;
- item_list[0].length_address = &foo;
- item_list[1].buffer_length = 0;
- item_list[1].item_code = 0;
- item_list[1].buffer_address = 0;
- item_list[1].length_address = 0;
- status = SYS$TRNLNM (0, &table_d, &name_d, 0, item_list);
- if ((status & 01) != 01)
- lib$signal (status);
- if (foo >= 0 && foo < size)
- buf[foo] = '\0';
- return ((status & 01) ? 0 : EOF);
- }
-
- /*
- * Determine the DECnet node name by translating the system logical name
- * SYS$NODE. We use this function rather than the getenv() function,
- * just to make sure the user doesn't define his/her own SYS$NODE variable
- * and pretend he/she is submitting the print job from somewhere else.
- */
-
- int
- get_decnet_node_name (buf, size)
- char *buf; int size;
- {
-
- if (!translate_logical_name ("LNM$SYSTEM_TABLE", "SYS$NODE", buf, size)) {
- char *p;
- while ((p = strrchr (buf, ':')))
- *p = '\0';
- return 0;
- }
- return EOF;
- }
-
- #ifndef MAKE_EMAIL_ADDRESS
- #define MAKE_EMAIL_ADDRESS(buf,user,dom) sprintf (buf, "%s@%s", user, dom)
- #endif
-
- struct hostent *
- gethostbynameoraddr (hostname)
- char *hostname;
- {
- if (isdigit (*hostname)) {
- static struct hostent x;
- static char *alias_list[1];
- static unsigned long *addr_list[2];
- static unsigned long ip_address;
-
- ip_address = inet_addr (hostname);
-
- addr_list[0] = &ip_address;
- addr_list[1] = NULL;
- alias_list[0] = NULL;
-
- x.h_name = hostname;
- x.h_aliases = alias_list;
- x.h_addrtype = AF_INET;
- x.h_length = sizeof (unsigned long);
- x.h_addr_list = (char **) addr_list;
- return &x;
- }
- return gethostbyname (hostname);
- }
-
- void
- sysdep()
- {
- struct passwd *pwd;
- char *p;
- struct hostent *hp;
- char *getenv ();
- char nodename[100];
-
- get_decnet_node_name (nodename, sizeof(nodename));
- gethostname (hostname, sizeof hostname);
-
- /* get user name (will be in ALL CAPS - yikes!) */
- cuserid (username);
-
- hp = gethostbyname (hostname);
- MAKE_EMAIL_ADDRESS(email_address, username, hp ? hp->h_name : hostname);
-
- /* lower case host name and user name */
- for (p = hostname; *p; ++p)
- if (isupper (*p))
- *p = tolower (*p);
-
- for (p = username; *p; ++p)
- if (isupper (*p))
- *p = tolower (*p);
- }
-
-
- /*
- * Allocate a socket and bind it to a local privileged port
- * We have to be running set-uid to root to do this.
- */
-
- int
- get_priv_tcp_socket ()
- {
- int fd;
- int port;
- struct sockaddr_in s;
-
- if ((fd = socket (AF_INET, SOCK_STREAM, 0)) == EOF) {
- perror ("socket");
- return EOF;
- }
- for (port = IPPORT_RESERVED-1; port > IPPORT_RESERVED / 2; port--) {
- extern int errno;
- s.sin_family = AF_INET;
- s.sin_addr.s_addr = INADDR_ANY;
- s.sin_port = htons (port);
- if (bind (fd, (struct sockaddr *) &s, sizeof (s)) == 0)
- return fd;
- if (errno == EACCES) {
- fprintf (stderr, "lpr warning: bind: cannot bind to privileged port\n");
- return fd;
- }
- }
- close (fd);
- return EOF;
- }
-
- /*
- * Open a TCP connection to an lpd-server.
- * This requires that this program be run set-uid to root in order to be able
- * to bind a socket to a privileged port.
- */
-
- int
- open_lpd (server)
- char *server;
- {
- int fd;
- int i;
- int last_connect_failed;
- struct hostent *hp;
- struct servent *sp;
- struct sockaddr_in s;
- void bcopy ();
-
- if (server == NULL || *server == '\0') {
- fprintf (stderr, "lpr: no server host was specified.\n");
- fprintf (stderr, " Supply one with the -S option, or\n");
- fprintf (stderr, " by defining the LPD_SERVER logical name\n");
- return EOF;
- }
- if ((hp = gethostbynameoraddr (server)) == NULL) {
- fprintf (stderr, "lpr: can't find network address for %s\n",
- server);
- fflush (stderr);
- return EOF;
- }
-
- s.sin_family = AF_INET;
- #if 1
- /* some bug in the VMS C optimizer seems to require this */
- s.sin_port = htons (515);
- #else
- if ((sp = getservbyname ("printer", "tcp")) == NULL)
- s.sin_port = htons (515);
- else
- s.sin_port = sp->s_port;
- #endif
-
- /*
- * On some systems h_addr is a macro that is defined to be h_addr_list[0]
- * On other (ancient) systems, h_addr is a member of the hostent structure.
- * So if h_addr is defined as a macro, then we must have the list...
- */
-
- #ifdef h_addr
- for (i = 0; hp->h_addr_list[i] ; ++i) {
- fd = get_priv_tcp_socket ();
- disable_special_privileges ();
- if (fd < 0)
- return EOF;
- bcopy ((char *) hp->h_addr_list[i], (char *) &s.sin_addr,
- sizeof (s.sin_addr));
- if (debug)
- fprintf (stderr, "Trying %s...", inet_ntoa (s.sin_addr));
- last_connect_failed = 0; /* "I'm ashamed of this." - SMK */
- if (connect (fd, &s, sizeof s) == 0) {
- if (debug)
- fprintf (stderr, "open\n");
- break;
- }
- else {
- close (fd); /* reuse fd */
- if (debug)
- perror ("");
- last_connect_failed = 1;
- }
- }
- if (last_connect_failed) {
- perror ("connect");
- return EOF;
- }
- #else
- fd = get_priv_tcp_socket ();
- disable_special_privileges ();
- if (fd < 0)
- return EOF;
- bcopy ((char *) hp->h_addr, (char *) &s.sin_addr, sizeof(s.sin_addr));
- if (connect (fd, &s, sizeof s) < 0) {
- perror ("connect");
- close (fd);
- return EOF;
- }
- #endif
-
- max_net_read = max_net_write = 32767;
- return fd;
- }
-
- /*
- * initialized data structures for disable_special_privileges (), below
- */
-
- int curr_proc_privs[2] = { 0, 0 }; /* current (image+perm) proc privs */
- int perm_proc_privs[2] = { 0, 0 }; /* permanent process privileges */
- int privs_length = 2;
-
- struct item_list jpi_item_list[] = {
- { sizeof curr_proc_privs, JPI$_CURPRIV, curr_proc_privs, &privs_length },
- { sizeof perm_proc_privs, JPI$_PROCPRIV, perm_proc_privs, &privs_length },
- { 0 },
- };
-
- /*
- * Turn off set-uid privileges.
- * We have to have either SYSPRV or BYPASS privilege to bind to a privileged
- * port. In order to minimize the security risk, we want to turn off these
- * privileges as soon as we acquire the binding. This function turns off
- * all privileges that are specific to this image.
- */
-
- static int
- disable_special_privileges ()
- {
- int status;
- int privs_to_disable[2];
-
- /* get current privileges */
- if ((status = sys$getjpiw (0, 0, 0, jpi_item_list, 0, 0, 0)) != SS$_NORMAL)
- exit (status);
- /*
- * Turn off any privileges that aren't in the permanent process priv mask.
- */
- privs_to_disable[0] = curr_proc_privs[0] & ~perm_proc_privs[0];
- privs_to_disable[1] = curr_proc_privs[1] & ~perm_proc_privs[1];
-
- if ((status = sys$setprv (0, privs_to_disable, 0, 0)) != SS$_NORMAL)
- exit (status);
- }
-
- /*
- * bcopy() is not provided by the VMS C library
- * This version is not particularly efficient, but we don't use it enough
- * here to write a better version.
- */
-
- void
- bcopy (src, dest, length)
- register char *src, *dest;
- unsigned int length;
- {
- if (length == 0)
- return;
- do {
- *dest++ = *src++;
- } while (--length);
- }
-
- /*
- * unlink() is not provided by the VMS C library (for reasons which have
- * always eluded me). delete() does essentially the same thing, but
- * doesn't return the same error codes as unlink. It is, however, sufficient
- * for our purposes.
- */
-
- int
- unlink (filename)
- char *filename;
- {
- return delete (filename);
- }
-