Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009
5 : Copyright (C) Andreas Schneider <asn@samba.org> 2016
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "includes.h"
22 : #include "system/kerberos.h"
23 : #include "auth/kerberos/kerberos.h"
24 : #include "kdc/samba_kdc.h"
25 : #include "libnet/libnet_export_keytab.h"
26 :
27 : #include "kdc/db-glue.h"
28 : #include "kdc/sdb.h"
29 :
30 20 : static NTSTATUS sdb_kt_copy(TALLOC_CTX *mem_ctx,
31 : krb5_context context,
32 : struct samba_kdc_db_context *db_ctx,
33 : const char *keytab_name,
34 : const char *principal,
35 : const char **error_string)
36 : {
37 20 : struct sdb_entry sentry = {};
38 0 : krb5_keytab keytab;
39 20 : krb5_error_code code = 0;
40 20 : NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
41 20 : char *entry_principal = NULL;
42 20 : bool copy_one_principal = (principal != NULL);
43 0 : krb5_data password;
44 :
45 20 : code = smb_krb5_kt_open_relative(context,
46 : keytab_name,
47 : true, /* write_access */
48 : &keytab);
49 20 : if (code != 0) {
50 0 : *error_string = talloc_asprintf(mem_ctx,
51 : "Failed to open keytab: %s",
52 : keytab_name);
53 0 : status = NT_STATUS_NO_SUCH_FILE;
54 0 : goto done;
55 : }
56 :
57 20 : if (copy_one_principal) {
58 0 : krb5_principal k5_princ;
59 :
60 16 : code = smb_krb5_parse_name(context, principal, &k5_princ);
61 16 : if (code != 0) {
62 0 : *error_string = smb_get_krb5_error_message(context,
63 : code,
64 : mem_ctx);
65 0 : status = NT_STATUS_UNSUCCESSFUL;
66 0 : goto done;
67 : }
68 :
69 16 : code = samba_kdc_fetch(context, db_ctx, k5_princ,
70 : SDB_F_GET_ANY | SDB_F_ADMIN_DATA,
71 : 0, &sentry);
72 :
73 16 : krb5_free_principal(context, k5_princ);
74 : } else {
75 4 : code = samba_kdc_firstkey(context, db_ctx, &sentry);
76 : }
77 :
78 74 : for (; code == 0; code = samba_kdc_nextkey(context, db_ctx, &sentry)) {
79 0 : int i;
80 :
81 70 : code = krb5_unparse_name(context,
82 70 : sentry.principal,
83 : &entry_principal);
84 70 : if (code != 0) {
85 0 : *error_string = smb_get_krb5_error_message(context,
86 : code,
87 : mem_ctx);
88 0 : status = NT_STATUS_UNSUCCESSFUL;
89 0 : goto done;
90 : }
91 :
92 70 : if (sentry.keys.len == 0) {
93 4 : SAFE_FREE(entry_principal);
94 4 : sdb_entry_free(&sentry);
95 :
96 4 : continue;
97 : }
98 :
99 256 : for (i = 0; i < sentry.keys.len; i++) {
100 190 : struct sdb_key *s = &(sentry.keys.val[i]);
101 0 : krb5_enctype enctype;
102 :
103 190 : enctype = KRB5_KEY_TYPE(&(s->key));
104 190 : password.length = KRB5_KEY_LENGTH(&s->key);
105 190 : password.data = (char *)KRB5_KEY_DATA(&s->key);
106 :
107 190 : DBG_INFO("smb_krb5_kt_add_entry for enctype=0x%04x\n",
108 : (int)enctype);
109 190 : code = smb_krb5_kt_add_entry(context,
110 : keytab,
111 90 : sentry.kvno,
112 : entry_principal,
113 : NULL,
114 : enctype,
115 : &password,
116 : true); /* no_salt */
117 190 : if (code != 0) {
118 0 : status = NT_STATUS_UNSUCCESSFUL;
119 0 : *error_string = smb_get_krb5_error_message(context,
120 : code,
121 : mem_ctx);
122 0 : DEBUG(0, ("smb_krb5_kt_add_entry failed code=%d, error = %s\n",
123 : code, *error_string));
124 0 : goto done;
125 : }
126 : }
127 :
128 66 : if (copy_one_principal) {
129 16 : break;
130 : }
131 :
132 50 : SAFE_FREE(entry_principal);
133 50 : sdb_entry_free(&sentry);
134 : }
135 :
136 20 : if (code != 0 && code != SDB_ERR_NOENTRY) {
137 0 : *error_string = smb_get_krb5_error_message(context,
138 : code,
139 : mem_ctx);
140 0 : status = NT_STATUS_NO_SUCH_USER;
141 0 : goto done;
142 : }
143 :
144 20 : status = NT_STATUS_OK;
145 20 : done:
146 20 : SAFE_FREE(entry_principal);
147 20 : sdb_entry_free(&sentry);
148 :
149 20 : return status;
150 : }
151 :
152 20 : NTSTATUS libnet_export_keytab(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_export_keytab *r)
153 : {
154 0 : krb5_error_code ret;
155 0 : struct smb_krb5_context *smb_krb5_context;
156 0 : struct samba_kdc_base_context *base_ctx;
157 20 : struct samba_kdc_db_context *db_ctx = NULL;
158 20 : const char *error_string = NULL;
159 0 : NTSTATUS status;
160 :
161 20 : ret = smb_krb5_init_context(ctx, ctx->lp_ctx, &smb_krb5_context);
162 20 : if (ret) {
163 0 : return NT_STATUS_NO_MEMORY;
164 : }
165 :
166 20 : base_ctx = talloc_zero(mem_ctx, struct samba_kdc_base_context);
167 20 : if (base_ctx == NULL) {
168 0 : return NT_STATUS_NO_MEMORY;
169 : }
170 :
171 20 : base_ctx->ev_ctx = ctx->event_ctx;
172 20 : base_ctx->lp_ctx = ctx->lp_ctx;
173 :
174 20 : status = samba_kdc_setup_db_ctx(mem_ctx, base_ctx, &db_ctx);
175 20 : if (!NT_STATUS_IS_OK(status)) {
176 0 : return status;
177 : }
178 :
179 20 : if (r->in.principal != NULL) {
180 16 : DEBUG(0, ("Export one principal to %s\n", r->in.keytab_name));
181 16 : status = sdb_kt_copy(mem_ctx,
182 16 : smb_krb5_context->krb5_context,
183 : db_ctx,
184 : r->in.keytab_name,
185 : r->in.principal,
186 : &error_string);
187 : } else {
188 4 : unlink(r->in.keytab_name);
189 4 : DEBUG(0, ("Export complete keytab to %s\n", r->in.keytab_name));
190 4 : status = sdb_kt_copy(mem_ctx,
191 4 : smb_krb5_context->krb5_context,
192 : db_ctx,
193 : r->in.keytab_name,
194 : NULL,
195 : &error_string);
196 : }
197 :
198 20 : talloc_free(db_ctx);
199 20 : talloc_free(base_ctx);
200 :
201 20 : if (!NT_STATUS_IS_OK(status)) {
202 0 : r->out.error_string = error_string;
203 : }
204 :
205 20 : return status;
206 : }
|