/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 | } |