Line data Source code
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 "locking/share_mode_lock.h"
27 : #include "smbd/smbd.h"
28 : #include "smbd/globals.h"
29 : #include "source3/smbd/smbXsrv_session.h"
30 : #include "ntdomain.h"
31 : #include "librpc/rpc/dcesrv_core.h"
32 : #include "printing/notify.h"
33 : #include "printing.h"
34 : #include "serverid.h"
35 : #include "messages.h"
36 : #include "passdb.h"
37 : #include "../lib/util/pidfile.h"
38 : #include "smbprofile.h"
39 : #include "libcli/auth/netlogon_creds_cli.h"
40 : #include "lib/gencache.h"
41 : #include "rpc_server/rpc_config.h"
42 : #include "lib/global_contexts.h"
43 :
44 0 : static struct files_struct *log_writeable_file_fn(
45 : struct files_struct *fsp, void *private_data)
46 : {
47 0 : bool *found = (bool *)private_data;
48 0 : char *path;
49 :
50 0 : if (!fsp->fsp_flags.can_write) {
51 0 : return NULL;
52 : }
53 0 : if (!(*found)) {
54 0 : DEBUG(0, ("Writable files open at exit:\n"));
55 0 : *found = true;
56 : }
57 :
58 0 : path = talloc_asprintf(talloc_tos(), "%s/%s", fsp->conn->connectpath,
59 0 : smb_fname_str_dbg(fsp->fsp_name));
60 0 : if (path == NULL) {
61 0 : DEBUGADD(0, ("<NOMEM>\n"));
62 : }
63 :
64 0 : DEBUGADD(0, ("%s\n", path));
65 :
66 0 : TALLOC_FREE(path);
67 0 : return NULL;
68 : }
69 :
70 : /****************************************************************************
71 : Exit the server.
72 : ****************************************************************************/
73 :
74 : /* Reasons for shutting down a server process. */
75 : enum server_exit_reason { SERVER_EXIT_NORMAL, SERVER_EXIT_ABNORMAL };
76 :
77 : static void exit_server_common(enum server_exit_reason how,
78 : const char *reason) _NORETURN_;
79 :
80 31552 : static void exit_server_common(enum server_exit_reason how,
81 : const char *reason)
82 : {
83 31552 : struct smbXsrv_client *client = global_smbXsrv_client;
84 31552 : struct smbXsrv_connection *xconn = NULL;
85 31552 : struct smbd_server_connection *sconn = NULL;
86 842 : NTSTATUS disconnect_status;
87 :
88 31552 : if (!exit_firsttime) {
89 0 : exit(0);
90 : }
91 31552 : exit_firsttime = false;
92 :
93 31552 : switch (how) {
94 31552 : case SERVER_EXIT_NORMAL:
95 31552 : disconnect_status = NT_STATUS_LOCAL_DISCONNECT;
96 31552 : break;
97 0 : case SERVER_EXIT_ABNORMAL:
98 : default:
99 0 : disconnect_status = NT_STATUS_INTERNAL_ERROR;
100 0 : break;
101 : }
102 :
103 31552 : if (client != NULL) {
104 842 : NTSTATUS status;
105 :
106 31549 : sconn = client->sconn;
107 31549 : xconn = client->connections;
108 :
109 : /*
110 : * Make sure we stop handling new multichannel
111 : * connections early!
112 : *
113 : * From here, we're not able to handle them.
114 : */
115 31549 : status = smbXsrv_client_remove(client);
116 31549 : if (!NT_STATUS_IS_OK(status)) {
117 0 : D_ERR("Server exit (%s)\n",
118 : (reason ? reason : "normal exit"));
119 0 : DBG_ERR("smbXsrv_client_remove() failed (%s)\n",
120 : nt_errstr(status));
121 : }
122 : }
123 :
124 31552 : change_to_root_user();
125 :
126 :
127 : /*
128 : * Here we typically have just one connection
129 : */
130 63975 : for (; xconn != NULL; xconn = xconn->next) {
131 : /*
132 : * This is typically the disconnect for the only
133 : * (or with multi-channel last) connection of the client.
134 : *
135 : * smbXsrv_connection_disconnect_transport() might be called already,
136 : * but calling it again is a no-op.
137 : */
138 31581 : smbXsrv_connection_disconnect_transport(xconn, disconnect_status);
139 : }
140 :
141 31552 : change_to_root_user();
142 :
143 31552 : if (sconn != NULL) {
144 31549 : if (lp_log_writeable_files_on_exit()) {
145 0 : bool found = false;
146 0 : files_forall(sconn, log_writeable_file_fn, &found);
147 : }
148 : }
149 :
150 31552 : change_to_root_user();
151 :
152 31552 : if (client != NULL) {
153 842 : NTSTATUS status;
154 :
155 : /*
156 : * Note: this is a no-op for smb2 as
157 : * conn->tcon_table is empty
158 : */
159 31549 : status = smb1srv_tcon_disconnect_all(client);
160 31549 : if (!NT_STATUS_IS_OK(status)) {
161 0 : DEBUG(0,("Server exit (%s)\n",
162 : (reason ? reason : "normal exit")));
163 0 : DEBUG(0, ("exit_server_common: "
164 : "smb1srv_tcon_disconnect_all() failed (%s) - "
165 : "triggering cleanup\n", nt_errstr(status)));
166 : }
167 :
168 31549 : status = smbXsrv_session_logoff_all(client);
169 31549 : if (!NT_STATUS_IS_OK(status)) {
170 50 : DEBUG(0,("Server exit (%s)\n",
171 : (reason ? reason : "normal exit")));
172 50 : DEBUG(0, ("exit_server_common: "
173 : "smbXsrv_session_logoff_all() failed (%s) - "
174 : "triggering cleanup\n", nt_errstr(status)));
175 : }
176 : }
177 :
178 31552 : change_to_root_user();
179 :
180 31552 : if (client != NULL) {
181 31549 : struct smbXsrv_connection *xconn_next = NULL;
182 :
183 31549 : for (xconn = client->connections;
184 63130 : xconn != NULL;
185 31581 : xconn = xconn_next) {
186 31581 : xconn_next = xconn->next;
187 31581 : DLIST_REMOVE(client->connections, xconn);
188 31581 : TALLOC_FREE(xconn);
189 : }
190 : }
191 :
192 31552 : change_to_root_user();
193 :
194 : #ifdef USE_DMAPI
195 : /* Destroy Samba DMAPI session only if we are master smbd process */
196 : if (am_parent) {
197 : if (!dmapi_destroy_session()) {
198 : DEBUG(0,("Unable to close Samba DMAPI session\n"));
199 : }
200 : }
201 : #endif
202 :
203 :
204 : /*
205 : * we need to force the order of freeing the following,
206 : * because smbd_msg_ctx is not a talloc child of smbd_server_conn.
207 : */
208 31552 : if (client != NULL) {
209 31549 : TALLOC_FREE(client->sconn);
210 : }
211 31552 : sconn = NULL;
212 31552 : xconn = NULL;
213 31552 : client = NULL;
214 31552 : netlogon_creds_cli_close_global_db();
215 31552 : TALLOC_FREE(global_smbXsrv_client);
216 31552 : smbprofile_dump();
217 31552 : global_messaging_context_free();
218 31552 : global_event_context_free();
219 31552 : TALLOC_FREE(smbd_memcache_ctx);
220 :
221 31552 : locking_end();
222 :
223 31552 : if (how != SERVER_EXIT_NORMAL) {
224 :
225 0 : smb_panic(reason);
226 :
227 : /* Notreached. */
228 : exit(1);
229 : } else {
230 31552 : DEBUG(3,("Server exit (%s)\n",
231 : (reason ? reason : "normal exit")));
232 31552 : if (am_parent) {
233 0 : pidfile_unlink(lp_pid_directory(), "smbd");
234 : }
235 : }
236 :
237 31552 : exit(0);
238 : }
239 :
240 0 : void smbd_exit_server(const char *const explanation)
241 : {
242 0 : exit_server_common(SERVER_EXIT_ABNORMAL, explanation);
243 : }
244 :
245 31552 : void smbd_exit_server_cleanly(const char *const explanation)
246 : {
247 31552 : exit_server_common(SERVER_EXIT_NORMAL, explanation);
248 : }
249 :
250 : /*
251 : * reinit_after_fork() wrapper that should be called when forking from
252 : * smbd.
253 : */
254 31566 : NTSTATUS smbd_reinit_after_fork(struct messaging_context *msg_ctx,
255 : struct tevent_context *ev_ctx,
256 : bool parent_longlived)
257 : {
258 842 : NTSTATUS ret;
259 31566 : am_parent = NULL;
260 31566 : ret = reinit_after_fork(msg_ctx, ev_ctx, parent_longlived);
261 31566 : initialize_password_db(true, ev_ctx);
262 31566 : return ret;
263 : }
|