Coverage Report

Created: 2025-10-13 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gss-ntlmssp/src/gss_ntlmssp.c
Line
Count
Source
1
/* Copyright 2013 Simo Sorce <simo@samba.org>, see COPYING for license */
2
3
#include <errno.h>
4
#include <stdlib.h>
5
#include <string.h>
6
#include <time.h>
7
8
#include "gssapi_ntlmssp.h"
9
#include "gss_ntlmssp.h"
10
11
#define SEC_LEVEL_MIN 0
12
#define SEC_LEVEL_MAX 5
13
14
1.16k
#define SEC_LM_OK 0x01
15
0
#define SEC_NTLM_OK 0x02
16
2.33k
#define SEC_EXT_SEC_OK 0x04
17
1.16k
#define SEC_V2_OK 0x08
18
1.16k
#define SEC_DC_LM_OK 0x10
19
1.16k
#define SEC_DC_NTLM_OK 0x20
20
1.16k
#define SEC_DC_V2_OK 0x40
21
22
const gss_OID_desc gssntlm_oid = {
23
    .length = GSS_NTLMSSP_OID_LENGTH,
24
    .elements = discard_const(GSS_NTLMSSP_OID_STRING)
25
};
26
27
bool gssntlm_required_security(int security_level, struct gssntlm_ctx *ctx)
28
1.16k
{
29
1.16k
    uint8_t resp;
30
31
    /* DC defaults */
32
1.16k
    resp = SEC_DC_LM_OK | SEC_DC_NTLM_OK | SEC_DC_V2_OK;
33
34
1.16k
    switch (security_level) {
35
0
    case 0:
36
0
        resp |= SEC_LM_OK | SEC_NTLM_OK;
37
0
        break;
38
0
    case 1:
39
0
        resp |= SEC_LM_OK | SEC_NTLM_OK | SEC_EXT_SEC_OK;
40
0
        break;
41
0
    case 2:
42
0
        resp |= SEC_NTLM_OK | SEC_EXT_SEC_OK;
43
0
        break;
44
1.16k
    case 3:
45
1.16k
        resp |= SEC_V2_OK | SEC_EXT_SEC_OK;
46
1.16k
        break;
47
0
    case 4:
48
0
        if (ctx->role == GSSNTLM_DOMAIN_CONTROLLER) resp &= ~SEC_DC_LM_OK;
49
0
        resp |= SEC_V2_OK | SEC_EXT_SEC_OK;
50
0
        break;
51
0
    case 5:
52
0
        if (ctx->role == GSSNTLM_DOMAIN_CONTROLLER) resp = SEC_DC_V2_OK;
53
0
        resp |= SEC_V2_OK | SEC_EXT_SEC_OK;
54
0
        break;
55
0
    default:
56
0
        return false;
57
1.16k
    }
58
59
1.16k
    ctx->sec_req = resp;
60
1.16k
    return true;
61
1.16k
}
62
63
void gssntlm_set_role(struct gssntlm_ctx *ctx,
64
                      int desired, char *nb_domain_name)
65
1.16k
{
66
1.16k
    if (desired == GSSNTLM_CLIENT) {
67
0
        ctx->role = GSSNTLM_CLIENT;
68
1.16k
    } else if (nb_domain_name && *nb_domain_name &&
69
1.16k
               strcmp(nb_domain_name, DEF_NB_DOMAIN) != 0) {
70
0
        ctx->role = GSSNTLM_DOMAIN_SERVER;
71
1.16k
    } else {
72
1.16k
        ctx->role = GSSNTLM_SERVER;
73
1.16k
    }
74
1.16k
}
75
76
bool gssntlm_role_is_client(struct gssntlm_ctx *ctx)
77
0
{
78
0
    return (ctx->role == GSSNTLM_CLIENT);
79
0
}
80
81
bool gssntlm_role_is_server(struct gssntlm_ctx *ctx)
82
962
{
83
962
    switch (ctx->role) {
84
962
    case GSSNTLM_SERVER:
85
962
    case GSSNTLM_DOMAIN_SERVER:
86
962
    case GSSNTLM_DOMAIN_CONTROLLER:
87
962
        return true;
88
0
    default:
89
0
        break;
90
962
    }
91
0
    return false;
92
962
}
93
94
bool gssntlm_role_is_domain_member(struct gssntlm_ctx *ctx)
95
982
{
96
982
    switch (ctx->role) {
97
0
    case GSSNTLM_DOMAIN_SERVER:
98
0
    case GSSNTLM_DOMAIN_CONTROLLER:
99
0
        return true;
100
982
    default:
101
982
        break;
102
982
    }
103
982
    return false;
104
982
}
105
106
bool gssntlm_sec_lm_ok(struct gssntlm_ctx *ctx)
107
1.16k
{
108
1.16k
    switch (ctx->role) {
109
0
    case GSSNTLM_CLIENT:
110
1.16k
    case GSSNTLM_SERVER:
111
1.16k
        return (ctx->sec_req & SEC_LM_OK);
112
0
    case GSSNTLM_DOMAIN_SERVER:
113
0
        return true; /* defer decision to DC */
114
0
    case GSSNTLM_DOMAIN_CONTROLLER:
115
0
        return (ctx->sec_req & SEC_DC_LM_OK);
116
1.16k
    }
117
0
    return false;
118
1.16k
}
119
120
bool gssntlm_sec_ntlm_ok(struct gssntlm_ctx *ctx)
121
0
{
122
0
    switch (ctx->role) {
123
0
    case GSSNTLM_CLIENT:
124
0
    case GSSNTLM_SERVER:
125
0
        return (ctx->sec_req & SEC_NTLM_OK);
126
0
    case GSSNTLM_DOMAIN_SERVER:
127
0
        return true; /* defer decision to DC */
128
0
    case GSSNTLM_DOMAIN_CONTROLLER:
129
0
        return (ctx->sec_req & SEC_DC_NTLM_OK);
130
0
    }
131
0
    return false;
132
0
}
133
134
bool gssntlm_sec_v2_ok(struct gssntlm_ctx *ctx)
135
0
{
136
0
    switch (ctx->role) {
137
0
    case GSSNTLM_CLIENT:
138
0
    case GSSNTLM_SERVER:
139
0
        return (ctx->sec_req & SEC_V2_OK);
140
0
    case GSSNTLM_DOMAIN_SERVER:
141
0
        return true; /* defer decision to DC */
142
0
    case GSSNTLM_DOMAIN_CONTROLLER:
143
0
        return (ctx->sec_req & SEC_DC_V2_OK);
144
0
    }
145
0
    return false;
146
0
}
147
148
bool gssntlm_ext_sec_ok(struct gssntlm_ctx *ctx)
149
1.16k
{
150
1.16k
    return (ctx->sec_req & SEC_EXT_SEC_OK);
151
1.16k
}
152
153
uint32_t gssntlm_context_is_valid(struct gssntlm_ctx *ctx, time_t *time_now)
154
0
{
155
0
    time_t now;
156
157
0
    if (!ctx) return GSS_S_NO_CONTEXT;
158
0
    if (!(ctx->int_flags & NTLMSSP_CTX_FLAG_ESTABLISHED)) {
159
0
        return GSS_S_NO_CONTEXT;
160
0
    }
161
162
0
    now = time(NULL);
163
0
    if (now > ctx->expiration_time) return GSS_S_CONTEXT_EXPIRED;
164
165
0
    if (time_now) *time_now = now;
166
0
    return GSS_S_COMPLETE;
167
0
}
168
169
int gssntlm_get_lm_compatibility_level(void)
170
1.16k
{
171
1.16k
    const char *envvar;
172
173
1.16k
    envvar = getenv("LM_COMPAT_LEVEL");
174
1.16k
    if (envvar != NULL) {
175
0
        return atoi(envvar);
176
0
    }
177
178
    /* use 3 by default for better compatibility */
179
1.16k
    return 3;
180
1.16k
}
181
182
uint32_t gssntlm_mech_invoke(uint32_t *minor_status,
183
                             const gss_OID desired_mech,
184
                             const gss_OID desired_object,
185
                             gss_buffer_t value)
186
0
{
187
0
    uint32_t retmaj = GSS_S_COMPLETE;
188
0
    uint32_t retmin = 0;
189
190
0
    if (minor_status == NULL) {
191
0
        return GSS_S_CALL_INACCESSIBLE_WRITE;
192
0
    }
193
194
0
    if (desired_mech != GSS_C_NO_OID &&
195
0
        !gss_oid_equal(desired_mech, &gssntlm_oid)) {
196
0
        return GSSERRS(0, GSS_S_BAD_MECH);
197
0
    }
198
199
0
    if (desired_object == GSS_C_NO_OID) {
200
0
        return GSSERRS(0, GSS_S_CALL_INACCESSIBLE_READ);
201
0
    }
202
203
0
    if (!gss_oid_equal(desired_object, &gssntlm_debug_oid)) {
204
0
        return GSSERRS(EINVAL, GSS_S_UNAVAILABLE);
205
0
    }
206
207
0
    retmin = gssntlm_debug_invoke(value);
208
0
    if (retmin != 0) {
209
0
        retmaj = GSS_S_UNAVAILABLE;
210
0
    }
211
212
0
    return GSSERR();
213
0
}