summaryrefslogtreecommitdiffstats
path: root/daemons/ipa-kdb/ipa_kdb_mspac.c
blob: 410f4306efd055ec5d613deb8ed8c5e0c568317a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
/*
 * MIT Kerberos KDC database backend for FreeIPA
 *
 * Authors: Simo Sorce <ssorce@redhat.com>
 *
 * Copyright (C) 2011  Simo Sorce, Red Hat
 * see file 'COPYING' for use and warranty information
 *
 * This program is free software you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "ipa_kdb.h"
#include "gen_ndr/ndr_krb5pac.h"
#include <krb5/krb5.h>
#include <kdb.h>

#define KRB5INT_PAC_SIGN_AVAILABLE 1

#if KRB5INT_PAC_SIGN_AVAILABLE
krb5_error_code
krb5int_pac_sign(krb5_context context,
                 krb5_pac pac,
                 krb5_timestamp authtime,
                 krb5_const_principal principal,
                 const krb5_keyblock *server_key,
                 const krb5_keyblock *privsvr_key,
                 krb5_data *data);
#define krb5_pac_sign krb5int_pac_sign
#define KRB5_PAC_LOGON_INFO 1
#endif


#define EMPTY_LSA_STRING { 0, 0, NULL }
const char simo[] = { 0x73, 0x00, 0x6a, 0x00, 0x6d, 0x00, 0x6f, 0x00 };
const char ipa[] = { 0x6a, 0x00, 0x70, 0x00, 0x61, 0x00, 0x00, 0x00 };


static krb5_error_code ipadb_get_pac(krb5_context context,
                                     krb5_db_entry *client,
                                     krb5_pac *pac)
{
    TALLOC_CTX *tmpctx;
    DATA_BLOB pac_data;
    krb5_data data;
    struct netr_SamInfo3 info3;
    struct dom_sid2 dom_sid;
    union PAC_INFO pac_info;
    krb5_error_code kerr;
    enum ndr_err_code ndr_err;

    memset(&info3, 0, sizeof(info3));
    memset(&pac_info, 0, sizeof(pac_info));

    tmpctx = talloc_new(NULL);
    if (!tmpctx) {
        return ENOMEM;
    }

    pac_info.logon_info.info = talloc_zero(tmpctx, struct PAC_LOGON_INFO);
    if (!tmpctx) {
        kerr = ENOMEM;
        goto done;
    }

/*  info3.base.last_logon
    info3.base.last_logoff
    info3.base.acct_expiry
    info3.base.last_password_change
    info3.base.allow_password_change
    info3.base.force_password_change */
    info3.base.account_name.length = sizeof(simo);
    info3.base.account_name.size = sizeof(simo);
    info3.base.account_name.string = simo;
    info3.base.full_name.length = sizeof(simo);
    info3.base.full_name.size = sizeof(simo);
    info3.base.full_name.string = simo;
/*  info3.base.logon_script
    info3.base.profile_path
    info3.base.home_directory
    info3.base.home_drive
    info3.base.logon_count
    info3.base.bad_password_count */
    info3.base.rid = 1000;
    info3.base.primary_gid = 1001;
/*  info3.base.groups */
    info3.base.user_flags = 0;
/*  info3.base.key */
    info3.base.logon_server.length = sizeof(ipa) - 2;
    info3.base.logon_server.size = sizeof(ipa);
    info3.base.logon_server.string = ipa;
    info3.base.domain.length = sizeof(ipa) - 2;
    info3.base.domain.size = sizeof(ipa);
    info3.base.domain.string = ipa;
    dom_sid.sid_rev_num = 1;
    dom_sid.num_auths = 4;
    dom_sid.id_auth[5] = 5;
    dom_sid.sub_auths[0] = 15;
    dom_sid.sub_auths[1] = 1;
    dom_sid.sub_auths[2] = 2;
    dom_sid.sub_auths[3] = 3;
    info3.base.domain_sid = &dom_sid;
/*  info3.base.LMSessKey */
    info3.base.acct_flags = 0;

    pac_info.logon_info.info->info3 = info3;

    ndr_err = ndr_push_union_blob(&pac_data, tmpctx, &pac_info,
                                  PAC_TYPE_LOGON_INFO,
                                  (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
    if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
        kerr = KRB5_KDB_INTERNAL_ERROR;
        goto done;
    }

    kerr = krb5_pac_init(context, pac);
    if (kerr) {
        goto done;
    }

    data.magic = KV5M_DATA;
    data.data = (char *)pac_data.data;
    data.length = pac_data.length;

    kerr = krb5_pac_add_buffer(context, *pac, KRB5_PAC_LOGON_INFO, &data);

done:
    talloc_free(tmpctx);
    return kerr;
}


krb5_error_code ipadb_sign_authdata(krb5_context context,
                                    unsigned int flags,
                                    krb5_const_principal client_princ,
                                    krb5_db_entry *client,
                                    krb5_db_entry *server,
                                    krb5_db_entry *krbtgt,
                                    krb5_keyblock *client_key,
                                    krb5_keyblock *server_key,
                                    krb5_keyblock *krbtgt_key,
                                    krb5_keyblock *session_key,
                                    krb5_timestamp authtime,
                                    krb5_authdata **tgt_auth_data,
                                    krb5_authdata ***signed_auth_data)
{
    krb5_const_principal ks_client_princ;
    krb5_authdata *authdata[2] = { NULL, NULL };
    krb5_authdata ad;
    krb5_boolean is_as_req;
    krb5_error_code kerr;
    krb5_pac pac = NULL;
    krb5_data pac_data;

    /* Prefer canonicalised name from client entry */
    if (client != NULL) {
        ks_client_princ = client->princ;
    } else {
        ks_client_princ = client_princ;
    }

    is_as_req = ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) != 0);

    if (is_as_req && (flags & KRB5_KDB_FLAG_INCLUDE_PAC)) {

        kerr = ipadb_get_pac(context, client, &pac);
        if (kerr != 0) {
            goto done;
        }
    }
#if 0
    if (!is_as_req) {
        code = ks_verify_pac(context, flags, ks_client_princ, client,
                             server_key, krbtgt_key, authtime,
                             tgt_auth_data, &pac);
        if (code != 0) {
            goto done;
        }
    }

    if (pac == NULL && client != NULL) {

        code = ks_get_pac(context, client, &pac);
        if (code != 0) {
            goto done;
        }
    }
#endif
    if (pac == NULL) {
        kerr = KRB5_KDB_DBTYPE_NOSUP;
        goto done;
    }

    kerr = krb5_pac_sign(context, pac, authtime, ks_client_princ,
                         server_key, krbtgt_key, &pac_data);
    if (kerr != 0) {
        goto done;
    }

    /* put in signed data */
    ad.magic = KV5M_AUTHDATA;
    ad.ad_type = KRB5_AUTHDATA_WIN2K_PAC;
    ad.contents = (krb5_octet *)pac_data.data;
    ad.length = pac_data.length;
    authdata[0] = &ad;

    kerr = krb5_encode_authdata_container(context,
                                          KRB5_AUTHDATA_IF_RELEVANT,
                                          &authdata,
                                          signed_auth_data);
    if (kerr != 0) {
        goto done;
    }

    kerr = 0;

done:
    krb5_pac_free(context, pac);
    return kerr;
}