/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
*/
/* $Id: lpd-port.c 155 2006-04-26 02:34:54Z ktou $ */
#include <config-site.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdarg.h>
#include <string.h>
#include <signal.h>
#include <netdb.h>
#include <errno.h>
#include <syslog.h>
#include <values.h>
#include <stropts.h> /* for sendfd */
#include <pwd.h>
#include <sys/sendfile.h>
#include <ctype.h>
#ifdef HAVE_PRIV_H
#include <priv.h>
#endif
#ifndef JOB_ID_FILE
#endif /* JOB_ID_FILE */
static int
{
#else
#ifdef CMSG_DATA
buf[1] = 0;
buf[0] = 0;
#else
#endif
msg.msg_namelen = 0;
#endif
}
static void
null(int i)
{
}
static int
{
#if defined(HAVE_GETIPNODEBYNAME) && defined(HAVE_RRESVPORT_AF)
#else
#endif
static void (*old_handler)();
/*
* Get the host address and port number to connect to.
*/
return (-1);
}
/* linux style NULL usage */
#if defined(HAVE_GETIPNODEBYNAME) && defined(HAVE_RRESVPORT_AF)
return (-1);
}
#else
return (-1);
}
#endif
return (-1);
}
#if defined(HAVE_GETIPNODEBYNAME) && defined(HAVE_RRESVPORT_AF)
#else
#endif
(void) alarm(0);
timo *= 2;
goto retry;
}
return (-1);
}
(void) alarm(0);
return (sock);
}
static int
{
/* gain back enough privilege to open the id file */
#ifdef PRIV_ALLSETS
return (-1);
}
#else
seteuid(0);
#endif
/* open the sequence file */
/* drop our privilege again */
#ifdef PRIV_ALLSETS
/* drop file access privilege */
#else
#endif
if (fd >= 0) {
/* wait for a lock on the file */
int next;
/* get the current id */
/* store the next id in the file */
}
}
return (result);
}
static int
{
int port;
/* gain back enough privilege to open a reserved port */
#ifdef PRIV_ALLSETS
if ((priv_set(
return (-1);
}
#else
seteuid(0);
#endif
#if defined(HAVE_GETIPNODEBYNAME) && defined(HAVE_RRESVPORT_AF)
port = 0; /* set to 0, rresvport_af() will find us one. */
#else
port--;
#endif
/* drop our privilege again */
#ifdef PRIV_ALLSETS
#else
#endif
return (result);
}
static char *
{
return (p->pw_name);
else
return ("unknown");
}
static void
{
while (ac--) {
}
}
static int
{
int host_present = 0;
return (-1);
return (-1);
}
if (ptr[0] == 'H') {
return (-1);
}
host_present = 1;
/* check the user name */
int len;
if (uid == 0) { /* let root do what they want */
continue;
}
return (-1); /* failed */
}
return (-1); /* failed */
}
ptr++;
return (-1);
}
/*
* As ptr is a copy of the string (df?XXX...) the code
* needs to work on the original, hence the need for
* mod_ptr. No need to check for a NULL mod_ptr
* because the required string must already exist as
* ptr is a copy of the original data.
*/
!= 0) {
return (-1);
}
} else {
return (-1);
}
}
}
if (!host_present) {
return (-1);
}
return (1);
}
static int
{
if (size == 0)
size = 1;
return (-1);
}
return (-1);
return (0);
}
static int
{
return (-1);
return (-1);
} else
return (-1);
if (fd != -1) {
/* write the data */
return (-1);
return (-1);
}
return (0);
}
static int
{
int len;
return (-1);
if (ptr[0] != 'H')
continue;
ptr++;
}
return (-1);
/* write the data */
return (-1);
return (-1);
return (0);
}
static int
{
int current = 0;
int sent_files = 0;
/* open the control file */
return (-1);
}
/* get the size of the control file */
return (-1);
}
/* allocate memory for the control file */
return (-1);
}
/* read in the control file */
return (-1);
}
/* massage the control file */
/* bad control data, dump the job */
"bad control file, possible subversion attempt");
return (-1);
}
/* request to transfer the job */
/* no such (or disabled) queue, got to love rfc-1179 */
return (-1);
}
/* send the control data */
return (-1);
}
/* walk the control file sending the data files */
if (ptr[0] != 'U')
continue;
if (name[0] != 'N')
continue;
ptr++;
name++;
return (-1);
}
sent_files++;
}
/* write back the job-id */
}
if (sent_files != 0) {
}
return (0);
}
static int
{
/* build the request */
rc = -1;
} else
rc = 0;
return (rc);
}
static int
{
/* build the request */
rc = -1;
} else
rc = 0;
return (rc);
}
static void
{
char *name;
else
name++;
name);
name);
name);
}
/*
* The main program temporarily loses privilege while searching the command
* line arguments. It then allocates any resources it need privilege for
* job-id, reserved port. Once it has the resources it needs, it perminently
* drops all elevated privilege. It ghen connects to the remote print service
* based on destination hostname. Doing it this way reduces the potenential
* opportunity for a breakout with elevated privilege, breakout with an
* unconnected reserved port, and exploitation of the remote print service
* by a calling program.
*/
int
{
#ifdef PRIV_ALLSETS
#endif
#ifdef PRIV_ALLSETS
/* lose as much as we can perminently and temporarily drop the rest. */
return (-1);
}
return (-1);
}
/*
* These privileges permanently dropped in next_job_id() and
* reserved_port()
*/
return (-1);
}
#else
#endif
switch (c) {
case 'H':
break;
case 't':
break;
case 'c':
break;
case 'q':
break;
case 's':
break;
default:
/* does not return */
}
}
if ((c = next_job_id()) < 0) {
return (-1);
}
if ((fd = reserved_port()) < 0) {
return (errno);
}
/*
* we no longer want or need any elevated privilege, lose it all
* permanently.
*/
/* connect to the print service */
return (errno);
/* perform the requested operation */
switch (operation) {
case OP_SUBMIT: /* transfer the job, close the fd */
break;
case OP_QUERY: /* send the query string, return the fd */
break;
case OP_CANCEL: /* send the cancel string, return the fd */
break;
default: /* This should never happen */
}
/* if the operation succeeded, send the fd to our parent */
/* sendfd() failed, dump the socket data for the heck of it */
}
return (exit_code);
}