Merge commit 'release-4-0-0alpha15' into master4-tmp
[mat/samba.git] / source3 / rpc_server / dcesrv_gssapi.c
1 /*
2  *  GSSAPI Acceptor
3  *  DCERPC Server functions
4  *  Copyright (C) Simo Sorce 2010.
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20
21 #include "includes.h"
22 #include "rpc_server/dcesrv_gssapi.h"
23 #include "../librpc/gen_ndr/ndr_krb5pac.h"
24 #include "librpc/crypto/gse.h"
25 #include "auth.h"
26 #ifdef HAVE_KRB5
27 #include "libcli/auth/krb5_wrap.h"
28 #endif
29 NTSTATUS gssapi_server_auth_start(TALLOC_CTX *mem_ctx,
30                                   bool do_sign,
31                                   bool do_seal,
32                                   bool is_dcerpc,
33                                   DATA_BLOB *token_in,
34                                   DATA_BLOB *token_out,
35                                   struct gse_context **ctx)
36 {
37         struct gse_context *gse_ctx = NULL;
38         uint32_t add_flags = 0;
39         NTSTATUS status;
40
41         if (is_dcerpc) {
42                 add_flags = GSS_C_DCE_STYLE;
43         }
44
45         /* Let's init the gssapi machinery for this connection */
46         /* passing a NULL server name means the server will try
47          * to accept any connection regardless of the name used as
48          * long as it can find a decryption key */
49         /* by passing NULL, the code will attempt to set a default
50          * keytab based on configuration options */
51         status = gse_init_server(mem_ctx, do_sign, do_seal,
52                                  add_flags, &gse_ctx);
53         if (!NT_STATUS_IS_OK(status)) {
54                 DEBUG(0, ("Failed to init dcerpc gssapi server (%s)\n",
55                           nt_errstr(status)));
56                 return status;
57         }
58
59         status = gse_get_server_auth_token(mem_ctx, gse_ctx,
60                                            token_in, token_out);
61         if (!NT_STATUS_IS_OK(status)) {
62                 DEBUG(0, ("Failed to parse initial client token (%s)\n",
63                           nt_errstr(status)));
64                 goto done;
65         }
66
67         *ctx = gse_ctx;
68         status = NT_STATUS_OK;
69
70 done:
71         if (!NT_STATUS_IS_OK(status)) {
72                 TALLOC_FREE(gse_ctx);
73         }
74
75         return status;
76 }
77
78 NTSTATUS gssapi_server_step(struct gse_context *gse_ctx,
79                             TALLOC_CTX *mem_ctx,
80                             DATA_BLOB *token_in,
81                             DATA_BLOB *token_out)
82 {
83         NTSTATUS status;
84
85         status = gse_get_server_auth_token(mem_ctx, gse_ctx,
86                                            token_in, token_out);
87         if (!NT_STATUS_IS_OK(status)) {
88                 return status;
89         }
90
91         if (gse_require_more_processing(gse_ctx)) {
92                 /* ask for next leg */
93                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
94         }
95
96         return NT_STATUS_OK;
97 }
98
99 NTSTATUS gssapi_server_check_flags(struct gse_context *gse_ctx)
100 {
101         return gse_verify_server_auth_flags(gse_ctx);
102 }
103
104 NTSTATUS gssapi_server_get_user_info(struct gse_context *gse_ctx,
105                                      TALLOC_CTX *mem_ctx,
106                                      struct client_address *client_id,
107                                      struct auth_serversupplied_info **server_info)
108 {
109         TALLOC_CTX *tmp_ctx;
110         DATA_BLOB pac_blob;
111         struct PAC_DATA *pac_data = NULL;
112         struct PAC_LOGON_INFO *logon_info = NULL;
113         unsigned int i;
114         bool is_mapped;
115         bool is_guest;
116         char *princ_name;
117         char *ntuser;
118         char *ntdomain;
119         char *username;
120         struct passwd *pw;
121         NTSTATUS status;
122
123         tmp_ctx = talloc_new(mem_ctx);
124         if (!tmp_ctx) {
125                 return NT_STATUS_NO_MEMORY;
126         }
127
128         status = gse_get_pac_blob(gse_ctx, tmp_ctx, &pac_blob);
129         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
130                 /* TODO: Fetch user by principal name ? */
131                 status = NT_STATUS_ACCESS_DENIED;
132                 goto done;
133         }
134         if (!NT_STATUS_IS_OK(status)) {
135                 goto done;
136         }
137
138 #ifdef HAVE_KRB5
139         status = kerberos_decode_pac(tmp_ctx,
140                                      pac_blob,
141                                      NULL, NULL, NULL, NULL, 0, &pac_data);
142 #else
143         status = NT_STATUS_ACCESS_DENIED;
144 #endif
145         data_blob_free(&pac_blob);
146         if (!NT_STATUS_IS_OK(status)) {
147                 goto done;
148         }
149
150         status = gse_get_client_name(gse_ctx, tmp_ctx, &princ_name);
151         if (!NT_STATUS_IS_OK(status)) {
152                 goto done;
153         }
154
155         /* get logon name and logon info */
156         for (i = 0; i < pac_data->num_buffers; i++) {
157                 struct PAC_BUFFER *data_buf = &pac_data->buffers[i];
158
159                 switch (data_buf->type) {
160                 case PAC_TYPE_LOGON_INFO:
161                         if (!data_buf->info) {
162                                 break;
163                         }
164                         logon_info = data_buf->info->logon_info.info;
165                         break;
166                 default:
167                         break;
168                 }
169         }
170         if (!logon_info) {
171                 DEBUG(1, ("Invalid PAC data, missing logon info!\n"));
172                 status = NT_STATUS_NOT_FOUND;
173                 goto done;
174         }
175
176         status = get_user_from_kerberos_info(tmp_ctx, client_id->name,
177                                              princ_name, logon_info,
178                                              &is_mapped, &is_guest,
179                                              &ntuser, &ntdomain,
180                                              &username, &pw);
181         if (!NT_STATUS_IS_OK(status)) {
182                 DEBUG(1, ("Failed to map kerberos principal to system user "
183                           "(%s)\n", nt_errstr(status)));
184                 status = NT_STATUS_ACCESS_DENIED;
185                 goto done;
186         }
187
188         /* TODO: save PAC data in netsamlogon cache ? */
189
190         status = make_session_info_krb5(mem_ctx,
191                                         ntuser, ntdomain, username, pw,
192                                         logon_info, is_guest, is_mapped, NULL /* No session key for now */,
193                                         server_info);
194         if (!NT_STATUS_IS_OK(status)) {
195                 DEBUG(1, ("Failed to map kerberos pac to server info (%s)\n",
196                           nt_errstr(status)));
197                 status = NT_STATUS_ACCESS_DENIED;
198                 goto done;
199         }
200
201         DEBUG(5, (__location__ "OK: user: %s domain: %s client: %s\n",
202                   ntuser, ntdomain, client_id->name));
203
204         status = NT_STATUS_OK;
205
206 done:
207         TALLOC_FREE(tmp_ctx);
208         return status;
209 }