Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
John McEleney
/
mailutils
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
Commit
2d1b5a5e
...
2d1b5a5e83edea9395e43cabc6455b6a57d4188b
authored
2005-08-12 06:37:51 +0000
by
Sergey Poznyakoff
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
Radius authentication/authorization.
1 parent
b5423ab5
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
571 additions
and
0 deletions
auth/radius.c
auth/radius.c
0 → 100644
View file @
2d1b5a5
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2005 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301 USA */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <mailutils/list.h>
#include <mailutils/iterator.h>
#include <mailutils/mailbox.h>
#include <mailutils/argp.h>
#include <mailutils/argcv.h>
#include <mailutils/mu_auth.h>
#include <mailutils/error.h>
#include <mailutils/errno.h>
#include <mailutils/nls.h>
#ifdef ENABLE_RADIUS
#include <radius/radius.h>
#define ARG_AUTH_REQUEST 256
#define ARG_GETPWNAM_REQUEST 257
#define ARG_GETPWUID_REQUEST 258
#define ARG_RADIUS_DIR 259
static
struct
argp_option
mu_radius_argp_option
[]
=
{
{
"radius-auth-request"
,
ARG_AUTH_REQUEST
,
N_
(
"REQUEST"
),
0
,
N_
(
"Radius request to authenitcate the user"
),
0
},
{
"radius-getpwnam-request"
,
ARG_GETPWNAM_REQUEST
,
N_
(
"REQUEST"
),
0
,
N_
(
"Radius request to retrieve a passwd entry based on username"
),
0
},
{
"radius-getpwuid-request"
,
ARG_GETPWUID_REQUEST
,
N_
(
"REQUEST"
),
0
,
N_
(
"Radius request to retrieve a passwd entry based on UID"
),
0
},
{
"radius-directory"
,
ARG_RADIUS_DIR
,
N_
(
"DIR"
),
0
,
N_
(
"Set path to the radius configuration directory"
),
0
},
{
NULL
}
};
static
char
*
auth_request_str
;
static
grad_avp_t
*
auth_request
;
static
char
*
getpwnam_request_str
;
static
grad_avp_t
*
getpwnam_request
;
static
char
*
getpwuid_request_str
;
static
grad_avp_t
*
getpwuid_request
;
static
int
MU_User_Name
;
static
int
MU_UID
;
static
int
MU_GID
;
static
int
MU_GECOS
;
static
int
MU_Dir
;
static
int
MU_Shell
;
static
int
MU_Mailbox
;
void
get_attribute
(
int
*
pattr
,
char
*
name
,
struct
argp_state
*
state
)
{
grad_dict_attr_t
*
attr
=
grad_attr_name_to_dict
(
name
);
if
(
!
attr
)
argp_error
(
state
,
_
(
"Radius attribute %s not defined"
),
name
);
*
pattr
=
attr
->
value
;
}
enum
parse_state
{
state_lhs
,
state_op
,
state_rhs
,
state_delim
};
int
parse_pairlist
(
grad_avp_t
**
plist
,
const
char
*
input
,
struct
argp_state
*
argp_state
)
{
int
rc
;
int
i
,
argc
;
char
**
argv
;
enum
parse_state
state
;
grad_locus_t
loc
;
char
*
name
;
char
*
op
;
/* FIXME: It is actually ignored. Should it be? */
if
(
!
input
)
return
1
;
if
((
rc
=
argcv_get
(
input
,
","
,
NULL
,
&
argc
,
&
argv
)))
argp_error
(
argp_state
,
_
(
"Cannot parse input `%s': %s"
),
input
,
mu_strerror
(
rc
));
loc
.
file
=
"<command line>"
;
/* FIXME */
loc
.
line
=
0
;
for
(
i
=
0
,
state
=
state_lhs
;
i
<
argc
;
i
++
)
{
grad_avp_t
*
pair
;
switch
(
state
)
{
case
state_lhs
:
name
=
argv
[
i
];
state
=
state_op
;
break
;
case
state_op
:
op
=
argv
[
i
];
state
=
state_rhs
;
break
;
case
state_rhs
:
loc
.
line
=
i
;
/* Just to keep track of error location */
pair
=
grad_create_pair
(
&
loc
,
name
,
grad_operator_equal
,
argv
[
i
]);
if
(
!
pair
)
argp_error
(
argp_state
,
_
(
"cannot create radius A/V pair `%s'"
),
name
);
grad_avl_merge
(
plist
,
&
pair
);
state
=
state_delim
;
break
;
case
state_delim
:
if
(
strcmp
(
argv
[
i
],
","
))
argp_error
(
argp_state
,
_
(
"expected `,' but found `%s'"
),
argv
[
i
]);
state
=
state_lhs
;
}
}
if
(
state
!=
state_delim
&&
state
!=
state_delim
)
argp_error
(
argp_state
,
_
(
"malformed radius A/V list"
));
argcv_free
(
argc
,
argv
);
return
0
;
}
static
void
init
(
struct
argp_state
*
state
)
{
grad_path_init
();
srand
(
time
(
NULL
)
+
getpid
());
if
(
grad_dict_init
())
argp_error
(
state
,
_
(
"Cannot read radius dictionaries"
));
/* Check whether mailutils attributes are defined */
get_attribute
(
&
MU_User_Name
,
"MU-User-Name"
,
state
);
get_attribute
(
&
MU_UID
,
"MU-UID"
,
state
);
get_attribute
(
&
MU_GID
,
"MU-GID"
,
state
);
get_attribute
(
&
MU_GECOS
,
"MU-GECOS"
,
state
);
get_attribute
(
&
MU_Dir
,
"MU-Dir"
,
state
);
get_attribute
(
&
MU_Shell
,
"MU-Shell"
,
state
);
get_attribute
(
&
MU_Mailbox
,
"MU-Mailbox"
,
state
);
/* Parse saved requests */
parse_pairlist
(
&
auth_request
,
auth_request_str
,
state
);
parse_pairlist
(
&
getpwnam_request
,
getpwnam_request_str
,
state
);
parse_pairlist
(
&
getpwuid_request
,
getpwuid_request_str
,
state
);
}
static
error_t
mu_radius_argp_parser
(
int
key
,
char
*
arg
,
struct
argp_state
*
state
)
{
switch
(
key
)
{
case
ARG_AUTH_REQUEST
:
auth_request_str
=
arg
;
break
;
case
ARG_GETPWNAM_REQUEST
:
getpwnam_request_str
=
arg
;
break
;
case
ARG_GETPWUID_REQUEST
:
getpwuid_request_str
=
arg
;
break
;
case
ARG_RADIUS_DIR
:
radius_dir
=
grad_estrdup
(
arg
);
break
;
case
ARGP_KEY_FINI
:
init
(
state
);
break
;
default:
return
ARGP_ERR_UNKNOWN
;
}
return
0
;
}
char
*
_expand_query
(
const
char
*
query
,
const
char
*
ustr
,
const
char
*
passwd
)
{
char
*
p
,
*
q
,
*
res
;
int
len
;
if
(
!
query
)
return
NULL
;
/* Compute resulting query length */
for
(
len
=
0
,
p
=
(
char
*
)
query
;
*
p
;
)
{
if
(
*
p
==
'%'
)
{
if
(
p
[
1
]
==
'u'
)
{
len
+=
ustr
?
strlen
(
ustr
)
:
2
;
p
+=
2
;
}
else
if
(
p
[
1
]
==
'p'
)
{
len
+=
passwd
?
strlen
(
passwd
)
:
2
;
p
+=
2
;
}
else
if
(
p
[
1
]
==
'%'
)
{
len
++
;
p
+=
2
;
}
else
{
len
++
;
p
++
;
}
}
else
{
len
++
;
p
++
;
}
}
res
=
grad_emalloc
(
len
+
1
);
if
(
!
res
)
return
res
;
for
(
p
=
(
char
*
)
query
,
q
=
res
;
*
p
;
)
{
if
(
*
p
==
'%'
)
{
switch
(
*++
p
)
{
case
'u'
:
if
(
ustr
)
{
strcpy
(
q
,
ustr
);
q
+=
strlen
(
q
);
}
else
{
*
q
++
=
'%'
;
*
q
++
=
'u'
;
}
p
++
;
break
;
case
'p'
:
if
(
passwd
)
{
strcpy
(
q
,
passwd
);
q
+=
strlen
(
q
);
}
else
{
*
q
++
=
'%'
;
*
q
++
=
'u'
;
}
p
++
;
break
;
case
'%'
:
*
q
++
=
*
p
++
;
break
;
default:
*
q
++
=
*
p
++
;
}
}
else
*
q
++
=
*
p
++
;
}
*
q
=
0
;
return
res
;
}
static
grad_avp_t
*
create_request
(
grad_avp_t
*
template
,
const
char
*
ustr
,
const
char
*
passwd
)
{
grad_avp_t
*
newp
,
*
p
;
newp
=
grad_avl_dup
(
template
);
for
(
p
=
newp
;
p
;
p
=
p
->
next
)
{
if
(
p
->
type
==
GRAD_TYPE_STRING
)
{
char
*
value
=
_expand_query
(
p
->
avp_strvalue
,
ustr
,
passwd
);
grad_free
(
p
->
avp_strvalue
);
p
->
avp_strvalue
=
value
;
p
->
avp_strlength
=
strlen
(
value
);
}
}
return
newp
;
}
grad_request_t
*
send_request
(
grad_avp_t
*
pairs
,
int
code
,
const
char
*
user
,
const
char
*
passwd
)
{
grad_avp_t
*
plist
=
create_request
(
pairs
,
user
,
passwd
);
if
(
plist
)
{
grad_server_queue_t
*
queue
=
grad_client_create_queue
(
1
,
0
,
0
);
grad_request_t
*
reply
=
grad_client_send
(
queue
,
GRAD_PORT_AUTH
,
code
,
plist
);
grad_client_destroy_queue
(
queue
);
grad_avl_free
(
plist
);
return
reply
;
}
return
NULL
;
}
#define DEFAULT_HOME_PREFIX "/home/"
#define DEFAULT_SHELL "/dev/null"
int
decode_reply
(
grad_request_t
*
reply
,
const
char
*
user_name
,
char
*
password
,
struct
mu_auth_data
**
return_data
)
{
grad_avp_t
*
p
;
int
rc
;
uid_t
uid
=
-
1
;
gid_t
gid
=
-
1
;
char
*
gecos
=
"RADIUS User"
;
char
*
dir
=
NULL
;
char
*
shell
=
NULL
;
char
*
mailbox
=
NULL
;
p
=
grad_avl_find
(
reply
->
avlist
,
MU_User_Name
);
if
(
p
)
user_name
=
p
->
avp_strvalue
;
p
=
grad_avl_find
(
reply
->
avlist
,
MU_UID
);
if
(
p
)
uid
=
p
->
avp_lvalue
;
else
{
mu_error
(
_
(
"Radius did not return UID for `%s'"
),
user_name
);
return
-
1
;
}
p
=
grad_avl_find
(
reply
->
avlist
,
MU_GID
);
if
(
p
)
gid
=
p
->
avp_lvalue
;
else
{
mu_error
(
_
(
"Radius did not return GID for `%s'"
),
user_name
);
return
-
1
;
}
p
=
grad_avl_find
(
reply
->
avlist
,
MU_GECOS
);
if
(
p
)
gecos
=
p
->
avp_strvalue
;
p
=
grad_avl_find
(
reply
->
avlist
,
MU_Dir
);
if
(
p
)
dir
=
strdup
(
p
->
avp_strvalue
);
else
/* Try to provide a reasonable default */
{
dir
=
malloc
(
sizeof
DEFAULT_HOME_PREFIX
+
strlen
(
user_name
));
if
(
!
dir
)
/* FIXME: Error code */
return
1
;
strcat
(
strcpy
(
dir
,
DEFAULT_HOME_PREFIX
),
user_name
);
}
p
=
grad_avl_find
(
reply
->
avlist
,
MU_Shell
);
if
(
p
)
shell
=
p
->
avp_strvalue
;
else
shell
=
DEFAULT_SHELL
;
p
=
grad_avl_find
(
reply
->
avlist
,
MU_Mailbox
);
if
(
p
)
mailbox
=
strdup
(
p
->
avp_strvalue
);
else
{
rc
=
mu_construct_user_mailbox_url
(
&
mailbox
,
user_name
);
if
(
rc
)
return
rc
;
}
rc
=
mu_auth_data_alloc
(
return_data
,
user_name
,
password
,
uid
,
gid
,
gecos
,
dir
,
shell
,
mailbox
,
1
);
free
(
dir
);
free
(
mailbox
);
return
rc
;
}
int
mu_radius_authenticate
(
struct
mu_auth_data
**
return_data
ARG_UNUSED
,
const
void
*
key
,
void
*
func_data
ARG_UNUSED
,
void
*
call_data
)
{
int
rc
;
grad_request_t
*
reply
;
const
struct
mu_auth_data
*
auth_data
=
key
;
if
(
!
auth_request
)
{
mu_error
(
_
(
"--radius-auth-request is not specified"
));
return
1
;
}
reply
=
send_request
(
auth_request
,
RT_ACCESS_REQUEST
,
auth_data
->
name
,
(
char
*
)
call_data
);
rc
=
!
reply
||
reply
->
code
!=
RT_ACCESS_ACCEPT
;
grad_request_free
(
reply
);
return
rc
;
}
static
int
mu_auth_radius_user_by_name
(
struct
mu_auth_data
**
return_data
,
const
void
*
key
,
void
*
unused_func_data
,
void
*
unused_call_data
)
{
int
rc
=
1
;
grad_request_t
*
reply
;
if
(
!
getpwnam_request
)
{
mu_error
(
_
(
"--radius-getpwnam-request is not specified"
));
return
1
;
}
reply
=
send_request
(
getpwnam_request
,
RT_ACCESS_REQUEST
,
key
,
NULL
);
if
(
!
reply
)
mu_error
(
_
(
"radius server did not respond"
));
else
if
(
reply
->
code
!=
RT_ACCESS_ACCEPT
)
mu_error
(
_
(
"%s: server returned %s"
),
(
char
*
)
key
,
grad_request_code_to_name
(
reply
->
code
));
else
rc
=
decode_reply
(
reply
,
key
,
"x"
,
return_data
);
grad_request_free
(
reply
);
return
rc
;
}
static
int
mu_auth_radius_user_by_uid
(
struct
mu_auth_data
**
return_data
,
const
void
*
key
,
void
*
func_data
,
void
*
call_data
)
{
int
rc
=
1
;
grad_request_t
*
reply
;
char
uidstr
[
64
];
if
(
!
key
)
{
errno
=
EINVAL
;
return
1
;
}
if
(
!
getpwuid_request
)
{
mu_error
(
_
(
"--radius-getpwuid-request is not specified"
));
return
1
;
}
snprintf
(
uidstr
,
sizeof
(
uidstr
),
"%u"
,
*
(
uid_t
*
)
key
);
reply
=
send_request
(
getpwuid_request
,
RT_ACCESS_REQUEST
,
uidstr
,
NULL
);
if
(
reply
->
code
!=
RT_ACCESS_ACCEPT
)
{
mu_error
(
_
(
"uid %s: server returned %s"
),
uidstr
,
grad_request_code_to_name
(
reply
->
code
));
}
else
{
rc
=
decode_reply
(
reply
,
uidstr
,
"x"
,
return_data
);
}
grad_request_free
(
reply
);
return
rc
;
}
struct
argp
mu_radius_argp
=
{
mu_radius_argp_option
,
mu_radius_argp_parser
,
};
#else
static
int
mu_radius_authenticate
(
struct
mu_auth_data
**
return_data
ARG_UNUSED
,
const
void
*
key
,
void
*
func_data
ARG_UNUSED
,
void
*
call_data
)
{
errno
=
ENOSYS
;
return
1
;
}
static
int
mu_auth_radius_user_by_name
(
struct
mu_auth_data
**
return_data
ARG_UNUSED
,
const
void
*
key
ARG_UNUSED
,
void
*
func_data
ARG_UNUSED
,
void
*
call_data
ARG_UNUSED
)
{
errno
=
ENOSYS
;
return
1
;
}
static
int
mu_auth_radius_user_by_uid
(
struct
mu_auth_data
**
return_data
,
const
void
*
key
,
void
*
func_data
,
void
*
call_data
)
{
errno
=
ENOSYS
;
return
1
;
}
#endif
struct
mu_auth_module
mu_auth_radius_module
=
{
"radius"
,
#ifdef ENABLE_RADIUS
&
mu_radius_argp
,
#else
NULL
,
#endif
mu_radius_authenticate
,
NULL
,
mu_auth_radius_user_by_name
,
NULL
,
mu_auth_radius_user_by_uid
,
NULL
};
Please
register
or
sign in
to post a comment