1 /***************************************************************************
2 * LPRng - An Extended Print Spooler System
3 *
4 * Copyright 1988-2003, Patrick Powell, San Diego, CA
5 * papowell@lprng.com
6 * See LICENSE for conditions of use.
7 *
8 ***************************************************************************/
9
10 #include "lp.h"
11 #include "user_auth.h"
12 #include "sendjob.h"
13 #include "permission.h"
14 #include "getqueue.h"
15 #include "errorcodes.h"
16 #include "linksupport.h"
17 #include "krb5_auth.h"
18 #include "fileopen.h"
19 #include "child.h"
20 #include "gethostinfo.h"
21 #include "sendauth.h"
22 /**** ENDINCLUDE ****/
23
24 /***************************************************************************
25 * Commentary:
26 * Patrick Powell Mon Apr 17 05:43:48 PDT 1995
27 *
28 * The protocol used to send a secure job consists of the following
29 * following:
30 *
31 * Client Server
32 * \REQ_SECUREprintername C/F user\n - receive a command
33 * 0 1 2
34 * \REQ_SECUREprintername C/F user controlfile\n - receive a job
35 * 0 1 2
36 *
37 * 1. Get a temporary file
38 * 2. Generate the compressed data files - this has the format
39 * Authentication
40 * \n
41 * \3count cfname\n
42 * [count control file bytes]
43 * \4count dfname\n
44 * [count data file bytes]
45 *
46 * 3. send the \REQ_SECRemotePrinter_DYN user@RemoteHost_DYN file size\n
47 * string to the remote RemoteHost_DYN, wait for an ACK
48 *
49 * 4. send the compressed data files - this has the format
50 * wait for an ACK
51 ***************************************************************************/
52
53 static void Put_in_auth( int tempfd, const char *key, char *value );
54
55 /*
56 * Send_auth_transfer
57 * 1. we send the command line and wait for ACK of 0
58 * \REQ_SEQUREprinter C/F sender_id authtype [jobsize]
59 * 2. if authtype == kerberos we do kerberos
60 * - send a file to the remote end
61 * - get back a file
62 * 3. if authtype == pgp we do pgp
63 * - same as kerberos
64 * 3. if otherwise, we start a process with command line options
65 * fd 0 - sock
66 * fd 1 - for reports
67 * fd 2 - for errors
68 * /filter -C -P printer -n sender_id -A authtype -R remote_id -Ttempfile
69 * The tempfile will be sent to the remote end and status
70 * written back on fd 2
71 * - we save this information
72 * - reopen the file and put error messages in it.
73 * RETURN:
74 * 0 - no error
75 * !=0 - error
76 */
77
Send_auth_transfer(int * sock,int transfer_timeout,struct job * job,struct job * logjob,char * error,int errlen,char * cmd,const struct security * security,struct line_list * info)78 int Send_auth_transfer( int *sock, int transfer_timeout,
79 struct job *job, struct job *logjob, char *error, int errlen, char *cmd,
80 const struct security *security, struct line_list *info )
81 {
82 struct stat statb;
83 int ack, len, n, fd; /* ACME! The best... */
84 int status = JFAIL; /* job status */
85 char *secure, *destination, *from, *client, *s;
86 char *tempfile;
87 char buffer[SMALLBUFFER];
88 errno = 0;
89
90 secure = 0;
91 fd = Make_temp_fd(&tempfile);
92
93 if( cmd && (s = safestrrchr(cmd,'\n')) ) *s = 0;
94 DEBUG1("Send_auth_transfer: cmd '%s'", cmd );
95
96 if(DEBUGL1)Dump_line_list("Send_auth_transfer: info ", info );
97
98 destination = Find_str_value(info, DESTINATION );
99 from = Find_str_value(info, FROM );
100 client = Find_str_value(info, CLIENT );
101
102 if( safestrcmp(security->config_tag, "kerberos") ){
103 Put_in_auth(fd,DESTINATION,destination);
104 if( Is_server ) Put_in_auth(fd,SERVER,from);
105 Put_in_auth(fd,CLIENT,client);
106 if( cmd ){
107 Put_in_auth(fd,INPUT,cmd);
108 }
109 } else {
110 if( cmd && (Write_fd_str(fd,cmd) < 0 || Write_fd_str(fd,"\n") < 0) ){
111 plp_snprintf(error, errlen, "Send_auth_transfer: '%s' write failed - %s",
112 tempfile, Errormsg(errno) );
113 goto error;
114 }
115 if( Is_server && (Write_fd_str(fd,client) < 0 || Write_fd_str(fd,"\n") < 0) ){
116 plp_snprintf(error, errlen, "Send_auth_transfer: '%s' write failed - %s",
117 tempfile, Errormsg(errno) );
118 goto error;
119 }
120 }
121
122 if( Write_fd_str(fd,"\n") < 0 ){
123 plp_snprintf(error, errlen, "Send_auth_transfer: '%s' write failed - %s",
124 tempfile, Errormsg(errno) );
125 goto error;
126 }
127
128 s = Find_str_value(info, CMD );
129 if( job ){
130 status = Send_normal( &fd, job, logjob, transfer_timeout, fd, 0);
131 if( status ) return( status );
132 errno = 0;
133 if( stat(tempfile,&statb) ){
134 Errorcode = JABORT;
135 logerr_die(LOG_INFO, "Send_auth_transfer: stat '%s' failed",
136 tempfile);
137 }
138 plp_snprintf( buffer,sizeof(buffer), " %0.0f",(double)(statb.st_size) );
139 secure = safestrdup3(s,buffer,"\n",__FILE__,__LINE__);
140 } else {
141 secure = safestrdup2(s,"\n",__FILE__,__LINE__);
142 }
143 close( fd ); fd = -1;
144
145 /* send the message */
146 DEBUG3("Send_auth_transfer: sending '%s'", secure );
147 status = Link_send( RemoteHost_DYN, sock, transfer_timeout,
148 secure, safestrlen(secure), &ack );
149 DEBUG3("Send_auth_transfer: status '%s'", Link_err_str(status) );
150 if( status ){
151 /* open output file */
152 if( (fd = Checkwrite(tempfile,&statb,O_WRONLY|O_TRUNC,1,0)) < 0){
153 Errorcode = JABORT;
154 logerr_die(LOG_INFO, "Send_auth_transfer: open '%s' for write failed",
155 tempfile);
156 }
157 /* we turn off IO from the socket */
158 shutdown(*sock,1);
159 if( (s = safestrchr(secure,'\n')) ) *s = 0;
160 plp_snprintf( error, errlen,
161 "error '%s' sending '%s' to %s@%s\n",
162 Link_err_str(status), secure, RemotePrinter_DYN, RemoteHost_DYN );
163 Write_fd_str( fd, error );
164 error[0] = 0;
165 DEBUG2("Send_auth_transfer: starting read");
166 len = 0;
167 while( (n = Read_fd_len_timeout(Send_query_rw_timeout_DYN, *sock,buffer+len,sizeof(buffer)-1-len)) > 0 ){
168 buffer[n+len] = 0;
169 DEBUG4("Send_auth_transfer: read '%s'", buffer);
170 while( (s = strchr(buffer,'\n')) ){
171 *s++ = 0;
172 DEBUG2("Send_auth_transfer: doing '%s'", buffer);
173 plp_snprintf(error,errlen, "%s\n", buffer );
174 if( Write_fd_str(fd,error) < 0 ){
175 Errorcode = JABORT;
176 logerr(LOG_INFO, "Send_auth_transfer: write '%s' failed",
177 tempfile );
178 goto error;
179 }
180 memmove(buffer,s,safestrlen(s)+1);
181 }
182 len = safestrlen(buffer);
183 }
184 if( buffer[0] ){
185 DEBUG2("Send_auth_transfer: doing '%s'", buffer);
186 plp_snprintf(error,errlen, "%s\n", buffer );
187 if( Write_fd_str(fd,error) < 0 ){
188 Errorcode = JABORT;
189 logerr(LOG_INFO, "Send_auth_transfer: write '%s' failed",
190 tempfile );
191 goto error;
192 }
193 }
194
195 close( fd ); fd = -1;
196 error[0] = 0;
197 goto error;
198 }
199
200 /*
201 * now we do the protocol dependent exchange
202 */
203
204 status = security->client_send( sock, transfer_timeout, tempfile,
205 error, errlen, security, info );
206
207 error:
208
209 DEBUG3("Send_auth_transfer: sock %d, exit status %d, error '%s'",
210 *sock, status, error );
211 /* we are going to put the returned error status in the temp file
212 * as the device to read from
213 */
214 if( secure ) free(secure); secure = 0;
215 if( error[0] ){
216 if( job ){
217 setstatus(logjob, "Send_auth_transfer: %s", error );
218 Set_str_value(&job->info,ERROR,error);
219 Set_nz_flag_value(&job->info,ERROR_TIME,time(0));
220 }
221 if( (fd = Checkwrite(tempfile,&statb,O_WRONLY|O_TRUNC,1,0)) < 0){
222 Errorcode = JFAIL;
223 logerr_die(LOG_INFO, "Send_auth_transfer: cannot open '%s'", tempfile );
224 }
225 Write_fd_str(fd,error);
226 close( fd ); fd = -1;
227 error[0] = 0;
228 }
229 if( *sock >= 0 ){
230 if( (fd = Checkread(tempfile,&statb)) < 0 ){
231 Errorcode = JFAIL;
232 logerr_die(LOG_INFO, "Send_auth_transfer: cannot open '%s'", tempfile );
233 }
234 if( dup2( fd, *sock ) == -1 ){
235 Errorcode = JFAIL;
236 logerr_die(LOG_INFO, "Send_auth_transfer: dup2(%d,%d)", fd, *sock );
237 }
238 if( fd != *sock ) close(fd); fd = -1;
239 }
240 Free_line_list(info);
241 DEBUG3("Send_auth_transfer: exit status %d, error '%s'",
242 status, error );
243 return( status );
244 }
245
246 /***************************************************************************
247 *
248 * struct security *Fix_send_auth( char *name, struct line_list *info
249 * char *error, int errlen )
250 *
251 * Find the information about the encrypt type and then make up the string
252 * to send to the server requesting the encryption
253 **************************************************************************/
254
Fix_send_auth(char * name,struct line_list * info,struct job * job,char * error,int errlen)255 const struct security *Fix_send_auth( char *name, struct line_list *info,
256 struct job *job, char *error, int errlen )
257 {
258 const struct security *security = 0;
259 char buffer[SMALLBUFFER], *from, *client, *destination;
260 const char *tag, *server_tag, *key;
261
262 if( name == 0 ){
263 if( Is_server ){
264 name = Auth_forward_DYN;
265 } else {
266 name = Auth_DYN;
267 }
268 }
269 DEBUG1("Fix_send_auth: name '%s'", name );
270 if( name ){
271 security = FindSecurity(name);
272 if( !security ){
273 plp_snprintf(error, errlen,
274 "Fix_send_auth: '%s' security not supported", name );
275 goto error;
276 } else {
277 DEBUG1("Fix_send_auth: name '%s' matches '%s'", name, security->name );
278 }
279 } else {
280 DEBUG1("Fix_send_auth: no security" );
281 return( 0 );
282 }
283
284 /* check to see if we use unix_socket */
285 if( security->auth_flags & IP_SOCKET_ONLY ){
286 Set_DYN( &Unix_socket_path_DYN, 0 );
287 }
288
289 if( !(tag = security->config_tag) ) tag = security->name;
290 plp_snprintf(buffer,sizeof(buffer), "%s_", tag );
291 Find_default_tags( info, Pc_var_list, buffer );
292 Find_tags( info, &Config_line_list, buffer );
293 Find_tags( info, &PC_entry_line_list, buffer );
294 Expand_hash_values( info );
295 if(DEBUGL1)Dump_line_list("Fix_send_auth: found info", info );
296
297 if( !(tag = security->config_tag) ) tag = security->name;
298 if( !(server_tag = security->server_tag) ) server_tag = tag;
299 if( Is_server ){
300 /* forwarding */
301 key = "F";
302 from = Find_str_value(info,ID);
303 if(!from)from = Find_str_value(info,"server_principal");
304 if( from == 0 && safestrcmp(tag,"kerberos") && safestrcmp(tag,"none") ){
305 plp_snprintf(error, errlen,
306 "Fix_send_auth: '%s' security missing '%s_id' info", tag, tag );
307 goto error;
308 }
309 Set_str_value(info,FROM,from);
310 if( job ){
311 client = Find_str_value(&job->info,AUTHUSER);
312 Set_str_value(info,CLIENT,client);
313 } else {
314 client = (char *)Perm_check.authuser;
315 }
316 if( client == 0
317 && !(client = Find_str_value(info,"default_client_name"))
318 && safestrcmp(tag,"none") ){
319 plp_snprintf(error, errlen,
320 "Fix_send_auth: security '%s' missing authenticated client", tag );
321 goto error;
322 }
323 Set_str_value(info,CLIENT,client);
324 destination = Find_str_value(info,FORWARD_ID);
325 if(!destination)destination = Find_str_value(info,"forward_principal");
326 if( destination == 0 && safestrcmp(tag, "kerberos")
327 && safestrcmp(tag, "none")){
328 plp_snprintf(error, errlen,
329 "Fix_send_auth: '%s' security missing '%s_forward_id' info", tag, tag );
330 goto error;
331 }
332 } else {
333 /* from client */
334 key = "C";
335 from = Logname_DYN;
336 Set_str_value(info,FROM,from);
337 client = Logname_DYN;
338 Set_str_value(info,CLIENT,client);
339 destination = Find_str_value(info,ID);
340 if(!destination)destination = Find_str_value(info,"server_principal");
341 if( destination == 0 && safestrcmp(tag, "kerberos")
342 && safestrcmp(tag, "none") ){
343 plp_snprintf(error, errlen,
344 "Fix_send_auth: '%s' security missing destination '%s_id' info", tag, tag );
345 goto error;
346 }
347 }
348
349 Set_str_value(info,DESTINATION,destination);
350
351 DEBUG1("Fix_send_auth: pr '%s', key '%s', from '%s', name '%s', tag '%s'",
352 RemotePrinter_DYN,key, from, server_tag, tag);
353 plp_snprintf( buffer, sizeof(buffer),
354 "%c%s %s %s %s",
355 REQ_SECURE,RemotePrinter_DYN,key, from, server_tag );
356 Set_str_value(info,CMD,buffer);
357 DEBUG1("Fix_send_auth: sending '%s'", buffer );
358
359 error:
360 if( error[0] ) security = 0;
361 DEBUG1("Fix_send_auth: error '%s'", error );
362 if(DEBUGL1)Dump_line_list("Fix_send_auth: info", info );
363
364 return(security);
365 }
366
Put_in_auth(int tempfd,const char * key,char * value)367 void Put_in_auth( int tempfd, const char *key, char *value )
368 {
369 char *v = Escape(value,1);
370 DEBUG1("Put_in_auth: fd %d, key '%s' value '%s', v '%s'",
371 tempfd, key, value, v );
372 if(
373 Write_fd_str(tempfd,key) < 0
374 || Write_fd_str(tempfd,"=") < 0
375 || Write_fd_str(tempfd,v) < 0
376 || Write_fd_str(tempfd,"\n") < 0
377 ){
378 Errorcode = JFAIL;
379 logerr_die(LOG_INFO, "Put_in_auth: cannot write to file" );
380 }
381 if( v ) free(v); v = 0;
382 }
383