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 13 : 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 13 : struct sdb_entry_ex sentry = {
38 : .free_entry = NULL,
39 : };
40 : krb5_keytab keytab;
41 13 : krb5_error_code code = 0;
42 13 : NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
43 13 : char *entry_principal = NULL;
44 13 : bool copy_one_principal = (principal != NULL);
45 : krb5_data password;
46 :
47 13 : code = smb_krb5_kt_open_relative(context,
48 : keytab_name,
49 : true, /* write_access */
50 : &keytab);
51 13 : if (code != 0) {
52 0 : *error_string = talloc_asprintf(mem_ctx,
53 : "Failed to open keytab: %s",
54 : keytab_name);
55 0 : status = NT_STATUS_NO_SUCH_FILE;
56 0 : goto done;
57 : }
58 :
59 13 : if (copy_one_principal) {
60 : krb5_principal k5_princ;
61 :
62 11 : code = smb_krb5_parse_name(context, principal, &k5_princ);
63 11 : if (code != 0) {
64 0 : *error_string = smb_get_krb5_error_message(context,
65 : code,
66 : mem_ctx);
67 0 : status = NT_STATUS_UNSUCCESSFUL;
68 0 : goto done;
69 : }
70 :
71 11 : code = samba_kdc_fetch(context, db_ctx, k5_princ,
72 : SDB_F_GET_ANY, 0, &sentry);
73 :
74 11 : krb5_free_principal(context, k5_princ);
75 : } else {
76 2 : code = samba_kdc_firstkey(context, db_ctx, &sentry);
77 : }
78 :
79 45 : for (; code == 0; code = samba_kdc_nextkey(context, db_ctx, &sentry)) {
80 : int i;
81 :
82 43 : code = krb5_unparse_name(context,
83 43 : sentry.entry.principal,
84 : &entry_principal);
85 43 : if (code != 0) {
86 0 : *error_string = smb_get_krb5_error_message(context,
87 : code,
88 : mem_ctx);
89 0 : status = NT_STATUS_UNSUCCESSFUL;
90 0 : goto done;
91 : }
92 :
93 43 : if (sentry.entry.keys.len == 0) {
94 8 : SAFE_FREE(entry_principal);
95 8 : sdb_free_entry(&sentry);
96 8 : sentry = (struct sdb_entry_ex) {
97 : .free_entry = NULL,
98 : };
99 :
100 8 : continue;
101 : }
102 :
103 138 : for (i = 0; i < sentry.entry.keys.len; i++) {
104 103 : struct sdb_key *s = &(sentry.entry.keys.val[i]);
105 : krb5_enctype enctype;
106 :
107 103 : enctype = KRB5_KEY_TYPE(&(s->key));
108 103 : password.length = KRB5_KEY_LENGTH(&s->key);
109 103 : password.data = (char *)KRB5_KEY_DATA(&s->key);
110 :
111 103 : DBG_INFO("smb_krb5_kt_add_entry for enctype=0x%04x\n",
112 : (int)enctype);
113 197 : code = smb_krb5_kt_add_entry(context,
114 : keytab,
115 94 : sentry.entry.kvno,
116 : entry_principal,
117 : NULL,
118 : enctype,
119 : &password,
120 : true, /* no_salt */
121 : false); /* keeyp_old_entries */
122 103 : if (code != 0) {
123 0 : status = NT_STATUS_UNSUCCESSFUL;
124 0 : *error_string = smb_get_krb5_error_message(context,
125 : code,
126 : mem_ctx);
127 0 : DEBUG(0, ("smb_krb5_kt_add_entry failed code=%d, error = %s\n",
128 : code, *error_string));
129 0 : goto done;
130 : }
131 : }
132 :
133 35 : if (copy_one_principal) {
134 11 : break;
135 : }
136 :
137 24 : SAFE_FREE(entry_principal);
138 24 : sdb_free_entry(&sentry);
139 24 : sentry = (struct sdb_entry_ex) {
140 : .free_entry = NULL,
141 : };
142 : }
143 :
144 13 : if (code != 0 && code != SDB_ERR_NOENTRY) {
145 0 : *error_string = smb_get_krb5_error_message(context,
146 : code,
147 : mem_ctx);
148 0 : status = NT_STATUS_NO_SUCH_USER;
149 0 : goto done;
150 : }
151 :
152 13 : status = NT_STATUS_OK;
153 13 : done:
154 13 : SAFE_FREE(entry_principal);
155 13 : sdb_free_entry(&sentry);
156 :
157 13 : return status;
158 : }
159 :
160 13 : NTSTATUS libnet_export_keytab(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_export_keytab *r)
161 : {
162 : krb5_error_code ret;
163 : struct smb_krb5_context *smb_krb5_context;
164 : struct samba_kdc_base_context *base_ctx;
165 13 : struct samba_kdc_db_context *db_ctx = NULL;
166 13 : const char *error_string = NULL;
167 : NTSTATUS status;
168 :
169 13 : ret = smb_krb5_init_context(ctx, ctx->lp_ctx, &smb_krb5_context);
170 13 : if (ret) {
171 0 : return NT_STATUS_NO_MEMORY;
172 : }
173 :
174 13 : base_ctx = talloc_zero(mem_ctx, struct samba_kdc_base_context);
175 13 : if (base_ctx == NULL) {
176 0 : return NT_STATUS_NO_MEMORY;
177 : }
178 :
179 13 : base_ctx->ev_ctx = ctx->event_ctx;
180 13 : base_ctx->lp_ctx = ctx->lp_ctx;
181 :
182 13 : status = samba_kdc_setup_db_ctx(mem_ctx, base_ctx, &db_ctx);
183 13 : if (!NT_STATUS_IS_OK(status)) {
184 0 : return status;
185 : }
186 :
187 13 : if (r->in.principal != NULL) {
188 11 : DEBUG(0, ("Export one principal to %s\n", r->in.keytab_name));
189 19 : status = sdb_kt_copy(mem_ctx,
190 11 : smb_krb5_context->krb5_context,
191 : db_ctx,
192 : r->in.keytab_name,
193 : r->in.principal,
194 : &error_string);
195 : } else {
196 2 : unlink(r->in.keytab_name);
197 2 : DEBUG(0, ("Export complete keytab to %s\n", r->in.keytab_name));
198 4 : status = sdb_kt_copy(mem_ctx,
199 2 : smb_krb5_context->krb5_context,
200 : db_ctx,
201 : r->in.keytab_name,
202 : NULL,
203 : &error_string);
204 : }
205 :
206 13 : talloc_free(db_ctx);
207 13 : talloc_free(base_ctx);
208 :
209 13 : if (!NT_STATUS_IS_OK(status)) {
210 0 : r->out.error_string = error_string;
211 : }
212 :
213 13 : return status;
214 : }
|