control.c
上传用户:xu_441
上传日期:2007-01-04
资源大小:1640k
文件大小:7k
源码类别:

Email客户端

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
  3.  * All rights reserved.
  4.  *
  5.  * By using this file, you agree to the terms and conditions set
  6.  * forth in the LICENSE file which can be found at the top level of
  7.  * the sendmail distribution.
  8.  *
  9.  */
  10. #ifndef lint
  11. static char id[] = "@(#)$Id: control.c,v 8.44 1999/11/29 22:03:49 ca Exp $";
  12. #endif /* ! lint */
  13. #include <sendmail.h>
  14. int ControlSocket = -1;
  15. /*
  16. **  OPENCONTROLSOCKET -- create/open the daemon control named socket
  17. **
  18. ** Creates and opens a named socket for external control over
  19. ** the sendmail daemon.
  20. **
  21. ** Parameters:
  22. ** none.
  23. **
  24. ** Returns:
  25. ** 0 if successful, -1 otherwise
  26. */
  27. int
  28. opencontrolsocket()
  29. {
  30. #if NETUNIX
  31. int save_errno;
  32. int rval;
  33. long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN;
  34. struct sockaddr_un controladdr;
  35. if (ControlSocketName == NULL)
  36. return 0;
  37. if (strlen(ControlSocketName) >= sizeof controladdr.sun_path)
  38. {
  39. errno = ENAMETOOLONG;
  40. return -1;
  41. }
  42. rval = safefile(ControlSocketName, RunAsUid, RunAsGid, RunAsUserName,
  43. sff, S_IRUSR|S_IWUSR, NULL);
  44. /* if not safe, don't create */
  45. if (rval != 0)
  46. {
  47. errno = rval;
  48. return -1;
  49. }
  50. ControlSocket = socket(AF_UNIX, SOCK_STREAM, 0);
  51. if (ControlSocket < 0)
  52. return -1;
  53. (void) unlink(ControlSocketName);
  54. memset(&controladdr, '', sizeof controladdr);
  55. controladdr.sun_family = AF_UNIX;
  56. (void) strlcpy(controladdr.sun_path, ControlSocketName,
  57.        sizeof controladdr.sun_path);
  58. if (bind(ControlSocket, (struct sockaddr *) &controladdr,
  59.  sizeof controladdr) < 0)
  60. {
  61. save_errno = errno;
  62. clrcontrol();
  63. errno = save_errno;
  64. return -1;
  65. }
  66. if (geteuid() == 0 && TrustedUid != 0)
  67. {
  68. if (chown(ControlSocketName, TrustedUid, -1) < 0)
  69. {
  70. save_errno = errno;
  71. sm_syslog(LOG_ALERT, NOQID,
  72.   "ownership change on %s failed: %s",
  73.   ControlSocketName, errstring(save_errno));
  74. message("050 ownership change on %s failed: %s",
  75. ControlSocketName, errstring(save_errno));
  76. closecontrolsocket(TRUE);
  77. errno = save_errno;
  78. return -1;
  79. }
  80. }
  81. if (chmod(ControlSocketName, S_IRUSR|S_IWUSR) < 0)
  82. {
  83. save_errno = errno;
  84. closecontrolsocket(TRUE);
  85. errno = save_errno;
  86. return -1;
  87. }
  88. if (listen(ControlSocket, 8) < 0)
  89. {
  90. save_errno = errno;
  91. closecontrolsocket(TRUE);
  92. errno = save_errno;
  93. return -1;
  94. }
  95. #endif /* NETUNIX */
  96. return 0;
  97. }
  98. /*
  99. **  CLOSECONTROLSOCKET -- close the daemon control named socket
  100. **
  101. ** Close a named socket.
  102. **
  103. ** Parameters:
  104. ** fullclose -- if set, close the socket and remove it;
  105. **      otherwise, just remove it
  106. **
  107. ** Returns:
  108. ** none.
  109. */
  110. void
  111. closecontrolsocket(fullclose)
  112. bool fullclose;
  113. {
  114. #if NETUNIX
  115. long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN;
  116. if (ControlSocket >= 0)
  117. {
  118. int rval;
  119. if (fullclose)
  120. {
  121. (void) close(ControlSocket);
  122. ControlSocket = -1;
  123. }
  124. rval = safefile(ControlSocketName, RunAsUid, RunAsGid, RunAsUserName,
  125. sff, S_IRUSR|S_IWUSR, NULL);
  126. /* if not safe, don't unlink */
  127. if (rval != 0)
  128. return;
  129. if (unlink(ControlSocketName) < 0)
  130. {
  131. sm_syslog(LOG_WARNING, NOQID,
  132.   "Could not remove control socket: %s",
  133.   errstring(errno));
  134. return;
  135. }
  136. }
  137. #endif /* NETUNIX */
  138. return;
  139. }
  140. /*
  141. **  CLRCONTROL -- reset the control connection
  142. **
  143. ** Parameters:
  144. ** none.
  145. **
  146. ** Returns:
  147. ** none.
  148. **
  149. ** Side Effects:
  150. ** releases any resources used by the control interface.
  151. */
  152. void
  153. clrcontrol()
  154. {
  155. #if NETUNIX
  156. if (ControlSocket >= 0)
  157. (void) close(ControlSocket);
  158. ControlSocket = -1;
  159. #endif /* NETUNIX */
  160. }
  161. #ifndef NOT_SENDMAIL
  162. /*
  163. **  CONTROL_COMMAND -- read and process command from named socket
  164. **
  165. ** Read and process the command from the opened socket.
  166. ** Exits when done since it is running in a forked child.
  167. **
  168. ** Parameters:
  169. ** sock -- the opened socket from getrequests()
  170. ** e -- the current envelope
  171. **
  172. ** Returns:
  173. ** none.
  174. */
  175. struct cmd
  176. {
  177. char *cmd_name; /* command name */
  178. int cmd_code; /* internal code, see below */
  179. };
  180. /* values for cmd_code */
  181. # define CMDERROR 0 /* bad command */
  182. # define CMDRESTART 1 /* restart daemon */
  183. # define CMDSHUTDOWN 2 /* end daemon */
  184. # define CMDHELP 3 /* help */
  185. # define CMDSTATUS 4 /* daemon status */
  186. static struct cmd CmdTab[] =
  187. {
  188. { "help", CMDHELP },
  189. { "restart", CMDRESTART },
  190. { "shutdown", CMDSHUTDOWN },
  191. { "status", CMDSTATUS },
  192. { NULL, CMDERROR }
  193. };
  194. static jmp_buf CtxControlTimeout;
  195. static void
  196. controltimeout(timeout)
  197. time_t timeout;
  198. {
  199. longjmp(CtxControlTimeout, 1);
  200. }
  201. void
  202. control_command(sock, e)
  203. int sock;
  204. ENVELOPE *e;
  205. {
  206. volatile int exitstat = EX_OK;
  207. FILE *s = NULL;
  208. EVENT *ev = NULL;
  209. FILE *traffic;
  210. FILE *oldout;
  211. char *cmd;
  212. char *p;
  213. struct cmd *c;
  214. char cmdbuf[MAXLINE];
  215. char inp[MAXLINE];
  216. sm_setproctitle(FALSE, e, "control cmd read");
  217. if (TimeOuts.to_control > 0)
  218. {
  219. /* handle possible input timeout */
  220. if (setjmp(CtxControlTimeout) != 0)
  221. {
  222. if (LogLevel > 2)
  223. sm_syslog(LOG_NOTICE, e->e_id,
  224.   "timeout waiting for input during control command");
  225. exit(EX_IOERR);
  226. }
  227. ev = setevent(TimeOuts.to_control, controltimeout,
  228.       TimeOuts.to_control);
  229. }
  230. s = fdopen(sock, "r+");
  231. if (s == NULL)
  232. {
  233. int save_errno = errno;
  234. (void) close(sock);
  235. errno = save_errno;
  236. exit(EX_IOERR);
  237. }
  238. setbuf(s, NULL);
  239. if (fgets(inp, sizeof inp, s) == NULL)
  240. {
  241. (void) fclose(s);
  242. exit(EX_IOERR);
  243. }
  244. (void) fflush(s);
  245. /* clean up end of line */
  246. fixcrlf(inp, TRUE);
  247. sm_setproctitle(FALSE, e, "control: %s", inp);
  248. /* break off command */
  249. for (p = inp; isascii(*p) && isspace(*p); p++)
  250. continue;
  251. cmd = cmdbuf;
  252. while (*p != '' &&
  253.        !(isascii(*p) && isspace(*p)) &&
  254.        cmd < &cmdbuf[sizeof cmdbuf - 2])
  255. *cmd++ = *p++;
  256. *cmd = '';
  257. /* throw away leading whitespace */
  258. while (isascii(*p) && isspace(*p))
  259. p++;
  260. /* decode command */
  261. for (c = CmdTab; c->cmd_name != NULL; c++)
  262. {
  263. if (!strcasecmp(c->cmd_name, cmdbuf))
  264. break;
  265. }
  266. switch (c->cmd_code)
  267. {
  268.   case CMDHELP: /* get help */
  269. traffic = TrafficLogFile;
  270. TrafficLogFile = NULL;
  271. oldout = OutChannel;
  272. OutChannel = s;
  273. help("control", e);
  274. TrafficLogFile = traffic;
  275. OutChannel = oldout;
  276. break;
  277.   case CMDRESTART: /* restart the daemon */
  278. fprintf(s, "OKrn");
  279. exitstat = EX_RESTART;
  280. break;
  281.   case CMDSHUTDOWN: /* kill the daemon */
  282. fprintf(s, "OKrn");
  283. exitstat = EX_SHUTDOWN;
  284. break;
  285.   case CMDSTATUS: /* daemon status */
  286. proc_list_probe();
  287. fprintf(s, "%d/%d/%ld/%drn", CurChildren, MaxChildren,
  288. freediskspace(QueueDir, NULL), sm_getla(NULL));
  289. proc_list_display(s);
  290. break;
  291.   case CMDERROR: /* unknown command */
  292. fprintf(s, "Bad command (%s)rn", cmdbuf);
  293. break;
  294. }
  295. (void) fclose(s);
  296. if (ev != NULL)
  297. clrevent(ev);
  298. exit(exitstat);
  299. }
  300. #endif /* ! NOT_SENDMAIL */