1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  */
27 
28 /* $Id: lpd-misc.c 155 2006-04-26 02:34:54Z ktou $ */
29 
30 #define	__EXTENSIONS__	/* for strtok_r() */
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <sys/types.h>
35 #include <fcntl.h>
36 #include <stdarg.h>
37 #include <string.h>
38 #include <signal.h>
39 #include <sys/socket.h>
40 #include <errno.h>
41 #include <wait.h>
42 #include <stropts.h>
43 #include <papi_impl.h>
44 
45 #include <config-site.h>
46 
47 char *
fdgets(char * buf,size_t len,int fd)48 fdgets(char *buf, size_t len, int fd)
49 {
50 	char	tmp;
51 	int	count = 0;
52 
53 	memset(buf, 0, len);
54 	while ((count < len) && (read(fd, &tmp, 1) > 0))
55 		if ((buf[count++] = tmp) == '\n') break;
56 
57 	if (count != 0)
58 		return (buf);
59 	return (NULL);
60 }
61 
62 char *
queue_name_from_uri(uri_t * uri)63 queue_name_from_uri(uri_t *uri)
64 {
65 	char *result = NULL;
66 
67 	if ((uri != NULL) && (uri->path != NULL)) {
68 		char *ptr = strrchr(uri->path, '/');
69 
70 		if (ptr == NULL)
71 			result = uri->path;
72 		else
73 			result = ++ptr;
74 	}
75 
76 	return (result);
77 }
78 
79 static int
recvfd(int sockfd)80 recvfd(int sockfd)
81 {
82 	int fd = -1;
83 #if defined(sun) && defined(unix) && defined(I_RECVFD)
84 	struct strrecvfd recv_fd;
85 
86 	memset(&recv_fd, 0, sizeof (recv_fd));
87 	if (ioctl(sockfd, I_RECVFD, &recv_fd) == 0)
88 		fd = recv_fd.fd;
89 #else
90 	struct iovec    iov[1];
91 	struct msghdr   msg;
92 
93 #ifdef CMSG_DATA
94 	struct cmsghdr cmp[1];
95 	char buf[24];	/* send/recv 2 byte protocol */
96 
97 	memset(buf, 0, sizeof (buf));
98 
99 	iov[0].iov_base = buf;
100 	iov[0].iov_len = sizeof (buf);
101 
102 	msg.msg_control = cmp;
103 	msg.msg_controllen = sizeof (struct cmsghdr) + sizeof (int);
104 #else
105 	iov[0].iov_base = NULL;
106 	iov[0].iov_len = 0;
107 	msg.msg_accrights = (caddr_t)&fd;
108 	msg.msg_accrights = sizeof (fd);
109 #endif
110 	msg.msg_iov = iov;
111 	msg.msg_iovlen = 1;
112 	msg.msg_name = NULL;
113 	msg.msg_namelen = 0;
114 
115 	if (recvmsg(sockfd, &msg, 0) < 0)
116 		fd = -1;
117 #ifdef CMSG_DATA
118 	else
119 		fd = * (int *)CMSG_DATA(cmp);
120 #endif
121 #endif
122 	return (fd);
123 }
124 
125 int
lpd_open(service_t * svc,char type,char ** args,int timeout)126 lpd_open(service_t *svc, char type, char **args, int timeout)
127 {
128 	int ac, rc = -1, fds[2];
129 	pid_t pid;
130 	char *av[64], *tmp, buf[BUFSIZ];
131 
132 	if ((svc == NULL) || (svc->uri == NULL))
133 		return (-1);
134 
135 #ifndef SUID_LPD_PORT
136 #define	SUID_LPD_PORT "/usr/lib/print/lpd-port"
137 #endif
138 
139 	av[0] = SUID_LPD_PORT;
140 	ac = 1;
141 
142 	/* server */
143 	av[ac++] = "-H";
144 	av[ac++] = svc->uri->host;
145 
146 	/* timeout */
147 	if (timeout > 0) {
148 		snprintf(buf, sizeof (buf), "%d", timeout);
149 		av[ac++] = "-t";
150 		av[ac++] = strdup(buf);
151 	}
152 
153 	/* operation */
154 	snprintf(buf, sizeof (buf), "-%c", type);
155 	av[ac++] = buf;
156 
157 	/* queue */
158 	if (svc->uri->path == NULL) {
159 		tmp = "";
160 	} else {
161 		if ((tmp = strrchr(svc->uri->path, '/')) == NULL)
162 			tmp = svc->uri->path;
163 		else
164 			tmp++;
165 	}
166 	av[ac++] = tmp;
167 
168 	/* args */
169 	if (args != NULL)
170 		while ((*args != NULL) && (ac < 62))
171 			av[ac++] = *args++;
172 
173 	av[ac++] = NULL;
174 
175 #if defined(sun) && defined(unix) && defined(I_RECVFD)
176 	pipe(fds);
177 #else
178 	socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
179 #endif
180 
181 	switch (pid = fork()) {
182 	case -1:	/* failed */
183 		break;
184 	case 0:	 /* child */
185 		dup2(fds[1], 1);
186 		execv(av[0], &av[0]);
187 		perror("exec");
188 		exit(1);
189 		break;
190 	default: {	/* parent */
191 		int err, status = 0;
192 
193 		while ((waitpid(pid, &status, 0) < 0) && (errno == EINTR))
194 			;
195 		errno = WEXITSTATUS(status);
196 
197 		if (errno == 0)
198 			rc = recvfd(fds[0]);
199 
200 		err = errno;
201 		close(fds[0]);
202 		close(fds[1]);
203 		errno = err;
204 		}
205 	}
206 
207 	return (rc);
208 }
209