Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117749664
afskrb.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
14 KB
Referenced Files
None
Subscribers
None
afskrb.c
View Options
/* afskrb.c - AFS PTS Group (Kerberos Canonicalization) Backend to ptloader
*
* Copyright (c) 1994-2008 Carnegie Mellon University. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The name "Carnegie Mellon University" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For permission or any legal
* details, please contact
* Carnegie Mellon University
* Center for Technology Transfer and Enterprise Creation
* 4615 Forbes Avenue
* Suite 302
* Pittsburgh, PA 15213
* (412) 268-7393, fax: (412) 268-7395
* innovation@andrew.cmu.edu
*
* 4. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by Computing Services
* at Carnegie Mellon University (http://www.cmu.edu/computing/)."
*
* CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: afskrb.c,v 1.19 2010/01/06 17:01:57 murch Exp $
*/
#include
<config.h>
#include
"ptloader.h"
#include
"exitcodes.h"
#include
"util.h"
#include
"xmalloc.h"
#ifdef HAVE_AFSKRB
#include
<string.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<sys/types.h>
#include
<sys/stat.h>
#include
<sys/types.h>
#include
<sys/param.h>
#include
<fcntl.h>
#include
<sys/socket.h>
#include
<sys/un.h>
#include
<sys/uio.h>
#ifdef AFSPTS_USE_KRB5
#include
<krb5.h>
#else
#include
<krb.h>
#endif
#include
"auth_pts.h"
#include
"libconfig.h"
#include
"strhash.h"
/* AFS stuff */
#include
<lock.h>
#include
<afs/ptserver.h>
#include
<afs/pterror.h>
#include
<afs/cellconfig.h>
#include
<rx/rxkad.h>
#include
<afs/auth.h>
/* blame transarc i've been told */
#ifndef AFSCONF_CLIENTNAME
#include
<afs/dirpath.h>
#define AFSCONF_CLIENTNAME AFSDIR_CLIENT_ETC_DIRPATH
#endif
/* Sanity Check */
#if PTS_DB_KEYSIZE < PR_MAXNAMELEN
#error PTS_DB_KEYSIZE is smaller than PR_MAXNAMELEN
#endif
static
const
char
*
localrealms
=
NULL
;
int
is_local_realm
(
const
char
*
realm
)
{
const
char
*
val
=
localrealms
;
if
(
!
val
||
!
realm
)
return
0
;
while
(
*
val
)
{
char
buf
[
1024
];
size_t
len
;
char
*
p
;
for
(
p
=
(
char
*
)
val
;
*
p
&&
!
Uisspace
(
*
p
);
p
++
);
len
=
p
-
val
;
if
(
len
>=
sizeof
(
buf
))
len
=
sizeof
(
buf
)
-
1
;
memcpy
(
buf
,
val
,
len
);
buf
[
len
]
=
'\0'
;
if
(
!
strcasecmp
(
realm
,
buf
))
{
return
1
;
}
val
=
p
;
while
(
*
val
&&
Uisspace
(
*
val
))
val
++
;
}
return
0
;
}
#ifdef AFSPTS_USE_KRB5
/*
* Convert 'identifier' into canonical form.
* Returns a pointer to a static buffer containing the canonical form
* or NULL if 'identifier' is invalid.
*/
static
char
*
afspts_canonifyid
(
const
char
*
identifier
,
size_t
len
)
{
static
char
*
retbuf
=
NULL
;
char
*
tmp
=
NULL
;
krb5_context
context
;
krb5_principal
princ
,
princ_dummy
;
char
*
realm
;
char
*
realmbegin
;
int
striprealm
=
0
;
char
*
identifier2
;
if
(
retbuf
)
free
(
retbuf
);
retbuf
=
NULL
;
if
(
!
identifier
)
return
NULL
;
if
(
!
len
)
len
=
strlen
(
identifier
);
if
(
strcasecmp
(
identifier
,
"anonymous"
)
==
0
)
return
"anonymous"
;
if
(
strcasecmp
(
identifier
,
"anyone"
)
==
0
)
return
"anyone"
;
identifier2
=
strdup
(
identifier
);
if
(
tmp
=
strchr
(
identifier2
,
'+'
))
{
syslog
(
LOG_DEBUG
,
"afspts_canonifyid stripping: %s"
,
identifier2
);
tmp
[
0
]
=
0
;
syslog
(
LOG_DEBUG
,
"afspts_canonifyid stripped: %s"
,
identifier2
);
}
if
(
krb5_init_context
(
&
context
))
{
syslog
(
LOG_ERR
,
"afspts_canonifyid krb5_init_context failed"
);
return
NULL
;
}
if
(
krb5_parse_name
(
context
,
identifier2
,
&
princ
))
{
krb5_free_context
(
context
);
free
(
identifier2
);
syslog
(
LOG_ERR
,
"afspts_canonifyid krb5_parse_name failed"
);
return
NULL
;
}
free
(
identifier2
);
if
(
config_getswitch
(
IMAPOPT_PTSKRB5_STRIP_DEFAULT_REALM
))
{
/* get local realm */
if
(
krb5_get_default_realm
(
context
,
&
realm
))
{
krb5_free_principal
(
context
,
princ
);
krb5_free_context
(
context
);
syslog
(
LOG_ERR
,
"afspts_canonifyid krb5_get_default_realm failed"
);
return
NULL
;
}
/* build dummy princ to compare realms */
if
(
krb5_build_principal
(
context
,
&
princ_dummy
,
strlen
(
realm
),
realm
,
"dummy"
,
0
))
{
krb5_free_principal
(
context
,
princ
);
krb5_free_context
(
context
);
free
(
realm
);
syslog
(
LOG_ERR
,
"afspts_canonifyid krb5_build_principal failed"
);
return
NULL
;
}
/* is this principal local ? */
if
(
krb5_realm_compare
(
context
,
princ
,
princ_dummy
))
{
striprealm
=
1
;
}
/* done w/ dummy princ free it & realm */
krb5_free_principal
(
context
,
princ_dummy
);
free
(
realm
);
}
if
(
config_getswitch
(
IMAPOPT_PTSKRB5_CONVERT524
))
{
char
nbuf
[
64
],
ibuf
[
64
],
rbuf
[
64
];
if
(
krb5_524_conv_principal
(
context
,
princ
,
nbuf
,
ibuf
,
rbuf
))
{
krb5_free_principal
(
context
,
princ
);
krb5_free_context
(
context
);
return
NULL
;
}
retbuf
=
xmalloc
(
3
*
64
+
3
);
sprintf
(
retbuf
,
"%s%s%s%s%s"
,
nbuf
,
ibuf
[
0
]
?
"."
:
""
,
ibuf
,
rbuf
[
0
]
?
"@"
:
""
,
rbuf
);
}
else
{
/* get the text version of princ */
if
(
krb5_unparse_name
(
context
,
princ
,
&
retbuf
))
{
krb5_free_principal
(
context
,
princ
);
krb5_free_context
(
context
);
syslog
(
LOG_ERR
,
"afspts_canonifyid krb5_unparse_name failed"
);
return
NULL
;
}
}
/* we have the canonical name pointed to by p -- strip realm if local */
realmbegin
=
strrchr
(
retbuf
,
'@'
);
if
(
realmbegin
)
{
if
(
!
striprealm
)
{
realm
=
realmbegin
+
1
;
if
(
is_local_realm
(
realm
))
striprealm
=
1
;
}
if
(
striprealm
)
{
*
realmbegin
=
'\0'
;
}
else
{
/* Force realm to uppercase */
while
(
*
(
++
realmbegin
))
{
*
realmbegin
=
toupper
(
*
realmbegin
);
}
}
}
krb5_free_principal
(
context
,
princ
);
krb5_free_context
(
context
);
return
retbuf
;
}
#else
/* AFSPTS_USE_KRB5 not defined */
/* Sanity Check */
# if PTS_DB_KEYSIZE < MAX_K_NAME_SZ
# error PTS_DB_KEYSIZE is smaller than MAX_K_NAME_SZ
# endif
/* where is krb.equiv? */
# ifndef KRB_MAPNAME
# define KRB_MAPNAME (SYSCONFDIR "/krb.equiv")
# endif
/*
* Parse a line 'src' from an /etc/krb.equiv file.
* Sets the buffer pointed to by 'principal' to be the kerberos
* identity and sets the buffer pointed to by 'localuser' to
* be the local user. Both buffers must be of size one larger than
* MAX_K_NAME_SZ. Returns 1 on success, 0 on failure.
*/
static
int
parse_krbequiv_line
(
const
char
*
src
,
char
*
principal
,
char
*
localuser
)
{
int
i
;
while
(
Uisspace
(
*
src
))
src
++
;
if
(
!*
src
)
return
0
;
for
(
i
=
0
;
*
src
&&
!
Uisspace
(
*
src
);
i
++
)
{
if
(
i
>=
MAX_K_NAME_SZ
)
return
0
;
*
principal
++
=
*
src
++
;
}
*
principal
=
0
;
if
(
!
Uisspace
(
*
src
))
return
0
;
/* Need at least one separator */
while
(
Uisspace
(
*
src
))
src
++
;
if
(
!*
src
)
return
0
;
for
(
i
=
0
;
*
src
&&
!
Uisspace
(
*
src
);
i
++
)
{
if
(
i
>=
MAX_K_NAME_SZ
)
return
0
;
*
localuser
++
=
*
src
++
;
}
*
localuser
=
0
;
return
1
;
}
/*
* Map a remote kerberos principal to a local username. If a mapping
* is found, a pointer to the local username is returned. Otherwise,
* a NULL pointer is returned.
* Eventually, this may be more sophisticated than a simple file scan.
*/
static
char
*
auth_map_krbid
(
const
char
*
real_aname
,
const
char
*
real_inst
,
const
char
*
real_realm
)
{
static
char
localuser
[
MAX_K_NAME_SZ
+
1
];
char
principal
[
MAX_K_NAME_SZ
+
1
];
char
aname
[
ANAME_SZ
];
char
inst
[
INST_SZ
];
char
realm
[
REALM_SZ
];
char
lrealm
[
REALM_SZ
];
char
krbhst
[
MAX_HSTNM
];
char
*
p
;
char
buf
[
1024
];
FILE
*
mapfile
;
if
(
!
(
mapfile
=
fopen
(
KRB_MAPNAME
,
"r"
)))
{
/* If the file can't be opened, don't do mappings */
return
0
;
}
for
(;;)
{
if
(
!
fgets
(
buf
,
sizeof
(
buf
),
mapfile
))
break
;
if
(
parse_krbequiv_line
(
buf
,
principal
,
localuser
)
==
0
||
kname_parse
(
aname
,
inst
,
realm
,
principal
)
!=
0
)
{
/* Ignore badly formed lines */
continue
;
}
if
(
!
strcmp
(
aname
,
real_aname
)
&&
!
strcmp
(
inst
,
real_inst
)
&&
!
strcmp
(
realm
,
real_realm
))
{
fclose
(
mapfile
);
aname
[
0
]
=
inst
[
0
]
=
realm
[
0
]
=
'\0'
;
if
(
kname_parse
(
aname
,
inst
,
realm
,
localuser
)
!=
0
)
{
return
0
;
}
/* Upcase realm name */
for
(
p
=
realm
;
*
p
;
p
++
)
{
if
(
Uislower
(
*
p
))
*
p
=
toupper
(
*
p
);
}
if
(
*
realm
)
{
if
(
krb_get_lrealm
(
lrealm
,
1
)
==
0
&&
strcmp
(
lrealm
,
realm
)
==
0
)
{
*
realm
=
0
;
}
else
if
(
krb_get_krbhst
(
krbhst
,
realm
,
1
))
{
return
0
;
/* Unknown realm */
}
}
strcpy
(
localuser
,
aname
);
if
(
*
inst
)
{
strcat
(
localuser
,
"."
);
strcat
(
localuser
,
inst
);
}
if
(
*
realm
)
{
strcat
(
localuser
,
"@"
);
strcat
(
localuser
,
realm
);
}
return
localuser
;
}
}
fclose
(
mapfile
);
return
0
;
}
/*
* Convert 'identifier' into canonical form.
* Returns a pointer to a static buffer containing the canonical form
* or NULL if 'identifier' is invalid.
*/
static
char
*
afspts_canonifyid
(
const
char
*
identifier
,
size_t
len
)
{
static
char
retbuf
[
MAX_K_NAME_SZ
+
1
];
char
aname
[
ANAME_SZ
];
char
inst
[
INST_SZ
];
char
realm
[
REALM_SZ
];
char
lrealm
[
REALM_SZ
];
char
krbhst
[
MAX_HSTNM
];
char
*
canon_buf
;
char
*
p
;
if
(
!
len
)
len
=
strlen
(
identifier
);
canon_buf
=
xmalloc
(
len
+
1
);
memcpy
(
canon_buf
,
identifier
,
len
);
canon_buf
[
len
]
=
'\0'
;
aname
[
0
]
=
inst
[
0
]
=
realm
[
0
]
=
'\0'
;
if
(
kname_parse
(
aname
,
inst
,
realm
,
canon_buf
)
!=
0
)
{
free
(
canon_buf
);
return
0
;
}
free
(
canon_buf
);
/* Upcase realm name */
for
(
p
=
realm
;
*
p
;
p
++
)
{
if
(
Uislower
(
*
p
))
*
p
=
toupper
(
*
p
);
}
if
(
*
realm
)
{
if
(
krb_get_lrealm
(
lrealm
,
1
)
==
0
&&
strcmp
(
lrealm
,
realm
)
==
0
)
{
*
realm
=
0
;
}
else
if
(
krb_get_krbhst
(
krbhst
,
realm
,
1
))
{
return
0
;
/* Unknown realm */
}
}
/* Check for krb.equiv remappings. */
p
=
auth_map_krbid
(
aname
,
inst
,
realm
);
if
(
p
)
{
strcpy
(
retbuf
,
p
);
return
retbuf
;
}
strcpy
(
retbuf
,
aname
);
if
(
*
inst
)
{
strcat
(
retbuf
,
"."
);
strcat
(
retbuf
,
inst
);
}
if
(
*
realm
&&
!
is_local_realm
(
realm
))
{
strcat
(
retbuf
,
"@"
);
strcat
(
retbuf
,
realm
);
}
return
retbuf
;
}
#endif
/* AFSPTS_USE_KRB5 */
/* API */
static
void
myinit
(
void
)
{
int
r
=
pr_Initialize
(
1L
,
AFSCONF_CLIENTNAME
,
config_getstring
(
IMAPOPT_AFSPTS_MYCELL
));
if
(
r
)
{
syslog
(
LOG_DEBUG
,
"pr_Initialize failed: %d"
,
r
);
fatal
(
"pr_initialize failed"
,
EC_TEMPFAIL
);
}
localrealms
=
config_getstring
(
IMAPOPT_AFSPTS_LOCALREALMS
);
return
;
}
static
struct
auth_state
*
myauthstate
(
const
char
*
identifier
,
size_t
size
,
const
char
**
reply
,
int
*
dsize
)
{
const
char
*
canon_id
=
afspts_canonifyid
(
identifier
,
size
);
char
canon_id_tmp
[
PTS_DB_KEYSIZE
+
1
];
namelist
groups
;
int
i
,
rc
;
struct
auth_state
*
newstate
;
if
(
canon_id
==
NULL
)
{
syslog
(
LOG_ERR
,
"afspts_canonifyid failed for %s"
,
identifier
);
return
NULL
;
}
*
reply
=
NULL
;
size
=
strlen
(
canon_id
);
memset
(
&
groups
,
0
,
sizeof
(
groups
));
groups
.
namelist_len
=
0
;
groups
.
namelist_val
=
NULL
;
/* canon_id_tmp is used because AFS would otherwise trample
* on our nice canonical user id */
strlcpy
(
canon_id_tmp
,
canon_id
,
sizeof
(
canon_id_tmp
));
if
((
rc
=
pr_ListMembers
(
canon_id_tmp
,
&
groups
)))
{
/* Failure may indicate that we need new tokens */
pr_End
();
rc
=
pr_Initialize
(
1L
,
AFSCONF_CLIENTNAME
,
0
);
if
(
rc
)
{
syslog
(
LOG_DEBUG
,
"pr_Initialize failed: %d"
,
rc
);
fatal
(
"pr_Initialize failed"
,
EC_TEMPFAIL
);
}
/* Okay, rerun it now */
rc
=
pr_ListMembers
(
canon_id_tmp
,
&
groups
);
}
/* Don't die because of afs, but log the error */
if
(
rc
)
{
syslog
(
LOG_ERR
,
"pr_ListMembers %s: %s"
,
canon_id
,
error_message
(
rc
));
}
/* fill in our new state structure */
*
dsize
=
sizeof
(
struct
auth_state
)
+
(
groups
.
namelist_len
*
sizeof
(
struct
auth_ident
));
newstate
=
(
struct
auth_state
*
)
xzmalloc
(
*
dsize
);
strcpy
(
newstate
->
userid
.
id
,
canon_id
);
newstate
->
userid
.
hash
=
strhash
(
canon_id
);
/* If we get a permission error, assume it may be temporary
authentication problem, and cache only for a minute.
Should negative cache time be configurable? */
if
(
rc
==
PRPERM
)
{
newstate
->
mark
=
time
(
0
)
+
60
-
(
config_getint
(
IMAPOPT_PTSCACHE_TIMEOUT
)
>
60
)
?
config_getint
(
IMAPOPT_PTSCACHE_TIMEOUT
)
:
60
;
}
else
newstate
->
mark
=
time
(
0
);
newstate
->
ngroups
=
groups
.
namelist_len
;
/* store group list in contiguous array for easy storage in the database */
memset
(
newstate
->
groups
,
0
,
newstate
->
ngroups
*
sizeof
(
struct
auth_ident
));
for
(
i
=
0
;
i
<
newstate
->
ngroups
;
i
++
)
{
strlcpy
(
newstate
->
groups
[
i
].
id
,
groups
.
namelist_val
[
i
],
sizeof
(
newstate
->
groups
[
i
].
id
));
newstate
->
groups
[
i
].
hash
=
strhash
(
groups
.
namelist_val
[
i
]);
/* don't free groups.namelist_val[i]. Something else currently
* takes care of that data.
*/
}
if
(
groups
.
namelist_val
!=
NULL
)
{
free
(
groups
.
namelist_val
);
}
return
newstate
;
}
#else
/* HAVE_AFSKRB */
static
void
myinit
(
void
)
{
fatal
(
"PTS module (afskrb) not compiled in"
,
EC_CONFIG
);
}
static
struct
auth_state
*
myauthstate
(
const
char
*
identifier
__attribute__
((
unused
)),
size_t
size
__attribute__
((
unused
)),
const
char
**
reply
__attribute__
((
unused
)),
int
*
dsize
__attribute__
((
unused
)))
{
fatal
(
"PTS module (afskrb) not compiled in"
,
EC_CONFIG
);
return
NULL
;
}
#endif
/* HAVE_AFSKRB */
struct
pts_module
pts_afskrb
=
{
"afskrb"
,
/* name */
&
myinit
,
&
myauthstate
,
};
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sat, Apr 4, 1:43 AM (1 w, 4 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18821993
Default Alt Text
afskrb.c (14 KB)
Attached To
Mode
R111 cyrus-imapd
Attached
Detach File
Event Timeline