main.c 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287
  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. * File: main.c $TOG: main.c /main/8 1999/09/30 15:31:41 mgreess $
  25. * Language: C
  26. *
  27. * (c) Copyright 1988, Hewlett-Packard Company, all rights reserved.
  28. *
  29. * (c) Copyright 1993, 1994 Hewlett-Packard Company *
  30. * (c) Copyright 1993, 1994 International Business Machines Corp. *
  31. * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
  32. * (c) Copyright 1993, 1994 Novell, Inc. *
  33. */
  34. #include <bms/sbport.h>
  35. #include <stdint.h>
  36. #include <stdlib.h>
  37. #include <stdio.h>
  38. #include <time.h> /* ctime() */
  39. #include <pwd.h>
  40. #include <errno.h>
  41. #include <signal.h>
  42. #include <unistd.h> /* initgroups() */
  43. #include <string.h>
  44. #include <libgen.h> /* basename() */
  45. #include <sys/param.h> /* MAXPATHLEN */
  46. #include <bms/bms.h>
  47. #include <bms/MemoryMgr.h>
  48. #include <bms/XeUserMsg.h>
  49. #include <bms/usersig.h>
  50. #include <bms/spc.h>
  51. #include <SPC/spcP.h>
  52. #include <SPC/spc-proto.h>
  53. #include <XlationSvc.h>
  54. #include <LocaleXlate.h>
  55. #include <Tt/tt_c.h>
  56. #include "spcd_event.h"
  57. static char *MOUNT_POINT = "DTMOUNTPOINT";
  58. /* Forward declarations */
  59. /** ------------------ **/
  60. static void Merge_Lang_Var(SPC_Channel_Ptr channel);
  61. void SPCD_Handle_Client_Data(void *channel, int *source, SbInputId *id );
  62. int SPCD_Initialize(void);
  63. void SPCD_Exit(int exitval);
  64. void SPCD_Handle_Application_Data(void *chn, XeString text, int size, int conn_type );
  65. void SPCD_Termination_Handler(SPC_Channel_Ptr channel, int pid, int type, int cause, void *data );
  66. int Client_Abort(protocol_request_ptr prot);
  67. int Client_Register(protocol_request_ptr prot);
  68. int Client_Unregister(protocol_request_ptr prot);
  69. int Client_Channel_Open(protocol_request_ptr prot);
  70. int Client_Channel_Close(protocol_request_ptr prot);
  71. int Client_Channel_Reset(protocol_request_ptr prot);
  72. int Client_Channel_Attach(protocol_request_ptr prot);
  73. int Client_Application_Spawn(protocol_request_ptr prot);
  74. int Client_Application_Signal(protocol_request_ptr prot);
  75. int Client_Application_Data(protocol_request_ptr prot);
  76. int Client_Server_Debug(protocol_request_ptr prot);
  77. int Client_Environ_Reset(protocol_request_ptr prot);
  78. int Client_Reply_Devices(protocol_request_ptr prot);
  79. int Client_Reply_Logfile(protocol_request_ptr prot);
  80. int Client_Delete_Logfile(protocol_request_ptr prot);
  81. int Client_Reset_Termio(protocol_request_ptr prot);
  82. int Client_Reset_Termios(protocol_request_ptr prot);
  83. int Client_Protocol_Version(protocol_request_ptr prot);
  84. int Client_Reply_Protocol(protocol_request_ptr prot);
  85. int Client_Reply_Hostinfo(protocol_request_ptr prot);
  86. /* New B.00 methods */
  87. int Client_Send_EOF(protocol_request_ptr prot);
  88. int Client_Channel_Termios(protocol_request_ptr prot);
  89. int Client_Enhanced_Spawn(protocol_request_ptr prot);
  90. #if defined(_AIX) || defined(__linux__)
  91. # define SA_HANDLER_INT_ARG
  92. #endif /* _AIX */
  93. void conditional_putenv(XeString env_str);
  94. void SPCD_Reply(SPC_Connection_Ptr connection, protocol_request_ptr prot, int retval, int errval );
  95. #ifdef SA_HANDLER_INT_ARG
  96. void SPCD_Alarm_Handler (int);
  97. #else
  98. void SPCD_Alarm_Handler (void);
  99. #endif /* SA_HANDLER_INT_ARG */
  100. /* Global data */
  101. protocol_request_handler spcd_protocol_dispatch_table[NREQS]={
  102. Client_Application_Data, /* APPLICATION_DATA */
  103. NULL, /* APPLICATION_STDOUT */
  104. NULL, /* APPLICATION_STDERR */
  105. Client_Abort, /* ABORT */
  106. Client_Register, /* REGISTER */
  107. Client_Unregister, /* UNREGISTER */
  108. Client_Channel_Open, /* CHANNEL_OPEN */
  109. Client_Channel_Close, /* CHANNEL_CLOSE */
  110. Client_Channel_Reset, /* CHANNEL_RESET */
  111. Client_Channel_Attach, /* CHANNEL_ATTACH */
  112. Client_Application_Spawn, /* APPLICATION_SPAWN */
  113. Client_Application_Signal, /* APPLICATION_SIGNAL */
  114. NULL, /* APPLICATION_DIED */
  115. NULL, /* SERVER_ERROR */
  116. NULL, /* REPLY */
  117. Client_Server_Debug, /* SERVER_DEBUG */
  118. Client_Environ_Reset, /* ENVIRON_RESET */
  119. Client_Reply_Devices, /* QUERY_DEVICES */
  120. NULL, /* DEVICE_REPLY */
  121. Client_Reply_Logfile, /* QUERY_LOGFILE */
  122. NULL, /* LOGFILE_REPLY */
  123. Client_Delete_Logfile, /* DELETE_LOGFILE */
  124. Client_Reset_Termio, /* RESET_TERMIO (obsolete) */
  125. Client_Reset_Termios, /* RESET_TERMIOS */
  126. Client_Send_EOF, /* CHANNEL_SEND_EOF */
  127. Client_Channel_Termios, /* CHANNEL_TERMIOS */
  128. Client_Enhanced_Spawn, /* APP_B00_SPAWN */
  129. };
  130. /*
  131. * HomeDir will be set to "HOME=pwent->pw_dir".
  132. *
  133. * ShellDir will be set to "SHELL=pwent->pw_shell".
  134. */
  135. XeChar HomeDir[MAXPATHLEN + 6];
  136. XeChar ShellDir[MAXPATHLEN + 7];
  137. XeString *default_environment;
  138. int client_validated=0;
  139. int SPCD_Abort_Okay = FALSE;
  140. SPC_Connection_Ptr client_connection;
  141. SPC_Channel client_channel;
  142. /*
  143. * This variable contains the number of minutes in the daemon's
  144. * exit timer. If the daemon has no activity within this period
  145. * of time and there are no sub-processes running, the daemon
  146. * will exit.
  147. */
  148. static int exit_timeout = SPCD_DEFAULT_TIMEOUT;
  149. /*
  150. * The following variable is used by the timer code to indicate
  151. * if a request is currently being serviced. This is necessary
  152. * because of the following scenario:
  153. *
  154. * t0 - a request is made
  155. * t1 - the request is serviced
  156. * t2 - the timer expires
  157. * t3 - the timer handler sees no sub-processes running so it exits
  158. * t4 - request is done, reply to client
  159. *
  160. * This variable is set to SPCD_REQUEST_PENDING at t0 and to
  161. * SPCD_NO_REQUST_PENDING at t4. If at t3 the variable is set
  162. * to SPCD_REQUEST_PENDING, the alarm will be reset and the
  163. * daemon will continue.
  164. */
  165. static int request_pending = SPCD_NO_REQUEST_PENDING;
  166. /*----------------------------------------------------------------------+*/
  167. int main(int argc, XeString *argv)
  168. /*----------------------------------------------------------------------+*/
  169. {
  170. /* Parse the command line and set globals accordingly. */
  171. XeString log_path = NULL;
  172. Boolean terminate_flag = FALSE;
  173. int i;
  174. struct sigaction alarm_vector;
  175. char tmp[200];
  176. char *pch;
  177. /*
  178. * The SPC library needs to know this is a SPC 'daemon' process
  179. * to ensure 'SPC_Initialize()' installs a SIGCLD handler.
  180. */
  181. SPC_who_am_i = SPC_I_AM_A_DAEMON;
  182. SPCD_Authentication_Dir = NULL;
  183. /* set up log file path */
  184. log_path = XeSBTempPath((XeString)"DTSPCD.log");
  185. if(NULL == freopen("/dev/null", "w", stderr)) {
  186. printf("Unable to open /dev/null\n");
  187. exit(EXIT_FAILURE);
  188. }
  189. /* Process arguments and set flags. */
  190. for (i=1; i < argc; i++) {
  191. if (!strcmp ("-log", argv[i])) {
  192. /* Log mode. Print information to a log file */
  193. /* Open an error log with whatever name the library wants to use */
  194. SPC_Open_Log(log_path, FALSE);
  195. }
  196. else if (!strcmp ("-debug", argv[i])) {
  197. /* Debug mode. Print protocol information to a log file */
  198. /* Open an error log with whatever name the library wants to use */
  199. SPC_Open_Log(log_path, FALSE);
  200. SPC_Print_Protocol = spc_logF;
  201. if(NULL == freopen(log_path, "a", stderr)) {
  202. printf("Unable to reopen '%s' as stderr\n", log_path);
  203. exit(EXIT_FAILURE);
  204. }
  205. setbuf(stderr, NULL);
  206. }
  207. else if (!strcmp ("-auth_dir", argv[i])) {
  208. /*
  209. * Used to override the default directory for authentication file
  210. */
  211. i++;
  212. if (i != argc) {
  213. SPC_Format_Log((XeString)"Authentication directory set to '%s'.",
  214. argv[i]);
  215. SPCD_Authentication_Dir = strdup (argv[i]);
  216. }
  217. }
  218. else if (!strcmp ("-mount_point", argv[i])) {
  219. /*
  220. * Mount point for the filename mapping system.
  221. */
  222. i++;
  223. if (i != argc) {
  224. (void) snprintf (tmp, sizeof(tmp), "%s=%s", MOUNT_POINT, argv[i]);
  225. if (putenv (tmp) == 0) {
  226. SPC_Format_Log((XeString)"Mount point set to '%s'.", argv[i]);
  227. SPC_mount_point_env_var = (char *) malloc (strlen (tmp) + 1);
  228. (void) strcpy (SPC_mount_point_env_var, tmp);
  229. }
  230. else
  231. SPC_Format_Log((XeString)"Failed to add the mount point '%s' to the environment.", tmp);
  232. }
  233. }
  234. else if (!strcmp ("-timeout", argv[i])) {
  235. /*
  236. * The timeout is specified, so use it instead of the default.
  237. */
  238. i++;
  239. if (i != argc) {
  240. exit_timeout = atoi(argv[i]);
  241. SPC_Format_Log((XeString)"Setting the exit timer to '%s' minutes.",
  242. argv[i]);
  243. }
  244. }
  245. else {
  246. /*
  247. * Unknown command option
  248. */
  249. SPC_Format_Log((XeString)"Command line option '%s' unrecognized.",
  250. argv[i]);
  251. }
  252. }
  253. /* free strings allocated for path */
  254. XeFree(log_path);
  255. /*
  256. * Initialize the i/o function pointers.
  257. */
  258. SbAddInput_hookfn = SPCD_AddInput;
  259. SbAddException_hookfn = SPCD_AddException;
  260. SbRemoveInput_hookfn = SPCD_RemoveInput;
  261. SbRemoveException_hookfn = SPCD_RemoveException;
  262. SbMainLoopUntil_hookfn = SPCD_MainLoopUntil;
  263. SbBreakMainLoop_hookfn = SPCD_BreakMainLoop;
  264. /* Initialization Commands */
  265. if (SPCD_Initialize()==SPC_ERROR)
  266. SPCD_Exit(1);
  267. client_connection=SPC_Start_Daemon(FALSE);
  268. if(client_connection==SPC_ERROR)
  269. SPCD_Exit(1);
  270. client_channel.connection = client_connection;
  271. SPC_XtAddInput(&client_channel,
  272. &client_connection->termination_id,
  273. client_connection->sid,
  274. SPCD_Handle_Client_Data,
  275. SPC_Client);
  276. if (exit_timeout != SPCD_NO_TIMER) {
  277. memset(&alarm_vector, 0, sizeof(struct sigaction));
  278. alarm_vector.sa_handler = SPCD_Alarm_Handler;
  279. alarm_vector.sa_flags = 0;
  280. (void) sigaction (SIGALRM, &alarm_vector, (struct sigaction *)NULL);
  281. (void) alarm (exit_timeout * 60);
  282. }
  283. /*
  284. * The daemon's mount point environment variable needs to be
  285. * saved. It will be used to override the client's mount point
  286. * setting or the mount point specified in any of the environment
  287. * files.
  288. */
  289. if (SPC_mount_point_env_var == NULL)
  290. if ((pch = getenv (MOUNT_POINT)) != NULL) {
  291. SPC_mount_point_env_var = (char *) malloc (strlen (pch) +
  292. strlen (MOUNT_POINT) + 2);
  293. (void) sprintf (SPC_mount_point_env_var, "%s=%s", MOUNT_POINT, pch);
  294. }
  295. XeCall_SbMainLoopUntil(&terminate_flag);
  296. SPCD_Exit(0);
  297. }
  298. /*----------------------------------------------------------------------+*/
  299. void SPCD_Handle_Client_Data(void *channel,
  300. int *UNUSED_PARM(source),
  301. SbInputId *UNUSED_PARM(id))
  302. /*----------------------------------------------------------------------+*/
  303. {
  304. protocol_request_ptr prot;
  305. int retval;
  306. SPC_Connection_Ptr connection=((SPC_Channel_Ptr)channel)->connection;
  307. request_pending = SPCD_REQUEST_PENDING;
  308. prot=SPC_Read_Protocol(connection);
  309. if(!prot)
  310. SPCD_Exit(0);
  311. /* Check for valid client (in other words, that we have registered
  312. this client). */
  313. if((!client_validated) && (prot->request_type != REGISTER)) {
  314. SPC_Error(SPC_Client_Not_Valid);
  315. if (exit_timeout != SPCD_NO_TIMER)
  316. (void) alarm (exit_timeout * 60);
  317. request_pending = SPCD_REQUEST_PENDING;
  318. SPC_Free_Protocol_Ptr(prot);
  319. return;
  320. }
  321. SPCD_Abort_Okay = TRUE;
  322. retval=SPC_Dispatch_Protocol(prot, spcd_protocol_dispatch_table);
  323. SPCD_Abort_Okay = FALSE;
  324. if(REPLY_EXPECTED(prot->request_type, TRUE) != NO_REPLY_VAL)
  325. SPCD_Reply(connection, prot, retval, errno);
  326. SPC_Free_Protocol_Ptr(prot);
  327. /*
  328. * Reset the alarm and go back to select.
  329. */
  330. if (exit_timeout != SPCD_NO_TIMER)
  331. (void) alarm (exit_timeout * 60);
  332. request_pending = SPCD_NO_REQUEST_PENDING;
  333. }
  334. /*----------------------------------------------------------------------+*/
  335. int SPCD_Initialize(void)
  336. /*----------------------------------------------------------------------+*/
  337. {
  338. XeString sys_env_file = NULL;
  339. /* Do initialization for SPC */
  340. if(SPC_Initialize()==SPC_ERROR)
  341. return(SPC_ERROR);
  342. /* Do Daemon specific initialization */
  343. /* Error handling */
  344. XeProgName=SPCD_PROG_NAME;
  345. default_environment=
  346. (XeString *) malloc(DEFAULT_ENVP_SIZE * sizeof(XeString));
  347. default_environment[0]=NULL;
  348. /*
  349. * First add the installed environment file.
  350. */
  351. sys_env_file = (XeString) malloc (strlen(SPCD_ENV_INSTALL_DIRECTORY) +
  352. strlen(SPCD_ENV_FILE) + 3);
  353. (void) sprintf (sys_env_file, "%s/%s",
  354. SPCD_ENV_INSTALL_DIRECTORY,
  355. SPCD_ENV_FILE);
  356. default_environment=SPC_Add_Env_File(sys_env_file,default_environment);
  357. /*
  358. * Now add the configured environment file.
  359. */
  360. sys_env_file = (XeString) realloc (sys_env_file,
  361. strlen(SPCD_ENV_CONFIG_DIRECTORY) +
  362. strlen(SPCD_ENV_FILE) + 3);
  363. (void) sprintf (sys_env_file, "%s/%s",
  364. SPCD_ENV_CONFIG_DIRECTORY,
  365. SPCD_ENV_FILE);
  366. default_environment=SPC_Add_Env_File(sys_env_file,default_environment);
  367. free (sys_env_file);
  368. return(TRUE);
  369. }
  370. /*----------------------------------------------------------------------+*/
  371. void SPCD_Exit(int exitval)
  372. /*----------------------------------------------------------------------+*/
  373. {
  374. int i;
  375. if (SPC_logfile_list != NULL)
  376. for (i = 0; SPC_logfile_list[i] != NULL; i++)
  377. (void) unlink (SPC_logfile_list[i]);
  378. SPC_Format_Log((XeString)"Exiting server. Retval: %d", exitval);
  379. SPC_Close_Log();
  380. exit(exitval);
  381. }
  382. /*----------------------------------------------------------------------+*/
  383. void SPCD_Handle_Application_Data(void * chn,
  384. XeString text,
  385. int size,
  386. int conn_type )
  387. /*----------------------------------------------------------------------+*/
  388. {
  389. SPC_Channel_Ptr channel= (SPC_Channel_Ptr) chn;
  390. SPC_Write_Protocol_Request(client_connection, channel,
  391. CONNECTOR_TO_PROT(conn_type), text, size);
  392. }
  393. /*----------------------------------------------------------------------+*/
  394. void SPCD_Termination_Handler(SPC_Channel_Ptr channel,
  395. int UNUSED_PARM(pid),
  396. int UNUSED_PARM(type),
  397. int UNUSED_PARM(cause),
  398. void * UNUSED_PARM(data))
  399. /*----------------------------------------------------------------------+*/
  400. {
  401. /* Write a termination protocol request */
  402. SPC_Write_Protocol_Request(client_connection, channel,
  403. APPLICATION_DIED, channel->status);
  404. /* That's all, folks! */
  405. }
  406. /*
  407. ***
  408. *** Protocol request handlers
  409. ***
  410. */
  411. /*----------------------------------------------------------------------+*/
  412. int Client_Abort(protocol_request_ptr prot)
  413. /*----------------------------------------------------------------------+*/
  414. {
  415. return(print_protocol_request((XeString)"--> ABORT", prot));
  416. }
  417. #define FREE_USER_PASS(a, b) free(a); free(b);
  418. /*----------------------------------------------------------------------+*/
  419. int Client_Register(protocol_request_ptr prot)
  420. /*----------------------------------------------------------------------+*/
  421. {
  422. XeString username;
  423. XeString passwd;
  424. XeString proto_ver;
  425. XeString hostinfo;
  426. struct passwd *pwent;
  427. XeString tmpfile, tmppath;
  428. XeChar buffer[MAXPATHLEN * 2];
  429. struct stat buf;
  430. XeString netfile;
  431. int free_netfile = 0;
  432. char *spc_prefix = "/.SPC_";
  433. char *spc_suffix;
  434. char tmpnam_buf[L_tmpnam + 1];
  435. size_t buffsize;
  436. print_protocol_request((XeString)"--> REGISTER", prot);
  437. prot->channel=0;
  438. READ_REGISTER(prot->dataptr, username, passwd, proto_ver, hostinfo);
  439. if(strcmp(username, "") != 0) {
  440. SPC_Format_Log ( "+++> Starting authentication for user '%s'\n from host '%s'.",
  441. username, hostinfo);
  442. /*
  443. * We have a username so generate a temp filename and send it
  444. * back to the client after creating the proper path for the file.
  445. */
  446. if(SPCD_Authentication_Dir)
  447. /*
  448. * Use the directory specified on the command line.
  449. */
  450. tmppath = strdup(SPCD_Authentication_Dir);
  451. else {
  452. /*
  453. * Use the $HOME directory if it can be retrieved from the
  454. * password file.
  455. */
  456. if(!(pwent=getpwnam(username))) {
  457. SPC_Format_Log ("+++> FAILURE: username '%s' is unknown.", username);
  458. SPC_Write_Protocol_Request(client_connection, NULL, LOGFILE_REPLY,
  459. FAILED_FILE_NAME, NULL, NULL);
  460. FREE_USER_PASS(username, passwd);
  461. SPC_Error(SPC_Bad_Username);
  462. free(hostinfo);
  463. return(SPC_ERROR);
  464. }
  465. else {
  466. tmppath = (XeString)(pwent->pw_dir);
  467. if ((lstat (tmppath, &buf) != 0) ||
  468. (!S_ISDIR(buf.st_mode)) ||
  469. (!(buf.st_mode & S_IRUSR)))
  470. /*
  471. * Use the default directory.
  472. */
  473. tmppath = XeSBTempPath(XeString_NULL);
  474. }
  475. }
  476. /*
  477. * tempnam(3) has side effects caused by permissions of the directory
  478. * given or the TMPDIR envirnoment variable. Because of these side
  479. * effects, the function may return "/tmp/.SPC_xxxxxx" and ignore
  480. * tmppath. The protocol will fail when this occurs. The fix is
  481. * to construct the tmpfile name.
  482. */
  483. tmpnam(tmpnam_buf);
  484. spc_suffix = basename(tmpnam_buf); /* Don't free result - not alloc'd! */
  485. /* Allocate space for tmppath, spc_prefix, and spc_suffix. */
  486. buffsize = strlen(tmppath) + strlen(spc_prefix) + strlen(spc_suffix) + 1;
  487. tmpfile = (char *)malloc(buffsize);
  488. if(tmpfile) {
  489. snprintf(tmpfile, buffsize, "%s%s%s", tmppath, spc_prefix, spc_suffix);
  490. }
  491. }
  492. else {
  493. #if 0
  494. /*
  495. * No username was supplied (this could happen with pre-CDE
  496. * clients) so generate a temp filename.
  497. */
  498. if(SPCD_Authentication_Dir)
  499. tmppath = strdup(SPCD_Authentication_Dir);
  500. else
  501. tmppath = XeSBTempPath(XeString_NULL);
  502. tmpfile = tempnam(tmppath, ".SPC_" );
  503. XeFree(tmppath);
  504. #endif
  505. SPC_Format_Log ("+++> FAILURE: NULL username.");
  506. SPC_Write_Protocol_Request(client_connection, NULL, LOGFILE_REPLY,
  507. FAILED_FILE_NAME, NULL, NULL);
  508. FREE_USER_PASS(username, passwd);
  509. SPC_Error(SPC_Bad_Username);
  510. free(hostinfo);
  511. return(SPC_ERROR);
  512. }
  513. if(!tmpfile) {
  514. SPC_Write_Protocol_Request(client_connection, NULL, LOGFILE_REPLY,
  515. FAILED_FILE_NAME, NULL, NULL);
  516. SPC_Format_Log("+++> FAILURE: cannot malloc.");
  517. SPC_Error(SPC_Out_Of_Memory);
  518. free(hostinfo);
  519. return(SPC_ERROR);
  520. }
  521. /*
  522. * Store info about the client (protocol version & host type)
  523. * For Pre A.01, this will be defaulted to (hpux 7.0 s300)
  524. */
  525. client_connection->hostinfo = hostinfo;
  526. if (proto_ver) {
  527. (void) sscanf(proto_ver, "%d", &client_connection->protocol_version);
  528. SPC_client_version_number = client_connection->protocol_version;
  529. XeFree(proto_ver);
  530. }
  531. else
  532. /* The client didn't send a protocol_version so set it to "1". */
  533. SPC_client_version_number = 1;
  534. SPC_Format_Log(" Client protocol version is '%d'.",
  535. SPC_client_version_number);
  536. SPC_Format_Log("+++> Authentication file is '%s'.", tmpfile);
  537. /*
  538. * For non-CDE clients, the clients expect the daemon to send
  539. * a "real" file name. Beginning with 'SPC_PROTOCOL_VERSION_CDE_BASE'
  540. * the clients are expecting a "netfile" name.
  541. */
  542. netfile = tmpfile;
  543. if (SPC_client_version_number >= SPC_PROTOCOL_VERSION_CDE_BASE) {
  544. netfile = tt_file_netfile (tmpfile);
  545. if (tt_ptr_error (netfile) != TT_OK) {
  546. SPC_Write_Protocol_Request(client_connection, NULL, LOGFILE_REPLY,
  547. FAILED_FILE_NAME, NULL, NULL);
  548. SPC_Format_Log("+++> FAILURE: cannot create a cannonical file name for the authentication file.\n (%s)",
  549. tt_status_message(tt_pointer_error(netfile)));
  550. XeFree(tmpfile);
  551. SPC_Error(SPC_Bad_Authentication);
  552. return(SPC_ERROR);
  553. }
  554. free_netfile = 1;
  555. SPC_Format_Log(" Authentication 'netfile' is '%s'.", netfile);
  556. }
  557. /* As we send the next packet, include protocol and host info about */
  558. /* us (the server). If going to a pre A.02 client, it will be */
  559. /* ignored by it. */
  560. SPC_Write_Protocol_Request(client_connection, NULL, LOGFILE_REPLY,
  561. netfile, SPC_PROTOCOL_VERSION_STR,
  562. SPC_LocalHostinfo());
  563. prot=SPC_Filter_Connection(client_connection, NULL, REGISTER, TRUE);
  564. if(prot==SPC_ERROR) {
  565. XeFree(tmpfile);
  566. return(SPC_ERROR);
  567. }
  568. sprintf(buffer, (XeString)"--> REGISTER (%s)", netfile);
  569. print_protocol_request(buffer, prot);
  570. SPC_Free_Protocol_Ptr(prot);
  571. /* Was the client able to create the authentication */
  572. /* file in the temp directory? */
  573. if(lstat(tmpfile, &buf)==ERROR) {
  574. int terrno = errno;
  575. SPC_Write_Protocol_Request(client_connection, NULL, LOGFILE_REPLY,
  576. FAILED_FILE_NAME, NULL, NULL);
  577. SPC_Format_Log("+++> FAILURE: lstat authentication file '%s'.", tmpfile);
  578. SPC_Format_Log("+++> FAILURE: lstat() returned error '%s'\n",
  579. strerror(terrno));
  580. if (free_netfile)
  581. tt_free(netfile);
  582. XeFree(tmpfile);
  583. SPC_Error(SPC_Bad_Authentication);
  584. return(SPC_ERROR);
  585. }
  586. if (S_ISLNK(buf.st_mode))
  587. { /* somebody is jerkin us around */
  588. SPC_Write_Protocol_Request(client_connection, NULL, LOGFILE_REPLY,
  589. FAILED_FILE_NAME, NULL, NULL);
  590. SPC_Format_Log("+++> FAILURE: lstat authentication file '%s' is a symlink! Possible compromise attempt.", tmpfile);
  591. if (free_netfile)
  592. tt_free(netfile);
  593. XeFree(tmpfile);
  594. SPC_Error(SPC_Bad_Authentication);
  595. return(SPC_ERROR);
  596. }
  597. /*
  598. * If the file does not have the setuid bit set then return failure.
  599. *
  600. * Note that if the protocol_version is < 2, this bit will
  601. * not be set and the client will not be able to connect.
  602. */
  603. if(!(buf.st_mode & S_ISUID)) {
  604. SPC_Write_Protocol_Request(client_connection, NULL, LOGFILE_REPLY,
  605. FAILED_FILE_NAME, NULL, NULL);
  606. SPC_Format_Log("+++> FAILURE: authentication file '%s' does not have the setuid bit set.",
  607. tmpfile);
  608. if (free_netfile)
  609. tt_free(netfile);
  610. XeFree(tmpfile);
  611. SPC_Error(SPC_Bad_Permission);
  612. return(SPC_ERROR);
  613. }
  614. unlink(tmpfile);
  615. XeFree(tmpfile);
  616. /*
  617. * Is uid associated with the authentication file created by the
  618. * client present in our password file?
  619. */
  620. if(!(pwent=getpwuid(buf.st_uid))) {
  621. SPC_Write_Protocol_Request(client_connection, NULL, LOGFILE_REPLY,
  622. FAILED_FILE_NAME, NULL, NULL);
  623. SPC_Format_Log("+++> FAILURE: the authentication file created by the client has a uid '%d'\n and this uid is not in the password file.",
  624. buf.st_uid);
  625. SPC_Error(SPC_Bad_Username);
  626. if (free_netfile)
  627. tt_free(netfile);
  628. return(SPC_ERROR);
  629. }
  630. /*
  631. * Comapre the user name in the request with the user name in
  632. * the passwd file. They must be the same to continue.
  633. */
  634. if (strcmp (pwent->pw_name, username) != 0) {
  635. SPC_Write_Protocol_Request(client_connection, NULL, LOGFILE_REPLY,
  636. FAILED_FILE_NAME, NULL, NULL);
  637. SPC_Format_Log("+++> FAILURE: the request is for username '%s' with uid '%d'\n but this uid has name '%s' in the password file.",
  638. username,
  639. buf.st_uid,
  640. pwent->pw_name);
  641. SPC_Error(SPC_Bad_Password);
  642. if (free_netfile)
  643. tt_free(netfile);
  644. return(SPC_ERROR);
  645. }
  646. client_validated=TRUE;
  647. /*
  648. * Need to initialize the group access list if a username
  649. * was supplied in the request.
  650. */
  651. if ((initgroups(username, pwent->pw_gid)) == -1) {
  652. SPC_Format_Log("+++> FAILURE: initgroups ('%s', '%s')",
  653. username,
  654. pwent->pw_gid);
  655. }
  656. /* We have authenticated ourselves. Set the process identifiers of
  657. this process to the looked up ones. */
  658. setgid(pwent->pw_gid);
  659. setuid(pwent->pw_uid);
  660. Xechdir(pwent->pw_dir);
  661. sprintf(HomeDir, (XeString)"HOME=%s", pwent->pw_dir);
  662. sprintf(ShellDir, (XeString)"SHELL=%s", pwent->pw_shell);
  663. putenv(HomeDir);
  664. putenv(ShellDir);
  665. spc_user_environment_file=(XeString)XeMalloc(MAXPATHLEN);
  666. sprintf(spc_user_environment_file, (XeString)"%s/%s/%s", pwent->pw_dir,
  667. SPCD_ENV_HOME_DIRECTORY, SPCD_ENV_FILE);
  668. default_environment=
  669. SPC_Add_Env_File(spc_user_environment_file, default_environment);
  670. SPC_Write_Protocol_Request(client_connection, NULL, LOGFILE_REPLY,
  671. PASSED_FILE_NAME, NULL, NULL);
  672. return(prot->seqno);
  673. }
  674. /*----------------------------------------------------------------------+*/
  675. int Client_Unregister(protocol_request_ptr prot)
  676. /*----------------------------------------------------------------------+*/
  677. {
  678. return(print_protocol_request((XeString)"--> UNREGISTER", prot));
  679. }
  680. /*----------------------------------------------------------------------+*/
  681. int Client_Channel_Open(protocol_request_ptr prot)
  682. /*----------------------------------------------------------------------+*/
  683. {
  684. int iomode;
  685. SPC_Channel_Ptr channel;
  686. print_protocol_request((XeString)"--> CHANNEL_OPEN", prot);
  687. READ_OPEN(prot->dataptr, iomode);
  688. /* Don't ever wanna wait, do line-oriented reads,
  689. use the toolkit, or execute as a system command */
  690. /* We don't do system commands because the client side has
  691. already converted the channel into the proper form for us */
  692. iomode &= ~(SPCIO_WAIT | SPCIO_LINEORIENTED |
  693. SPCIO_USE_XTOOLKIT | SPCIO_SYSTEM);
  694. /* However, we do always want our termination to be synchronous */
  695. iomode |= SPCIO_SYNC_TERMINATOR;
  696. channel=XeSPCOpen(NULL, iomode);
  697. if(channel==SPC_ERROR)
  698. return(SPC_ERROR);
  699. XeSPCAddInput(channel, SPCD_Handle_Application_Data, channel);
  700. XeSPCRegisterTerminator(channel, SPCD_Termination_Handler, channel);
  701. return((int) (intptr_t) channel);
  702. }
  703. /*----------------------------------------------------------------------+*/
  704. int Client_Channel_Close(protocol_request_ptr prot)
  705. /*----------------------------------------------------------------------+*/
  706. {
  707. SPC_Channel_Ptr channel=prot->channel;
  708. print_protocol_request((XeString)"--> CHANNEL_CLOSE", prot);
  709. if(IS_ACTIVE(channel)) {
  710. /*
  711. Uh-oh. We have received a close request, but the channel is
  712. active. We kill the process, and explicitly wait for the
  713. process to terminate.
  714. */
  715. XeSPCSignalProcess(channel, SIGKILL);
  716. SPC_Wait_For_Termination(channel);
  717. }
  718. return(XeSPCClose(channel));
  719. }
  720. /*----------------------------------------------------------------------+*/
  721. int Client_Channel_Reset(protocol_request_ptr prot)
  722. /*----------------------------------------------------------------------+*/
  723. {
  724. SPC_Channel_Ptr channel=prot->channel;
  725. print_protocol_request((XeString)"--> CHANNEL_RESET", prot);
  726. return(XeSPCReset(channel));
  727. }
  728. /*----------------------------------------------------------------------+*/
  729. int Client_Channel_Attach(protocol_request_ptr prot)
  730. /*----------------------------------------------------------------------+*/
  731. {
  732. SPC_Channel_Ptr channel=prot->channel;
  733. int pid;
  734. print_protocol_request((XeString)"--> ATTACH", prot);
  735. READ_ATTACH(prot->dataptr, pid);
  736. return(XeSPCAttach(channel, pid));
  737. }
  738. static void
  739. Merge_Lang_Var(SPC_Channel_Ptr channel)
  740. {
  741. XeString stdLang;
  742. if ((stdLang = SPC_Getenv((XeString)"LANG", channel->envp))
  743. != (XeString)NULL)
  744. {
  745. _DtXlateDb db = NULL;
  746. char platform[_DtPLATFORM_MAX_LEN];
  747. XeChar *langBuf;
  748. int execVer;
  749. int compVer;
  750. XeString myLang;
  751. if (_DtLcxOpenAllDbs(&db) == 0)
  752. {
  753. if ((_DtXlateGetXlateEnv(db, platform, &execVer, &compVer) == 0) &&
  754. (_DtLcxXlateStdToOp(db, platform, compVer, DtLCX_OPER_SETLOCALE,
  755. stdLang, NULL, NULL, NULL, &myLang) == 0))
  756. {
  757. if ((langBuf = (XeChar *)malloc((strlen(myLang) + 6)
  758. * sizeof(XeChar)))
  759. != (XeChar *)NULL)
  760. {
  761. sprintf(langBuf, "LANG=%s", myLang);
  762. channel->envp = SPC_Putenv(langBuf, channel->envp);
  763. free(langBuf);
  764. }
  765. free(myLang);
  766. }
  767. _DtLcxCloseDb(&db);
  768. }
  769. }
  770. }
  771. /*----------------------------------------------------------------------+*/
  772. int Client_Application_Spawn(protocol_request_ptr prot)
  773. /*----------------------------------------------------------------------+*/
  774. {
  775. SPC_Channel_Ptr channel=prot->channel;
  776. int retval;
  777. print_protocol_request((XeString)"--> APPLICATION_SPAWN", prot);
  778. READ_APPLICATION_SPAWN(prot->dataptr,
  779. channel->path,
  780. channel->context_dir,
  781. channel->argv, channel->envp);
  782. Merge_Lang_Var(channel);
  783. channel->IOMode |= SPCIO_DEALLOC_ARGV;
  784. channel->envp=SPC_Merge_Envp(channel->envp, default_environment);
  785. retval=XeSPCExecuteProcess(channel);
  786. if(retval==SPC_ERROR)
  787. return(SPC_ERROR);
  788. return(channel->pid);
  789. }
  790. /*----------------------------------------------------------------------+*/
  791. int Client_Application_Signal(protocol_request_ptr prot)
  792. /*----------------------------------------------------------------------+*/
  793. {
  794. XeString signame;
  795. int sig = 0;
  796. SPC_Channel_Ptr channel=prot->channel;
  797. print_protocol_request((XeString)"--> APPLICATION_SIGNAL", prot);
  798. READ_STRING_NO_COPY(prot->dataptr, signame);
  799. if (client_connection->protocol_version >= 2) {
  800. if ( (sig = XeNameToSignal( signame )) == XE_SIG_NOT_IN_TABLE ) {
  801. SPC_Error(SPC_Bad_Signal_Name, signame);
  802. return (SPC_ERROR);
  803. }
  804. } else {
  805. /* Must be the old 1.0, 1.1 protocol, assume its a number. */
  806. /* Note however, that this is not portable as the signal numbers */
  807. /* differ from system to system. This should really be an error */
  808. /* 1.0 code allowed signal 0 (check if process alive), but its */
  809. /* part of XPG3 so we don't honor it .. nobody ever used it anyway */
  810. int ok = sscanf(signame, "%x", &sig); /* WRITE_INT (%x) was used */
  811. if ( (ok == EOF) || (sig == 0) ) {
  812. SPC_Error(SPC_Bad_Signal_Format, signame);
  813. return (SPC_ERROR);
  814. }
  815. }
  816. return(XeSPCSignalProcess(channel, sig));
  817. }
  818. /*----------------------------------------------------------------------+*/
  819. int Client_Application_Data(protocol_request_ptr prot)
  820. /*----------------------------------------------------------------------+*/
  821. {
  822. SPC_Channel_Ptr channel=prot->channel;
  823. buffered_data_ptr pdata=prot->dataptr;
  824. print_protocol_request((XeString)"--> APPLICATION_DATA", prot);
  825. return(XeSPCWrite(channel,
  826. pdata->data+REQUEST_HEADER_LENGTH,
  827. pdata->len));
  828. }
  829. /*----------------------------------------------------------------------+*/
  830. int Client_Server_Debug(protocol_request_ptr prot)
  831. /*----------------------------------------------------------------------+*/
  832. {
  833. SPC_Channel_Ptr channel=prot->channel;
  834. buffered_data_ptr pdata=prot->dataptr;
  835. XeChar filename[MAXPATHLEN];
  836. time_t timeval;
  837. print_protocol_request((XeString)"--> SERVER_DEBUG", prot);
  838. READ_DEBUG(pdata, filename);
  839. if(SPC_Print_Protocol)
  840. fclose(SPC_Print_Protocol);
  841. SPC_Print_Protocol=fopen(filename, (XeString)"a+");
  842. if(!SPC_Print_Protocol)
  843. return(ERROR);
  844. setbuf(SPC_Print_Protocol, NULL);
  845. time(&timeval);
  846. fprintf(SPC_Print_Protocol, (XeString)"Begin protocol filedump: %s", ctime(&timeval));
  847. return(TRUE);
  848. }
  849. /*
  850. ***
  851. *** The purpose of this routine is to filter out environment variables
  852. *** which should not get put into the environment.
  853. ***
  854. */
  855. /*----------------------------------------------------------------------+*/
  856. void conditional_putenv(XeString env_str)
  857. /*----------------------------------------------------------------------+*/
  858. {
  859. if(strncmp(env_str, (XeString)"HOME=", 5) && /* HOME may be different */
  860. strncmp(env_str, (XeString)"PWD=", 4) /* PWD set by chdir, may change */
  861. /* Should SHELL be on this list? */
  862. )
  863. {
  864. putenv(env_str);
  865. }
  866. }
  867. /*----------------------------------------------------------------------+*/
  868. int Client_Environ_Reset(protocol_request_ptr prot)
  869. /*----------------------------------------------------------------------+*/
  870. {
  871. int num_vars;
  872. XeString envp[100];
  873. char **ret;
  874. int outlen, i;
  875. ret = NULL;
  876. READ_ENVIRON_RESET(prot->dataptr, num_vars);
  877. if(num_vars < 100)
  878. ret = envp;
  879. ret = SPC_Get_Multi_Packet(client_connection, prot,
  880. ret, &outlen,
  881. ENVIRON_RESET, "--> ENVIRON_RESET");
  882. if(ret == NULL)
  883. return(SPC_ERROR);
  884. for(i=0; i<outlen; i++)
  885. if(ret[i] && *ret[i])
  886. conditional_putenv(ret[i]);
  887. if(ret != envp)
  888. free((char *)ret);
  889. return(TRUE);
  890. }
  891. /*----------------------------------------------------------------------+*/
  892. int Client_Reply_Devices(protocol_request_ptr prot)
  893. /*----------------------------------------------------------------------+*/
  894. {
  895. SPC_Channel_Ptr channel=prot->channel;
  896. print_protocol_request((XeString)"--> QUERY_DEVICES", prot);
  897. SPC_Write_Protocol_Request(client_connection, channel, DEVICE_REPLY,
  898. channel->wires[STDIN]->master_name,
  899. channel->wires[STDIN]->slave_name,
  900. channel->wires[STDOUT]->master_name,
  901. channel->wires[STDOUT]->slave_name,
  902. channel->wires[STDERR]->master_name,
  903. channel->wires[STDERR]->slave_name);
  904. return(TRUE);
  905. }
  906. /*----------------------------------------------------------------------+*/
  907. int Client_Reply_Logfile(protocol_request_ptr prot)
  908. /*----------------------------------------------------------------------+*/
  909. {
  910. char *netfile;
  911. SPC_Channel_Ptr channel=prot->channel;
  912. print_protocol_request((XeString)"--> QUERY_LOGFILE", prot);
  913. if (SPC_client_version_number >= SPC_PROTOCOL_VERSION_CDE_BASE &&
  914. IS_SPCIO_USE_LOGFILE(channel->IOMode)) {
  915. netfile = tt_file_netfile (channel->logfile);
  916. if (tt_ptr_error (netfile) != TT_OK) {
  917. SPC_Format_Log("+++> FAILURE: cannot create a 'netfile' name for the logfile.\n (%s)",
  918. tt_status_message(tt_pointer_error(netfile)));
  919. return(SPC_ERROR);
  920. }
  921. SPC_Write_Protocol_Request(client_connection, channel, LOGFILE_REPLY,
  922. netfile, NULL, NULL);
  923. tt_free (netfile);
  924. }
  925. else
  926. SPC_Write_Protocol_Request(client_connection, channel, LOGFILE_REPLY,
  927. channel->logfile, NULL, NULL);
  928. return(TRUE);
  929. }
  930. /*----------------------------------------------------------------------+*/
  931. int Client_Delete_Logfile(protocol_request_ptr prot)
  932. /*----------------------------------------------------------------------+*/
  933. {
  934. SPC_Channel_Ptr channel=prot->channel;
  935. print_protocol_request((XeString)"--> DELETE_LOGFILE", prot);
  936. return(XeSPCRemoveLogfile(channel));
  937. }
  938. /*----------------------------------------------------------------------+*/
  939. int Client_Reset_Termio(protocol_request_ptr prot)
  940. /*----------------------------------------------------------------------+*/
  941. {
  942. /* This handles old 1.0 versions of the SPC code. We used to send */
  943. /* an hp-ux version of the termio struct in a non-portable manner */
  944. /* We need to be able to "eat" such an request if we get one. */
  945. print_protocol_request((XeString)"--> RESET_TERMIO", prot);
  946. return(SPC_Get_Termio(prot));
  947. }
  948. /*----------------------------------------------------------------------+*/
  949. int Client_Reset_Termios(protocol_request_ptr prot)
  950. /*----------------------------------------------------------------------+*/
  951. {
  952. print_protocol_request((XeString)"--> RESET_TERMIOS", prot);
  953. return(SPC_Get_Termios(prot));
  954. }
  955. /* New B.00 methods */
  956. /*----------------------------------------------------------------------+*/
  957. int Client_Send_EOF(protocol_request_ptr prot)
  958. /*----------------------------------------------------------------------+*/
  959. {
  960. SPC_Channel_Ptr channel=prot->channel;
  961. print_protocol_request((XeString)"--> SEND_EOF", prot);
  962. return(XeSPCSendEOF(channel));
  963. }
  964. int Client_Channel_Termios(protocol_request_ptr prot)
  965. {
  966. SPC_Channel_Ptr channel=prot->channel;
  967. int connection, side;
  968. char buffer[1024];
  969. struct termios t;
  970. print_protocol_request((XeString)"--> CHANNEL_TERMIOS", prot);
  971. READ_TERMIOS(prot->dataptr, connection, side, buffer);
  972. SPC_Encode_Termios(buffer, &t);
  973. return(XeSPCSetTermio(channel, connection, side, &t));
  974. }
  975. int Client_Enhanced_Spawn(protocol_request_ptr prot)
  976. {
  977. SPC_Channel_Ptr channel = prot->channel;
  978. int num_vars;
  979. XeString buf[100];
  980. char **ret;
  981. int numenv, numarg;
  982. int return_value, outlen, i;
  983. ret = NULL;
  984. READ_ENVIRON_RESET(prot->dataptr, num_vars);
  985. if(num_vars < 100)
  986. ret = buf;
  987. ret = SPC_Get_Multi_Packet(client_connection, prot,
  988. ret, &outlen,
  989. APP_B00_SPAWN, "--> APP_B00_SPAWN");
  990. if(ret == NULL)
  991. return(SPC_ERROR);
  992. channel->path = strdup(ret[0]);
  993. channel->context_dir = strdup(ret[1]);
  994. numarg = atoi(ret[2]);
  995. numenv = atoi(ret[3]);
  996. if(numarg == 0)
  997. channel->argv = NULL;
  998. else {
  999. channel->argv = &ret[4];
  1000. ret[numarg+3] = NULL;
  1001. }
  1002. if(numenv == 0)
  1003. channel->envp = NULL;
  1004. else {
  1005. channel->envp = (char **)XeMalloc((numenv+1)*sizeof(char *));
  1006. channel->envp[0] = NULL;
  1007. channel->envp = SPC_Merge_Envp(channel->envp, &ret[numarg+4]);
  1008. Merge_Lang_Var(channel);
  1009. channel->envp = SPC_Merge_Envp(channel->envp, default_environment);
  1010. }
  1011. return_value = XeSPCExecuteProcess(channel);
  1012. /* Make the world safe for freeing the channel */
  1013. channel->argv = NULL;
  1014. if(channel->envp == &ret[numarg+4])
  1015. channel->envp = NULL;
  1016. for(i=0; i<outlen; i++)
  1017. if(ret[i])
  1018. free(ret[i]);
  1019. if(ret != buf)
  1020. free((char *)ret);
  1021. if(return_value==SPC_ERROR)
  1022. return(SPC_ERROR);
  1023. return(channel->pid);
  1024. }
  1025. /*----------------------------------------------------------------------+*/
  1026. void SPCD_Reply(SPC_Connection_Ptr connection,
  1027. protocol_request_ptr prot,
  1028. int retval,
  1029. int errval)
  1030. /*----------------------------------------------------------------------+*/
  1031. {
  1032. if(retval==SPC_ERROR)
  1033. retval= (-XeSPCErrorNumber);
  1034. SPC_Write_Reply(connection, prot, retval, errval);
  1035. }
  1036. /*----------------------------------------------------------------------+*/
  1037. /*
  1038. * This function is invoked when the exit timer expires.
  1039. * If sub-processes are running, return to select;
  1040. * otherwise exit.
  1041. */
  1042. #ifdef SA_HANDLER_INT_ARG
  1043. void SPCD_Alarm_Handler(int not_used)
  1044. #else
  1045. void SPCD_Alarm_Handler()
  1046. #endif /* SA_HANDLER_INT_ARG */
  1047. /*----------------------------------------------------------------------+*/
  1048. {
  1049. int i;
  1050. if (exit_timeout == SPCD_NO_TIMER)
  1051. return;
  1052. if (SPC_pid_list != NULL)
  1053. for (i=0; SPC_pid_list[i] != 0; i++) {
  1054. if (SPC_pid_list[i] != SPCD_DEAD_PROCESS) {
  1055. /*
  1056. * Have at least one sub- process running so reset the
  1057. * alarm and return to select.
  1058. */
  1059. (void) alarm (exit_timeout * 60);
  1060. return;
  1061. }
  1062. }
  1063. /*
  1064. * There are no sub-processes running. Exit if a request is not pending
  1065. */
  1066. if (request_pending != SPCD_REQUEST_PENDING) {
  1067. SPC_Format_Log((XeString)
  1068. "Exit timer expired after '%d' minutes of no activity.",
  1069. exit_timeout);
  1070. SPCD_Exit (0);
  1071. }
  1072. }