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