2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
24 * $TOG: spc-proto.c /main/12 1999/10/14 16:00:27 mgreess $
27 * (c) Copyright 1996 Digital Equipment Corporation.
28 * (c) Copyright 1989,1993,1994,1996 Hewlett-Packard Company.
29 * (c) Copyright 1993,1994,1996 International Business Machines Corp.
30 * (c) Copyright 1993,1994,1996 Sun Microsystems, Inc.
31 * (c) Copyright 1993,1994,1996 Novell, Inc.
32 * (c) Copyright 1996 FUJITSU LIMITED.
33 * (c) Copyright 1996 Hitachi.
36 #define __need_timeval
37 #define __need_all_errors
39 #include <bms/sbport.h> /* NOTE: sbport.h must be the first include. */
42 #include <sys/utsname.h>
45 #define X_INCLUDE_PWD_H
46 #define XOS_USE_XT_LOCKING
47 #include <X11/Xos_r.h>
51 #include <bms/MemoryMgr.h>
53 #include <SPC/spc-proto.h>
56 #include "DtSvcLock.h"
61 extern struct termios *XeTermioStruct; /* In pty.c */
63 extern XeString *environ;
64 extern SPC_Channel_Ptr spc_activation_list;
69 /* FILE *SPC_Print_Protocol=NULL; -- now in bmsglob.c */
71 SPC_Connection_Ptr connection_list = NULL;
72 protocol_request_ptr free_protocol_requests = NULL;
77 static int SPC_Send_Termios(protocol_request_ptr prot_request);
78 static int SPC_Send_B00_Spawn(SPC_Connection_Ptr connection,
79 protocol_request_ptr prot,
85 /*----------------------------------------------------------------------+*/
86 buffered_data_ptr SPC_New_Buffered_Data_Ptr(void)
87 /*----------------------------------------------------------------------+*/
89 buffered_data_ptr bdata;
91 bdata=(buffered_data_ptr)XeMalloc(sizeof(buffered_data));
92 bdata->len = bdata->offset = 0;
97 /*----------------------------------------------------------------------+*/
98 void SPC_Reset_Protocol_Ptr (protocol_request_ptr prot,
99 SPC_Channel_Ptr channel,
102 /*----------------------------------------------------------------------+*/
104 buffered_data_ptr dptr=prot->dataptr;
109 prot->request_type = req;
110 prot->channel = channel;
112 memset(dptr->data, (XeChar)' ', REQUEST_HEADER_LENGTH);
115 /*----------------------------------------------------------------------+*/
116 protocol_request_ptr SPC_New_Protocol_Ptr (SPC_Channel_Ptr channel,
119 /*----------------------------------------------------------------------+*/
121 protocol_request_ptr prot;
124 if(free_protocol_requests) {
125 prot = free_protocol_requests;
126 free_protocol_requests = free_protocol_requests->next;
128 prot = (protocol_request_ptr)XeMalloc(sizeof(protocol_request));
129 prot->dataptr = SPC_New_Buffered_Data_Ptr();
131 SPC_Reset_Protocol_Ptr(prot, channel, req, len);
132 _DtSvcProcessUnlock();
136 /*----------------------------------------------------------------------+*/
137 void SPC_Free_Protocol_Ptr(protocol_request_ptr prot)
138 /*----------------------------------------------------------------------+*/
141 prot->next = free_protocol_requests;
142 free_protocol_requests = prot;
143 _DtSvcProcessUnlock();
147 /*----------------------------------------------------------------------+*/
148 SPC_Channel_Ptr SPC_Lookup_Channel(int cid,
149 SPC_Connection_Ptr connection)
150 /*----------------------------------------------------------------------+*/
159 for(spc=spc_activation_list; spc; spc=spc->next)
160 /* This test is here because:
161 a. Only remote channels have cid's
162 b. It is possible for multiple remote servers to have
163 the same cid (which is simply the address of the channel),
164 so we need to distinguish among remote channels, but
165 c. channels on the remote daemon have cid's, but a null connection.
167 if((spc->cid == cid) &&
169 (spc->connection == connection))) {
170 _DtSvcProcessUnlock();
174 _DtSvcProcessUnlock();
179 * Connection management routines
183 /*----------------------------------------------------------------------+*/
184 SPC_Connection_Ptr SPC_Alloc_Connection(void)
185 /*----------------------------------------------------------------------+*/
187 SPC_Connection_Ptr conn;
190 conn=(SPC_Connection_Ptr) XeMalloc(sizeof(SPC_Connection));
191 /* Zero the connection */
192 memset(conn, 0, sizeof(SPC_Connection));
193 conn->queued_remote_data = Xe_make_queue(FALSE);
194 conn->termination_id = (-1);
195 /* Init the socket id to "-1" because "0" is a valid file descriptor. */
197 _DtSvcProcessUnlock();
202 /*----------------------------------------------------------------------+*/
203 SPC_Connection_Ptr SPC_Lookup_Connection(XeString hostname)
204 /*----------------------------------------------------------------------+*/
206 /* Search for an existing connection to a server */
207 SPC_Connection_Ptr conn;
210 for (conn = connection_list; conn != NULL; conn = conn->next) {
212 /* Look for a connection with the same hostname */
213 if (!strcmp(conn->hostname, hostname)) {
214 _DtSvcProcessUnlock();
219 _DtSvcProcessUnlock();
223 /*----------------------------------------------------------------------+*/
224 SPC_Connection_Ptr SPC_Lookup_Connection_Fd(int fd)
225 /*----------------------------------------------------------------------+*/
227 /* Search for an existing connection to a server, using fd (file descriptor)
229 SPC_Connection_Ptr conn;
232 for (conn = connection_list; conn != NULL; conn = conn->next) {
234 /* Look for a connection with the same hostname */
236 _DtSvcProcessUnlock();
241 _DtSvcProcessUnlock();
245 /*----------------------------------------------------------------------+*/
246 SPC_Connection_Ptr SPC_Make_Connection(XeString hostname)
247 /*----------------------------------------------------------------------+*/
249 /* Search for a connection to hostname, create one if none exists */
251 SPC_Connection_Ptr conn;
253 /* Searching for connected host maintains only one connection per remote */
255 if(hostname && (conn=SPC_Lookup_Connection(hostname)))
258 /* Not found, so make one */
260 if((conn = SPC_Alloc_Connection())==SPC_ERROR)
264 strcpy(conn->hostname, hostname);
266 SPC_Add_Connection(conn);
270 /*----------------------------------------------------------------------+*/
271 void SPC_Add_Connection(SPC_Connection_Ptr connection)
272 /*----------------------------------------------------------------------+*/
275 /* Add a connection to the connection_list */
277 connection->next = connection_list;
278 connection_list = connection;
279 _DtSvcProcessUnlock();
282 /*----------------------------------------------------------------------+*/
283 void SPC_Close_Connection(SPC_Connection_Ptr connection)
284 /*----------------------------------------------------------------------+*/
286 SPC_Channel_Ptr channel;
287 SPC_Channel_Ptr next;
288 SPC_Connection_Ptr trail, ptr;
290 /* We have to be careful here. SPC_Input_Handler may call the users
291 termination handler, which in turn might close the channel, which
292 may deallocate the channel. Therefore, we grab the next channel
293 from the list while we are still alive. */
296 channel=spc_activation_list;
297 connection->connected = FALSE;
301 if(channel->connection == connection) {
302 if(!IS_SPCIO_DELAY_CLOSE(channel->IOMode))
303 SPC_Channel_Terminated(channel);
304 channel->connection = NULL;
309 SPC_XtRemoveInput(&connection->termination_id, SPC_Terminator);
311 spc_close(connection->sid);
312 connection->sid = (-1);
314 if (connection->hostinfo)
315 XeFree(connection->hostinfo);
317 /* Remove the connection from the connection list */
319 if(connection_list == connection)
320 connection_list = connection->next;
322 trail = connection_list;
325 if(ptr == connection) {
326 trail->next = ptr->next;
332 /* Here if no such connection found. */
336 free((char *)connection);
337 _DtSvcProcessUnlock();
342 ** Read the specified number of characters, or die trying.
346 /*----------------------------------------------------------------------+*/
347 int SPC_Read_Chars(SPC_Connection_Ptr connection,
350 /*----------------------------------------------------------------------+*/
353 int numchars, numread;
354 int numtoread=request_len;
355 int sid=connection->sid;
359 while(numread<request_len) {
361 numchars=read(sid, charptr, numtoread);
362 while(numchars == ERROR && errno == EINTR);
363 if(numchars == ERROR) {
364 XeString connection_hostname = CONNECTION_HOSTNAME(connection);
365 if(errno == ECONNRESET)
366 SPC_Error(SPC_Connection_Reset, connection_hostname);
368 SPC_Error(SPC_Reading, connection_hostname);
369 XeFree(connection_hostname);
373 XeString connection_hostname = CONNECTION_HOSTNAME(connection);
374 SPC_Error(SPC_Connection_EOF, connection_hostname);
375 XeFree(connection_hostname);
376 return(SPC_ERROR); /* Bad news, EOF on incoming channel */
380 numtoread -= numchars;
382 *charptr=(XeChar)'\0';
386 /* Write len chars, or die trying */
388 /*----------------------------------------------------------------------+*/
389 int SPC_Write_Chars(int fd,
392 /*----------------------------------------------------------------------+*/
394 int numchars, numwritten;
395 int numtowrite=request_len;
399 while(numwritten<request_len) {
401 numchars=write(fd, charptr, numtowrite);
402 while(numchars == ERROR && errno == EINTR);
406 if(SPC_Print_Protocol)
407 fprintf(SPC_Print_Protocol,
408 "SPC_Write_Chars -- wrote: %d of %d, expected: %d, errno: %d\n",
409 numchars, request_len, numtowrite, errno);
410 _DtSvcProcessUnlock();
413 if(numchars == ERROR)
417 numwritten += numchars;
418 numtowrite -= numchars;
426 ** Read a single protocol request from the passed channel.
430 /*----------------------------------------------------------------------+*/
431 protocol_request_ptr SPC_Read_Protocol(SPC_Connection_Ptr connection)
432 /*----------------------------------------------------------------------+*/
435 protocol_request_ptr prot;
436 buffered_data_ptr dptr;
439 if(!connection->connected)
442 if((prot=SPC_New_Protocol_Ptr(NULL, 0, 0))==SPC_ERROR) {
443 SPC_Close_Connection(connection);
451 len=SPC_Read_Chars(connection, REQUEST_HEADER_LENGTH, dptr->data);
452 if(len != REQUEST_HEADER_LENGTH) {
453 SPC_Close_Connection(connection);
454 SPC_Free_Protocol_Ptr(prot);
458 /* we have the header. Parse out the fields */
461 &channel_id, &prot->request_type, &dptr->len, &prot->seqno);
462 prot->channel=SPC_Lookup_Channel(channel_id, connection);
465 /* JET - 11/12/2001 - correct an exploitable buffer overrun where the user */
466 /* can supply a data len that is larger than the available buffer */
468 /* CERT - VU#172583 */
470 if (dptr->len >= MAXREQLEN)
471 { /* we have a problem. Initiate DefCon 1 */
472 /* and launch our missiles. */
473 XeString connection_hostname = CONNECTION_HOSTNAME(connection);
475 SPC_Error(SPC_Buffer_Overflow, connection_hostname);
476 XeFree(connection_hostname);
477 SPC_Close_Connection(connection);
478 SPC_Free_Protocol_Ptr(prot);
484 len=SPC_Read_Chars(connection, dptr->len, dptr->data+REQUEST_HEADER_LENGTH);
485 if(len != dptr->len) {
486 SPC_Close_Connection(connection);
487 SPC_Free_Protocol_Ptr(prot);
491 dptr->offset=REQUEST_HEADER_LENGTH;
498 ** Filter the connection for the desired type of protocol request.
499 ** If there is a protocol request of the desired type already queued,
500 ** return it. If not, read a new one. If we read requests destined
501 ** for another channel, or for our channel but not the correct
502 ** request type, queue it up. If the deletep flag is TRUE, remove it
507 /*----------------------------------------------------------------------+*/
508 protocol_request_ptr SPC_Filter_Connection(SPC_Connection_Ptr connection,
509 SPC_Channel_Ptr channel,
512 /*----------------------------------------------------------------------+*/
514 SPC_Connection_Ptr connptr=NULL;
515 SPC_Channel_Ptr conn_channel;
517 protocol_request_ptr retval;
520 /* check if there are any queued prot. requests. If so,
521 check for their having the type we want */
523 if(channel && (tmpqueue=channel->queued_remote_data)) {
524 tmpqueue=channel->queued_remote_data;
526 Xe_for_queue(protocol_request_ptr, retval, tmpqueue) {
527 /* found a queued packet. Is it what we are looking for? */
528 if(retval->request_type == reqtype) {
531 Xe_delete_queue_element(channel->queued_remote_data, retval);
538 /* No queued elements. Read until we get the reply we
541 if((retval=SPC_Read_Protocol(connection))==SPC_ERROR)
544 protreqtype=retval->request_type;
545 conn_channel=retval->channel;
547 if(protreqtype == ABORT) {
548 XeString connection_hostname = CONNECTION_HOSTNAME(connection);
549 SPC_Error(SPC_Protocol_Abort, connection_hostname);
550 XeFree (connection_hostname);
555 if(protreqtype == SERVER_ERROR) {
556 READ_ERROR(retval->dataptr, XeSPCErrorNumber);
557 SPC_Error(XeSPCErrorNumber, XeString_NULL, 0);
558 _DtSvcProcessUnlock();
561 _DtSvcProcessUnlock();
566 if((conn_channel == channel) && (protreqtype == reqtype)) {
567 /* We found one that matches. Check if we need to queue it up. */
569 Xe_push_queue(conn_channel->queued_remote_data, retval);
573 /* No match. Queue it up */
574 if(IS_SPCIO_SYNC_TERM(channel->IOMode))
575 Xe_push_queue(connection->queued_remote_data, retval);
577 Xe_push_queue(conn_channel->queued_remote_data, retval);
582 /*----------------------------------------------------------------------+*/
583 void SPC_Flush_Queued_Data(SPC_Channel_Ptr channel)
584 /*----------------------------------------------------------------------+*/
587 protocol_request_ptr prot;
589 if(tmpqueue=channel->queued_remote_data) {
590 while(prot=(protocol_request_ptr)Xe_pop_queue(tmpqueue))
591 SPC_Free_Protocol_Ptr(prot);
594 if(channel->connection && (tmpqueue=channel->connection->queued_remote_data))
596 Xe_for_queue(protocol_request_ptr, prot, tmpqueue) {
597 if(prot->channel == channel) {
598 Xe_delete_queue_element(tmpqueue, prot);
599 SPC_Free_Protocol_Ptr(prot);
605 /*----------------------------------------------------------------------+*/
606 int SPC_Read_Remote_Data(SPC_Channel_Ptr channel,
608 XeString client_buffer,
610 /*----------------------------------------------------------------------+*/
614 SPC_Connection_Ptr connection=channel->connection;
615 protocol_request_ptr prot;
616 buffered_data_ptr pdata;
617 int req_type=CONNECTOR_TO_PROT(connector);
619 prot=SPC_Filter_Connection(connection, channel, req_type, FALSE);
625 ret_len = min(nbytes, pdata->len);
627 memcpy(client_buffer, pdata->data+pdata->offset, ret_len);
628 pdata->offset += ret_len;
629 pdata->len -= ret_len;
630 if(pdata->len == 0) {
631 SPC_Filter_Connection(connection, channel, req_type, TRUE);
632 SPC_Free_Protocol_Ptr(prot);
638 /* Dump out a protocol request */
640 /*----------------------------------------------------------------------+*/
641 int print_protocol_request(XeString name, protocol_request_ptr proto)
642 /*----------------------------------------------------------------------+*/
644 buffered_data_ptr dptr = proto->dataptr;
647 if(!SPC_Print_Protocol) {
648 _DtSvcProcessUnlock();
652 dptr->data[dptr->offset+dptr->len]=0;
654 fprintf(SPC_Print_Protocol,
655 "%s channel: %x, request: %d, length: %d, seq: %d data: %s\n",
656 name, proto->channel, proto->request_type, dptr->len, proto->seqno,
657 dptr->data+dptr->offset);
659 fflush(SPC_Print_Protocol);
661 _DtSvcProcessUnlock();
666 * Write a protocol request to the given channel
670 int current_sequence_number=1;
672 /*----------------------------------------------------------------------+*/
673 int SPC_Write_Protocol_Request (SPC_Connection_Ptr connection,
674 SPC_Channel_Ptr channel,
677 /*----------------------------------------------------------------------+*/
680 protocol_request_ptr prot_request;
681 buffered_data_ptr pdata;
683 XeString prot_name=NULL;
685 prot_request=SPC_New_Protocol_Ptr(channel, request, 0);
686 pdata=prot_request->dataptr;
688 prot_request->seqno = current_sequence_number++;
689 _DtSvcProcessUnlock();
691 /* We are overloading the "channel" field. We put the cid rather */
692 /* than the actual channel pointer in when we pass it to the other */
693 /* side of the connection. */
694 prot_request->channel=(SPC_Channel_Ptr)(channel ? channel->cid : 0);
699 pdata->len=WRITE_ABORT(pdata, 0);
700 prot_name=(XeString)" <-- ABORT";
710 va_start(ap, request);
711 username=va_arg(ap, XeString );
712 passwd=va_arg(ap, XeString );
713 proto_ver=va_arg(ap, XeString );
714 hostinfo=va_arg(ap, XeString );
716 pdata->len=WRITE_REGISTER(pdata, username, passwd, proto_ver, hostinfo);
717 prot_name=(XeString)" <-- REGISTER";
723 prot_name=(XeString)" <-- UNREGISTER";
727 va_start(ap, request);
728 pdata->len=WRITE_OPEN(pdata, va_arg(ap, int));
730 prot_name=(XeString)" <-- CHANNEL_OPEN";
734 /* This is correct. This protocol request takes no args */
735 prot_name=(XeString)" <-- CHANNEL_CLOSE";
739 /* This one, either */
740 prot_name=(XeString)" <-- CHANNEL_RESET";
744 prot_name=(XeString)" <-- CHANNEL_ATTACH";
745 va_start(ap, request);
746 pdata->len=WRITE_ATTACH(pdata, va_arg(ap, int));
750 case APPLICATION_SPAWN:
757 va_start(ap, request);
759 /* It is left as an exercise to the reader to figure out
760 what would happen if we didn't use these temp. variables
761 and instead used the va_arg macros directly in the
762 WRITE_APPLICATION_SPAWN... */
764 path=va_arg(ap, XeString );
765 dir =va_arg(ap, XeString );
766 argv=va_arg(ap, XeString *);
767 envp=va_arg(ap, XeString *);
769 pdata->len=WRITE_APPLICATION_SPAWN(pdata, path, dir, argv, envp);
770 if(pdata->len == SPC_ERROR)
772 prot_name=(XeString)" <-- APPLICATION_SPAWN";
776 case APPLICATION_SIGNAL:
778 if (connection->protocol_version >= 2)
782 va_start(ap, request);
783 signame = va_arg(ap, XeString);
786 pdata->len=WRITE_STRING(pdata, signame);
792 va_start(ap, request);
793 sig = va_arg(ap, int);
796 pdata->len=WRITE_INT(pdata, sig);
799 prot_name=(XeString)" <-- APPLICATION_SIGNAL";
803 case APPLICATION_DIED:
804 va_start(ap, request);
805 pdata->len=WRITE_APPLICATION_DIED(pdata, va_arg(ap, int));
807 prot_name=(XeString)" <-- APPLICATION_DIED";
810 case APPLICATION_DATA:
811 prot_name=(XeString)" <-- APPLICATION_DATA";
813 case APPLICATION_STDOUT:
815 prot_name=(XeString)" <-- APPLICATION_STDOUT";
817 case APPLICATION_STDERR:
823 prot_name=(XeString)" <-- APPLICATION_STDERR";
825 va_start(ap, request);
826 buffer=va_arg(ap, XeString );
827 buflen=va_arg(ap, int);
830 pdata->len=WRITE_APP_DATA(pdata, buffer, buflen);
836 va_start(ap, request);
837 pdata->len=WRITE_ERROR(pdata, va_arg(ap, int));
839 prot_name=(XeString)" <-- SERVER_ERROR";
844 int replyval, errval;
846 va_start(ap, request);
847 prot_request->seqno=va_arg(ap, int);
848 replyval=va_arg(ap, int);
849 errval=va_arg(ap, int);
851 pdata->len=WRITE_REPLY(pdata, replyval, errval);
852 prot_name=(XeString)" <-- REPLY";
865 va_start(ap, request);
866 m0=va_arg(ap, XeString );
867 s0=va_arg(ap, XeString );
868 m1=va_arg(ap, XeString );
869 s1=va_arg(ap, XeString );
870 m2=va_arg(ap, XeString );
871 s2=va_arg(ap, XeString );
873 pdata->len=WRITE_DEVICE_REPLY(pdata, m0, s0, m1, s1, m2, s2);
874 prot_name=(XeString)" <-- DEVICE_REPLY";
879 prot_name=(XeString)" <-- QUERY_DEVICES";
888 va_start(ap, request);
889 fname=va_arg(ap, XeString );
890 proto_ver=va_arg(ap, XeString );
891 hostinfo=va_arg(ap, XeString );
893 pdata->len=WRITE_LOGFILE_REPLY(pdata, fname, proto_ver, hostinfo);
894 prot_name=(XeString)" <-- LOGFILE_REPLY";
899 prot_name=(XeString)" <-- QUERY_LOGFILE";
903 prot_name=(XeString)" <-- DELETE_LOGFILE";
907 va_start(ap, request);
908 pdata->len=WRITE_DEBUG(pdata, va_arg(ap, XeString));
910 prot_name=(XeString)" <-- SERVER_DEBUG";
914 return(SPC_Send_Environ(connection, prot_request));
916 /* We used to send the hp-ux version of a termio struct */
917 /* This is non-portable, so we don't do it anymore. */
920 pdata->len=SPC_Send_Termios(prot_request);
921 prot_name=(XeString)" <-- RESET_TERMIOS";
924 /* B.00 (protocol version 3) requests */
926 case CHANNEL_SEND_EOF:
928 if(connection->protocol_version < 3) {
929 SPC_Error(SPC_Protocol_Version_Error,
930 3, channel->connection->protocol_version);
934 prot_name = (XeString)" <-- CHANNEL_SEND_EOF";
937 case CHANNEL_TERMIOS:
939 if(connection->protocol_version < 3) {
940 SPC_Error(SPC_Protocol_Version_Error,
941 3, channel->connection->protocol_version);
947 struct termios *termios_ptr;
950 va_start(ap, request);
952 connector = va_arg(ap, int);
953 side = va_arg(ap, int);
954 termios_ptr = va_arg(ap, struct termios *);
957 buffer = SPC_Decode_Termios(termios_ptr);
958 pdata->len=WRITE_TERMIOS(pdata, connector, side, buffer);
959 prot_name=(XeString)" <-- CHANNEL_TERMIOS";
964 if(connection->protocol_version < 3) {
965 SPC_Error(SPC_Protocol_Version_Error,
966 3, channel->connection->protocol_version);
977 va_start(ap, request);
979 /* It is left as an exercise to the reader to figure out
980 what would happen if we didn't use these temp. variables
981 and instead used the va_arg macros directly in the
982 WRITE_APPLICATION_SPAWN... */
984 path=va_arg(ap, XeString );
985 dir =va_arg(ap, XeString );
986 argv=va_arg(ap, XeString *);
987 envp=va_arg(ap, XeString *);
991 SPC_Send_B00_Spawn(connection, prot_request, path, dir, argv, envp);
998 SPC_Write_Single_Prot_Request(connection, prot_name, prot_request);
1000 SPC_Free_Protocol_Ptr(prot_request);
1001 return(reply_expected);
1005 /*----------------------------------------------------------------------+*/
1006 int SPC_Write_Single_Prot_Request(SPC_Connection_Ptr connection,
1008 protocol_request_ptr prot)
1009 /*----------------------------------------------------------------------+*/
1011 int reply_expected, length;
1012 buffered_data_ptr pdata=prot->dataptr;
1014 if(!connection->connected)
1018 REPLY_EXPECTED(prot->request_type, prot->seqno);
1019 length=WRITE_HEADER(pdata, prot->channel,
1023 pdata->data[length]=(XeChar)' ';
1025 length=pdata->len+REQUEST_HEADER_LENGTH;
1026 if(SPC_Write_Chars(connection->sid, pdata->data, length) == ERROR) {
1027 XeString connection_hostname = CONNECTION_HOSTNAME(connection);
1028 SPC_Close_Connection(connection);
1029 SPC_Error(SPC_Write_Prot, connection_hostname);
1030 XeFree(connection_hostname);
1031 reply_expected = (SPC_ERROR);
1034 pdata->offset=REQUEST_HEADER_LENGTH;
1035 print_protocol_request(name, prot);
1037 return(reply_expected);
1040 /*----------------------------------------------------------------------+*/
1041 int SPC_Waitfor_Reply(SPC_Connection_Ptr connection,
1042 SPC_Channel_Ptr channel,
1044 /*----------------------------------------------------------------------+*/
1047 protocol_request_ptr prot;
1051 if(seqno == NO_REPLY_VAL)
1054 if(seqno==SPC_ERROR)
1057 prot=SPC_Filter_Connection(connection, channel, REPLY, TRUE);
1062 thisseq = prot->seqno;
1063 READ_REPLY(prot->dataptr, retval, errval);
1065 SPC_Free_Protocol_Ptr(prot);
1067 if(thisseq != seqno) {
1068 SPC_Error(SPC_Unexpected_Reply);
1075 if(retval != SPC_Protocol_Abort) {
1076 if (retval == SPC_Cannot_Create_Netfilename)
1077 SPC_Error(retval, channel->context_dir, connection->hostname);
1078 else if (retval == SPC_Cannot_Exec)
1079 SPC_Error(retval, channel->path, 0);
1080 else if (retval == SPC_cannot_Chdir)
1081 SPC_Error(retval, channel->context_dir, 0);
1083 SPC_Error(retval, XeString_NULL, 0);
1091 /*----------------------------------------------------------------------+*/
1092 int SPC_Dispatch_Protocol(protocol_request_ptr proto,
1093 protocol_request_handler *table)
1094 /*----------------------------------------------------------------------+*/
1100 req_type=proto->request_type;
1102 if(req_type<0 || req_type>NREQS)
1105 return((* table[req_type])(proto));
1108 /*----------------------------------------------------------------------+*/
1109 int SPC_Write_Reply(SPC_Connection_Ptr conn,
1110 protocol_request_ptr proto,
1113 /*----------------------------------------------------------------------+*/
1115 _DtSvcProcessLock();
1117 retval=(-XeSPCErrorNumber);
1118 _DtSvcProcessUnlock();
1120 return(SPC_Write_Protocol_Request(conn, proto->channel, REPLY,
1121 proto->seqno, retval, errval));
1126 ** Send the current environment out to the world.
1130 #define valid_str(x) (((x) != NULL) && (*(x) != 0))
1131 #define NULL_STR "\001\001\001"
1132 #define EMPTY_STR "\001\002\003"
1134 int SPC_Send_Multi_Packet(SPC_Connection_Ptr connection,
1135 protocol_request_ptr prot,
1142 int counter, tmp_len;
1143 int bytes_left, numbytes;
1150 _DtSvcProcessLock();
1151 this_seqno=current_sequence_number;
1152 numbytes=WRITE_ENVIRON_RESET(prot->dataptr, num_str);
1153 bytes_left=SPC_BUFSIZ-numbytes;
1154 buf=(PDRP(prot->dataptr) + numbytes);
1155 reply_seqno=prot->seqno;
1157 for(counter=0; counter<num_str; counter++) {
1158 this_str = str_vect[counter];
1160 if(this_str == NULL)
1161 this_str = NULL_STR;
1162 if(*this_str == '\0')
1163 this_str = EMPTY_STR;
1165 tmp_len=strlen(this_str)+1; /* Room for NULL char */
1166 if((bytes_left-tmp_len) < 1) {
1168 prot->dataptr->len=numbytes+1;
1169 SPC_Write_Single_Prot_Request(connection, name, prot);
1170 SPC_Free_Protocol_Ptr(prot);
1171 prot=SPC_New_Protocol_Ptr(0, req, 0);
1172 prot->seqno=current_sequence_number++;
1174 bytes_left=SPC_BUFSIZ;
1175 buf=(PDRP(prot->dataptr) + numbytes);
1178 if(tmp_len>SPC_BUFSIZ-1) {
1182 SPC_Free_Protocol_Ptr(prot);
1183 if(this_seqno != current_sequence_number)
1184 SPC_Write_Protocol_Request(connection, NULL, ABORT);
1185 _DtSvcProcessUnlock();
1186 return(reply_seqno);
1189 strncpy(buf, this_str, tmp_len);
1190 bytes_left -= tmp_len;
1191 numbytes += tmp_len;
1197 prot->dataptr->len=numbytes+1;
1198 SPC_Write_Single_Prot_Request(connection, (XeString)" <-- ENVIRON_RESET", prot);
1199 SPC_Free_Protocol_Ptr(prot);
1202 _DtSvcProcessUnlock();
1203 return(reply_seqno);
1207 char **SPC_Get_Multi_Packet(SPC_Connection_Ptr connection,
1208 protocol_request_ptr prot,
1215 int num_vars, i, len;
1217 protocol_request_ptr localprot = NULL;
1219 print_protocol_request(name, prot);
1220 READ_ENVIRON_RESET(prot->dataptr, num_vars);
1221 bufptr=strchr(PDRP(prot->dataptr), Space)+1;
1223 out = (char **)malloc((num_vars+1) * sizeof(char **));
1225 for(i=0; i<num_vars; i++) {
1229 SPC_Free_Protocol_Ptr(localprot);
1230 prot=SPC_Filter_Connection(connection, NULL, request, TRUE);
1233 print_protocol_request(name, prot);
1235 bufptr=PDRP(prot->dataptr);
1238 if(strcmp(bufptr, NULL_STR) == 0)
1241 if(strcmp(bufptr, EMPTY_STR) == 0)
1242 out[i] = strdup("");
1244 out[i] = strdup(bufptr);
1249 SPC_Free_Protocol_Ptr(localprot);
1252 out[num_vars] = NULL;
1257 /*----------------------------------------------------------------------+*/
1258 int SPC_Send_Environ(SPC_Connection_Ptr connection,
1259 protocol_request_ptr prot)
1260 /*----------------------------------------------------------------------+*/
1266 _DtSvcProcessLock();
1267 while(environ[ep_count])
1270 result = SPC_Send_Multi_Packet(connection, prot, environ, ep_count,
1271 ENVIRON_RESET, " <-- ENVIRON_RESET",
1273 _DtSvcProcessUnlock();
1277 /*----------------------------------------------------------------------+*/
1278 int sprint_counted_string(XeString buf,
1282 /*----------------------------------------------------------------------+*/
1284 XeString bufptr=buf;
1287 int limit=orig_limit;
1288 #define ERRBUFLEN 100
1289 char errbuf[ERRBUFLEN];
1291 len=sprintf_len(bufptr, (XeString)"%x ", count)+1;
1293 sprintf(errbuf, "(%d chars), max. length is %d", len, orig_limit);
1294 SPC_Error(SPC_Arg_Too_Long,
1302 for(i=0; i<count; (i++, vect++)) {
1304 len = strlen(*vect)+1;
1309 sprintf(errbuf, "(%d chars), max. length is %d", len, orig_limit);
1310 SPC_Error(SPC_Arg_Too_Long,
1315 sprintf(bufptr, "%s", *vect ? *vect : "");
1323 /*----------------------------------------------------------------------+*/
1324 XeString *sscan_counted_string(XeString buf,
1326 /*----------------------------------------------------------------------+*/
1329 int i, numstrings, len;
1334 sscanf(buf, (XeString)"%x", &numstrings);
1338 tmpptr=(XeString*)XeMalloc((numstrings+1) * sizeof(XeString *));
1341 for(i=0; i<numstrings; (i++, tmpidx++)){
1342 len=strlen(bufptr)+1; /* len is string SIZE (with room for NULL) */
1343 *tmpidx=(XeString)XeMalloc(len);
1344 strncpy(*tmpidx, bufptr, len);
1345 (*tmpidx)[len-1]='\0';
1354 /*----------------------------------------------------------------------+*/
1356 sprint_application_data(XeString buf,
1357 XeString UNUSED_PARM(fmt),
1362 int UNUSED_PARM(chars_used))
1363 /*----------------------------------------------------------------------+*/
1373 while(argv[av_count]) av_count++;
1376 while(envp[ep_count]) ep_count++;
1380 tmp_len = sprint_counted_string(buf, 1, &path, limit);
1381 if(tmp_len == SPC_ERROR)
1385 data_len += tmp_len;
1387 tmp_len = sprint_counted_string(buf, 1, &dir, limit);
1388 if(tmp_len == SPC_ERROR)
1392 data_len += tmp_len;
1394 tmp_len = sprint_counted_string(buf, av_count, argv, limit);
1395 if(tmp_len == SPC_ERROR)
1399 data_len += tmp_len;
1401 tmp_len = sprint_counted_string(buf, ep_count, envp, limit);
1402 if(tmp_len == SPC_ERROR)
1406 data_len += tmp_len;
1411 /*----------------------------------------------------------------------+*/
1413 sscan_application_data(XeString buf,
1414 XeString UNUSED_PARM(fmt),
1419 int UNUSED_PARM(offset))
1420 /*----------------------------------------------------------------------+*/
1427 tmp_vect=sscan_counted_string(bufptr, &bufptr);
1428 if(tmp_vect==SPC_ERROR)
1430 *path = (*tmp_vect);
1432 tmp_vect=sscan_counted_string(bufptr, &bufptr);
1433 if(tmp_vect==SPC_ERROR)
1437 *argv=sscan_counted_string(bufptr, &bufptr);
1438 if(*argv==SPC_ERROR)
1441 *envp=sscan_counted_string(bufptr, &bufptr);
1442 if(*envp==SPC_ERROR)
1446 /*----------------------------------------------------------------------+*/
1448 sprint_device_data(XeString buf,
1455 /*----------------------------------------------------------------------+*/
1467 i=sprint_counted_string(buf, 6, args, SPC_BUFSIZ);
1473 /*----------------------------------------------------------------------+*/
1475 sscan_device_data(XeString buf,
1482 /*----------------------------------------------------------------------+*/
1486 args=sscan_counted_string(buf, NULL);
1503 /*----------------------------------------------------------------------+*/
1505 sprint_logfile_data(XeString buf,
1509 /*----------------------------------------------------------------------+*/
1518 i=sprint_counted_string(buf, 3, args, SPC_BUFSIZ);
1524 /*----------------------------------------------------------------------+*/
1526 sscan_logfile_data(XeString buf,
1528 XeString *proto_ver,
1530 /*----------------------------------------------------------------------+*/
1534 args=sscan_counted_string(buf, NULL);
1540 /* args[1] and args[2] will only be around for protocol revision 2 or later */
1542 *proto_ver = *hostinfo = XeString_NULL;
1545 *proto_ver = args[1];
1546 *hostinfo = args[2];
1549 *hostinfo = strdup(SPC_UNKNOWN_HOSTINFO_STR);
1556 /*----------------------------------------------------------------------+*/
1558 sprint_register_data(XeString buf,
1563 /*----------------------------------------------------------------------+*/
1573 i=sprint_counted_string(buf, 4, args, SPC_BUFSIZ);
1579 /*----------------------------------------------------------------------+*/
1581 sscan_register_data(XeString buf,
1584 XeString *proto_ver,
1586 /*----------------------------------------------------------------------+*/
1590 args=sscan_counted_string(buf, NULL);
1598 /* args[2] and args[3] will only be around for protocol revision 2 or later */
1600 *proto_ver = *hostinfo = XeString_NULL;
1603 *proto_ver = args[2];
1604 *hostinfo = args[3];
1607 *hostinfo = strdup(SPC_UNKNOWN_HOSTINFO_STR);
1616 ** Request / reply protocol requests
1620 /*----------------------------------------------------------------------+*/
1621 int SPC_Query_Devices(SPC_Channel_Ptr channel)
1622 /*----------------------------------------------------------------------+*/
1624 SPC_Connection_Ptr connection=channel->connection;
1625 protocol_request_ptr prot;
1627 SPC_Write_Protocol_Request(connection, channel, QUERY_DEVICES);
1628 prot=SPC_Filter_Connection(connection, channel, DEVICE_REPLY, TRUE);
1632 READ_DEVICE_REPLY(prot->dataptr,
1633 &(channel->wires[STDIN]->master_name),
1634 &(channel->wires[STDIN]->slave_name),
1635 &(channel->wires[STDOUT]->master_name),
1636 &(channel->wires[STDOUT]->slave_name),
1637 &(channel->wires[STDERR]->master_name),
1638 &(channel->wires[STDERR]->slave_name));
1640 SPC_Free_Protocol_Ptr(prot);
1644 /*----------------------------------------------------------------------+*/
1645 int SPC_Query_Logfile(SPC_Channel_Ptr channel)
1646 /*----------------------------------------------------------------------+*/
1648 SPC_Connection_Ptr connection=channel->connection;
1649 protocol_request_ptr prot;
1650 XeString junk1, junk2;
1652 SPC_Write_Protocol_Request(connection, channel, QUERY_LOGFILE);
1653 prot=SPC_Filter_Connection(connection, channel, LOGFILE_REPLY, TRUE);
1657 READ_LOGFILE_REPLY(prot->dataptr, &channel->logfile, &junk1, &junk2);
1658 if (junk1) XeFree(junk1);
1659 if (junk1) XeFree(junk2);
1661 SPC_Free_Protocol_Ptr(prot);
1665 #define UNK_TOKEN "unknown"
1667 /*----------------------------------------------------------------------+*/
1668 XeString SPC_LocalHostinfo(void)
1669 /*----------------------------------------------------------------------+*/
1671 struct utsname name;
1673 static XeString s = 0;
1675 _DtSvcProcessLock();
1677 if (uname(&name) >= 0) {
1678 s_len = strlen(name.sysname) +
1679 strlen(name.nodename) +
1680 strlen(name.release) +
1681 strlen(name.machine) + 4;
1682 s = (XeString) XeMalloc(s_len * sizeof(XeChar));
1683 sprintf(s, "%s:%s:%s:%s", name.nodename, name.sysname, name.release, name.machine);
1686 s_len = 4 * strlen(UNK_TOKEN) + 4;
1687 s = (XeString) XeMalloc(s_len * sizeof(XeChar));
1688 sprintf(s, "%s:%s:%s:%s", UNK_TOKEN, UNK_TOKEN, UNK_TOKEN, UNK_TOKEN);
1692 _DtSvcProcessUnlock();
1696 /*----------------------------------------------------------------------+*/
1698 SPC_Validate_User(XeString hostname,
1699 SPC_Connection_Ptr connection)
1700 /*----------------------------------------------------------------------+*/
1701 /* Called by client to register itself to spcd */
1703 XeString username = XeString_NULL;
1708 protocol_request_ptr prot;
1709 int open_status, chmod_status;
1710 XeString logfile = NULL;
1711 XeString junk1 = NULL, junk2 = NULL;
1712 XeString connection_hostname=CONNECTION_HOSTNAME(connection);
1713 _Xgetpwparams pwd_buf;
1714 struct passwd * pwd_ret;
1716 hostinfo = SPC_LocalHostinfo();
1719 * We are now including the user ID to generate the LOGFILE
1720 * (i.e., the authentication file)
1724 if((pwd_ret = _XGetpwuid(this_uid, pwd_buf)) == NULL) {
1726 * Very strange situation - the uid isn't in the passwd file
1728 username = XeString_NULL; /* we'll use the original /tmp subdirectory */
1731 username=(XeString)(pwd_ret->pw_name);
1734 SPC_Write_Protocol_Request(connection, NULL, REGISTER,
1735 username, XeString_Empty,
1736 SPC_PROTOCOL_VERSION_STR, hostinfo);
1739 prot=SPC_Filter_Connection(connection, NULL, LOGFILE_REPLY, TRUE);
1740 if(prot==SPC_ERROR) {
1741 XeFree(connection_hostname);
1745 /* In repsonse to the register, the daemon will send back a LOGFILE_REPLY */
1746 /* message that contains the name of a logfile to be used to do user */
1747 /* authentication. For A.02 and later daemons, it will also contain */
1748 /* the spc protocol version and info about the host the daemon is on. */
1750 READ_LOGFILE_REPLY(prot->dataptr, &logfile, &proto_ver, &hostinfo);
1752 /* For Pre A.01, this will be defaulted to (hpux 7.0 s300) */
1753 connection->hostinfo = hostinfo;
1756 sscanf(proto_ver, "%d", &connection->protocol_version);
1760 SPC_Free_Protocol_Ptr(prot);
1762 if(!strcmp(logfile, PASSED_FILE_NAME))
1764 if(!strcmp(logfile, FAILED_FILE_NAME)) {
1765 SPC_Error(SPC_Register_Username,
1766 (username) ? username : (XeString)"<empty user>",
1767 connection_hostname);
1768 XeFree(connection_hostname);
1769 if (logfile) XeFree(logfile);
1774 * Get a pathname to the authentication file.
1776 path=tt_netfile_file(logfile);
1778 if(tt_ptr_error (path) != TT_OK) {
1779 SPC_Write_Protocol_Request(connection, NULL, ABORT);
1780 SPC_Error(SPC_Register_Netrc,
1782 connection_hostname);
1783 XeFree(connection_hostname);
1784 if (logfile) XeFree(logfile);
1788 open_status=open(path, O_CREAT, S_ISUID);
1789 if(open_status==ERROR) {
1790 SPC_Write_Protocol_Request(connection, NULL, ABORT);
1791 SPC_Error(SPC_Register_Open,
1793 connection_hostname);
1795 XeFree(connection_hostname);
1796 if (logfile) XeFree(logfile);
1800 /* We need to also do a chmod because of an apparent Domain/OS bug
1801 where the open call does not properly set the UID bit. We
1802 let chmod set the bit. */
1804 chmod_status=chmod(path, S_ISUID);
1805 if(chmod_status==ERROR) {
1806 SPC_Write_Protocol_Request(connection, NULL, ABORT);
1807 SPC_Error(SPC_Register_Open,
1809 connection_hostname);
1811 XeFree(connection_hostname);
1812 if (logfile) XeFree(logfile);
1816 SPC_Write_Protocol_Request(connection, NULL, REGISTER, logfile, NULL, NULL, NULL);
1817 prot=SPC_Filter_Connection(connection, NULL, LOGFILE_REPLY, TRUE);
1823 if(prot==SPC_ERROR) {
1824 XeFree(connection_hostname);
1829 * Free logfile before it gets malloc'd again.
1833 READ_LOGFILE_REPLY(prot->dataptr, &logfile, &junk1, &junk2);
1834 if (junk1) XeFree(junk1);
1835 if (junk2) XeFree(junk2);
1837 SPC_Free_Protocol_Ptr(prot);
1839 if(!strcmp(logfile, PASSED_FILE_NAME)) {
1840 XeFree(connection_hostname);
1841 if (logfile) XeFree(logfile);
1844 if(!strcmp(logfile, FAILED_FILE_NAME)) {
1845 SPC_Error(SPC_Register_Handshake,
1847 connection_hostname);
1848 XeFree(connection_hostname);
1849 if (logfile) XeFree(logfile);
1853 if (logfile) XeFree(logfile);
1854 XeFree(connection_hostname);
1855 SPC_Error(SPC_Protocol);
1860 /*----------------------------------------------------------------------+*/
1861 static int SPC_Send_Termios(protocol_request_ptr prot_request)
1862 /*----------------------------------------------------------------------+*/
1864 struct termios *tio;
1868 tio = SPC_Get_Current_Termio(); /* Gets a (malloced) copy */
1869 s = SPC_Decode_Termios( tio ); /* Get ASCII representation */
1871 retval = WRITE_STRING(prot_request->dataptr, s);
1880 /*----------------------------------------------------------------------+*/
1881 int SPC_Get_Termios(protocol_request_ptr prot_request)
1882 /*----------------------------------------------------------------------+*/
1887 _DtSvcProcessLock();
1888 if(XeTermioStruct == NULL) {
1889 XeTermioStruct = (struct termios *)XeMalloc(sizeof(struct termios));
1891 for(i=0; i<NCCS; i++)
1892 XeTermioStruct->c_cc[i] = 0;
1895 READ_STRING_NO_COPY(prot_request->dataptr, s);
1897 SPC_Encode_Termios(s, XeTermioStruct);
1899 _DtSvcProcessUnlock();
1900 return(XeSetpgrp(FALSE));
1905 /*----------------------------------------------------------------------+*/
1906 int SPC_Get_Termio(protocol_request_ptr UNUSED_PARM(prot_request))
1907 /*----------------------------------------------------------------------+*/
1909 /* This is for old 1.0, 1.1 versions of the SPC code. We used to */
1910 /* pass an HPUX version of the termio struct around. This was not */
1911 /* portable. If we get one of these requests, just bit bucket it */
1912 /* as we do not know how to deal with it. */
1914 return(XeSetpgrp(FALSE));
1917 static int SPC_Send_B00_Spawn(SPC_Connection_Ptr connection,
1918 protocol_request_ptr prot,
1925 int num_elts=0, this_elt, num_argv, num_envp;
1926 char argv_buf[20], envp_buf[20];
1930 while(argv && argv[num_argv++])
1934 while(envp && envp[num_envp++])
1937 merged_ptr = (char **)malloc((num_elts+6) * sizeof(char *));
1939 sprintf(argv_buf, "%d", num_argv);
1940 sprintf(envp_buf, "%d", num_envp);
1943 merged_ptr[num_elts++] = path;
1944 merged_ptr[num_elts++] = dir;
1945 merged_ptr[num_elts++] = argv_buf;
1946 merged_ptr[num_elts++] = envp_buf;
1949 while(argv && argv[this_elt])
1950 merged_ptr[num_elts++] = argv[this_elt++];
1952 merged_ptr[num_elts++] = "DUMMY";
1955 while(envp && envp[this_elt])
1956 merged_ptr[num_elts++] = envp[this_elt++];
1958 merged_ptr[num_elts] = NULL;
1960 retval = SPC_Send_Multi_Packet(connection, prot,
1961 merged_ptr, num_elts,
1962 APP_B00_SPAWN, " <-- APP_B00_SPAWN",
1965 free((char *)merged_ptr);