Convert uses of XKeycodeToKeysym (deprecated) to XkbKeycodeToKeysym
[oweals/cde.git] / cde / lib / DtSvc / DtEncap / spc-proto.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
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
22  */
23 /*
24  * $TOG: spc-proto.c /main/12 1999/10/14 16:00:27 mgreess $
25  * Language:     C
26  *
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.
34  */
35
36 #define __need_timeval
37 #define __need_all_errors
38
39 #include <bms/sbport.h> /* NOTE: sbport.h must be the first include. */
40 #include <errno.h>
41 #include <stdarg.h>
42 #include <sys/utsname.h>
43 #include <limits.h>
44 #include <stdint.h>
45
46 #define X_INCLUDE_PWD_H
47 #define XOS_USE_XT_LOCKING
48 #include <X11/Xos_r.h>
49
50 #include <SPC/spcP.h>
51
52 #include <bms/MemoryMgr.h>
53
54 #include <SPC/spc-proto.h>
55
56 #include <Tt/tt_c.h>
57 #include "DtSvcLock.h"
58
59 /* Externals */
60 /*************/
61
62 extern struct termios *XeTermioStruct;    /* In pty.c */
63
64 extern XeString *environ;
65 extern SPC_Channel_Ptr spc_activation_list;
66
67 /* Gobals */
68 /**********/
69
70 /* FILE *SPC_Print_Protocol=NULL; -- now in bmsglob.c */
71
72 SPC_Connection_Ptr connection_list = NULL;
73 protocol_request_ptr free_protocol_requests = NULL;
74
75 /* Forwards */
76 /************/
77
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,
81                               char *path,
82                               char *dir,
83                               char **argv,
84                               char **envp);
85
86 /*----------------------------------------------------------------------+*/
87 buffered_data_ptr SPC_New_Buffered_Data_Ptr(void)
88 /*----------------------------------------------------------------------+*/
89 {
90   buffered_data_ptr bdata;
91
92   bdata=(buffered_data_ptr)XeMalloc(sizeof(buffered_data));
93   bdata->len = bdata->offset = 0;
94   return(bdata);
95 }
96
97
98 /*----------------------------------------------------------------------+*/
99 void SPC_Reset_Protocol_Ptr (protocol_request_ptr prot, 
100                              SPC_Channel_Ptr channel, 
101                              XeChar req, 
102                              int len)
103 /*----------------------------------------------------------------------+*/
104 {
105   buffered_data_ptr  dptr=prot->dataptr;
106   
107   dptr->len          = len;
108   dptr->offset       = 0;
109   prot->seqno        = 0;
110   prot->request_type = req;
111   prot->channel      = channel;
112   prot->next         = NULL;
113   memset(dptr->data, (XeChar)' ', REQUEST_HEADER_LENGTH);
114 }
115
116 /*----------------------------------------------------------------------+*/
117 protocol_request_ptr SPC_New_Protocol_Ptr (SPC_Channel_Ptr channel, 
118                                            XeChar req, 
119                                            int len)
120 /*----------------------------------------------------------------------+*/
121 {
122   protocol_request_ptr prot;
123
124   _DtSvcProcessLock();
125   if(free_protocol_requests) {
126     prot = free_protocol_requests;
127     free_protocol_requests = free_protocol_requests->next;
128   } else {
129     prot = (protocol_request_ptr)XeMalloc(sizeof(protocol_request));
130     prot->dataptr = SPC_New_Buffered_Data_Ptr();
131   }
132   SPC_Reset_Protocol_Ptr(prot, channel, req, len);
133   _DtSvcProcessUnlock();
134   return(prot);
135 }
136
137 /*----------------------------------------------------------------------+*/
138 void SPC_Free_Protocol_Ptr(protocol_request_ptr prot)
139 /*----------------------------------------------------------------------+*/
140 {
141   _DtSvcProcessLock();
142   prot->next = free_protocol_requests;
143   free_protocol_requests = prot;
144   _DtSvcProcessUnlock();
145 }
146
147
148 /*----------------------------------------------------------------------+*/
149 SPC_Channel_Ptr SPC_Lookup_Channel(int cid,
150                                    SPC_Connection_Ptr connection)
151 /*----------------------------------------------------------------------+*/
152 {
153   
154   SPC_Channel_Ptr spc;
155
156   if(!cid)
157     return(NULL);
158   
159   _DtSvcProcessLock();
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.
167        */
168     if((spc->cid == cid) &&
169        (!spc->connection ||
170         (spc->connection == connection))) {
171         _DtSvcProcessUnlock();
172         return(spc);
173     }
174   
175   _DtSvcProcessUnlock();
176   return(NULL);
177 }
178
179 /*
180  * Connection management routines
181  */
182
183
184 /*----------------------------------------------------------------------+*/
185 SPC_Connection_Ptr SPC_Alloc_Connection(void)
186 /*----------------------------------------------------------------------+*/
187 {
188   SPC_Connection_Ptr conn;
189
190   _DtSvcProcessLock();
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. */
197   conn->sid = (-1);
198   _DtSvcProcessUnlock();
199   return(conn);
200 }
201
202
203 /*----------------------------------------------------------------------+*/
204 SPC_Connection_Ptr SPC_Lookup_Connection(XeString hostname)
205 /*----------------------------------------------------------------------+*/
206 {
207   /* Search for an existing connection to a server */
208   SPC_Connection_Ptr conn;
209
210   _DtSvcProcessLock();
211   for (conn = connection_list; conn != NULL; conn = conn->next) {
212
213     /* Look for a connection with the same hostname */
214       if (!strcmp(conn->hostname, hostname)) {
215           _DtSvcProcessUnlock();
216           return(conn);
217       }
218   }
219   
220   _DtSvcProcessUnlock();
221   return(FALSE);
222 }
223
224 /*----------------------------------------------------------------------+*/
225 SPC_Connection_Ptr SPC_Lookup_Connection_Fd(int fd)
226 /*----------------------------------------------------------------------+*/
227 {
228   /* Search for an existing connection to a server, using fd (file descriptor)
229    as a key */
230   SPC_Connection_Ptr conn;
231
232   _DtSvcProcessLock();
233   for (conn = connection_list; conn != NULL; conn = conn->next) {
234
235     /* Look for a connection with the same hostname */
236       if (conn->sid==fd) {
237           _DtSvcProcessUnlock();
238           return(conn);
239       }
240   }
241   
242   _DtSvcProcessUnlock();
243   return(FALSE);
244 }
245
246 /*----------------------------------------------------------------------+*/
247 SPC_Connection_Ptr SPC_Make_Connection(XeString hostname)
248 /*----------------------------------------------------------------------+*/
249 {
250   /* Search for a connection to hostname, create one if none exists */
251   
252   SPC_Connection_Ptr conn;
253
254   /* Searching for connected host maintains only one connection per remote */
255
256   if(hostname && (conn=SPC_Lookup_Connection(hostname)))
257     return(conn);
258   
259   /* Not found, so make one */
260   
261   if((conn = SPC_Alloc_Connection())==SPC_ERROR)
262     return(SPC_ERROR);
263
264   if(hostname)
265     strcpy(conn->hostname, hostname);
266   
267   SPC_Add_Connection(conn);
268   return(conn);
269 }
270
271 /*----------------------------------------------------------------------+*/
272 void SPC_Add_Connection(SPC_Connection_Ptr connection)
273 /*----------------------------------------------------------------------+*/
274 {
275   
276   /* Add a connection to the connection_list */
277   _DtSvcProcessLock();
278   connection->next = connection_list;
279   connection_list = connection;
280   _DtSvcProcessUnlock();
281 }
282
283 /*----------------------------------------------------------------------+*/
284 void SPC_Close_Connection(SPC_Connection_Ptr connection)
285 /*----------------------------------------------------------------------+*/
286 {
287   SPC_Channel_Ptr channel;
288   SPC_Channel_Ptr next;
289   SPC_Connection_Ptr trail, ptr;
290
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. */
295
296   _DtSvcProcessLock();
297   channel=spc_activation_list;
298   connection->connected = FALSE;
299   
300   while(channel) {
301     next=channel->next;
302     if(channel->connection == connection) {
303       if(!IS_SPCIO_DELAY_CLOSE(channel->IOMode))
304         SPC_Channel_Terminated(channel);
305       channel->connection = NULL;
306     }
307     channel=next;
308   }
309   
310   SPC_XtRemoveInput(&connection->termination_id, SPC_Terminator);
311
312   spc_close(connection->sid);
313   connection->sid = (-1);
314
315   if (connection->hostinfo)
316       XeFree(connection->hostinfo);
317
318   /* Remove the connection from the connection list */
319
320   if(connection_list == connection)
321     connection_list = connection->next;
322   else {
323     trail = connection_list;
324     while(trail) {
325       ptr = trail->next;
326       if(ptr == connection) {
327         trail->next = ptr->next;
328         break;
329       }
330       trail=ptr;
331     }
332     if(!trail) {
333       /* Here if no such connection found. */
334     }
335   }
336
337   free((char *)connection);
338   _DtSvcProcessUnlock();
339 }
340
341 /*
342  **
343  ** Read the specified number of characters, or die trying.
344  **
345 */
346
347 /*----------------------------------------------------------------------+*/
348 int SPC_Read_Chars(SPC_Connection_Ptr   connection,
349                    int                  request_len,
350                    XeString             charptr)
351 /*----------------------------------------------------------------------+*/
352 {
353
354   int numchars, numread;
355   int numtoread=request_len;
356   int sid=connection->sid;
357   
358   numread=0;
359
360   while(numread<request_len) {
361     do
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);
368       else
369         SPC_Error(SPC_Reading, connection_hostname);
370       XeFree(connection_hostname);
371       return(SPC_ERROR);
372     }
373     if(numchars == 0) {
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 */
378     }
379     charptr += numchars;
380     numread += numchars;
381     numtoread -= numchars;
382   }
383   *charptr=(XeChar)'\0';
384   return(numread);
385 }
386
387 /* Write len chars, or die trying */
388
389 /*----------------------------------------------------------------------+*/
390 int SPC_Write_Chars(int         fd,
391                     XeString    charptr,
392                     int         request_len)
393 /*----------------------------------------------------------------------+*/
394 {
395   int numchars, numwritten;
396   int numtowrite=request_len;
397   
398   numwritten=0;
399   
400   while(numwritten<request_len) {
401     do
402       numchars=write(fd, charptr, numtowrite);
403     while(numchars == ERROR && errno == EINTR);
404
405 #ifdef DEBUG
406     _DtSvcProcessLock();
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();
412 #endif    
413        
414     if(numchars == ERROR)
415       return(ERROR);
416
417     charptr    += numchars;
418     numwritten += numchars;
419     numtowrite -= numchars;
420   }
421   return(numwritten);
422 }
423   
424
425 /*
426  **
427  ** Read a single protocol request from the passed channel.
428  **
429 */
430
431 /*----------------------------------------------------------------------+*/
432 protocol_request_ptr SPC_Read_Protocol(SPC_Connection_Ptr connection)
433 /*----------------------------------------------------------------------+*/
434 {
435   int                channel_id;
436   protocol_request_ptr prot;
437   buffered_data_ptr        dptr;
438   int len;
439
440   if(!connection->connected)
441     return(SPC_ERROR);
442   
443   if((prot=SPC_New_Protocol_Ptr(NULL, 0, 0))==SPC_ERROR) {
444     SPC_Close_Connection(connection);
445     return(SPC_ERROR);
446   }
447   
448   /* read header */
449
450   dptr=prot->dataptr;
451
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);
456     return(SPC_ERROR);
457   }
458   
459   /* we have the header.  Parse out the fields */
460   
461   READ_HEADER(dptr,
462               &channel_id, &prot->request_type, &dptr->len, &prot->seqno);
463   prot->channel=SPC_Lookup_Channel(channel_id, connection);
464   
465
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 */
468   /* MAXREQLEN */
469   /* CERT - VU#172583 */
470
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);
475
476       SPC_Error(SPC_Buffer_Overflow, connection_hostname);
477       XeFree(connection_hostname);
478       SPC_Close_Connection(connection);
479       SPC_Free_Protocol_Ptr(prot);
480       return(SPC_ERROR);
481     }
482
483   /* read header */
484   
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);
489     return(SPC_ERROR);
490   }
491
492   dptr->offset=REQUEST_HEADER_LENGTH;
493   return(prot);
494   
495 }
496
497 /*
498  **
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
504  ** from the queue.
505  **
506 */
507
508 /*----------------------------------------------------------------------+*/
509 protocol_request_ptr  SPC_Filter_Connection(SPC_Connection_Ptr connection,
510                                             SPC_Channel_Ptr channel,
511                                             int reqtype, 
512                                             int deletep)
513 /*----------------------------------------------------------------------+*/
514 {
515   SPC_Connection_Ptr connptr=NULL;
516   SPC_Channel_Ptr conn_channel;
517   XeQueue   tmpqueue;
518   protocol_request_ptr retval;
519   int protreqtype;
520
521   /* check if there are any queued prot. requests.  If so,
522      check for their having the type we want */
523   
524   if(channel && (tmpqueue=channel->queued_remote_data)) {
525     tmpqueue=channel->queued_remote_data;
526     {
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) {
530           /* yes. */
531           if(deletep)
532             Xe_delete_queue_element(channel->queued_remote_data, retval);
533           return(retval);
534         }
535       }
536     }
537   }
538   
539   /* No queued elements.  Read until we get the reply we
540      are looking for */
541   while(TRUE) {
542     if((retval=SPC_Read_Protocol(connection))==SPC_ERROR)
543       return(SPC_ERROR);
544
545     protreqtype=retval->request_type;
546     conn_channel=retval->channel;
547
548     if(protreqtype == ABORT) {
549       XeString connection_hostname = CONNECTION_HOSTNAME(connection);
550       SPC_Error(SPC_Protocol_Abort, connection_hostname);
551       XeFree (connection_hostname);
552       return(SPC_ERROR);
553     }
554
555     _DtSvcProcessLock();
556     if(protreqtype == SERVER_ERROR) {
557       READ_ERROR(retval->dataptr, XeSPCErrorNumber);
558       SPC_Error(XeSPCErrorNumber, XeString_NULL, 0);
559       _DtSvcProcessUnlock();
560       return(SPC_ERROR);
561     }
562     _DtSvcProcessUnlock();
563
564     if(!conn_channel)
565       return(retval);
566
567     if((conn_channel == channel) && (protreqtype == reqtype)) {
568       /* We found one that matches.  Check if we need to queue it up. */
569       if(!deletep)
570         Xe_push_queue(conn_channel->queued_remote_data, retval);
571       return(retval);
572     }
573     
574     /* No match.  Queue it up */
575     if(IS_SPCIO_SYNC_TERM(channel->IOMode))
576       Xe_push_queue(connection->queued_remote_data, retval);
577     else
578       Xe_push_queue(conn_channel->queued_remote_data, retval);
579     
580   }
581 }
582
583 /*----------------------------------------------------------------------+*/
584 void SPC_Flush_Queued_Data(SPC_Channel_Ptr channel)
585 /*----------------------------------------------------------------------+*/
586 {
587   XeQueue tmpqueue;
588   protocol_request_ptr prot;
589   
590   if((tmpqueue=channel->queued_remote_data)) {
591     while((prot=(protocol_request_ptr)Xe_pop_queue(tmpqueue)))
592       SPC_Free_Protocol_Ptr(prot);
593   }
594
595   if(channel->connection && (tmpqueue=channel->connection->queued_remote_data))
596     {
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);
601         }
602       }
603     }
604 }
605
606 /*----------------------------------------------------------------------+*/
607 int SPC_Read_Remote_Data(SPC_Channel_Ptr channel,
608                          int connector,
609                          XeString client_buffer,
610                          int nbytes)
611 /*----------------------------------------------------------------------+*/
612 {
613   int ret_len;
614
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);
619
620   prot=SPC_Filter_Connection(connection, channel, req_type, FALSE);
621   if(prot==SPC_ERROR)
622     return(SPC_ERROR);
623   
624   pdata=prot->dataptr;
625   
626   ret_len = min(nbytes, pdata->len);
627   
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);
634   }
635
636   return(ret_len);
637 }
638
639 /* Dump out a protocol request */
640
641 /*----------------------------------------------------------------------+*/
642 int print_protocol_request(XeString name, protocol_request_ptr proto)
643 /*----------------------------------------------------------------------+*/
644 {
645   buffered_data_ptr dptr = proto->dataptr;
646
647   _DtSvcProcessLock();
648   if(!SPC_Print_Protocol) {
649     _DtSvcProcessUnlock();
650     return FALSE;
651   }
652
653   dptr->data[dptr->offset+dptr->len]=0;
654   
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);
659
660   fflush(SPC_Print_Protocol);
661
662   _DtSvcProcessUnlock();
663   return TRUE;
664 }
665   
666 /*
667  * Write a protocol request to the given channel
668  *
669 */
670
671 int current_sequence_number=1;
672
673 /*----------------------------------------------------------------------+*/
674 int SPC_Write_Protocol_Request (SPC_Connection_Ptr connection, 
675                                 SPC_Channel_Ptr channel, 
676                                 int request, 
677                                 ...)
678 /*----------------------------------------------------------------------+*/
679 {
680   va_list               ap;
681   protocol_request_ptr  prot_request;
682   buffered_data_ptr     pdata;
683   int                   reply_expected;
684   XeString              prot_name=NULL;
685   
686   prot_request=SPC_New_Protocol_Ptr(channel, request, 0);
687   pdata=prot_request->dataptr;
688   _DtSvcProcessLock();
689   prot_request->seqno = current_sequence_number++;
690   _DtSvcProcessUnlock();
691
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);
696   
697   switch (request) {
698
699   case ABORT:
700     pdata->len=WRITE_ABORT(pdata, 0);
701     prot_name=(XeString)"  <-- ABORT";
702     break;
703     
704  case REGISTER:
705     {
706     XeString username;
707     XeString passwd;
708     XeString proto_ver;
709     XeString hostinfo;
710
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 );
716     va_end(ap);
717     pdata->len=WRITE_REGISTER(pdata, username, passwd, proto_ver, hostinfo);
718     prot_name=(XeString)"  <-- REGISTER";
719     break;
720     }
721     
722     
723   case UNREGISTER:
724     prot_name=(XeString)"  <-- UNREGISTER";
725     break;
726     
727   case CHANNEL_OPEN:
728     va_start(ap, request);
729     pdata->len=WRITE_OPEN(pdata, va_arg(ap, int));
730     va_end(ap);
731     prot_name=(XeString)"  <-- CHANNEL_OPEN";
732     break;
733
734   case CHANNEL_CLOSE:
735     /* This is correct.  This protocol request takes no args */
736     prot_name=(XeString)"  <-- CHANNEL_CLOSE";
737     break;
738     
739   case CHANNEL_RESET:
740     /* This one, either */
741     prot_name=(XeString)"  <-- CHANNEL_RESET";
742     break;
743     
744   case CHANNEL_ATTACH:
745     prot_name=(XeString)"  <-- CHANNEL_ATTACH";
746     va_start(ap, request);
747     pdata->len=WRITE_ATTACH(pdata, va_arg(ap, int));
748     va_end(ap);
749     break;
750     
751   case APPLICATION_SPAWN:
752     {
753     XeString path;
754     XeString dir;
755     XeString *argv;
756     XeString *envp;
757     
758     va_start(ap, request);
759
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... */
764     
765     path=va_arg(ap, XeString );
766     dir =va_arg(ap, XeString );
767     argv=va_arg(ap, XeString *);
768     envp=va_arg(ap, XeString *);
769     va_end(ap);
770     pdata->len=WRITE_APPLICATION_SPAWN(pdata, path, dir, argv, envp);
771     if(pdata->len == SPC_ERROR) {
772       SPC_Free_Protocol_Ptr(prot_request);
773       return(SPC_ERROR);
774     }
775     prot_name=(XeString)"  <-- APPLICATION_SPAWN";
776     break;
777     }
778     
779   case APPLICATION_SIGNAL:
780     {
781         if (connection->protocol_version >= 2) 
782         {
783             XeString signame;
784             
785             va_start(ap, request);
786             signame = va_arg(ap, XeString);
787             va_end(ap);
788             
789             pdata->len=WRITE_STRING(pdata, signame);
790         }
791         else
792         {
793             int      sig;
794             
795             va_start(ap, request);
796             sig = va_arg(ap, int);
797             va_end(ap);
798
799             pdata->len=WRITE_INT(pdata, sig);
800         }
801         
802         prot_name=(XeString)"  <-- APPLICATION_SIGNAL";
803         break;
804     }
805     
806   case APPLICATION_DIED:
807     va_start(ap, request);
808     pdata->len=WRITE_APPLICATION_DIED(pdata, va_arg(ap, int));
809     va_end(ap);
810     prot_name=(XeString)"  <-- APPLICATION_DIED";
811     break;
812
813   case APPLICATION_DATA:
814     prot_name=(XeString)"  <-- APPLICATION_DATA";
815     
816   case APPLICATION_STDOUT:
817     if(!prot_name)
818       prot_name=(XeString)"  <-- APPLICATION_STDOUT";
819     
820   case APPLICATION_STDERR:
821     {
822     int      buflen;
823     XeString buffer;
824     
825     if(!prot_name)
826       prot_name=(XeString)"  <-- APPLICATION_STDERR";
827     
828     va_start(ap, request);
829     buffer=va_arg(ap, XeString );
830     buflen=va_arg(ap, int);
831     va_end(ap);
832
833     pdata->len=WRITE_APP_DATA(pdata, buffer, buflen);
834
835     break;
836     }
837
838   case SERVER_ERROR:
839     va_start(ap, request);
840     pdata->len=WRITE_ERROR(pdata, va_arg(ap, int));
841     va_end(ap);
842     prot_name=(XeString)"  <-- SERVER_ERROR";
843     break;
844     
845   case REPLY:
846     {
847     int replyval, errval;
848     
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);
853     va_end(ap);
854     pdata->len=WRITE_REPLY(pdata, replyval, errval);
855     prot_name=(XeString)"  <-- REPLY";
856     break;
857     }
858
859   case DEVICE_REPLY:
860     { 
861     XeString m0;
862     XeString s0;
863     XeString m1;
864     XeString s1;
865     XeString m2;
866     XeString s2;
867
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 );
875     va_end(ap);
876     pdata->len=WRITE_DEVICE_REPLY(pdata, m0, s0, m1, s1, m2, s2);
877     prot_name=(XeString)"  <-- DEVICE_REPLY";
878     break;
879     }
880     
881   case QUERY_DEVICES:
882     prot_name=(XeString)"  <-- QUERY_DEVICES";
883     break;
884
885  case LOGFILE_REPLY:
886     {
887     XeString fname;
888     XeString proto_ver;
889     XeString hostinfo;
890
891     va_start(ap, request);
892     fname=va_arg(ap, XeString );
893     proto_ver=va_arg(ap, XeString );
894     hostinfo=va_arg(ap, XeString );
895     va_end(ap);
896     pdata->len=WRITE_LOGFILE_REPLY(pdata, fname, proto_ver, hostinfo);
897     prot_name=(XeString)"  <-- LOGFILE_REPLY";
898     break;
899     }
900     
901   case QUERY_LOGFILE:
902     prot_name=(XeString)"  <-- QUERY_LOGFILE";
903     break;
904
905   case DELETE_LOGFILE:
906     prot_name=(XeString)"  <-- DELETE_LOGFILE";
907     break;
908
909   case SERVER_DEBUG:
910     va_start(ap, request);
911     pdata->len=WRITE_DEBUG(pdata, va_arg(ap, XeString));
912     va_end(ap);
913     prot_name=(XeString)"  <-- SERVER_DEBUG";
914     break;
915
916   case ENVIRON_RESET:
917     return(SPC_Send_Environ(connection, prot_request));
918
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.     */
921
922   case RESET_TERMIOS:
923     pdata->len=SPC_Send_Termios(prot_request);
924     prot_name=(XeString)"  <-- RESET_TERMIOS";
925     break;
926
927   /* B.00 (protocol version 3) requests */
928     
929   case CHANNEL_SEND_EOF:
930
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);
935       return(SPC_ERROR);
936     }
937   
938     prot_name = (XeString)"  <-- CHANNEL_SEND_EOF";
939     break;
940
941   case CHANNEL_TERMIOS:
942
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);
947       return(SPC_ERROR);
948     }
949   
950     {
951       int connector, side;
952       struct termios *termios_ptr;
953       char *buffer;
954
955       va_start(ap, request);
956
957       connector   = va_arg(ap, int);
958       side        = va_arg(ap, int);
959       termios_ptr = va_arg(ap, struct termios *);
960       va_end(ap);
961
962       buffer = SPC_Decode_Termios(termios_ptr);
963       pdata->len=WRITE_TERMIOS(pdata, connector, side, buffer);
964       prot_name=(XeString)"  <-- CHANNEL_TERMIOS";
965       free(buffer);
966       break;
967     }
968
969   case APP_B00_SPAWN:
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);
974       return(SPC_ERROR);
975     }
976
977     {
978     XeString path;
979     XeString dir;
980     XeString *argv;
981     XeString *envp;
982     int retval;
983     
984     va_start(ap, request);
985
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... */
990     
991     path=va_arg(ap, XeString );
992     dir =va_arg(ap, XeString );
993     argv=va_arg(ap, XeString *);
994     envp=va_arg(ap, XeString *);
995     va_end(ap);
996
997     retval =
998       SPC_Send_B00_Spawn(connection, prot_request, path, dir, argv, envp);
999     return(retval);
1000     }
1001     
1002   }
1003
1004   reply_expected=
1005     SPC_Write_Single_Prot_Request(connection, prot_name, prot_request);
1006     
1007   SPC_Free_Protocol_Ptr(prot_request);
1008   return(reply_expected);
1009 }
1010
1011
1012 /*----------------------------------------------------------------------+*/
1013 int SPC_Write_Single_Prot_Request(SPC_Connection_Ptr connection,
1014                                   XeString name,
1015                                   protocol_request_ptr prot)
1016 /*----------------------------------------------------------------------+*/
1017 {
1018   int reply_expected, length;
1019   buffered_data_ptr   pdata=prot->dataptr;
1020
1021   if(!connection->connected)
1022     return(SPC_ERROR);
1023   
1024   reply_expected=
1025     REPLY_EXPECTED(prot->request_type, prot->seqno);
1026   length=WRITE_HEADER(pdata, prot->channel,
1027                       prot->request_type,
1028                       pdata->len,
1029                       prot->seqno);
1030   pdata->data[length]=(XeChar)' ';
1031   
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);
1039   }
1040   
1041   pdata->offset=REQUEST_HEADER_LENGTH;
1042   print_protocol_request(name, prot);
1043
1044   return(reply_expected);
1045 }
1046
1047 /*----------------------------------------------------------------------+*/
1048 int SPC_Waitfor_Reply(SPC_Connection_Ptr connection,
1049                       SPC_Channel_Ptr channel,
1050                       int seqno)
1051 /*----------------------------------------------------------------------+*/
1052 {
1053
1054   protocol_request_ptr prot;
1055   int retval, errval;
1056   int thisseq;
1057   
1058   if(seqno == NO_REPLY_VAL)
1059     return(TRUE);
1060
1061   if(seqno==SPC_ERROR)
1062     return(SPC_ERROR);
1063   
1064   prot=SPC_Filter_Connection(connection, channel, REPLY, TRUE);
1065
1066   if(prot==SPC_ERROR)
1067     return(SPC_ERROR);
1068
1069   thisseq = prot->seqno;
1070   READ_REPLY(prot->dataptr, retval, errval);
1071
1072   SPC_Free_Protocol_Ptr(prot);
1073   
1074   if(thisseq != seqno) {
1075     SPC_Error(SPC_Unexpected_Reply);
1076     return(SPC_ERROR);
1077   }
1078   
1079   if(retval<0) {
1080     errno=errval;
1081     retval = -retval;
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);
1089       else
1090          SPC_Error(retval, XeString_NULL, 0);
1091     }
1092     return(SPC_ERROR);
1093   }
1094   return(retval);
1095 }
1096       
1097
1098 /*----------------------------------------------------------------------+*/
1099 int SPC_Dispatch_Protocol(protocol_request_ptr proto,
1100                           protocol_request_handler *table)
1101 /*----------------------------------------------------------------------+*/
1102 {
1103   int req_type;
1104   
1105   if(!proto)
1106     return(FALSE);
1107   req_type=proto->request_type;
1108   
1109   if(req_type<0 || req_type>NREQS)
1110     return(FALSE);
1111
1112   return((* table[req_type])(proto));
1113 }
1114
1115 /*----------------------------------------------------------------------+*/
1116 int SPC_Write_Reply(SPC_Connection_Ptr conn,
1117                     protocol_request_ptr proto,
1118                     int retval,
1119                     int errval)
1120 /*----------------------------------------------------------------------+*/
1121 {
1122   _DtSvcProcessLock();
1123   if(retval==ERROR)
1124     retval=(-XeSPCErrorNumber);
1125   _DtSvcProcessUnlock();
1126
1127   return(SPC_Write_Protocol_Request(conn, proto->channel, REPLY,
1128                                     proto->seqno, retval, errval));
1129 }
1130
1131 /*
1132  **
1133  ** Send the current environment out to the world.
1134  **
1135 */
1136
1137 #define valid_str(x) (((x) != NULL) && (*(x) != 0))
1138 #define NULL_STR     "\001\001\001"
1139 #define EMPTY_STR    "\001\002\003"
1140
1141 int SPC_Send_Multi_Packet(SPC_Connection_Ptr connection,
1142                           protocol_request_ptr prot,
1143                           char **str_vect,
1144                           int num_str,
1145                           int req,
1146                           XeString name,
1147                           int errid)
1148 {
1149   int counter, tmp_len;
1150   int bytes_left, numbytes;
1151   XeString buf;
1152   int reply_seqno;
1153   int this_seqno;
1154   int valid_ep = 0;
1155   char *this_str;
1156
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;
1163   
1164   for(counter=0; counter<num_str; counter++) {
1165     this_str = str_vect[counter];
1166     
1167     if(this_str == NULL)
1168       this_str = NULL_STR;
1169     if(*this_str == '\0')
1170       this_str = EMPTY_STR;
1171     
1172     tmp_len=strlen(this_str)+1;         /* Room for NULL char */
1173     if((bytes_left-tmp_len) < 1) {
1174       *buf='\0';
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++;
1180       numbytes=0;
1181       bytes_left=SPC_BUFSIZ;
1182       buf=(PDRP(prot->dataptr) + numbytes);
1183     }
1184     
1185     if(tmp_len>SPC_BUFSIZ-1) {
1186       SPC_Error(errid,
1187                 this_str,
1188                 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);
1194     }
1195
1196     strncpy(buf, this_str, tmp_len);
1197     bytes_left -= tmp_len;
1198     numbytes   += tmp_len;
1199     buf        += tmp_len;
1200   }
1201   
1202   if(numbytes) {
1203     *buf='\0';
1204     prot->dataptr->len=numbytes+1;
1205     SPC_Write_Single_Prot_Request(connection, (XeString)"  <-- ENVIRON_RESET", prot);
1206     SPC_Free_Protocol_Ptr(prot);
1207   }
1208
1209   _DtSvcProcessUnlock();
1210   return(reply_seqno);
1211   
1212 }
1213
1214 char **SPC_Get_Multi_Packet(SPC_Connection_Ptr connection,
1215                             protocol_request_ptr prot,
1216                             char **out,
1217                             int *outlen,
1218                             int request,
1219                             XeString name)
1220
1221 {
1222   int num_vars, i, len;
1223   XeString bufptr;
1224   protocol_request_ptr localprot = NULL;
1225
1226   print_protocol_request(name, prot);
1227   READ_ENVIRON_RESET(prot->dataptr, num_vars);
1228   bufptr=strchr(PDRP(prot->dataptr), Space)+1;
1229   if(out == NULL)
1230     out = (char **)malloc((num_vars+1) * sizeof(char **));
1231   
1232   for(i=0; i<num_vars; i++) {
1233     len=strlen(bufptr);
1234     if(len==0) {
1235       if(localprot)
1236         SPC_Free_Protocol_Ptr(localprot);
1237       prot=SPC_Filter_Connection(connection, NULL, request, TRUE);
1238       if(prot==SPC_ERROR) {
1239         free(out);
1240         return(SPC_ERROR);
1241       }
1242       print_protocol_request(name, prot);
1243       localprot=prot;
1244       bufptr=PDRP(prot->dataptr);
1245       len=strlen(bufptr);
1246     }
1247     if(strcmp(bufptr, NULL_STR) == 0)
1248       out[i] = NULL;
1249     else {
1250       if(strcmp(bufptr, EMPTY_STR) == 0)
1251         out[i] = strdup("");
1252       else
1253         out[i] = strdup(bufptr);
1254     }
1255     bufptr += (len+1);
1256   }
1257   if(localprot)
1258     SPC_Free_Protocol_Ptr(localprot);
1259
1260   *outlen = num_vars;
1261   out[num_vars] = NULL;
1262   
1263   return(out);
1264 }
1265  
1266 /*----------------------------------------------------------------------+*/
1267 int SPC_Send_Environ(SPC_Connection_Ptr connection,
1268                      protocol_request_ptr prot)
1269 /*----------------------------------------------------------------------+*/
1270 {
1271
1272   int ep_count=0;
1273   int result;
1274
1275   _DtSvcProcessLock();
1276   while(environ[ep_count])
1277     ep_count++;
1278   
1279   result = SPC_Send_Multi_Packet(connection, prot, environ, ep_count,
1280                                ENVIRON_RESET, "  <-- ENVIRON_RESET",
1281                                SPC_Env_Too_Big);
1282   _DtSvcProcessUnlock();
1283   return (result);
1284 }
1285
1286 /*----------------------------------------------------------------------+*/
1287 int sprint_counted_string(XeString buf,
1288                           int count,
1289                           XeString *vect,
1290                           int orig_limit)
1291 /*----------------------------------------------------------------------+*/
1292 {
1293   XeString bufptr=buf;
1294   int len;
1295   int i;
1296   int limit=orig_limit;
1297 #define ERRBUFLEN 100
1298   char errbuf[ERRBUFLEN];
1299
1300   len=sprintf_len(bufptr, (XeString)"%x ", count)+1;
1301   if(len>limit) {
1302     sprintf(errbuf, "(%d chars), max. length is %d", len, orig_limit);
1303     SPC_Error(SPC_Arg_Too_Long,
1304               bufptr,
1305               errbuf);
1306     return(SPC_ERROR);
1307   }
1308   bufptr += len;
1309   limit  -= len;
1310   
1311   for(i=0; i<count; (i++, vect++)) {
1312     if (*vect)
1313       len = strlen(*vect)+1;
1314     else
1315       len = 1;
1316
1317     if(len>limit) {
1318       sprintf(errbuf, "(%d chars), max. length is %d", len, orig_limit);
1319       SPC_Error(SPC_Arg_Too_Long,
1320                 *vect,
1321                 errbuf);
1322       return(SPC_ERROR);
1323     }
1324     sprintf(bufptr, "%s", *vect ? *vect : "");
1325     bufptr += len;
1326     limit  -= len;
1327   }
1328   
1329   return(bufptr-buf);
1330 }
1331
1332 /*----------------------------------------------------------------------+*/
1333 XeString *sscan_counted_string(XeString buf,
1334                                XeString *newbuf)
1335 /*----------------------------------------------------------------------+*/
1336 {
1337   
1338   int i, numstrings, len;
1339   XeString bufptr; 
1340   XeString *tmpptr;
1341   XeString *tmpidx;
1342   
1343   sscanf(buf, (XeString)"%x", &numstrings);
1344   len=strlen(buf)+1;
1345   bufptr=buf+len;
1346   
1347   tmpptr=(XeString*)XeMalloc((numstrings+1) * sizeof(XeString *));
1348   tmpidx=tmpptr;
1349   
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';
1355     bufptr+= len;
1356   }
1357   *tmpidx=NULL;
1358   if (newbuf)
1359     *newbuf=bufptr;
1360   return(tmpptr);
1361 }
1362
1363 /*----------------------------------------------------------------------+*/
1364 int 
1365 sprint_application_data(XeString buf,
1366                         XeString UNUSED_PARM(fmt),
1367                         XeString path,
1368                         XeString dir,
1369                         XeString *argv,
1370                         XeString *envp,
1371                         int      UNUSED_PARM(chars_used))
1372 /*----------------------------------------------------------------------+*/
1373 {
1374
1375   int av_count=0;
1376   int ep_count=0;
1377   int data_len=0;
1378   int tmp_len;
1379   int limit;
1380   
1381   if(argv)
1382     while(argv[av_count]) av_count++;
1383   
1384   if(envp)
1385     while(envp[ep_count]) ep_count++;
1386
1387   limit=SPC_BUFSIZ;
1388     
1389   tmp_len = sprint_counted_string(buf, 1, &path, limit);
1390   if(tmp_len == SPC_ERROR)
1391     return(SPC_ERROR);
1392   limit    -= tmp_len;
1393   buf      += tmp_len;
1394   data_len += tmp_len;
1395   
1396   tmp_len = sprint_counted_string(buf, 1, &dir, limit);
1397   if(tmp_len == SPC_ERROR)
1398     return(SPC_ERROR);
1399   limit    -= tmp_len;
1400   buf      += tmp_len;
1401   data_len += tmp_len;
1402   
1403   tmp_len = sprint_counted_string(buf, av_count, argv, limit);
1404   if(tmp_len == SPC_ERROR)
1405     return(SPC_ERROR);
1406   limit    -= tmp_len;
1407   buf      += tmp_len;
1408   data_len += tmp_len;
1409   
1410   tmp_len = sprint_counted_string(buf, ep_count, envp, limit);
1411   if(tmp_len == SPC_ERROR)
1412     return(SPC_ERROR);
1413   limit    -= tmp_len;
1414   buf      += tmp_len;
1415   data_len += tmp_len;
1416   
1417   return(data_len);
1418 }
1419
1420 /*----------------------------------------------------------------------+*/
1421 int
1422 sscan_application_data(XeString buf,
1423                        XeString UNUSED_PARM(fmt),
1424                        XeString *path,
1425                        XeString *dir,
1426                        XeString **argv,
1427                        XeString **envp,
1428                        int      UNUSED_PARM(offset))
1429 /*----------------------------------------------------------------------+*/
1430 {
1431   XeString bufptr;
1432   XeString *tmp_vect;
1433   
1434   bufptr=buf;
1435
1436   tmp_vect=sscan_counted_string(bufptr, &bufptr);
1437   if(tmp_vect==SPC_ERROR)
1438     return(SPC_ERROR);
1439   *path = (*tmp_vect);
1440   
1441   tmp_vect=sscan_counted_string(bufptr, &bufptr);
1442   if(tmp_vect==SPC_ERROR)
1443     return(SPC_ERROR);
1444   *dir = (*tmp_vect);
1445   
1446   *argv=sscan_counted_string(bufptr, &bufptr);
1447   if(*argv==SPC_ERROR)
1448     return(SPC_ERROR);
1449
1450   *envp=sscan_counted_string(bufptr, &bufptr);
1451   if(*envp==SPC_ERROR)
1452     return(SPC_ERROR);
1453     
1454   return(TRUE);
1455 }
1456
1457 /*----------------------------------------------------------------------+*/
1458 int
1459 sprint_device_data(XeString buf,
1460                    XeString m0, 
1461                    XeString s0, 
1462                    XeString m1, 
1463                    XeString s1, 
1464                    XeString m2, 
1465                    XeString s2)
1466 /*----------------------------------------------------------------------+*/
1467 {
1468   XeString args[6];
1469   int i;
1470
1471   args[0]=m0;
1472   args[1]=s0;
1473   args[2]=m1;
1474   args[3]=s1;
1475   args[4]=m2;
1476   args[5]=s2;
1477
1478   i=sprint_counted_string(buf, 6, args, SPC_BUFSIZ);
1479   if(i==SPC_ERROR)
1480     return(SPC_ERROR);
1481   return(i);
1482 }
1483
1484 /*----------------------------------------------------------------------+*/
1485 int
1486 sscan_device_data(XeString buf,
1487                   XeString *m0, 
1488                   XeString *s0, 
1489                   XeString *m1, 
1490                   XeString *s1, 
1491                   XeString *m2, 
1492                   XeString *s2)
1493 /*----------------------------------------------------------------------+*/
1494 {
1495   XeString *args;
1496
1497   args=sscan_counted_string(buf, NULL);
1498
1499   if(args==SPC_ERROR)
1500     return(SPC_ERROR);
1501   
1502   *m0=args[0];
1503   *s0=args[1];
1504   *m1=args[2];
1505   *s1=args[3];
1506   *m2=args[4];
1507   *s2=args[5];
1508
1509   free((char *)args);
1510   
1511   return(TRUE);
1512 }
1513
1514 /*----------------------------------------------------------------------+*/
1515 int
1516 sprint_logfile_data(XeString buf,
1517                     XeString logfile,
1518                     XeString proto_ver,
1519                     XeString hostinfo)
1520 /*----------------------------------------------------------------------+*/
1521 {
1522   int i;
1523   XeString args[3];
1524   
1525   args[0]=logfile;
1526   args[1]=proto_ver;
1527   args[2]=hostinfo;
1528   
1529   i=sprint_counted_string(buf, 3, args, SPC_BUFSIZ);
1530   if(i==SPC_ERROR)
1531     return(SPC_ERROR);
1532   return(i);
1533 }
1534
1535 /*----------------------------------------------------------------------+*/
1536 int
1537 sscan_logfile_data(XeString buf,
1538                    XeString *logfile,
1539                    XeString *proto_ver,
1540                    XeString *hostinfo)
1541 /*----------------------------------------------------------------------+*/
1542 {
1543   XeString *args;
1544
1545   args=sscan_counted_string(buf, NULL);
1546
1547   if(args==SPC_ERROR)
1548     return(SPC_ERROR);
1549   
1550   *logfile=args[0];
1551   /* args[1] and args[2] will only be around for protocol revision 2 or later */
1552
1553   *proto_ver = *hostinfo = XeString_NULL;
1554
1555   if (args[1]) { 
1556       *proto_ver = args[1];
1557       *hostinfo  = args[2];
1558   }
1559   else
1560       *hostinfo = strdup(SPC_UNKNOWN_HOSTINFO_STR);     
1561
1562   free((char *)args);
1563   
1564   return(TRUE);
1565 }
1566
1567 /*----------------------------------------------------------------------+*/
1568 int
1569 sprint_register_data(XeString buf,
1570                      XeString username, 
1571                      XeString passwd,
1572                      XeString proto_ver,
1573                      XeString hostinfo)
1574 /*----------------------------------------------------------------------+*/
1575 {
1576   int i;
1577   XeString args[4];
1578
1579   args[0]=username;
1580   args[1]=passwd;
1581   args[2]=proto_ver;
1582   args[3]=hostinfo;  
1583   
1584   i=sprint_counted_string(buf, 4, args, SPC_BUFSIZ);
1585   if(i==SPC_ERROR)
1586     return(SPC_ERROR);
1587   return(i);
1588 }
1589
1590 /*----------------------------------------------------------------------+*/
1591 int
1592 sscan_register_data(XeString buf,
1593                     XeString *username,
1594                     XeString *passwd,
1595                     XeString *proto_ver,
1596                     XeString *hostinfo)
1597 /*----------------------------------------------------------------------+*/
1598 {
1599   XeString *args;
1600
1601   args=sscan_counted_string(buf, NULL);
1602
1603   if(args==SPC_ERROR)
1604     return(SPC_ERROR);
1605   
1606   *username=args[0];
1607   *passwd=args[1];
1608
1609   /* args[2] and args[3] will only be around for protocol revision 2 or later */
1610
1611   *proto_ver = *hostinfo = XeString_NULL;
1612
1613   if (args[2]) { 
1614       *proto_ver = args[2];
1615       *hostinfo  = args[3];
1616   }
1617   else
1618       *hostinfo = strdup(SPC_UNKNOWN_HOSTINFO_STR);     
1619
1620   free((char *)args);
1621   
1622   return(TRUE);
1623 }
1624
1625 /*
1626  **
1627  ** Request / reply protocol requests
1628  **
1629 */
1630
1631 /*----------------------------------------------------------------------+*/
1632 int SPC_Query_Devices(SPC_Channel_Ptr channel)
1633 /*----------------------------------------------------------------------+*/
1634 {
1635   SPC_Connection_Ptr connection=channel->connection;
1636   protocol_request_ptr prot;
1637   
1638   SPC_Write_Protocol_Request(connection, channel, QUERY_DEVICES);
1639   prot=SPC_Filter_Connection(connection, channel, DEVICE_REPLY, TRUE);
1640   if(prot==SPC_ERROR)
1641     return(SPC_ERROR);
1642   
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));
1650
1651   SPC_Free_Protocol_Ptr(prot);
1652   return (TRUE);
1653 }
1654
1655 /*----------------------------------------------------------------------+*/
1656 int SPC_Query_Logfile(SPC_Channel_Ptr channel)
1657 /*----------------------------------------------------------------------+*/
1658 {
1659   SPC_Connection_Ptr connection=channel->connection;
1660   protocol_request_ptr prot;
1661   XeString junk1, junk2;
1662   
1663   SPC_Write_Protocol_Request(connection, channel, QUERY_LOGFILE);
1664   prot=SPC_Filter_Connection(connection, channel, LOGFILE_REPLY, TRUE);
1665   if(prot==SPC_ERROR)
1666     return(SPC_ERROR);
1667   
1668   READ_LOGFILE_REPLY(prot->dataptr, &channel->logfile, &junk1, &junk2);
1669   if (junk1) XeFree(junk1);
1670   if (junk2) XeFree(junk2);
1671                      
1672   SPC_Free_Protocol_Ptr(prot);
1673   return (TRUE);
1674 }
1675
1676 #define UNK_TOKEN       "unknown"
1677
1678 /*----------------------------------------------------------------------+*/
1679 XeString SPC_LocalHostinfo(void)
1680 /*----------------------------------------------------------------------+*/
1681 {
1682     struct utsname      name;
1683     int                 s_len;
1684     static XeString     s = 0;
1685
1686     _DtSvcProcessLock();
1687     if (!s) {
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);
1695         }
1696         else {
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);
1700         }
1701     }
1702
1703     _DtSvcProcessUnlock();
1704     return s;
1705 }
1706
1707 /*----------------------------------------------------------------------+*/
1708 int
1709 SPC_Validate_User(XeString hostname,
1710                   SPC_Connection_Ptr connection)
1711 /*----------------------------------------------------------------------+*/
1712     /* Called by client to register itself to spcd */
1713 {
1714   XeString username = XeString_NULL;
1715   uid_t this_uid;
1716   XeString proto_ver;
1717   XeString hostinfo;
1718   XeString path;
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;
1726
1727   hostinfo = SPC_LocalHostinfo();
1728
1729   /*
1730    *  We are now including the user ID to generate the LOGFILE
1731    *  (i.e., the authentication file)
1732    */
1733   this_uid=getuid();
1734
1735   if((pwd_ret = _XGetpwuid(this_uid, pwd_buf)) == NULL) {
1736     /* 
1737      * Very strange situation - the uid isn't in the passwd file 
1738      */
1739     username = XeString_NULL;  /* we'll use the original /tmp subdirectory */
1740   }
1741   else {
1742     username=(XeString)(pwd_ret->pw_name);
1743   }
1744
1745   SPC_Write_Protocol_Request(connection, NULL, REGISTER, 
1746                              username, XeString_Empty, 
1747                              SPC_PROTOCOL_VERSION_STR, hostinfo);
1748
1749   
1750   prot=SPC_Filter_Connection(connection, NULL, LOGFILE_REPLY, TRUE);
1751   if(prot==SPC_ERROR) {
1752     XeFree(connection_hostname);
1753     return(SPC_ERROR);
1754   }
1755
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.     */
1760
1761   READ_LOGFILE_REPLY(prot->dataptr, &logfile, &proto_ver, &hostinfo);
1762
1763   /* For Pre A.01, this will be defaulted to (hpux 7.0 s300) */
1764   connection->hostinfo = hostinfo;
1765
1766   if (proto_ver) {
1767      sscanf(proto_ver, "%d", &connection->protocol_version);
1768      XeFree(proto_ver);
1769    }
1770
1771   SPC_Free_Protocol_Ptr(prot);
1772
1773   if(!strcmp(logfile, PASSED_FILE_NAME))
1774     return(TRUE);
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);
1781     return(SPC_ERROR);
1782   }
1783
1784   /*
1785    * Get a pathname to the authentication file.
1786    */
1787   path=tt_netfile_file(logfile);
1788   
1789   if(tt_ptr_error (path) != TT_OK) {
1790     SPC_Write_Protocol_Request(connection, NULL, ABORT);
1791     SPC_Error(SPC_Register_Netrc,
1792               logfile,
1793               connection_hostname);
1794     XeFree(connection_hostname);
1795     if (logfile) XeFree(logfile);
1796     return(SPC_ERROR);
1797   }
1798
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,
1803               path,
1804               connection_hostname);
1805     tt_free (path);
1806     XeFree(connection_hostname);
1807     if (logfile) XeFree(logfile);
1808     return(SPC_ERROR);
1809   }
1810   
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. */
1814
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,
1819               path,
1820               connection_hostname);
1821     tt_free (path);
1822     XeFree(connection_hostname);
1823     if (logfile) XeFree(logfile);
1824     close(open_status);
1825     return(SPC_ERROR);
1826   }
1827   
1828   SPC_Write_Protocol_Request(connection, NULL, REGISTER, logfile, NULL, NULL, NULL);
1829   prot=SPC_Filter_Connection(connection, NULL, LOGFILE_REPLY, TRUE);
1830
1831   close(open_status);
1832   unlink(path);
1833   tt_free (path);
1834   
1835   if(prot==SPC_ERROR) {
1836     XeFree(connection_hostname);
1837     return(SPC_ERROR);
1838   }
1839   
1840   /*
1841    * Free logfile before it gets malloc'd again.
1842    */
1843   XeFree(logfile);
1844   logfile = NULL;
1845   READ_LOGFILE_REPLY(prot->dataptr, &logfile, &junk1, &junk2);
1846   if (junk1) XeFree(junk1);
1847   if (junk2) XeFree(junk2);
1848   
1849   SPC_Free_Protocol_Ptr(prot);
1850
1851   if(!strcmp(logfile, PASSED_FILE_NAME)) {
1852     XeFree(connection_hostname);
1853     if (logfile) XeFree(logfile);
1854     return(TRUE);
1855   }
1856   if(!strcmp(logfile, FAILED_FILE_NAME)) {
1857     SPC_Error(SPC_Register_Handshake,
1858               username,
1859               connection_hostname);
1860     XeFree(connection_hostname);
1861     if (logfile) XeFree(logfile);
1862     return(SPC_ERROR);
1863   }
1864
1865   if (logfile) XeFree(logfile);
1866   XeFree(connection_hostname);
1867   SPC_Error(SPC_Protocol);
1868   return(SPC_ERROR);
1869 }
1870
1871
1872 /*----------------------------------------------------------------------+*/
1873 static int SPC_Send_Termios(protocol_request_ptr prot_request)
1874 /*----------------------------------------------------------------------+*/
1875 {
1876   struct termios *tio;
1877   int retval;
1878   XeString s;
1879
1880   tio = SPC_Get_Current_Termio();       /* Gets a (malloced) copy */
1881   s = SPC_Decode_Termios( tio );        /* Get ASCII representation */
1882   
1883   retval = WRITE_STRING(prot_request->dataptr, s);
1884   XeFree(tio);
1885   XeFree(s);
1886
1887   return(retval);
1888   
1889 }
1890
1891
1892 /*----------------------------------------------------------------------+*/
1893 int SPC_Get_Termios(protocol_request_ptr prot_request)
1894 /*----------------------------------------------------------------------+*/
1895 {
1896     XeString s;
1897     int      i;
1898
1899     _DtSvcProcessLock();
1900     if(XeTermioStruct == NULL) {
1901         XeTermioStruct = (struct termios *)XeMalloc(sizeof(struct termios));
1902
1903         for(i=0; i<NCCS; i++) 
1904             XeTermioStruct->c_cc[i] = 0;
1905     }
1906     
1907     READ_STRING_NO_COPY(prot_request->dataptr, s);
1908     
1909     SPC_Encode_Termios(s, XeTermioStruct);
1910
1911     _DtSvcProcessUnlock();
1912     return(XeSetpgrp(FALSE));
1913 }
1914
1915
1916
1917 /*----------------------------------------------------------------------+*/
1918 int SPC_Get_Termio(protocol_request_ptr UNUSED_PARM(prot_request))
1919 /*----------------------------------------------------------------------+*/
1920 {
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.                          */
1925
1926     return(XeSetpgrp(FALSE));
1927 }
1928
1929 static int SPC_Send_B00_Spawn(SPC_Connection_Ptr connection,
1930                               protocol_request_ptr prot,
1931                               char *path,
1932                               char *dir,
1933                               char **argv,
1934                               char **envp)
1935 {
1936   char **merged_ptr;
1937   int num_elts=0, this_elt, num_argv, num_envp;
1938   char argv_buf[20], envp_buf[20];
1939   int retval;
1940   
1941   num_argv = 0;
1942   while(argv && argv[num_argv++])
1943     num_elts++;
1944
1945   num_envp = 0;
1946   while(envp && envp[num_envp++])
1947     num_elts++;
1948
1949   merged_ptr = (char **)malloc((num_elts+6) * sizeof(char *));
1950
1951   sprintf(argv_buf, "%d", num_argv);
1952   sprintf(envp_buf, "%d", num_envp);
1953   
1954   num_elts=0;
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;
1959
1960   this_elt = 0;
1961   while(argv && argv[this_elt])
1962     merged_ptr[num_elts++] = argv[this_elt++];
1963   
1964   merged_ptr[num_elts++] = "DUMMY";
1965
1966   this_elt = 0;
1967   while(envp && envp[this_elt])
1968     merged_ptr[num_elts++] = envp[this_elt++];
1969
1970   merged_ptr[num_elts] = NULL;
1971   
1972   retval = SPC_Send_Multi_Packet(connection, prot,
1973                                  merged_ptr, num_elts,
1974                                  APP_B00_SPAWN, "  <-- APP_B00_SPAWN",
1975                                  SPC_Arg_Too_Long);
1976   
1977   free((char *)merged_ptr);
1978
1979   return(retval);
1980 }