source: trunk/third/sendmail/src/control.c @ 12554

Revision 12554, 6.8 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12553, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
3 *
4 * By using this file, you agree to the terms and conditions set
5 * forth in the LICENSE file which can be found at the top level of
6 * the sendmail distribution.
7 *
8 */
9
10#ifndef lint
11static char sccsid[] = "@(#)control.c   8.18 (Berkeley) 1/17/1999";
12#endif /* not lint */
13
14#include "sendmail.h"
15
16int ControlSocket = -1;
17
18/*
19**  OPENCONTROLSOCKET -- create/open the daemon control named socket
20**
21**      Creates and opens a named socket for external control over
22**      the sendmail daemon.
23**
24**      Parameters:
25**              none.
26**
27**      Returns:
28**              0 if successful, -1 otherwise
29*/
30
31int
32opencontrolsocket()
33{
34#ifdef NETUNIX
35# if _FFR_CONTROL_SOCKET
36        int rval;
37        int sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN;
38        struct sockaddr_un controladdr;
39
40        if (ControlSocketName == NULL)
41                return 0;
42
43        if (strlen(ControlSocketName) >= sizeof controladdr.sun_path)
44        {
45                errno = ENAMETOOLONG;
46                return -1;
47        }
48
49        rval = safefile(ControlSocketName, RunAsUid, RunAsGid, RunAsUserName,
50                        sff, S_IRUSR|S_IWUSR, NULL);
51
52        /* if not safe, don't create */
53        if (rval != 0)
54        {
55                errno = rval;
56                return -1;
57        }
58
59        ControlSocket = socket(AF_UNIX, SOCK_STREAM, 0);
60        if (ControlSocket < 0)
61                return -1;
62
63        unlink(ControlSocketName);
64        bzero(&controladdr, sizeof controladdr);
65        controladdr.sun_family = AF_UNIX;
66        strcpy(controladdr.sun_path, ControlSocketName);
67
68        if (bind(ControlSocket, (struct sockaddr *) &controladdr,
69                 sizeof controladdr) < 0)
70        {
71                int save_errno = errno;
72
73                clrcontrol();
74                errno = save_errno;
75                return -1;
76        }
77
78#  if _FFR_TRUSTED_USER
79        if (geteuid() == 0 && TrustedUid != 0)
80        {
81                if (chown(ControlSocketName, TrustedUid, -1) < 0)
82                {
83                        int save_errno = errno;
84
85                        sm_syslog(LOG_ALERT, NOQID,
86                                  "ownership change on %s failed: %s",
87                                  ControlSocketName, errstring(save_errno));
88                        message("050 ownership change on %s failed: %s",
89                                ControlSocketName, errstring(save_errno));
90                        closecontrolsocket(TRUE);
91                        errno = save_errno;
92                        return -1;
93                }
94        }
95#  endif
96
97        if (chmod(ControlSocketName, S_IRUSR|S_IWUSR) < 0)
98        {
99                int save_errno = errno;
100
101                closecontrolsocket(TRUE);
102                errno = save_errno;
103                return -1;
104        }
105
106        if (listen(ControlSocket, 8) < 0)
107        {
108                int save_errno = errno;
109
110                closecontrolsocket(TRUE);
111                errno = save_errno;
112                return -1;
113        }
114# endif
115#endif
116        return 0;
117}
118/*
119**  CLOSECONTROLSOCKET -- close the daemon control named socket
120**
121**      Close a named socket.
122**
123**      Parameters:
124**              fullclose -- if set, close the socket and remove it;
125**                           otherwise, just remove it
126**
127**      Returns:
128**              none.
129*/
130
131void
132closecontrolsocket(fullclose)
133        bool fullclose;
134{
135#ifdef NETUNIX
136# if _FFR_CONTROL_SOCKET
137        int sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN;
138
139        if (ControlSocket >= 0)
140        {
141                int rval;
142
143                if (fullclose)
144                {
145                        (void) close(ControlSocket);
146                        ControlSocket = -1;
147                }
148
149                rval = safefile(ControlSocketName, RunAsUid, RunAsGid, RunAsUserName,
150                                sff, S_IRUSR|S_IWUSR, NULL);
151               
152                /* if not safe, don't unlink */
153                if (rval != 0)
154                        return;
155
156                if (unlink(ControlSocketName) < 0)
157                {
158                        sm_syslog(LOG_WARNING, NOQID,
159                                  "Could not remove control socket: %s",
160                                  errstring(errno));
161                        return;
162                }
163        }
164# endif
165#endif
166        return;
167}
168/*
169**  CLRCONTROL -- reset the control connection
170**
171**      Parameters:
172**              none.
173**
174**      Returns:
175**              none.
176**
177**      Side Effects:
178**              releases any resources used by the control interface.
179*/
180
181void
182clrcontrol()
183{
184#ifdef NETUNIX
185# if _FFR_CONTROL_SOCKET
186        if (ControlSocket >= 0)
187                (void) close(ControlSocket);
188        ControlSocket = -1;
189# endif
190#endif
191}
192
193#ifndef NOT_SENDMAIL
194
195/*
196**  CONTROL_COMMAND -- read and process command from named socket
197**
198**      Read and process the command from the opened socket.
199**      Return the results down the same socket.
200**
201**      Parameters:
202**              sock -- the opened socket from getrequests()
203**              e -- the current envelope
204**
205**      Returns:
206**              none.
207*/
208
209struct cmd
210{
211        char    *cmdname;       /* command name */
212        int     cmdcode;        /* internal code, see below */
213};
214
215/* values for cmdcode */
216# define CMDERROR       0       /* bad command */
217# define CMDRESTART     1       /* restart daemon */
218# define CMDSHUTDOWN    2       /* end daemon */
219# define CMDHELP        3       /* help */
220# define CMDSTATUS      4       /* daemon status */
221
222static struct cmd       CmdTab[] =
223{
224        { "help",       CMDHELP         },
225        { "restart",    CMDRESTART      },
226        { "shutdown",   CMDSHUTDOWN     },
227        { "status",     CMDSTATUS       },
228        { NULL,         CMDERROR        }
229};
230
231void
232control_command(sock, e)
233        int sock;
234        ENVELOPE *e;
235{
236        FILE *s;
237        FILE *traffic;
238        FILE *oldout;
239        char *cmd;
240        char *p;
241        struct cmd *c;
242        char cmdbuf[MAXLINE];
243        char inp[MAXLINE];
244        extern char **SaveArgv;
245        extern void help __P((char *));
246
247        sm_setproctitle(FALSE, "control cmd read");
248               
249        s = fdopen(sock, "r+");
250        if (s == NULL)
251        {
252                int save_errno = errno;
253
254                close(sock);
255                errno = save_errno;
256                return;
257        }
258        setbuf(s, NULL);
259
260        if (fgets(inp, sizeof inp, s) == NULL)
261        {
262                fclose(s);
263                return;
264        }
265        (void) fflush(s);
266
267        /* clean up end of line */
268        fixcrlf(inp, TRUE);
269
270        sm_setproctitle(FALSE, "control: %s", inp);
271
272        /* break off command */
273        for (p = inp; isascii(*p) && isspace(*p); p++)
274                continue;
275        cmd = cmdbuf;
276        while (*p != '\0' &&
277               !(isascii(*p) && isspace(*p)) &&
278               cmd < &cmdbuf[sizeof cmdbuf - 2])
279                *cmd++ = *p++;
280        *cmd = '\0';
281       
282        /* throw away leading whitespace */
283        while (isascii(*p) && isspace(*p))
284                p++;
285       
286        /* decode command */
287        for (c = CmdTab; c->cmdname != NULL; c++)
288        {
289                if (!strcasecmp(c->cmdname, cmdbuf))
290                        break;
291        }
292
293        switch (c->cmdcode)
294        {
295          case CMDHELP:         /* get help */
296                traffic = TrafficLogFile;
297                TrafficLogFile = NULL;
298                oldout = OutChannel;
299                OutChannel = s;
300                help("control");
301                TrafficLogFile = traffic;
302                OutChannel = oldout;
303                break;
304               
305          case CMDRESTART:      /* restart the daemon */
306                if (SaveArgv[0][0] != '/')
307                {
308                        fprintf(s, "ERROR: could not restart: need full path\r\n");
309                        break;
310                }
311                if (LogLevel > 3)
312                        sm_syslog(LOG_INFO, NOQID,
313                                  "restarting %s on due to control command",
314                                  SaveArgv[0]);
315                closecontrolsocket(FALSE);
316                if (drop_privileges(TRUE) != EX_OK)
317                {
318                        if (LogLevel > 0)
319                                sm_syslog(LOG_ALERT, NOQID,
320                                          "could not set[ug]id(%d, %d): %m",
321                                          RunAsUid, RunAsGid);
322
323                        fprintf(s, "ERROR: could not set[ug]id(%d, %d): %s, exiting...\r\n",
324                                (int)RunAsUid, (int)RunAsGid, errstring(errno));
325                        finis(FALSE, EX_OSERR);
326                }
327                fprintf(s, "OK\r\n");
328                clrcontrol();
329                (void) fcntl(sock, F_SETFD, 1);
330                execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron);
331                if (LogLevel > 0)
332                        sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %m",
333                                  SaveArgv[0]);
334                fprintf(s, "ERROR: could not exec %s: %s, exiting...\r\n",
335                        SaveArgv[0], errstring(errno));
336                finis(FALSE, EX_OSFILE);
337                break;
338
339          case CMDSHUTDOWN:     /* kill the daemon */
340                fprintf(s, "OK\r\n");
341                finis(FALSE, EX_OK);
342                break;
343
344          case CMDSTATUS:       /* daemon status */
345                proc_list_probe();
346                fprintf(s, "%d/%d\r\n", CurChildren, MaxChildren);
347                proc_list_display(s);
348                break;
349
350          case CMDERROR:        /* unknown command */
351                fprintf(s, "Bad command (%s)\r\n", cmdbuf);
352                break;
353        }
354        fclose(s);
355}
356#endif
Note: See TracBrowser for help on using the repository browser.