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 libraries 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>
46 #define X_INCLUDE_PWD_H
47 #define XOS_USE_XT_LOCKING
48 #include <X11/Xos_r.h>
52 #include <bms/MemoryMgr.h>
54 #include <SPC/spc-proto.h>
57 #include "DtSvcLock.h"
62 extern struct termios *XeTermioStruct; /* In pty.c */
64 extern XeString *environ;
65 extern SPC_Channel_Ptr spc_activation_list;
70 /* FILE *SPC_Print_Protocol=NULL; -- now in bmsglob.c */
72 SPC_Connection_Ptr connection_list = NULL;
73 protocol_request_ptr free_protocol_requests = NULL;
78 static int SPC_Send_Termios(protocol_request_ptr prot_request);
79 static int SPC_Send_B00_Spawn(SPC_Connection_Ptr connection,
80 protocol_request_ptr prot,
86 /*----------------------------------------------------------------------+*/
87 buffered_data_ptr SPC_New_Buffered_Data_Ptr(void)
88 /*----------------------------------------------------------------------+*/
90 buffered_data_ptr bdata;
92 bdata=(buffered_data_ptr)XeMalloc(sizeof(buffered_data));
93 bdata->len = bdata->offset = 0;
98 /*----------------------------------------------------------------------+*/
99 void SPC_Reset_Protocol_Ptr (protocol_request_ptr prot,
100 SPC_Channel_Ptr channel,
103 /*----------------------------------------------------------------------+*/
105 buffered_data_ptr dptr=prot->dataptr;
110 prot->request_type = req;
111 prot->channel = channel;
113 memset(dptr->data, (XeChar)' ', REQUEST_HEADER_LENGTH);
116 /*----------------------------------------------------------------------+*/
117 protocol_request_ptr SPC_New_Protocol_Ptr (SPC_Channel_Ptr channel,
120 /*----------------------------------------------------------------------+*/
122 protocol_request_ptr prot;
125 if(free_protocol_requests) {
126 prot = free_protocol_requests;
127 free_protocol_requests = free_protocol_requests->next;
129 prot = (protocol_request_ptr)XeMalloc(sizeof(protocol_request));
130 prot->dataptr = SPC_New_Buffered_Data_Ptr();
132 SPC_Reset_Protocol_Ptr(prot, channel, req, len);
133 _DtSvcProcessUnlock();
137 /*----------------------------------------------------------------------+*/
138 void SPC_Free_Protocol_Ptr(protocol_request_ptr prot)
139 /*----------------------------------------------------------------------+*/
142 prot->next = free_protocol_requests;
143 free_protocol_requests = prot;
144 _DtSvcProcessUnlock();
148 /*----------------------------------------------------------------------+*/
149 SPC_Channel_Ptr SPC_Lookup_Channel(int cid,
150 SPC_Connection_Ptr connection)
151 /*----------------------------------------------------------------------+*/
160 for(spc=spc_activation_list; spc; spc=spc->next)
161 /* This test is here because:
162 a. Only remote channels have cid's
163 b. It is possible for multiple remote servers to have
164 the same cid (which is simply the address of the channel),
165 so we need to distinguish among remote channels, but
166 c. channels on the remote daemon have cid's, but a null connection.
168 if((spc->cid == cid) &&
170 (spc->connection == connection))) {
171 _DtSvcProcessUnlock();
175 _DtSvcProcessUnlock();
180 * Connection management routines
184 /*----------------------------------------------------------------------+*/
185 SPC_Connection_Ptr SPC_Alloc_Connection(void)
186 /*----------------------------------------------------------------------+*/
188 SPC_Connection_Ptr conn;
191 conn=(SPC_Connection_Ptr) XeMalloc(sizeof(SPC_Connection));
192 /* Zero the connection */
193 memset(conn, 0, sizeof(SPC_Connection));
194 conn->queued_remote_data = Xe_make_queue(FALSE);
195 conn->termination_id = (-1);
196 /* Init the socket id to "-1" because "0" is a valid file descriptor. */
198 _DtSvcProcessUnlock();
203 /*----------------------------------------------------------------------+*/
204 SPC_Connection_Ptr SPC_Lookup_Connection(XeString hostname)
205 /*----------------------------------------------------------------------+*/
207 /* Search for an existing connection to a server */
208 SPC_Connection_Ptr conn;
211 for (conn = connection_list; conn != NULL; conn = conn->next) {
213 /* Look for a connection with the same hostname */
214 if (!strcmp(conn->hostname, hostname)) {
215 _DtSvcProcessUnlock();
220 _DtSvcProcessUnlock();
224 /*----------------------------------------------------------------------+*/
225 SPC_Connection_Ptr SPC_Lookup_Connection_Fd(int fd)
226 /*----------------------------------------------------------------------+*/
228 /* Search for an existing connection to a server, using fd (file descriptor)
230 SPC_Connection_Ptr conn;
233 for (conn = connection_list; conn != NULL; conn = conn->next) {
235 /* Look for a connection with the same hostname */
237 _DtSvcProcessUnlock();
242 _DtSvcProcessUnlock();
246 /*----------------------------------------------------------------------+*/
247 SPC_Connection_Ptr SPC_Make_Connection(XeString hostname)
248 /*----------------------------------------------------------------------+*/
250 /* Search for a connection to hostname, create one if none exists */
252 SPC_Connection_Ptr conn;
254 /* Searching for connected host maintains only one connection per remote */
256 if(hostname && (conn=SPC_Lookup_Connection(hostname)))
259 /* Not found, so make one */
261 if((conn = SPC_Alloc_Connection())==SPC_ERROR)
265 strcpy(conn->hostname, hostname);
267 SPC_Add_Connection(conn);
271 /*----------------------------------------------------------------------+*/
272 void SPC_Add_Connection(SPC_Connection_Ptr connection)
273 /*----------------------------------------------------------------------+*/
276 /* Add a connection to the connection_list */
278 connection->next = connection_list;
279 connection_list = connection;
280 _DtSvcProcessUnlock();
283 /*----------------------------------------------------------------------+*/
284 void SPC_Close_Connection(SPC_Connection_Ptr connection)
285 /*----------------------------------------------------------------------+*/
287 SPC_Channel_Ptr channel;
288 SPC_Channel_Ptr next;
289 SPC_Connection_Ptr trail, ptr;
291 /* We have to be careful here. SPC_Input_Handler may call the users
292 termination handler, which in turn might close the channel, which
293 may deallocate the channel. Therefore, we grab the next channel
294 from the list while we are still alive. */
297 channel=spc_activation_list;
298 connection->connected = FALSE;
302 if(channel->connection == connection) {
303 if(!IS_SPCIO_DELAY_CLOSE(channel->IOMode))
304 SPC_Channel_Terminated(channel);
305 channel->connection = NULL;
310 SPC_XtRemoveInput(&connection->termination_id, SPC_Terminator);
312 spc_close(connection->sid);
313 connection->sid = (-1);
315 if (connection->hostinfo)
316 XeFree(connection->hostinfo);
318 /* Remove the connection from the connection list */
320 if(connection_list == connection)
321 connection_list = connection->next;
323 trail = connection_list;
326 if(ptr == connection) {
327 trail->next = ptr->next;
333 /* Here if no such connection found. */
337 free((char *)connection);
338 _DtSvcProcessUnlock();
343 ** Read the specified number of characters, or die trying.
347 /*----------------------------------------------------------------------+*/
348 int SPC_Read_Chars(SPC_Connection_Ptr connection,
351 /*----------------------------------------------------------------------+*/
354 int numchars, numread;
355 int numtoread=request_len;
356 int sid=connection->sid;
360 while(numread<request_len) {
362 numchars=read(sid, charptr, numtoread);
363 while(numchars == ERROR && errno == EINTR);
364 if(numchars == ERROR) {
365 XeString connection_hostname = CONNECTION_HOSTNAME(connection);
366 if(errno == ECONNRESET)
367 SPC_Error(SPC_Connection_Reset, connection_hostname);
369 SPC_Error(SPC_Reading, connection_hostname);
370 XeFree(connection_hostname);
374 XeString connection_hostname = CONNECTION_HOSTNAME(connection);
375 SPC_Error(SPC_Connection_EOF, connection_hostname);
376 XeFree(connection_hostname);
377 return(SPC_ERROR); /* Bad news, EOF on incoming channel */
381 numtoread -= numchars;
383 *charptr=(XeChar)'\0';
387 /* Write len chars, or die trying */
389 /*----------------------------------------------------------------------+*/
390 int SPC_Write_Chars(int fd,
393 /*----------------------------------------------------------------------+*/
395 int numchars, numwritten;
396 int numtowrite=request_len;
400 while(numwritten<request_len) {
402 numchars=write(fd, charptr, numtowrite);
403 while(numchars == ERROR && errno == EINTR);
407 if(SPC_Print_Protocol)
408 fprintf(SPC_Print_Protocol,
409 "SPC_Write_Chars -- wrote: %d of %d, expected: %d, errno: %d\n",
410 numchars, request_len, numtowrite, errno);
411 _DtSvcProcessUnlock();
414 if(numchars == ERROR)
418 numwritten += numchars;
419 numtowrite -= numchars;
427 ** Read a single protocol request from the passed channel.
431 /*----------------------------------------------------------------------+*/
432 protocol_request_ptr SPC_Read_Protocol(SPC_Connection_Ptr connection)
433 /*----------------------------------------------------------------------+*/
436 protocol_request_ptr prot;
437 buffered_data_ptr dptr;
440 if(!connection->connected)
443 if((prot=SPC_New_Protocol_Ptr(NULL, 0, 0))==SPC_ERROR) {
444 SPC_Close_Connection(connection);
452 len=SPC_Read_Chars(connection, REQUEST_HEADER_LENGTH, dptr->data);
453 if(len != REQUEST_HEADER_LENGTH) {
454 SPC_Close_Connection(connection);
455 SPC_Free_Protocol_Ptr(prot);
459 /* we have the header. Parse out the fields */
462 &channel_id, &prot->request_type, &dptr->len, &prot->seqno);
463 prot->channel=SPC_Lookup_Channel(channel_id, connection);
466 /* JET - 11/12/2001 - correct an exploitable buffer overrun where the user */
467 /* can supply a data len that is larger than the available buffer */
469 /* CERT - VU#172583 */
471 if (dptr->len >= MAXREQLEN)
472 { /* we have a problem. Initiate DefCon 1 */
473 /* and launch our missiles. */
474 XeString connection_hostname = CONNECTION_HOSTNAME(connection);
476 SPC_Error(SPC_Buffer_Overflow, connection_hostname);
477 XeFree(connection_hostname);
478 SPC_Close_Connection(connection);
479 SPC_Free_Protocol_Ptr(prot);
485 len=SPC_Read_Chars(connection, dptr->len, dptr->data+REQUEST_HEADER_LENGTH);
486 if(len != dptr->len) {
487 SPC_Close_Connection(connection);
488 SPC_Free_Protocol_Ptr(prot);
492 dptr->offset=REQUEST_HEADER_LENGTH;
499 ** Filter the connection for the desired type of protocol request.
500 ** If there is a protocol request of the desired type already queued,
501 ** return it. If not, read a new one. If we read requests destined
502 ** for another channel, or for our channel but not the correct
503 ** request type, queue it up. If the deletep flag is TRUE, remove it
508 /*----------------------------------------------------------------------+*/
509 protocol_request_ptr SPC_Filter_Connection(SPC_Connection_Ptr connection,
510 SPC_Channel_Ptr channel,
513 /*----------------------------------------------------------------------+*/
515 SPC_Connection_Ptr connptr=NULL;
516 SPC_Channel_Ptr conn_channel;
518 protocol_request_ptr retval;
521 /* check if there are any queued prot. requests. If so,
522 check for their having the type we want */
524 if(channel && (tmpqueue=channel->queued_remote_data)) {
525 tmpqueue=channel->queued_remote_data;
527 Xe_for_queue(protocol_request_ptr, retval, tmpqueue) {
528 /* found a queued packet. Is it what we are looking for? */
529 if(retval->request_type == reqtype) {
532 Xe_delete_queue_element(channel->queued_remote_data, retval);
539 /* No queued elements. Read until we get the reply we
542 if((retval=SPC_Read_Protocol(connection))==SPC_ERROR)
545 protreqtype=retval->request_type;
546 conn_channel=retval->channel;
548 if(protreqtype == ABORT) {
549 XeString connection_hostname = CONNECTION_HOSTNAME(connection);
550 SPC_Error(SPC_Protocol_Abort, connection_hostname);
551 XeFree (connection_hostname);
556 if(protreqtype == SERVER_ERROR) {
557 READ_ERROR(retval->dataptr, XeSPCErrorNumber);
558 SPC_Error(XeSPCErrorNumber, XeString_NULL, 0);
559 _DtSvcProcessUnlock();
562 _DtSvcProcessUnlock();
567 if((conn_channel == channel) && (protreqtype == reqtype)) {
568 /* We found one that matches. Check if we need to queue it up. */
570 Xe_push_queue(conn_channel->queued_remote_data, retval);
574 /* No match. Queue it up */
575 if(IS_SPCIO_SYNC_TERM(channel->IOMode))
576 Xe_push_queue(connection->queued_remote_data, retval);
578 Xe_push_queue(conn_channel->queued_remote_data, retval);
583 /*----------------------------------------------------------------------+*/
584 void SPC_Flush_Queued_Data(SPC_Channel_Ptr channel)
585 /*----------------------------------------------------------------------+*/
588 protocol_request_ptr prot;
590 if((tmpqueue=channel->queued_remote_data)) {
591 while((prot=(protocol_request_ptr)Xe_pop_queue(tmpqueue)))
592 SPC_Free_Protocol_Ptr(prot);
595 if(channel->connection && (tmpqueue=channel->connection->queued_remote_data))
597 Xe_for_queue(protocol_request_ptr, prot, tmpqueue) {
598 if(prot->channel == channel) {
599 Xe_delete_queue_element(tmpqueue, prot);
600 SPC_Free_Protocol_Ptr(prot);
606 /*----------------------------------------------------------------------+*/
607 int SPC_Read_Remote_Data(SPC_Channel_Ptr channel,
609 XeString client_buffer,
611 /*----------------------------------------------------------------------+*/
615 SPC_Connection_Ptr connection=channel->connection;
616 protocol_request_ptr prot;
617 buffered_data_ptr pdata;
618 int req_type=CONNECTOR_TO_PROT(connector);
620 prot=SPC_Filter_Connection(connection, channel, req_type, FALSE);
626 ret_len = min(nbytes, pdata->len);
628 memcpy(client_buffer, pdata->data+pdata->offset, ret_len);
629 pdata->offset += ret_len;
630 pdata->len -= ret_len;
631 if(pdata->len == 0) {
632 SPC_Filter_Connection(connection, channel, req_type, TRUE);
633 SPC_Free_Protocol_Ptr(prot);
639 /* Dump out a protocol request */
641 /*----------------------------------------------------------------------+*/
642 int print_protocol_request(XeString name, protocol_request_ptr proto)
643 /*----------------------------------------------------------------------+*/
645 buffered_data_ptr dptr = proto->dataptr;
648 if(!SPC_Print_Protocol) {
649 _DtSvcProcessUnlock();
653 dptr->data[dptr->offset+dptr->len]=0;
655 fprintf(SPC_Print_Protocol,
656 "%s channel: %p, request: %d, length: %d, seq: %d data: %s\n",
657 name, proto->channel, proto->request_type, dptr->len, proto->seqno,
658 dptr->data+dptr->offset);
660 fflush(SPC_Print_Protocol);
662 _DtSvcProcessUnlock();
667 * Write a protocol request to the given channel
671 int current_sequence_number=1;
673 /*----------------------------------------------------------------------+*/
674 int SPC_Write_Protocol_Request (SPC_Connection_Ptr connection,
675 SPC_Channel_Ptr channel,
678 /*----------------------------------------------------------------------+*/
681 protocol_request_ptr prot_request;
682 buffered_data_ptr pdata;
684 XeString prot_name=NULL;
686 prot_request=SPC_New_Protocol_Ptr(channel, request, 0);
687 pdata=prot_request->dataptr;
689 prot_request->seqno = current_sequence_number++;
690 _DtSvcProcessUnlock();
692 /* We are overloading the "channel" field. We put the cid rather */
693 /* than the actual channel pointer in when we pass it to the other */
694 /* side of the connection. */
695 prot_request->channel=(SPC_Channel_Ptr) (intptr_t) (channel ? channel->cid : 0);
700 pdata->len=WRITE_ABORT(pdata, 0);
701 prot_name=(XeString)" <-- ABORT";
711 va_start(ap, request);
712 username=va_arg(ap, XeString );
713 passwd=va_arg(ap, XeString );
714 proto_ver=va_arg(ap, XeString );
715 hostinfo=va_arg(ap, XeString );
717 pdata->len=WRITE_REGISTER(pdata, username, passwd, proto_ver, hostinfo);
718 prot_name=(XeString)" <-- REGISTER";
724 prot_name=(XeString)" <-- UNREGISTER";
728 va_start(ap, request);
729 pdata->len=WRITE_OPEN(pdata, va_arg(ap, int));
731 prot_name=(XeString)" <-- CHANNEL_OPEN";
735 /* This is correct. This protocol request takes no args */
736 prot_name=(XeString)" <-- CHANNEL_CLOSE";
740 /* This one, either */
741 prot_name=(XeString)" <-- CHANNEL_RESET";
745 prot_name=(XeString)" <-- CHANNEL_ATTACH";
746 va_start(ap, request);
747 pdata->len=WRITE_ATTACH(pdata, va_arg(ap, int));
751 case APPLICATION_SPAWN:
758 va_start(ap, request);
760 /* It is left as an exercise to the reader to figure out
761 what would happen if we didn't use these temp. variables
762 and instead used the va_arg macros directly in the
763 WRITE_APPLICATION_SPAWN... */
765 path=va_arg(ap, XeString );
766 dir =va_arg(ap, XeString );
767 argv=va_arg(ap, XeString *);
768 envp=va_arg(ap, XeString *);
770 pdata->len=WRITE_APPLICATION_SPAWN(pdata, path, dir, argv, envp);
771 if(pdata->len == SPC_ERROR) {
772 SPC_Free_Protocol_Ptr(prot_request);
775 prot_name=(XeString)" <-- APPLICATION_SPAWN";
779 case APPLICATION_SIGNAL:
781 if (connection->protocol_version >= 2)
785 va_start(ap, request);
786 signame = va_arg(ap, XeString);
789 pdata->len=WRITE_STRING(pdata, signame);
795 va_start(ap, request);
796 sig = va_arg(ap, int);
799 pdata->len=WRITE_INT(pdata, sig);
802 prot_name=(XeString)" <-- APPLICATION_SIGNAL";
806 case APPLICATION_DIED:
807 va_start(ap, request);
808 pdata->len=WRITE_APPLICATION_DIED(pdata, va_arg(ap, int));
810 prot_name=(XeString)" <-- APPLICATION_DIED";
813 case APPLICATION_DATA:
814 prot_name=(XeString)" <-- APPLICATION_DATA";
816 case APPLICATION_STDOUT:
818 prot_name=(XeString)" <-- APPLICATION_STDOUT";
820 case APPLICATION_STDERR:
826 prot_name=(XeString)" <-- APPLICATION_STDERR";
828 va_start(ap, request);
829 buffer=va_arg(ap, XeString );
830 buflen=va_arg(ap, int);
833 pdata->len=WRITE_APP_DATA(pdata, buffer, buflen);
839 va_start(ap, request);
840 pdata->len=WRITE_ERROR(pdata, va_arg(ap, int));
842 prot_name=(XeString)" <-- SERVER_ERROR";
847 int replyval, errval;
849 va_start(ap, request);
850 prot_request->seqno=va_arg(ap, int);
851 replyval=va_arg(ap, int);
852 errval=va_arg(ap, int);
854 pdata->len=WRITE_REPLY(pdata, replyval, errval);
855 prot_name=(XeString)" <-- REPLY";
868 va_start(ap, request);
869 m0=va_arg(ap, XeString );
870 s0=va_arg(ap, XeString );
871 m1=va_arg(ap, XeString );
872 s1=va_arg(ap, XeString );
873 m2=va_arg(ap, XeString );
874 s2=va_arg(ap, XeString );
876 pdata->len=WRITE_DEVICE_REPLY(pdata, m0, s0, m1, s1, m2, s2);
877 prot_name=(XeString)" <-- DEVICE_REPLY";
882 prot_name=(XeString)" <-- QUERY_DEVICES";
891 va_start(ap, request);
892 fname=va_arg(ap, XeString );
893 proto_ver=va_arg(ap, XeString );
894 hostinfo=va_arg(ap, XeString );
896 pdata->len=WRITE_LOGFILE_REPLY(pdata, fname, proto_ver, hostinfo);
897 prot_name=(XeString)" <-- LOGFILE_REPLY";
902 prot_name=(XeString)" <-- QUERY_LOGFILE";
906 prot_name=(XeString)" <-- DELETE_LOGFILE";
910 va_start(ap, request);
911 pdata->len=WRITE_DEBUG(pdata, va_arg(ap, XeString));
913 prot_name=(XeString)" <-- SERVER_DEBUG";
917 return(SPC_Send_Environ(connection, prot_request));
919 /* We used to send the hp-ux version of a termio struct */
920 /* This is non-portable, so we don't do it anymore. */
923 pdata->len=SPC_Send_Termios(prot_request);
924 prot_name=(XeString)" <-- RESET_TERMIOS";
927 /* B.00 (protocol version 3) requests */
929 case CHANNEL_SEND_EOF:
931 if(connection->protocol_version < 3) {
932 SPC_Error(SPC_Protocol_Version_Error,
933 3, channel->connection->protocol_version);
934 SPC_Free_Protocol_Ptr(prot_request);
938 prot_name = (XeString)" <-- CHANNEL_SEND_EOF";
941 case CHANNEL_TERMIOS:
943 if(connection->protocol_version < 3) {
944 SPC_Error(SPC_Protocol_Version_Error,
945 3, channel->connection->protocol_version);
946 SPC_Free_Protocol_Ptr(prot_request);
952 struct termios *termios_ptr;
955 va_start(ap, request);
957 connector = va_arg(ap, int);
958 side = va_arg(ap, int);
959 termios_ptr = va_arg(ap, struct termios *);
962 buffer = SPC_Decode_Termios(termios_ptr);
963 pdata->len=WRITE_TERMIOS(pdata, connector, side, buffer);
964 prot_name=(XeString)" <-- CHANNEL_TERMIOS";
970 if(connection->protocol_version < 3) {
971 SPC_Error(SPC_Protocol_Version_Error,
972 3, channel->connection->protocol_version);
973 SPC_Free_Protocol_Ptr(prot_request);
984 va_start(ap, request);
986 /* It is left as an exercise to the reader to figure out
987 what would happen if we didn't use these temp. variables
988 and instead used the va_arg macros directly in the
989 WRITE_APPLICATION_SPAWN... */
991 path=va_arg(ap, XeString );
992 dir =va_arg(ap, XeString );
993 argv=va_arg(ap, XeString *);
994 envp=va_arg(ap, XeString *);
998 SPC_Send_B00_Spawn(connection, prot_request, path, dir, argv, envp);
1005 SPC_Write_Single_Prot_Request(connection, prot_name, prot_request);
1007 SPC_Free_Protocol_Ptr(prot_request);
1008 return(reply_expected);
1012 /*----------------------------------------------------------------------+*/
1013 int SPC_Write_Single_Prot_Request(SPC_Connection_Ptr connection,
1015 protocol_request_ptr prot)
1016 /*----------------------------------------------------------------------+*/
1018 int reply_expected, length;
1019 buffered_data_ptr pdata=prot->dataptr;
1021 if(!connection->connected)
1025 REPLY_EXPECTED(prot->request_type, prot->seqno);
1026 length=WRITE_HEADER(pdata, prot->channel,
1030 pdata->data[length]=(XeChar)' ';
1032 length=pdata->len+REQUEST_HEADER_LENGTH;
1033 if(SPC_Write_Chars(connection->sid, pdata->data, length) == ERROR) {
1034 XeString connection_hostname = CONNECTION_HOSTNAME(connection);
1035 SPC_Close_Connection(connection);
1036 SPC_Error(SPC_Write_Prot, connection_hostname);
1037 XeFree(connection_hostname);
1038 reply_expected = (SPC_ERROR);
1041 pdata->offset=REQUEST_HEADER_LENGTH;
1042 print_protocol_request(name, prot);
1044 return(reply_expected);
1047 /*----------------------------------------------------------------------+*/
1048 int SPC_Waitfor_Reply(SPC_Connection_Ptr connection,
1049 SPC_Channel_Ptr channel,
1051 /*----------------------------------------------------------------------+*/
1054 protocol_request_ptr prot;
1058 if(seqno == NO_REPLY_VAL)
1061 if(seqno==SPC_ERROR)
1064 prot=SPC_Filter_Connection(connection, channel, REPLY, TRUE);
1069 thisseq = prot->seqno;
1070 READ_REPLY(prot->dataptr, retval, errval);
1072 SPC_Free_Protocol_Ptr(prot);
1074 if(thisseq != seqno) {
1075 SPC_Error(SPC_Unexpected_Reply);
1082 if(retval != SPC_Protocol_Abort) {
1083 if (retval == SPC_Cannot_Create_Netfilename)
1084 SPC_Error(retval, channel->context_dir, connection->hostname);
1085 else if (retval == SPC_Cannot_Exec)
1086 SPC_Error(retval, channel->path, 0);
1087 else if (retval == SPC_cannot_Chdir)
1088 SPC_Error(retval, channel->context_dir, 0);
1090 SPC_Error(retval, XeString_NULL, 0);
1098 /*----------------------------------------------------------------------+*/
1099 int SPC_Dispatch_Protocol(protocol_request_ptr proto,
1100 protocol_request_handler *table)
1101 /*----------------------------------------------------------------------+*/
1107 req_type=proto->request_type;
1109 if(req_type<0 || req_type>NREQS)
1112 return((* table[req_type])(proto));
1115 /*----------------------------------------------------------------------+*/
1116 int SPC_Write_Reply(SPC_Connection_Ptr conn,
1117 protocol_request_ptr proto,
1120 /*----------------------------------------------------------------------+*/
1122 _DtSvcProcessLock();
1124 retval=(-XeSPCErrorNumber);
1125 _DtSvcProcessUnlock();
1127 return(SPC_Write_Protocol_Request(conn, proto->channel, REPLY,
1128 proto->seqno, retval, errval));
1133 ** Send the current environment out to the world.
1137 #define valid_str(x) (((x) != NULL) && (*(x) != 0))
1138 #define NULL_STR "\001\001\001"
1139 #define EMPTY_STR "\001\002\003"
1141 int SPC_Send_Multi_Packet(SPC_Connection_Ptr connection,
1142 protocol_request_ptr prot,
1149 int counter, tmp_len;
1150 int bytes_left, numbytes;
1157 _DtSvcProcessLock();
1158 this_seqno=current_sequence_number;
1159 numbytes=WRITE_ENVIRON_RESET(prot->dataptr, num_str);
1160 bytes_left=SPC_BUFSIZ-numbytes;
1161 buf=(PDRP(prot->dataptr) + numbytes);
1162 reply_seqno=prot->seqno;
1164 for(counter=0; counter<num_str; counter++) {
1165 this_str = str_vect[counter];
1167 if(this_str == NULL)
1168 this_str = NULL_STR;
1169 if(*this_str == '\0')
1170 this_str = EMPTY_STR;
1172 tmp_len=strlen(this_str)+1; /* Room for NULL char */
1173 if((bytes_left-tmp_len) < 1) {
1175 prot->dataptr->len=numbytes+1;
1176 SPC_Write_Single_Prot_Request(connection, name, prot);
1177 SPC_Free_Protocol_Ptr(prot);
1178 prot=SPC_New_Protocol_Ptr(0, req, 0);
1179 prot->seqno=current_sequence_number++;
1181 bytes_left=SPC_BUFSIZ;
1182 buf=(PDRP(prot->dataptr) + numbytes);
1185 if(tmp_len>SPC_BUFSIZ-1) {
1189 SPC_Free_Protocol_Ptr(prot);
1190 if(this_seqno != current_sequence_number)
1191 SPC_Write_Protocol_Request(connection, NULL, ABORT);
1192 _DtSvcProcessUnlock();
1193 return(reply_seqno);
1196 strncpy(buf, this_str, tmp_len);
1197 bytes_left -= tmp_len;
1198 numbytes += tmp_len;
1204 prot->dataptr->len=numbytes+1;
1205 SPC_Write_Single_Prot_Request(connection, (XeString)" <-- ENVIRON_RESET", prot);
1206 SPC_Free_Protocol_Ptr(prot);
1209 _DtSvcProcessUnlock();
1210 return(reply_seqno);
1214 char **SPC_Get_Multi_Packet(SPC_Connection_Ptr connection,
1215 protocol_request_ptr prot,
1222 int num_vars, i, len;
1224 protocol_request_ptr localprot = NULL;
1226 print_protocol_request(name, prot);
1227 READ_ENVIRON_RESET(prot->dataptr, num_vars);
1228 bufptr=strchr(PDRP(prot->dataptr), Space)+1;
1230 out = (char **)malloc((num_vars+1) * sizeof(char **));
1232 for(i=0; i<num_vars; i++) {
1236 SPC_Free_Protocol_Ptr(localprot);
1237 prot=SPC_Filter_Connection(connection, NULL, request, TRUE);
1238 if(prot==SPC_ERROR) {
1242 print_protocol_request(name, prot);
1244 bufptr=PDRP(prot->dataptr);
1247 if(strcmp(bufptr, NULL_STR) == 0)
1250 if(strcmp(bufptr, EMPTY_STR) == 0)
1251 out[i] = strdup("");
1253 out[i] = strdup(bufptr);
1258 SPC_Free_Protocol_Ptr(localprot);
1261 out[num_vars] = NULL;
1266 /*----------------------------------------------------------------------+*/
1267 int SPC_Send_Environ(SPC_Connection_Ptr connection,
1268 protocol_request_ptr prot)
1269 /*----------------------------------------------------------------------+*/
1275 _DtSvcProcessLock();
1276 while(environ[ep_count])
1279 result = SPC_Send_Multi_Packet(connection, prot, environ, ep_count,
1280 ENVIRON_RESET, " <-- ENVIRON_RESET",
1282 _DtSvcProcessUnlock();
1286 /*----------------------------------------------------------------------+*/
1287 int sprint_counted_string(XeString buf,
1291 /*----------------------------------------------------------------------+*/
1293 XeString bufptr=buf;
1296 int limit=orig_limit;
1297 #define ERRBUFLEN 100
1298 char errbuf[ERRBUFLEN];
1300 len=sprintf_len(bufptr, (XeString)"%x ", count)+1;
1302 sprintf(errbuf, "(%d chars), max. length is %d", len, orig_limit);
1303 SPC_Error(SPC_Arg_Too_Long,
1311 for(i=0; i<count; (i++, vect++)) {
1313 len = strlen(*vect)+1;
1318 sprintf(errbuf, "(%d chars), max. length is %d", len, orig_limit);
1319 SPC_Error(SPC_Arg_Too_Long,
1324 sprintf(bufptr, "%s", *vect ? *vect : "");
1332 /*----------------------------------------------------------------------+*/
1333 XeString *sscan_counted_string(XeString buf,
1335 /*----------------------------------------------------------------------+*/
1338 int i, numstrings, len;
1343 sscanf(buf, (XeString)"%x", &numstrings);
1347 tmpptr=(XeString*)XeMalloc((numstrings+1) * sizeof(XeString *));
1350 for(i=0; i<numstrings; (i++, tmpidx++)){
1351 len=strlen(bufptr)+1; /* len is string SIZE (with room for NULL) */
1352 *tmpidx=(XeString)XeMalloc(len);
1353 strncpy(*tmpidx, bufptr, len);
1354 (*tmpidx)[len-1]='\0';
1363 /*----------------------------------------------------------------------+*/
1365 sprint_application_data(XeString buf,
1366 XeString UNUSED_PARM(fmt),
1371 int UNUSED_PARM(chars_used))
1372 /*----------------------------------------------------------------------+*/
1382 while(argv[av_count]) av_count++;
1385 while(envp[ep_count]) ep_count++;
1389 tmp_len = sprint_counted_string(buf, 1, &path, limit);
1390 if(tmp_len == SPC_ERROR)
1394 data_len += tmp_len;
1396 tmp_len = sprint_counted_string(buf, 1, &dir, limit);
1397 if(tmp_len == SPC_ERROR)
1401 data_len += tmp_len;
1403 tmp_len = sprint_counted_string(buf, av_count, argv, limit);
1404 if(tmp_len == SPC_ERROR)
1408 data_len += tmp_len;
1410 tmp_len = sprint_counted_string(buf, ep_count, envp, limit);
1411 if(tmp_len == SPC_ERROR)
1415 data_len += tmp_len;
1420 /*----------------------------------------------------------------------+*/
1422 sscan_application_data(XeString buf,
1423 XeString UNUSED_PARM(fmt),
1428 int UNUSED_PARM(offset))
1429 /*----------------------------------------------------------------------+*/
1436 tmp_vect=sscan_counted_string(bufptr, &bufptr);
1437 if(tmp_vect==SPC_ERROR)
1439 *path = (*tmp_vect);
1441 tmp_vect=sscan_counted_string(bufptr, &bufptr);
1442 if(tmp_vect==SPC_ERROR)
1446 *argv=sscan_counted_string(bufptr, &bufptr);
1447 if(*argv==SPC_ERROR)
1450 *envp=sscan_counted_string(bufptr, &bufptr);
1451 if(*envp==SPC_ERROR)
1457 /*----------------------------------------------------------------------+*/
1459 sprint_device_data(XeString buf,
1466 /*----------------------------------------------------------------------+*/
1478 i=sprint_counted_string(buf, 6, args, SPC_BUFSIZ);
1484 /*----------------------------------------------------------------------+*/
1486 sscan_device_data(XeString buf,
1493 /*----------------------------------------------------------------------+*/
1497 args=sscan_counted_string(buf, NULL);
1514 /*----------------------------------------------------------------------+*/
1516 sprint_logfile_data(XeString buf,
1520 /*----------------------------------------------------------------------+*/
1529 i=sprint_counted_string(buf, 3, args, SPC_BUFSIZ);
1535 /*----------------------------------------------------------------------+*/
1537 sscan_logfile_data(XeString buf,
1539 XeString *proto_ver,
1541 /*----------------------------------------------------------------------+*/
1545 args=sscan_counted_string(buf, NULL);
1551 /* args[1] and args[2] will only be around for protocol revision 2 or later */
1553 *proto_ver = *hostinfo = XeString_NULL;
1556 *proto_ver = args[1];
1557 *hostinfo = args[2];
1560 *hostinfo = strdup(SPC_UNKNOWN_HOSTINFO_STR);
1567 /*----------------------------------------------------------------------+*/
1569 sprint_register_data(XeString buf,
1574 /*----------------------------------------------------------------------+*/
1584 i=sprint_counted_string(buf, 4, args, SPC_BUFSIZ);
1590 /*----------------------------------------------------------------------+*/
1592 sscan_register_data(XeString buf,
1595 XeString *proto_ver,
1597 /*----------------------------------------------------------------------+*/
1601 args=sscan_counted_string(buf, NULL);
1609 /* args[2] and args[3] will only be around for protocol revision 2 or later */
1611 *proto_ver = *hostinfo = XeString_NULL;
1614 *proto_ver = args[2];
1615 *hostinfo = args[3];
1618 *hostinfo = strdup(SPC_UNKNOWN_HOSTINFO_STR);
1627 ** Request / reply protocol requests
1631 /*----------------------------------------------------------------------+*/
1632 int SPC_Query_Devices(SPC_Channel_Ptr channel)
1633 /*----------------------------------------------------------------------+*/
1635 SPC_Connection_Ptr connection=channel->connection;
1636 protocol_request_ptr prot;
1638 SPC_Write_Protocol_Request(connection, channel, QUERY_DEVICES);
1639 prot=SPC_Filter_Connection(connection, channel, DEVICE_REPLY, TRUE);
1643 READ_DEVICE_REPLY(prot->dataptr,
1644 &(channel->wires[STDIN]->master_name),
1645 &(channel->wires[STDIN]->slave_name),
1646 &(channel->wires[STDOUT]->master_name),
1647 &(channel->wires[STDOUT]->slave_name),
1648 &(channel->wires[STDERR]->master_name),
1649 &(channel->wires[STDERR]->slave_name));
1651 SPC_Free_Protocol_Ptr(prot);
1655 /*----------------------------------------------------------------------+*/
1656 int SPC_Query_Logfile(SPC_Channel_Ptr channel)
1657 /*----------------------------------------------------------------------+*/
1659 SPC_Connection_Ptr connection=channel->connection;
1660 protocol_request_ptr prot;
1661 XeString junk1, junk2;
1663 SPC_Write_Protocol_Request(connection, channel, QUERY_LOGFILE);
1664 prot=SPC_Filter_Connection(connection, channel, LOGFILE_REPLY, TRUE);
1668 READ_LOGFILE_REPLY(prot->dataptr, &channel->logfile, &junk1, &junk2);
1669 if (junk1) XeFree(junk1);
1670 if (junk2) XeFree(junk2);
1672 SPC_Free_Protocol_Ptr(prot);
1676 #define UNK_TOKEN "unknown"
1678 /*----------------------------------------------------------------------+*/
1679 XeString SPC_LocalHostinfo(void)
1680 /*----------------------------------------------------------------------+*/
1682 struct utsname name;
1684 static XeString s = 0;
1686 _DtSvcProcessLock();
1688 if (uname(&name) >= 0) {
1689 s_len = strlen(name.sysname) +
1690 strlen(name.nodename) +
1691 strlen(name.release) +
1692 strlen(name.machine) + 4;
1693 s = (XeString) XeMalloc(s_len * sizeof(XeChar));
1694 sprintf(s, "%s:%s:%s:%s", name.nodename, name.sysname, name.release, name.machine);
1697 s_len = 4 * strlen(UNK_TOKEN) + 4;
1698 s = (XeString) XeMalloc(s_len * sizeof(XeChar));
1699 sprintf(s, "%s:%s:%s:%s", UNK_TOKEN, UNK_TOKEN, UNK_TOKEN, UNK_TOKEN);
1703 _DtSvcProcessUnlock();
1707 /*----------------------------------------------------------------------+*/
1709 SPC_Validate_User(XeString hostname,
1710 SPC_Connection_Ptr connection)
1711 /*----------------------------------------------------------------------+*/
1712 /* Called by client to register itself to spcd */
1714 XeString username = XeString_NULL;
1719 protocol_request_ptr prot;
1720 int open_status, chmod_status;
1721 XeString logfile = NULL;
1722 XeString junk1 = NULL, junk2 = NULL;
1723 XeString connection_hostname=CONNECTION_HOSTNAME(connection);
1724 _Xgetpwparams pwd_buf;
1725 struct passwd * pwd_ret;
1727 hostinfo = SPC_LocalHostinfo();
1730 * We are now including the user ID to generate the LOGFILE
1731 * (i.e., the authentication file)
1735 if((pwd_ret = _XGetpwuid(this_uid, pwd_buf)) == NULL) {
1737 * Very strange situation - the uid isn't in the passwd file
1739 username = XeString_NULL; /* we'll use the original /tmp subdirectory */
1742 username=(XeString)(pwd_ret->pw_name);
1745 SPC_Write_Protocol_Request(connection, NULL, REGISTER,
1746 username, XeString_Empty,
1747 SPC_PROTOCOL_VERSION_STR, hostinfo);
1750 prot=SPC_Filter_Connection(connection, NULL, LOGFILE_REPLY, TRUE);
1751 if(prot==SPC_ERROR) {
1752 XeFree(connection_hostname);
1756 /* In repsonse to the register, the daemon will send back a LOGFILE_REPLY */
1757 /* message that contains the name of a logfile to be used to do user */
1758 /* authentication. For A.02 and later daemons, it will also contain */
1759 /* the spc protocol version and info about the host the daemon is on. */
1761 READ_LOGFILE_REPLY(prot->dataptr, &logfile, &proto_ver, &hostinfo);
1763 /* For Pre A.01, this will be defaulted to (hpux 7.0 s300) */
1764 connection->hostinfo = hostinfo;
1767 sscanf(proto_ver, "%d", &connection->protocol_version);
1771 SPC_Free_Protocol_Ptr(prot);
1773 if(!strcmp(logfile, PASSED_FILE_NAME))
1775 if(!strcmp(logfile, FAILED_FILE_NAME)) {
1776 SPC_Error(SPC_Register_Username,
1777 (username) ? username : (XeString)"<empty user>",
1778 connection_hostname);
1779 XeFree(connection_hostname);
1780 if (logfile) XeFree(logfile);
1785 * Get a pathname to the authentication file.
1787 path=tt_netfile_file(logfile);
1789 if(tt_ptr_error (path) != TT_OK) {
1790 SPC_Write_Protocol_Request(connection, NULL, ABORT);
1791 SPC_Error(SPC_Register_Netrc,
1793 connection_hostname);
1794 XeFree(connection_hostname);
1795 if (logfile) XeFree(logfile);
1799 open_status=open(path, O_CREAT, S_ISUID);
1800 if(open_status==ERROR) {
1801 SPC_Write_Protocol_Request(connection, NULL, ABORT);
1802 SPC_Error(SPC_Register_Open,
1804 connection_hostname);
1806 XeFree(connection_hostname);
1807 if (logfile) XeFree(logfile);
1811 /* We need to also do a chmod because of an apparent Domain/OS bug
1812 where the open call does not properly set the UID bit. We
1813 let chmod set the bit. */
1815 chmod_status=chmod(path, S_ISUID);
1816 if(chmod_status==ERROR) {
1817 SPC_Write_Protocol_Request(connection, NULL, ABORT);
1818 SPC_Error(SPC_Register_Open,
1820 connection_hostname);
1822 XeFree(connection_hostname);
1823 if (logfile) XeFree(logfile);
1828 SPC_Write_Protocol_Request(connection, NULL, REGISTER, logfile, NULL, NULL, NULL);
1829 prot=SPC_Filter_Connection(connection, NULL, LOGFILE_REPLY, TRUE);
1835 if(prot==SPC_ERROR) {
1836 XeFree(connection_hostname);
1841 * Free logfile before it gets malloc'd again.
1845 READ_LOGFILE_REPLY(prot->dataptr, &logfile, &junk1, &junk2);
1846 if (junk1) XeFree(junk1);
1847 if (junk2) XeFree(junk2);
1849 SPC_Free_Protocol_Ptr(prot);
1851 if(!strcmp(logfile, PASSED_FILE_NAME)) {
1852 XeFree(connection_hostname);
1853 if (logfile) XeFree(logfile);
1856 if(!strcmp(logfile, FAILED_FILE_NAME)) {
1857 SPC_Error(SPC_Register_Handshake,
1859 connection_hostname);
1860 XeFree(connection_hostname);
1861 if (logfile) XeFree(logfile);
1865 if (logfile) XeFree(logfile);
1866 XeFree(connection_hostname);
1867 SPC_Error(SPC_Protocol);
1872 /*----------------------------------------------------------------------+*/
1873 static int SPC_Send_Termios(protocol_request_ptr prot_request)
1874 /*----------------------------------------------------------------------+*/
1876 struct termios *tio;
1880 tio = SPC_Get_Current_Termio(); /* Gets a (malloced) copy */
1881 s = SPC_Decode_Termios( tio ); /* Get ASCII representation */
1883 retval = WRITE_STRING(prot_request->dataptr, s);
1892 /*----------------------------------------------------------------------+*/
1893 int SPC_Get_Termios(protocol_request_ptr prot_request)
1894 /*----------------------------------------------------------------------+*/
1899 _DtSvcProcessLock();
1900 if(XeTermioStruct == NULL) {
1901 XeTermioStruct = (struct termios *)XeMalloc(sizeof(struct termios));
1903 for(i=0; i<NCCS; i++)
1904 XeTermioStruct->c_cc[i] = 0;
1907 READ_STRING_NO_COPY(prot_request->dataptr, s);
1909 SPC_Encode_Termios(s, XeTermioStruct);
1911 _DtSvcProcessUnlock();
1912 return(XeSetpgrp(FALSE));
1917 /*----------------------------------------------------------------------+*/
1918 int SPC_Get_Termio(protocol_request_ptr UNUSED_PARM(prot_request))
1919 /*----------------------------------------------------------------------+*/
1921 /* This is for old 1.0, 1.1 versions of the SPC code. We used to */
1922 /* pass an HPUX version of the termio struct around. This was not */
1923 /* portable. If we get one of these requests, just bit bucket it */
1924 /* as we do not know how to deal with it. */
1926 return(XeSetpgrp(FALSE));
1929 static int SPC_Send_B00_Spawn(SPC_Connection_Ptr connection,
1930 protocol_request_ptr prot,
1937 int num_elts=0, this_elt, num_argv, num_envp;
1938 char argv_buf[20], envp_buf[20];
1942 while(argv && argv[num_argv++])
1946 while(envp && envp[num_envp++])
1949 merged_ptr = (char **)malloc((num_elts+6) * sizeof(char *));
1951 sprintf(argv_buf, "%d", num_argv);
1952 sprintf(envp_buf, "%d", num_envp);
1955 merged_ptr[num_elts++] = path;
1956 merged_ptr[num_elts++] = dir;
1957 merged_ptr[num_elts++] = argv_buf;
1958 merged_ptr[num_elts++] = envp_buf;
1961 while(argv && argv[this_elt])
1962 merged_ptr[num_elts++] = argv[this_elt++];
1964 merged_ptr[num_elts++] = "DUMMY";
1967 while(envp && envp[this_elt])
1968 merged_ptr[num_elts++] = envp[this_elt++];
1970 merged_ptr[num_elts] = NULL;
1972 retval = SPC_Send_Multi_Packet(connection, prot,
1973 merged_ptr, num_elts,
1974 APP_B00_SPAWN, " <-- APP_B00_SPAWN",
1977 free((char *)merged_ptr);