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