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