spc-net.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  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. /* $XConsortium: spc-net.c /main/9 1996/11/21 19:53:44 drk $
  24. * File: spc-net.c
  25. * Language: C
  26. *
  27. * (c) Copyright 1989, 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. #define __need_timeval
  35. #define __need_fd_set
  36. #define __need_all_errors
  37. #include <bms/sbport.h> /* NOTE: sbport.h must be the first include. */
  38. #include <errno.h>
  39. #include <sys/socket.h>
  40. #include <netinet/in.h>
  41. #define X_INCLUDE_NETDB_H
  42. #define XOS_USE_XT_LOCKING
  43. #include <X11/Xos_r.h>
  44. #include <SPC/spcP.h>
  45. #include <bms/MemoryMgr.h>
  46. #include <SPC/spc-proto.h>
  47. #include "DtSvcLock.h"
  48. extern int SPC_Initialized;
  49. /*
  50. ****
  51. **** Client-side code
  52. ****
  53. */
  54. /* Variables representing the local machine (initialized only once) */
  55. static struct hostent *official_hp = NULL;
  56. XeString official_hostname = NULL;
  57. /*
  58. * my_gethost will return a copy of the data returned by gethostbyname
  59. *
  60. */
  61. /*----------------------------------------------------------------------+*/
  62. static struct hostent *my_gethost(XeString hostname)
  63. /*----------------------------------------------------------------------+*/
  64. {
  65. struct hostent *host_def, *copy;
  66. int alias_count, i, addr_count, addrlen;
  67. _Xgethostbynameparams host_buf;
  68. host_def = _XGethostbyname(hostname, host_buf);
  69. if (host_def == NULL)
  70. return(FALSE);
  71. copy=(struct hostent *)XeMalloc(sizeof(struct hostent));
  72. /* Copy non-pointer info */
  73. memcpy((char *)copy, (char *)host_def, sizeof(struct hostent));
  74. alias_count=0;
  75. while(host_def->h_aliases[alias_count++]);
  76. copy->h_aliases=(char **)XeMalloc(alias_count*(sizeof(XeString)));
  77. addr_count=0;
  78. while(host_def->h_addr_list[addr_count++]);
  79. copy->h_addr_list=(char **)XeMalloc(addr_count*(sizeof(XeString)));
  80. /* Copy Hostname */
  81. copy->h_name=SPC_copy_string(host_def->h_name);
  82. /* Copy the host address. We do not use SPC_copy_string here,
  83. because the address is not a string, and may have embedded
  84. NULLs in it. */
  85. addrlen = host_def->h_length;
  86. addr_count -= 1;
  87. copy->h_addr_list[addr_count]=XeChar_NULL;
  88. for (i=0; i < addr_count; i++) {
  89. copy->h_addr_list[i]=(char *)XeMalloc(addrlen);
  90. memcpy(copy->h_addr_list[i], host_def->h_addr_list[i], addrlen);
  91. }
  92. while(alias_count--) {
  93. copy->h_aliases[alias_count]=SPC_copy_string(host_def->h_aliases[alias_count]);
  94. }
  95. return(copy);
  96. }
  97. /*
  98. * SPC_Lookup_Host will try its darndest to return a hostent structure
  99. * for the passed hostname.
  100. *
  101. */
  102. /*----------------------------------------------------------------------+*/
  103. static struct hostent *SPC_Lookup_Host(XeString hostname)
  104. /*----------------------------------------------------------------------+*/
  105. {
  106. struct hostent *official_def;
  107. official_def = my_gethost(hostname);
  108. if(!official_def) {
  109. SPC_Error(SPC_Unknown_Host, hostname);
  110. return(SPC_ERROR);
  111. }
  112. return(official_def);
  113. }
  114. /*
  115. *
  116. * SPC_Init_Local_Host_Info will initialize the local host info. It
  117. * is intended to be called only once.
  118. *
  119. */
  120. /*----------------------------------------------------------------------+*/
  121. Boolean SPC_Init_Local_Host_Info(void)
  122. /*----------------------------------------------------------------------+*/
  123. {
  124. _DtSvcProcessLock();
  125. official_hostname=(XeString) XeMalloc(MAXHOSTNAMELEN+1);
  126. Xegethostname(official_hostname, MAXHOSTNAMELEN);
  127. official_hostname[MAXHOSTNAMELEN]=0;
  128. if(!official_hp)
  129. official_hp = SPC_Lookup_Host(official_hostname);
  130. _DtSvcProcessUnlock();
  131. return(official_hp != NULL);
  132. }
  133. /*
  134. * SPC_Local_Hostname takes a string indicating a hostname, and returns
  135. * TRUE if it represents a local host, and FALSE if it is remote.
  136. */
  137. /*----------------------------------------------------------------------+*/
  138. int
  139. SPC_Local_Hostname(XeString hostname)
  140. /*----------------------------------------------------------------------+*/
  141. {
  142. /* Return TRUE if the specified hostname is local, otherwise it's remote */
  143. /* If no hostname specified, then local by definition */
  144. if (!hostname || !*hostname) return TRUE;
  145. #ifdef DEBUG
  146. return(FALSE);
  147. #endif
  148. return(XeIsLocalHostP(hostname));
  149. }
  150. /*
  151. *
  152. * SPC_Open_Connection will a connection pointer to be used for any
  153. * subsequent communication to the remote host. It will either return
  154. * an already opened connection, or create and initialize a new one.
  155. *
  156. */
  157. /*----------------------------------------------------------------------+*/
  158. SPC_Connection_Ptr SPC_Open_Connection(XeString hostname)
  159. /*----------------------------------------------------------------------+*/
  160. {
  161. SPC_Connection_Ptr connection;
  162. int seqno;
  163. XeString canonical_hostname;
  164. int tmp_errorno;
  165. /* I was told that XeFindShortHost was the correct routine to use here,
  166. but that may change in the future. */
  167. canonical_hostname=XeFindShortHost(hostname);
  168. /* check for a currently open connection */
  169. connection=SPC_Lookup_Connection(canonical_hostname);
  170. if(connection) {
  171. if(connection->connected) {
  172. XeFree(canonical_hostname);
  173. return(connection);
  174. }
  175. else {
  176. SPC_Close_Connection(connection);
  177. connection=NULL;
  178. }
  179. }
  180. /* None currently open. Grab a new one & initialize it. */
  181. if((connection = SPC_Make_Connection(canonical_hostname))==SPC_ERROR) {
  182. SPC_Close_Connection(connection);
  183. XeFree(canonical_hostname);
  184. return(SPC_ERROR);
  185. }
  186. connection->local=official_hp;
  187. if((connection->remote = SPC_Lookup_Host(canonical_hostname)) == SPC_ERROR) {
  188. SPC_Close_Connection(connection);
  189. XeFree(canonical_hostname);
  190. return(SPC_ERROR);
  191. }
  192. if(SPC_Contact_Server(connection)==SPC_ERROR) {
  193. SPC_Close_Connection(connection);
  194. XeFree(canonical_hostname);
  195. return(SPC_ERROR);
  196. }
  197. connection->connected=TRUE;
  198. if(SPC_Validate_User(canonical_hostname, connection)==SPC_ERROR) {
  199. SPC_Close_Connection(connection);
  200. XeFree(canonical_hostname);
  201. return(SPC_ERROR);
  202. }
  203. seqno=SPC_Write_Protocol_Request(connection, NULL, ENVIRON_RESET);
  204. _DtSvcProcessLock();
  205. tmp_errorno = XeSPCErrorNumber;
  206. if(SPC_Waitfor_Reply(connection, NULL, seqno) == SPC_ERROR) {
  207. SPC_Close_Connection(connection);
  208. /*
  209. * XeSPCErrorNumber could have been changed but want to
  210. * return the value from Write_Protocol_Request to the
  211. * client.
  212. */
  213. if (tmp_errorno != 0)
  214. XeSPCErrorNumber = tmp_errorno;
  215. XeFree(canonical_hostname);
  216. _DtSvcProcessUnlock();
  217. return(SPC_ERROR);
  218. }
  219. _DtSvcProcessUnlock();
  220. /* We no long ever send a RESET_TERMIO request as this was hpux */
  221. /* specific and VERY non-portable. */
  222. if (connection->protocol_version >= 2) {
  223. seqno=SPC_Write_Protocol_Request(connection, NULL, RESET_TERMIOS);
  224. if(SPC_Waitfor_Reply(connection, NULL, seqno) == SPC_ERROR) {
  225. SPC_Close_Connection(connection);
  226. XeFree(canonical_hostname);
  227. return(SPC_ERROR);
  228. }
  229. }
  230. XeFree(canonical_hostname);
  231. return(connection);
  232. }
  233. /*----------------------------------------------------------------------+*/
  234. int
  235. SPC_Open_Socket(SPC_Connection_Ptr conn,
  236. int type)
  237. /*----------------------------------------------------------------------+*/
  238. {
  239. struct servent *service;
  240. conn->sid=socket(type, SOCK_STREAM, 0);
  241. if(conn->sid == ERROR) {
  242. SPC_Error(SPC_Bad_Socket);
  243. return(SPC_ERROR);
  244. }
  245. service=getservbyname(SPC_SERVICE, SPC_PROTOCOL);
  246. if (!service) {
  247. SPC_Error(SPC_Bad_Service, SPC_SERVICE, SPC_PROTOCOL);
  248. return(FALSE);
  249. }
  250. return(service->s_port);
  251. }
  252. /*
  253. *
  254. * SPC_Contact_Server will attempt to contact the server specified by
  255. * the passed connection data structure. IT ASSUMES THAT ALL FIELDS
  256. * EXCEPT THE SOCKET ID ARE FILLED IN!!!
  257. *
  258. */
  259. /*----------------------------------------------------------------------+*/
  260. int
  261. SPC_Contact_Server(SPC_Connection_Ptr connection)
  262. /*----------------------------------------------------------------------+*/
  263. {
  264. struct sockaddr_in saddr;
  265. short addrtype;
  266. struct hostent *remote;
  267. /* Check that the connection is initialized correctly */
  268. if(!connection)
  269. return(SPC_ERROR);
  270. if(!(remote=connection->remote))
  271. return(SPC_ERROR);
  272. if(connection->connected)
  273. return(TRUE);
  274. addrtype=saddr.sin_family=remote->h_addrtype;
  275. if(!(saddr.sin_port=SPC_Open_Socket(connection, addrtype)))
  276. return(SPC_ERROR);
  277. memcpy(&saddr.sin_addr, remote->h_addr, remote->h_length);
  278. if(connect(connection->sid, (struct sockaddr *)&saddr, sizeof(saddr)) == ERROR) {
  279. XeString shorthost = XeFindShortHost(remote->h_name);
  280. SPC_Error(SPC_Bad_Connect, shorthost);
  281. XeFree(shorthost);
  282. return(SPC_ERROR);
  283. }
  284. return(TRUE);
  285. }
  286. /*
  287. ****
  288. **** Server (daemon) side code
  289. ****
  290. */
  291. #define BACKLOG 50
  292. #define MAX_SERVER_BIND_ATTEMPTS 30
  293. #define SERVER_PAUSE_INTERVAL 10
  294. /*----------------------------------------------------------------------+*/
  295. SPC_Connection_Ptr SPC_Init_Child(SPC_Connection_Ptr conn,
  296. int from)
  297. /*----------------------------------------------------------------------+*/
  298. {
  299. /* We are the child. Close the connection file descriptor
  300. (which is the socket, not our input). */
  301. close(conn->sid);
  302. /* Make the from file descriptor correspond to STDIN/STDOUT */
  303. dup2(from, STDIN);
  304. close(from);
  305. dup2(STDIN, STDOUT);
  306. /* make conn point to STDIN */
  307. conn->sid=STDIN;
  308. return(conn);
  309. }
  310. SPC_Connection_Ptr SPC_Standalone_Daemon(SPC_Connection_Ptr conn)
  311. {
  312. struct sockaddr_in saddr, client_saddr;
  313. int len=sizeof(client_saddr);
  314. int server_bind_attempts = MAX_SERVER_BIND_ATTEMPTS;
  315. int server_bind_pause = SERVER_PAUSE_INTERVAL;
  316. int pid, from;
  317. #if defined(__aix)
  318. int on=1; /* required by setsockopt */
  319. #endif
  320. saddr.sin_family=AF_INET;
  321. if(!(saddr.sin_port=SPC_Open_Socket(conn, saddr.sin_family)))
  322. return(SPC_ERROR);
  323. saddr.sin_addr.s_addr=INADDR_ANY; /* Any host address */
  324. /* Reuse the socket address if it is still in a timeout state */
  325. #if defined(__aix)
  326. if (setsockopt(conn->sid, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))==ERROR) {
  327. #else
  328. if (setsockopt(conn->sid, SOL_SOCKET, SO_REUSEADDR, NULL, 0)==ERROR) {
  329. #endif
  330. SPC_Error(SPC_Bad_Reuse);
  331. return(SPC_ERROR);
  332. }
  333. while (bind(conn->sid, (struct sockaddr *)&saddr, sizeof(saddr)) == ERROR) {
  334. if (errno == EADDRINUSE) {
  335. SPC_Error(SPC_Bind_Timeout);
  336. /* Try to get the connection in a little while */
  337. if (server_bind_attempts > 0) {
  338. server_bind_attempts--;
  339. sleep(server_bind_pause);
  340. }
  341. else {
  342. /* We don't want to wait forever */
  343. SPC_Error(SPC_Timeout);
  344. return(SPC_ERROR);
  345. }
  346. } else {
  347. SPC_Error(SPC_Bad_Bind);
  348. return(SPC_ERROR);
  349. }
  350. }
  351. /* Set up a queue for incoming connection requests */
  352. listen(conn->sid, BACKLOG);
  353. /* We are running standalone, so we need to loop forever waiting for
  354. requests. When we get one, we will fork a child to take care of
  355. the processing for us, and then the parent will listen some more */
  356. for(;;) {
  357. struct hostent *addr_ret;
  358. _Xgethostbynameparams addr_buf;
  359. /* Attempt to accept a connection with a client */
  360. from = accept(conn->sid, (struct sockaddr *)&client_saddr, &len);
  361. if (from == ERROR) {
  362. SPC_Error(SPC_Bad_Accept);
  363. return(SPC_ERROR);
  364. }
  365. addr_ret = _XGethostbyaddr((char *)&client_saddr.sin_addr,
  366. sizeof(client_saddr.sin_addr),
  367. client_saddr.sin_family,
  368. addr_buf);
  369. conn->remote = addr_ret;
  370. strncpy(conn->hostname, conn->remote->h_name, MAXHOSTNAMELEN);
  371. #ifdef DEBUG
  372. pid = NULL;
  373. #else
  374. /* Fork a process to handle I/O from/to client */
  375. pid = fork();
  376. #endif
  377. if (pid == ERROR) {
  378. SPC_Error(SPC_Cannot_Fork);
  379. /* We don't return here, but simply go around for a new try */
  380. }
  381. if (!pid)
  382. /* We are the child. Do whatever processing we need to do
  383. on the connection & return */
  384. return(SPC_Init_Child(conn, from));
  385. /* Otherwise, we are still the parent. Loop around for another
  386. connection request */
  387. }
  388. }
  389. /*----------------------------------------------------------------------+*/
  390. int
  391. SPC_Inetd_Daemon(SPC_Connection_Ptr conn)
  392. /*----------------------------------------------------------------------+*/
  393. {
  394. conn->sid=0;
  395. return(TRUE);
  396. }
  397. /*----------------------------------------------------------------------+*/
  398. SPC_Connection_Ptr SPC_Start_Daemon(int standalone)
  399. /*----------------------------------------------------------------------+*/
  400. {
  401. SPC_Connection_Ptr connection;
  402. /* Do whatever it takes to initialize SPC */
  403. _DtSvcProcessLock();
  404. if (!SPC_Initialized)
  405. if(SPC_Initialize()==SPC_ERROR) {
  406. _DtSvcProcessUnlock();
  407. return(SPC_ERROR);
  408. }
  409. _DtSvcProcessUnlock();
  410. /* Get ourselves a connection structure. We don't know the name
  411. of the remote client yet, so use the null string as hostname */
  412. if((connection=SPC_Make_Connection(NULL))==SPC_ERROR)
  413. return(SPC_ERROR);
  414. connection->local=official_hp;
  415. if(standalone) {
  416. if((SPC_Standalone_Daemon(connection))==SPC_ERROR)
  417. return(SPC_ERROR);
  418. } else {
  419. if((SPC_Inetd_Daemon(connection))==SPC_ERROR)
  420. return(SPC_ERROR);
  421. }
  422. connection->connected=TRUE;
  423. return(connection);
  424. }