vfs_shadow_copy2: add a blackbox test suite
[obnox/samba/samba-obnox.git] / source3 / smbd / server_exit.c
1 /*
2    Unix SMB/CIFS implementation.
3    Main SMB server routines
4    Copyright (C) Andrew Tridgell                1992-1998
5    Copyright (C) Martin Pool                    2002
6    Copyright (C) Jelmer Vernooij                2002-2003
7    Copyright (C) Volker Lendecke                1993-2007
8    Copyright (C) Jeremy Allison                 1993-2007
9    Copyright (C) Andrew Bartlett                2010
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26 #include "smbd/smbd.h"
27 #include "smbd/globals.h"
28 #include "ntdomain.h"
29 #include "../librpc/gen_ndr/srv_dfs.h"
30 #include "../librpc/gen_ndr/srv_dssetup.h"
31 #include "../librpc/gen_ndr/srv_echo.h"
32 #include "../librpc/gen_ndr/srv_eventlog.h"
33 #include "../librpc/gen_ndr/srv_initshutdown.h"
34 #include "../librpc/gen_ndr/srv_lsa.h"
35 #include "../librpc/gen_ndr/srv_netlogon.h"
36 #include "../librpc/gen_ndr/srv_ntsvcs.h"
37 #include "../librpc/gen_ndr/srv_samr.h"
38 #include "../librpc/gen_ndr/srv_spoolss.h"
39 #include "../librpc/gen_ndr/srv_srvsvc.h"
40 #include "../librpc/gen_ndr/srv_svcctl.h"
41 #include "../librpc/gen_ndr/srv_winreg.h"
42 #include "../librpc/gen_ndr/srv_wkssvc.h"
43 #include "printing/notify.h"
44 #include "printing.h"
45 #include "serverid.h"
46 #include "messages.h"
47 #include "../lib/util/pidfile.h"
48 #include "smbprofile.h"
49
50 static struct files_struct *log_writeable_file_fn(
51         struct files_struct *fsp, void *private_data)
52 {
53         bool *found = (bool *)private_data;
54         char *path;
55
56         if (!fsp->can_write) {
57                 return NULL;
58         }
59         if (!(*found)) {
60                 DEBUG(0, ("Writable files open at exit:\n"));
61                 *found = true;
62         }
63
64         path = talloc_asprintf(talloc_tos(), "%s/%s", fsp->conn->connectpath,
65                                smb_fname_str_dbg(fsp->fsp_name));
66         if (path == NULL) {
67                 DEBUGADD(0, ("<NOMEM>\n"));
68         }
69
70         DEBUGADD(0, ("%s\n", path));
71
72         TALLOC_FREE(path);
73         return NULL;
74 }
75
76 /****************************************************************************
77  Exit the server.
78 ****************************************************************************/
79
80 /* Reasons for shutting down a server process. */
81 enum server_exit_reason { SERVER_EXIT_NORMAL, SERVER_EXIT_ABNORMAL };
82
83 static void exit_server_common(enum server_exit_reason how,
84         const char *reason) _NORETURN_;
85
86 static void exit_server_common(enum server_exit_reason how,
87         const char *reason)
88 {
89         struct smbXsrv_client *client = global_smbXsrv_client;
90         struct smbXsrv_connection *xconn = NULL;
91         struct smbd_server_connection *sconn = NULL;
92         struct messaging_context *msg_ctx = server_messaging_context();
93
94         if (client != NULL) {
95                 sconn = client->sconn;
96                 /*
97                  * Here we typically have just one connection
98                  */
99                 xconn = client->connections;
100         }
101
102         if (!exit_firsttime)
103                 exit(0);
104         exit_firsttime = false;
105
106         change_to_root_user();
107
108         if (xconn != NULL) {
109                 /*
110                  * This is typically the disconnect for the only
111                  * (or with multi-channel last) connection of the client
112                  */
113                 if (NT_STATUS_IS_OK(xconn->transport.status)) {
114                         switch (how) {
115                         case SERVER_EXIT_ABNORMAL:
116                                 xconn->transport.status = NT_STATUS_INTERNAL_ERROR;
117                                 break;
118                         case SERVER_EXIT_NORMAL:
119                                 xconn->transport.status = NT_STATUS_LOCAL_DISCONNECT;
120                                 break;
121                         }
122                 }
123
124                 TALLOC_FREE(xconn->smb1.negprot.auth_context);
125         }
126
127         change_to_root_user();
128
129         if (sconn != NULL) {
130                 if (lp_log_writeable_files_on_exit()) {
131                         bool found = false;
132                         files_forall(sconn, log_writeable_file_fn, &found);
133                 }
134         }
135
136         change_to_root_user();
137
138         if (xconn != NULL) {
139                 NTSTATUS status;
140
141                 /*
142                  * Note: this is a no-op for smb2 as
143                  * conn->tcon_table is empty
144                  */
145                 status = smb1srv_tcon_disconnect_all(xconn);
146                 if (!NT_STATUS_IS_OK(status)) {
147                         DEBUG(0,("Server exit (%s)\n",
148                                 (reason ? reason : "normal exit")));
149                         DEBUG(0, ("exit_server_common: "
150                                   "smb1srv_tcon_disconnect_all() failed (%s) - "
151                                   "triggering cleanup\n", nt_errstr(status)));
152                         how = SERVER_EXIT_ABNORMAL;
153                         reason = "smb1srv_tcon_disconnect_all failed";
154                 }
155
156                 status = smbXsrv_session_logoff_all(xconn);
157                 if (!NT_STATUS_IS_OK(status)) {
158                         DEBUG(0,("Server exit (%s)\n",
159                                 (reason ? reason : "normal exit")));
160                         DEBUG(0, ("exit_server_common: "
161                                   "smbXsrv_session_logoff_all() failed (%s) - "
162                                   "triggering cleanup\n", nt_errstr(status)));
163                         how = SERVER_EXIT_ABNORMAL;
164                         reason = "smbXsrv_session_logoff_all failed";
165                 }
166         }
167
168         change_to_root_user();
169
170         /* 3 second timeout. */
171         print_notify_send_messages(msg_ctx, 3);
172
173         /* delete our entry in the serverid database. */
174         if (am_parent) {
175                 /*
176                  * For children the parent takes care of cleaning up
177                  */
178                 serverid_deregister(messaging_server_id(msg_ctx));
179         }
180
181 #ifdef USE_DMAPI
182         /* Destroy Samba DMAPI session only if we are master smbd process */
183         if (am_parent) {
184                 if (!dmapi_destroy_session()) {
185                         DEBUG(0,("Unable to close Samba DMAPI session\n"));
186                 }
187         }
188 #endif
189
190         if (am_parent) {
191                 rpc_wkssvc_shutdown();
192                 rpc_dssetup_shutdown();
193 #ifdef DEVELOPER
194                 rpc_rpcecho_shutdown();
195 #endif
196                 rpc_netdfs_shutdown();
197                 rpc_initshutdown_shutdown();
198                 rpc_eventlog_shutdown();
199                 rpc_ntsvcs_shutdown();
200                 rpc_svcctl_shutdown();
201                 rpc_spoolss_shutdown();
202
203                 rpc_srvsvc_shutdown();
204                 rpc_winreg_shutdown();
205
206                 rpc_netlogon_shutdown();
207                 rpc_samr_shutdown();
208                 rpc_lsarpc_shutdown();
209         }
210
211         /*
212          * we need to force the order of freeing the following,
213          * because smbd_msg_ctx is not a talloc child of smbd_server_conn.
214          */
215         if (client != NULL) {
216                 struct smbXsrv_connection *next;
217
218                 for (; xconn != NULL; xconn = next) {
219                         next = xconn->next;
220                         DLIST_REMOVE(client->connections, xconn);
221                         talloc_free(xconn);
222                         DO_PROFILE_INC(disconnect);
223                 }
224                 TALLOC_FREE(client->sconn);
225         }
226         sconn = NULL;
227         xconn = NULL;
228         client = NULL;
229         TALLOC_FREE(global_smbXsrv_client);
230         smbprofile_dump();
231         server_messaging_context_free();
232         server_event_context_free();
233         TALLOC_FREE(smbd_memcache_ctx);
234
235         locking_end();
236         printing_end();
237
238         if (how != SERVER_EXIT_NORMAL) {
239
240                 smb_panic(reason);
241
242                 /* Notreached. */
243                 exit(1);
244         } else {
245                 DEBUG(3,("Server exit (%s)\n",
246                         (reason ? reason : "normal exit")));
247                 if (am_parent) {
248                         pidfile_unlink(lp_pid_directory(), "smbd");
249                 }
250                 gencache_stabilize();
251         }
252
253         exit(0);
254 }
255
256 void smbd_exit_server(const char *const explanation)
257 {
258         exit_server_common(SERVER_EXIT_ABNORMAL, explanation);
259 }
260
261 void smbd_exit_server_cleanly(const char *const explanation)
262 {
263         exit_server_common(SERVER_EXIT_NORMAL, explanation);
264 }
265
266 /*
267  * reinit_after_fork() wrapper that should be called when forking from
268  * smbd.
269  */
270 NTSTATUS smbd_reinit_after_fork(struct messaging_context *msg_ctx,
271                                 struct tevent_context *ev_ctx,
272                                 bool parent_longlived, const char *comment)
273 {
274         am_parent = NULL;
275         return reinit_after_fork(msg_ctx, ev_ctx, parent_longlived, comment);
276 }