/src/samba/source3/smbd/server_exit.c
Line | Count | Source (jump to first uncovered line) |
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 | | static struct files_struct *log_writeable_file_fn( |
45 | | struct files_struct *fsp, void *private_data) |
46 | 0 | { |
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 | 0 | } |
53 | 0 | if (!(*found)) { |
54 | 0 | DEBUG(0, ("Writable files open at exit:\n")); |
55 | 0 | *found = true; |
56 | 0 | } |
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 | 0 | } |
63 | |
|
64 | 0 | DEBUGADD(0, ("%s\n", path)); |
65 | |
|
66 | 0 | TALLOC_FREE(path); |
67 | 0 | return NULL; |
68 | 0 | } |
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 | | static void exit_server_common(enum server_exit_reason how, |
81 | | const char *reason) |
82 | 0 | { |
83 | 0 | struct smbXsrv_client *client = global_smbXsrv_client; |
84 | 0 | struct smbXsrv_connection *xconn = NULL; |
85 | 0 | struct smbd_server_connection *sconn = NULL; |
86 | 0 | NTSTATUS disconnect_status; |
87 | |
|
88 | 0 | if (!exit_firsttime) { |
89 | 0 | exit(0); |
90 | 0 | } |
91 | 0 | exit_firsttime = false; |
92 | |
|
93 | 0 | switch (how) { |
94 | 0 | case SERVER_EXIT_NORMAL: |
95 | 0 | disconnect_status = NT_STATUS_LOCAL_DISCONNECT; |
96 | 0 | break; |
97 | 0 | case SERVER_EXIT_ABNORMAL: |
98 | 0 | default: |
99 | 0 | disconnect_status = NT_STATUS_INTERNAL_ERROR; |
100 | 0 | break; |
101 | 0 | } |
102 | | |
103 | 0 | if (client != NULL) { |
104 | 0 | NTSTATUS status; |
105 | |
|
106 | 0 | sconn = client->sconn; |
107 | 0 | 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 | 0 | status = smbXsrv_client_remove(client); |
116 | 0 | if (!NT_STATUS_IS_OK(status)) { |
117 | 0 | D_ERR("Server exit (%s)\n", |
118 | 0 | (reason ? reason : "normal exit")); |
119 | 0 | DBG_ERR("smbXsrv_client_remove() failed (%s)\n", |
120 | 0 | nt_errstr(status)); |
121 | 0 | } |
122 | 0 | } |
123 | |
|
124 | 0 | change_to_root_user(); |
125 | | |
126 | | |
127 | | /* |
128 | | * Here we typically have just one connection |
129 | | */ |
130 | 0 | 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 | 0 | smbXsrv_connection_disconnect_transport(xconn, disconnect_status); |
139 | 0 | } |
140 | |
|
141 | 0 | change_to_root_user(); |
142 | |
|
143 | 0 | if (sconn != NULL) { |
144 | 0 | if (lp_log_writeable_files_on_exit()) { |
145 | 0 | bool found = false; |
146 | 0 | files_forall(sconn, log_writeable_file_fn, &found); |
147 | 0 | } |
148 | 0 | } |
149 | |
|
150 | 0 | change_to_root_user(); |
151 | |
|
152 | 0 | if (client != NULL) { |
153 | 0 | NTSTATUS status; |
154 | | |
155 | | /* |
156 | | * Note: this is a no-op for smb2 as |
157 | | * conn->tcon_table is empty |
158 | | */ |
159 | 0 | status = smb1srv_tcon_disconnect_all(client); |
160 | 0 | if (!NT_STATUS_IS_OK(status)) { |
161 | 0 | DEBUG(0,("Server exit (%s)\n", |
162 | 0 | (reason ? reason : "normal exit"))); |
163 | 0 | DEBUG(0, ("exit_server_common: " |
164 | 0 | "smb1srv_tcon_disconnect_all() failed (%s) - " |
165 | 0 | "triggering cleanup\n", nt_errstr(status))); |
166 | 0 | } |
167 | |
|
168 | 0 | status = smbXsrv_session_logoff_all(client); |
169 | 0 | if (!NT_STATUS_IS_OK(status)) { |
170 | 0 | DEBUG(0,("Server exit (%s)\n", |
171 | 0 | (reason ? reason : "normal exit"))); |
172 | 0 | DEBUG(0, ("exit_server_common: " |
173 | 0 | "smbXsrv_session_logoff_all() failed (%s) - " |
174 | 0 | "triggering cleanup\n", nt_errstr(status))); |
175 | 0 | } |
176 | 0 | } |
177 | |
|
178 | 0 | change_to_root_user(); |
179 | |
|
180 | 0 | if (client != NULL) { |
181 | 0 | struct smbXsrv_connection *xconn_next = NULL; |
182 | |
|
183 | 0 | for (xconn = client->connections; |
184 | 0 | xconn != NULL; |
185 | 0 | xconn = xconn_next) { |
186 | 0 | xconn_next = xconn->next; |
187 | 0 | DLIST_REMOVE(client->connections, xconn); |
188 | 0 | TALLOC_FREE(xconn); |
189 | 0 | } |
190 | 0 | } |
191 | |
|
192 | 0 | 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 | 0 | if (client != NULL) { |
209 | 0 | TALLOC_FREE(client->sconn); |
210 | 0 | } |
211 | 0 | sconn = NULL; |
212 | 0 | xconn = NULL; |
213 | 0 | client = NULL; |
214 | 0 | netlogon_creds_cli_close_global_db(); |
215 | 0 | TALLOC_FREE(global_smbXsrv_client); |
216 | 0 | smbprofile_dump(NULL); |
217 | 0 | global_messaging_context_free(); |
218 | 0 | global_event_context_free(); |
219 | 0 | TALLOC_FREE(smbd_memcache_ctx); |
220 | |
|
221 | 0 | locking_end(); |
222 | |
|
223 | 0 | if (how != SERVER_EXIT_NORMAL) { |
224 | |
|
225 | 0 | smb_panic(reason); |
226 | | |
227 | | /* Notreached. */ |
228 | 0 | exit(1); |
229 | 0 | } else { |
230 | 0 | DEBUG(3,("Server exit (%s)\n", |
231 | 0 | (reason ? reason : "normal exit"))); |
232 | 0 | if (am_parent) { |
233 | 0 | pidfile_unlink(lp_pid_directory(), "smbd"); |
234 | 0 | } |
235 | 0 | } |
236 | | |
237 | 0 | exit(0); |
238 | 0 | } |
239 | | |
240 | | void smbd_exit_server(const char *const explanation) |
241 | 0 | { |
242 | 0 | exit_server_common(SERVER_EXIT_ABNORMAL, explanation); |
243 | 0 | } |
244 | | |
245 | | void smbd_exit_server_cleanly(const char *const explanation) |
246 | 0 | { |
247 | 0 | exit_server_common(SERVER_EXIT_NORMAL, explanation); |
248 | 0 | } |
249 | | |
250 | | /* |
251 | | * reinit_after_fork() wrapper that should be called when forking from |
252 | | * smbd. |
253 | | */ |
254 | | NTSTATUS smbd_reinit_after_fork(struct messaging_context *msg_ctx, |
255 | | struct tevent_context *ev_ctx, |
256 | | bool parent_longlived) |
257 | 0 | { |
258 | 0 | NTSTATUS ret; |
259 | 0 | am_parent = NULL; |
260 | 0 | ret = reinit_after_fork(msg_ctx, ev_ctx, parent_longlived); |
261 | 0 | initialize_password_db(true, ev_ctx); |
262 | 0 | return ret; |
263 | 0 | } |