1 /* auth_krb.c -- Kerberos authorization
2 *
3 * Copyright (c) 1994-2008 Carnegie Mellon University. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 *
17 * 3. The name "Carnegie Mellon University" must not be used to
18 * endorse or promote products derived from this software without
19 * prior written permission. For permission or any legal
20 * details, please contact
21 * Carnegie Mellon University
22 * Center for Technology Transfer and Enterprise Creation
23 * 4615 Forbes Avenue
24 * Suite 302
25 * Pittsburgh, PA 15213
26 * (412) 268-7393, fax: (412) 268-7395
27 * innovation@andrew.cmu.edu
28 *
29 * 4. Redistributions of any form whatsoever must retain the following
30 * acknowledgment:
31 * "This product includes software developed by Computing Services
32 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
33 *
34 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
35 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
36 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
37 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
38 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
39 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
40 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
41 */
42
43 #include <config.h>
44 #include <stdlib.h>
45 #include <sysexits.h>
46
47 #include "auth.h"
48 #include "xmalloc.h"
49 #include "util.h"
50
51 #ifdef HAVE_KRB
52
53 #include <limits.h>
54 #include <stdio.h>
55 #include <ctype.h>
56 #include <string.h>
57 #include <sys/types.h>
58
59 #include <krb.h>
60 #ifdef HAVE_BDB
61 #ifdef HAVE_DB_185_H
62 #include <db_185.h>
63 #else
64 #include <db.h>
65 #endif
66 #else
67 #include <ndbm.h>
68 #endif
69 #include <krb.h>
70
71 #ifndef KRB_MAPNAME
72 #define KRB_MAPNAME (SYSCONF_DIR "/krb.equiv")
73 #endif
74
75 struct auth_state {
76 char userid[MAX_K_NAME_SZ+1];
77 char aname[ANAME_SZ];
78 char inst[INST_SZ];
79 char realm[REALM_SZ];
80 };
81
82 static struct auth_state auth_anonymous = {
83 "anonymous", "anonymous", "", ""
84 };
85
86
87
88 static int parse_krbequiv_line (const char *src,
89 char *principal, char *localuser);
90 static char *auth_map_krbid (const char *real_aname, const char *real_inst,
91 const char *real_realm);
92
93 /*
94 * Determine if the user is a member of 'identifier'
95 * Returns one of:
96 * 0 User does not match identifier
97 * 1 identifier matches everybody
98 * 2 User is in the group that is identifier
99 * 3 User is identifer
100 */
mymemberof(const struct auth_state * auth_state,const char * identifier)101 static int mymemberof(const struct auth_state *auth_state, const char *identifier)
102 {
103 char aname[ANAME_SZ];
104 char inst[INST_SZ];
105 char realm[REALM_SZ];
106
107 if (!auth_state) auth_state = &auth_anonymous;
108
109 if (strcmp(identifier, "anyone") == 0) return 1;
110
111 if (strcmp(identifier, auth_state->userid) == 0) return 3;
112
113 /* "anonymous" is not a member of any group */
114 if (strcmp(auth_state->userid, "anonymous") == 0) return 0;
115
116 aname[0] = inst[0] = realm[0] = '\0';
117 if (kname_parse(aname, inst, realm, (char *) identifier) != 0) {
118 return 0;
119 }
120
121 if (strcmp(aname, auth_state->aname) != 0 && strcmp(aname, "*") != 0) {
122 return 0;
123 }
124 if (strcmp(inst, auth_state->inst) != 0 && strcmp(inst, "*") != 0) {
125 return 0;
126 }
127 if (strcmp(realm, auth_state->realm) != 0 && strcmp(realm, "*") != 0) {
128 return 0;
129 }
130 return 2;
131 }
132
133 /*
134 * Parse a line 'src' from an /etc/krb.equiv file.
135 * Sets the buffer pointed to by 'principal' to be the kerberos
136 * identity and sets the buffer pointed to by 'localuser' to
137 * be the local user. Both buffers must be of size one larger than
138 * MAX_K_NAME_SZ. Returns 1 on success, 0 on failure.
139 */
140 static int
parse_krbequiv_line(const char * src,char * principal,char * localuser)141 parse_krbequiv_line(const char *src, char *principal, char *localuser)
142 {
143 int i;
144
145 while (Uisspace(*src)) src++;
146 if (!*src) return 0;
147
148 for (i = 0; *src && !Uisspace(*src); i++) {
149 if (i >= MAX_K_NAME_SZ) return 0;
150 *principal++ = *src++;
151 }
152 *principal = 0;
153
154 if (!Uisspace(*src)) return 0; /* Need at least one separator */
155 while (Uisspace(*src)) src++;
156 if (!*src) return 0;
157
158 for (i = 0; *src && !Uisspace(*src); i++) {
159 if (i >= MAX_K_NAME_SZ) return 0;
160 *localuser++ = *src++;
161 }
162 *localuser = 0;
163 return 1;
164 }
165
166 /*
167 * Map a remote kerberos principal to a local username. If a mapping
168 * is found, a pointer to the local username is returned. Otherwise,
169 * a NULL pointer is returned.
170 * Eventually, this may be more sophisticated than a simple file scan.
171 */
auth_map_krbid(real_aname,real_inst,real_realm)172 static char *auth_map_krbid(real_aname, real_inst, real_realm)
173 const char *real_aname;
174 const char *real_inst;
175 const char *real_realm;
176 {
177 static char localuser[MAX_K_NAME_SZ + 1];
178 char principal[MAX_K_NAME_SZ + 1];
179 char aname[ANAME_SZ];
180 char inst[INST_SZ];
181 char realm[REALM_SZ];
182 char lrealm[REALM_SZ];
183 char krbhst[256];
184 char *p;
185 char buf[1024];
186 FILE *mapfile;
187
188 if (!(mapfile = fopen(KRB_MAPNAME, "r"))) {
189 /* If the file can't be opened, don't do mappings */
190 return 0;
191 }
192
193 for (;;) {
194 if (!fgets(buf, sizeof(buf), mapfile)) break;
195 if (parse_krbequiv_line(buf, principal, localuser) == 0 ||
196 kname_parse(aname, inst, realm, principal) != 0) {
197 /* Ignore badly formed lines */
198 continue;
199 }
200 if (!strcmp(aname, real_aname) && !strcmp(inst, real_inst) &&
201 !strcmp(realm, real_realm)) {
202 fclose(mapfile);
203
204 aname[0] = inst[0] = realm[0] = '\0';
205 if (kname_parse(aname, inst, realm, localuser) != 0) {
206 return 0;
207 }
208
209 /* Upcase realm name */
210 for (p = realm; *p; p++) {
211 if (Uislower(*p)) *p = toupper(*p);
212 }
213
214 if (*realm) {
215 if (krb_get_lrealm(lrealm,1) == 0 &&
216 strcmp(lrealm, realm) == 0) {
217 *realm = 0;
218 }
219 else if (krb_get_krbhst(krbhst, realm, 1)) {
220 return 0; /* Unknown realm */
221 }
222 }
223
224 strcpy(localuser, aname);
225 if (*inst) {
226 strcat(localuser, ".");
227 strcat(localuser, inst);
228 }
229 if (*realm) {
230 strcat(localuser, "@");
231 strcat(localuser, realm);
232 }
233
234 return localuser;
235 }
236 }
237
238 fclose(mapfile);
239 return 0;
240 }
241
242 /*
243 * Convert 'identifier' into canonical form.
244 * Returns a pointer to a static buffer containing the canonical form
245 * or NULL if 'identifier' is invalid.
246 */
mycanonifyid(const char * identifier,size_t len)247 static const char *mycanonifyid(const char *identifier, size_t len)
248 {
249 static char retbuf[MAX_K_NAME_SZ+1];
250 char aname[ANAME_SZ];
251 char inst[INST_SZ];
252 char realm[REALM_SZ];
253 char lrealm[REALM_SZ];
254 char krbhst[256];
255 char *canon_buf;
256 char *p;
257
258 if(!len) len = strlen(identifier);
259
260 canon_buf = malloc(len + 1);
261 if(!canon_buf) return 0;
262 memcpy(canon_buf, identifier, len);
263 canon_buf[len] = '\0';
264
265 aname[0] = inst[0] = realm[0] = '\0';
266 if (kname_parse(aname, inst, realm, canon_buf) != 0) {
267 free(canon_buf);
268 return 0;
269 }
270
271 free(canon_buf);
272
273 /* Upcase realm name */
274 for (p = realm; *p; p++) {
275 if (Uislower(*p)) *p = toupper(*p);
276 }
277
278 if (*realm) {
279 if (krb_get_lrealm(lrealm,1) == 0 &&
280 strcmp(lrealm, realm) == 0) {
281 *realm = 0;
282 }
283 else if (krb_get_krbhst(krbhst, realm, 1)) {
284 return 0; /* Unknown realm */
285 }
286 }
287
288 /* Check for krb.equiv remappings. */
289 if ((p = auth_map_krbid(aname, inst, realm)) ) {
290 strcpy(retbuf, p);
291 return retbuf;
292 }
293
294 strcpy(retbuf, aname);
295 if (*inst) {
296 strcat(retbuf, ".");
297 strcat(retbuf, inst);
298 }
299 if (*realm) {
300 strcat(retbuf, "@");
301 strcat(retbuf, realm);
302 }
303
304 return retbuf;
305 }
306
307 /*
308 * Set the current user to 'identifier'. 'cacheid', if non-null,
309 * points to a 16-byte binary key to cache identifier's information
310 * with.
311 */
mynewstate(const char * identifier)312 static struct auth_state *mynewstate(const char *identifier)
313 {
314 struct auth_state *newstate;
315
316 identifier = auth_canonifyid(identifier, 0);
317 if (!identifier) return 0;
318
319 newstate = (struct auth_state *)xmalloc(sizeof(struct auth_state));
320
321 strcpy(newstate->userid, identifier);
322 newstate->aname[0] = newstate->inst[0] = newstate->realm[0] = '\0';
323 kname_parse(newstate->aname, newstate->inst, newstate->realm, (char *) identifier);
324
325 return newstate;
326 }
327
myfreestate(struct auth_state * auth_state)328 static void myfreestate(struct auth_state *auth_state)
329 {
330 free((char *)auth_state);
331 }
332
make_krb_wildcard(const char * aname,const char * inst,const char * realm)333 static char *make_krb_wildcard(const char *aname, const char *inst, const char *realm)
334 {
335 return strconcat(
336 (aname ? aname : "*"),
337 ".",
338 (inst ? inst : "*"),
339 "@",
340 (realm ? realm : "*"),
341 NULL
342 );
343 }
344
345 /* KRB4 groups are just principals with wildcarded components.
346 * XXX This hasn't even been so much as compile-tested for lack of
347 * a kerberos test environment! If you use this, please provide
348 * feedback.
349 */
mygroups(const struct auth_state * auth_state)350 static strarray_t *mygroups(const struct auth_state *auth_state)
351 {
352 strarray_t *sa = strarray_new();
353 char *tmp = NULL;
354
355 /* *.*@* */
356 tmp = make_krb_wildcard(NULL, NULL, NULL);
357 strarray_appendm(sa, tmp);
358
359 /* *.*@realm */
360 if (auth_state->realm) {
361 tmp = make_krb_wildcard(NULL, NULL, auth_state->realm);
362 strarray_appendm(sa, tmp);
363 }
364
365 /* *.inst@* */
366 if (auth_state->inst) {
367 tmp = make_krb_wildcard(NULL, auth_state->inst, NULL);
368 strarray_appendm(sa, tmp);
369 if (auth_state->realm) {
370 tmp = make_krb_wildcard(NULL, auth_state->inst, auth_state->realm);
371 strarray_appendm(sa, tmp);
372 }
373 }
374
375 /* aname.*@* */
376 if (auth_state->aname) {
377 tmp = make_krb_wildcard(auth_state->aname, NULL, NULL);
378 strarray_appendm(sa, tmp);
379 if (auth_state->realm) {
380 tmp = make_krb_wildcard(auth_state->aname, NULL, auth_state->realm);
381 strarray_appendm(sa, tmp);
382 }
383 if (auth_state->inst) {
384 tmp = make_krb_wildcard(auth_state->aname, auth_state->inst, NULL);
385 strarray_appendm(sa, tmp);
386 }
387 /* n.b. non-wildcard "aname.inst@realm" is NOT a group! */
388 }
389
390 return sa;
391 }
392
393 #else /* HAVE_KRB */
394
mymemberof(const struct auth_state * auth_state,const char * identifier)395 static int mymemberof(
396 const struct auth_state *auth_state __attribute__((unused)),
397 const char *identifier __attribute__((unused)))
398 {
399 fatal("Authentication mechanism (krb) not compiled in", EX_CONFIG);
400 return 0;
401 }
402
mycanonifyid(const char * identifier,size_t len)403 static const char *mycanonifyid(
404 const char *identifier __attribute__((unused)),
405 size_t len __attribute__((unused)))
406 {
407 fatal("Authentication mechanism (krb) not compiled in", EX_CONFIG);
408 return NULL;
409 }
410
mynewstate(const char * identifier)411 static struct auth_state *mynewstate(
412 const char *identifier __attribute__((unused)))
413 {
414 fatal("Authentication mechanism (krb) not compiled in", EX_CONFIG);
415 return NULL;
416 }
417
myfreestate(struct auth_state * auth_state)418 static void myfreestate(
419 struct auth_state *auth_state __attribute__((unused)))
420 {
421 fatal("Authentication mechanism (krb) not compiled in", EX_CONFIG);
422 }
423
mygroups(const struct auth_state * auth_state)424 static strarray_t *mygroups(
425 const struct auth_state *auth_state __attribute__((unused)))
426 {
427 fatal("Authentication mechanism (krb) not compiled in", EX_CONFIG);
428 }
429
430 #endif
431
432 HIDDEN struct auth_mech auth_krb =
433 {
434 "krb", /* name */
435
436 &mycanonifyid,
437 &mymemberof,
438 &mynewstate,
439 &myfreestate,
440 &mygroups,
441 };
442