tdb/toos: allow transactions with TDB_MUTEX_LOCKING
[obnox/samba/samba-obnox.git] / auth / gensec / ncalrpc.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    dcerpc ncalrpc as system operations
5
6    Copyright (C) 2014      Andreas Schneider <asn@samba.org>
7    Copyright (C) 2014      Stefan Metzmacher <metze@samba.org>
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "auth/auth.h"
25 #include "auth/gensec/gensec.h"
26 #include "auth/gensec/gensec_internal.h"
27 #include "librpc/gen_ndr/dcerpc.h"
28 #include "lib/param/param.h"
29 #include "tsocket.h"
30
31 _PUBLIC_ NTSTATUS gensec_ncalrpc_as_system_init(void);
32
33 struct gensec_ncalrpc_state {
34         enum {
35                 GENSEC_NCALRPC_START,
36                 GENSEC_NCALRPC_MORE,
37                 GENSEC_NCALRPC_DONE,
38                 GENSEC_NCALRPC_ERROR,
39         } step;
40
41         struct auth_user_info_dc *user_info_dc;
42 };
43
44 static NTSTATUS gensec_ncalrpc_client_start(struct gensec_security *gensec_security)
45 {
46         struct gensec_ncalrpc_state *state;
47
48         state = talloc_zero(gensec_security,
49                             struct gensec_ncalrpc_state);
50         if (state == NULL) {
51                 return NT_STATUS_NO_MEMORY;
52         }
53         gensec_security->private_data = state;
54
55         state->step = GENSEC_NCALRPC_START;
56         return NT_STATUS_OK;
57 }
58
59 static NTSTATUS gensec_ncalrpc_server_start(struct gensec_security *gensec_security)
60 {
61         struct gensec_ncalrpc_state *state;
62
63         state = talloc_zero(gensec_security,
64                             struct gensec_ncalrpc_state);
65         if (state == NULL) {
66                 return NT_STATUS_NO_MEMORY;
67         }
68         gensec_security->private_data = state;
69
70         state->step = GENSEC_NCALRPC_START;
71         return NT_STATUS_OK;
72 }
73
74 static NTSTATUS gensec_ncalrpc_update(struct gensec_security *gensec_security,
75                                       TALLOC_CTX *mem_ctx,
76                                       struct tevent_context *ev,
77                                       const DATA_BLOB in,
78                                       DATA_BLOB *out)
79 {
80         struct gensec_ncalrpc_state *state =
81                 talloc_get_type_abort(gensec_security->private_data,
82                 struct gensec_ncalrpc_state);
83         DATA_BLOB magic_req = data_blob_string_const("NCALRPC_AUTH_TOKEN");
84         DATA_BLOB magic_ok = data_blob_string_const("NCALRPC_AUTH_OK");
85         DATA_BLOB magic_fail = data_blob_string_const("NCALRPC_AUTH_FAIL");
86         char *unix_path = NULL;
87         int cmp;
88         NTSTATUS status;
89
90         *out = data_blob_null;
91
92         if (state->step >= GENSEC_NCALRPC_DONE) {
93                 return NT_STATUS_INVALID_PARAMETER;
94         }
95
96         switch (gensec_security->gensec_role) {
97         case GENSEC_CLIENT:
98                 switch (state->step) {
99                 case GENSEC_NCALRPC_START:
100                         *out = data_blob_dup_talloc(mem_ctx, magic_req);
101                         if (out->data == NULL) {
102                                 state->step = GENSEC_NCALRPC_ERROR;
103                                 return NT_STATUS_NO_MEMORY;
104                         }
105
106                         state->step = GENSEC_NCALRPC_MORE;
107                         return NT_STATUS_MORE_PROCESSING_REQUIRED;
108
109                 case GENSEC_NCALRPC_MORE:
110                         cmp = data_blob_cmp(&in, &magic_ok);
111                         if (cmp != 0) {
112                                 state->step = GENSEC_NCALRPC_ERROR;
113                                 return NT_STATUS_LOGON_FAILURE;
114                         }
115
116                         state->step = GENSEC_NCALRPC_DONE;
117                         return NT_STATUS_OK;
118
119                 case GENSEC_NCALRPC_DONE:
120                 case GENSEC_NCALRPC_ERROR:
121                         break;
122                 }
123
124                 state->step = GENSEC_NCALRPC_ERROR;
125                 return NT_STATUS_INTERNAL_ERROR;
126
127         case GENSEC_SERVER:
128                 if (state->step != GENSEC_NCALRPC_START) {
129                         state->step = GENSEC_NCALRPC_ERROR;
130                         return NT_STATUS_INTERNAL_ERROR;
131                 }
132
133                 cmp = data_blob_cmp(&in, &magic_req);
134                 if (cmp != 0) {
135                         state->step = GENSEC_NCALRPC_ERROR;
136                         *out = data_blob_dup_talloc(mem_ctx, magic_fail);
137                         if (out->data == NULL) {
138                                 return NT_STATUS_NO_MEMORY;
139                         }
140                         return NT_STATUS_LOGON_FAILURE;
141                 }
142
143                 if (gensec_security->remote_addr == NULL) {
144                         state->step = GENSEC_NCALRPC_ERROR;
145                         *out = data_blob_dup_talloc(mem_ctx, magic_fail);
146                         if (out->data == NULL) {
147                                 return NT_STATUS_NO_MEMORY;
148                         }
149                         return NT_STATUS_LOGON_FAILURE;
150                 }
151
152                 unix_path = tsocket_address_unix_path(gensec_security->remote_addr,
153                                                       state);
154                 if (unix_path == NULL) {
155                         state->step = GENSEC_NCALRPC_ERROR;
156                         *out = data_blob_dup_talloc(mem_ctx, magic_fail);
157                         if (out->data == NULL) {
158                                 return NT_STATUS_NO_MEMORY;
159                         }
160                         return NT_STATUS_LOGON_FAILURE;
161                 }
162
163                 cmp = strcmp(unix_path, "/root/ncalrpc_as_system");
164                 TALLOC_FREE(unix_path);
165                 if (cmp != 0) {
166                         state->step = GENSEC_NCALRPC_ERROR;
167                         *out = data_blob_dup_talloc(mem_ctx, magic_fail);
168                         if (out->data == NULL) {
169                                 return NT_STATUS_NO_MEMORY;
170                         }
171                         return NT_STATUS_LOGON_FAILURE;
172                 }
173
174                 status = auth_system_user_info_dc(state,
175                                 lpcfg_netbios_name(gensec_security->settings->lp_ctx),
176                                 &state->user_info_dc);
177                 if (!NT_STATUS_IS_OK(status)) {
178                         state->step = GENSEC_NCALRPC_ERROR;
179                         *out = data_blob_dup_talloc(mem_ctx, magic_fail);
180                         if (out->data == NULL) {
181                                 return NT_STATUS_NO_MEMORY;
182                         }
183                         return status;
184                 }
185
186                 *out = data_blob_dup_talloc(mem_ctx, magic_ok);
187                 if (out->data == NULL) {
188                         state->step = GENSEC_NCALRPC_ERROR;
189                         return NT_STATUS_NO_MEMORY;
190                 }
191
192                 state->step = GENSEC_NCALRPC_DONE;
193                 return NT_STATUS_OK;
194         }
195
196         state->step = GENSEC_NCALRPC_ERROR;
197         return NT_STATUS_INTERNAL_ERROR;
198 }
199
200 static NTSTATUS gensec_ncalrpc_session_info(struct gensec_security *gensec_security,
201                                             TALLOC_CTX *mem_ctx,
202                                             struct auth_session_info **psession_info)
203 {
204         struct gensec_ncalrpc_state *state =
205                 talloc_get_type_abort(gensec_security->private_data,
206                 struct gensec_ncalrpc_state);
207         struct auth4_context *auth_ctx = gensec_security->auth_context;
208         struct auth_session_info *session_info = NULL;
209         uint32_t session_info_flags = 0;
210         NTSTATUS status;
211
212         if (gensec_security->gensec_role != GENSEC_SERVER) {
213                 return NT_STATUS_INVALID_PARAMETER;
214         }
215
216         if (state->step != GENSEC_NCALRPC_DONE) {
217                 return NT_STATUS_INVALID_PARAMETER;
218         }
219
220         if (auth_ctx == NULL) {
221                 DEBUG(0, ("Cannot generate a session_info without the auth_context\n"));
222                 return NT_STATUS_INTERNAL_ERROR;
223         }
224
225         if (auth_ctx->generate_session_info == NULL) {
226                 DEBUG(0, ("Cannot generate a session_info without the generate_session_info hook\n"));
227                 return NT_STATUS_INTERNAL_ERROR;
228         }
229
230         if (gensec_security->want_features & GENSEC_FEATURE_UNIX_TOKEN) {
231                 session_info_flags |= AUTH_SESSION_INFO_UNIX_TOKEN;
232         }
233
234         session_info_flags |= AUTH_SESSION_INFO_SIMPLE_PRIVILEGES;
235
236         status = auth_ctx->generate_session_info(
237                                 auth_ctx,
238                                 mem_ctx,
239                                 state->user_info_dc,
240                                 state->user_info_dc->info->account_name,
241                                 session_info_flags,
242                                 &session_info);
243         if (!NT_STATUS_IS_OK(status)) {
244                 return status;
245         }
246
247         *psession_info = session_info;
248         return NT_STATUS_OK;
249 }
250
251 /* We have no features */
252 static bool gensec_ncalrpc_have_feature(struct gensec_security *gensec_security,
253                                  uint32_t feature)
254 {
255         if (feature & GENSEC_FEATURE_DCE_STYLE) {
256                 return true;
257         }
258
259         return false;
260 }
261
262 static const struct gensec_security_ops gensec_ncalrpc_security_ops = {
263         .name           = "naclrpc_as_system",
264         .auth_type      = DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM,
265         .client_start   = gensec_ncalrpc_client_start,
266         .server_start   = gensec_ncalrpc_server_start,
267         .update         = gensec_ncalrpc_update,
268         .session_info   = gensec_ncalrpc_session_info,
269         .have_feature   = gensec_ncalrpc_have_feature,
270         .enabled        = true,
271         .priority       = GENSEC_EXTERNAL,
272 };
273
274 _PUBLIC_ NTSTATUS gensec_ncalrpc_as_system_init(void)
275 {
276         NTSTATUS status;
277
278         status = gensec_register(&gensec_ncalrpc_security_ops);
279         if (!NT_STATUS_IS_OK(status)) {
280                 DEBUG(0, ("Failed to register '%s' gensec backend!\n",
281                           gensec_ncalrpc_security_ops.name));
282                 return status;
283         }
284
285         return status;
286 }