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
0112e3c0
...
0112e3c07a2b8fcfb642ace4b880575f86fcf933
authored
2007-12-03 16:29:02 +0000
by
Sergey Poznyakoff
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
Add preauth.c
1 parent
d2ff5151
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
520 additions
and
1 deletions
ChangeLog
NEWS
imap4d/preauth.c
ChangeLog
View file @
0112e3c
2007-12-03 Sergey Poznyakoff <gray@gnu.org.ua>
* NEWS: Update.
* gnulib.modules: Add des. Sort lines.
* imap4d/Makefile.am (imap4d_SOURCES): Add preauth.c
* imap4d/preauth.c: New file.
* imap4d/authenticate.c (imap4d_authenticate): Use
imap4d_session_setup.
* imap4d/imap4d.c (imap4d_session_setup)
...
...
NEWS
View file @
0112e3c
GNU mailutils NEWS -- history of user-visible changes. 2007-1
1-30
GNU mailutils NEWS -- history of user-visible changes. 2007-1
2-03
Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
See the end of file for copying conditions.
...
...
@@ -146,6 +146,33 @@ Previous versions incorrectly understood such an URL as `a/b'
* Fixed APOP handling.
* imap4d supports PREAUTH mode.
Three mechanisms are provided for authentifying the connection in
PREAUTH mode:
1. stdio - PREAUTH mode is enabled automatically if imap4d is started
from command line in interactive mode (-i command line
option). The current login name is used as the user name.
2. ident - The remote machine is asked about the requester identity
using the identification protocol (RFC 1413). Both plaintext and
DES encrypted replies are understood.
3. prog - Imap4d invokes an external program to authenticate the
connection. Four arguments are supplied to the program:
1) Remote IP address in dotted-quad notation;
2) Remote port number;
3) Local IP address (currently "0.0.0.0");
4) Local port number.
If the connection is authenticated, the program should print the
user name, followed by a newline character, on its standard
output and exit with code 0.
Otherwise, it shoud exit with a non-zero exit code.
* Remove v0.6 compatibility layer.
...
...
imap4d/preauth.c
0 → 100644
View file @
0112e3c
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2001, 2002, 2003, 2004,
2005, 2006, 2007 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Mailutils 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Mailutils; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA */
/* Preauth support for imap4d */
#include "imap4d.h"
#include "des.h"
/* Stdio preauth */
static
char
*
do_preauth_stdio
(
struct
sockaddr_in
*
pcs
)
{
struct
passwd
*
pw
=
getpwuid
(
getuid
());
return
pw
?
strdup
(
pw
->
pw_name
)
:
NULL
;
}
/* IDENT (AUTH, RFC1413) preauth */
#define USERNAME_C "USERID :"
/* If the reply matches sscanf expression
"%*[^:]: USERID :%*[^:]:%s"
returns a malloced copy of the %s part. Otherwise, return NULL. */
static
char
*
ident_extract_username
(
char
*
reply
)
{
char
*
p
;
p
=
strchr
(
reply
,
':'
);
if
(
!
p
)
return
NULL
;
if
(
p
[
1
]
!=
' '
||
strncmp
(
p
+
2
,
USERNAME_C
,
sizeof
(
USERNAME_C
)
-
1
))
return
NULL
;
p
+=
2
+
sizeof
(
USERNAME_C
)
-
1
;
p
=
strchr
(
p
,
':'
);
if
(
!
p
)
return
NULL
;
do
p
++
;
while
(
*
p
==
' '
);
return
p
;
}
static
int
trimcrlf
(
char
*
buf
)
{
int
len
=
strlen
(
buf
);
if
(
len
==
0
)
return
0
;
if
(
buf
[
len
-
1
]
==
'\n'
)
{
len
--
;
if
(
buf
[
len
-
1
]
==
'\r'
)
len
--
;
buf
[
len
]
=
0
;
}
return
len
;
}
static
int
is_des_p
(
const
char
*
name
)
{
int
len
=
strlen
(
name
);
return
len
>
1
&&
name
[
0
]
==
'['
&&
name
[
len
-
1
]
==
']'
;
}
#define smask(step) ((1<<step)-1)
#define pstep(x,step) (((x)&smask(step))^(((x)>>step)&smask(step)))
#define parity_char(x) pstep(pstep(pstep((x),4),2),1)
static
void
des_fixup_key_parity
(
unsigned
char
key
[
8
])
{
int
i
;
for
(
i
=
0
;
i
<
8
;
i
++
)
{
key
[
i
]
&=
0xfe
;
key
[
i
]
|=
1
^
parity_char
(
key
[
i
]);
}
}
static
void
des_cbc_cksum
(
gl_des_ctx
*
ctx
,
unsigned
char
*
buf
,
size_t
bufsize
,
unsigned
char
out
[
8
],
unsigned
char
key
[
8
])
{
while
(
bufsize
>
0
)
{
if
(
bufsize
>=
8
)
{
unsigned
char
*
p
=
key
;
*
p
++
^=
*
buf
++
;
*
p
++
^=
*
buf
++
;
*
p
++
^=
*
buf
++
;
*
p
++
^=
*
buf
++
;
*
p
++
^=
*
buf
++
;
*
p
++
^=
*
buf
++
;
*
p
++
^=
*
buf
++
;
*
p
++
^=
*
buf
++
;
bufsize
-=
8
;
}
else
{
unsigned
char
*
p
=
key
+
bufsize
;
buf
+=
bufsize
;
switch
(
bufsize
)
{
case
7
:
*--
p
^=
*--
buf
;
case
6
:
*--
p
^=
*--
buf
;
case
5
:
*--
p
^=
*--
buf
;
case
4
:
*--
p
^=
*--
buf
;
case
3
:
*--
p
^=
*--
buf
;
case
2
:
*--
p
^=
*--
buf
;
case
1
:
*--
p
^=
*--
buf
;
}
bufsize
=
0
;
}
gl_des_ecb_crypt
(
ctx
,
key
,
key
,
0
);
}
}
static
void
des_string_to_key
(
char
*
buf
,
size_t
bufsize
,
unsigned
char
key
[
8
])
{
size_t
i
;
int
j
;
unsigned
temp
;
unsigned
char
*
p
;
char
*
p_char
;
char
k_char
[
64
];
gl_des_ctx
context
;
char
*
pstr
;
int
forward
=
1
;
p_char
=
k_char
;
memset
(
k_char
,
0
,
sizeof
(
k_char
));
/* get next 8 bytes, strip parity, xor */
pstr
=
buf
;
for
(
i
=
1
;
i
<=
bufsize
;
i
++
)
{
/* get next input key byte */
temp
=
(
unsigned
int
)
*
pstr
++
;
/* loop through bits within byte, ignore parity */
for
(
j
=
0
;
j
<=
6
;
j
++
)
{
if
(
forward
)
*
p_char
++
^=
(
int
)
temp
&
01
;
else
*--
p_char
^=
(
int
)
temp
&
01
;
temp
=
temp
>>
1
;
}
while
(
--
j
>
0
);
/* check and flip direction */
if
((
i
%
8
)
==
0
)
forward
=
!
forward
;
}
p_char
=
k_char
;
p
=
(
unsigned
char
*
)
key
;
for
(
i
=
0
;
i
<=
7
;
i
++
)
{
temp
=
0
;
for
(
j
=
0
;
j
<=
6
;
j
++
)
temp
|=
*
p_char
++
<<
(
1
+
j
);
*
p
++
=
(
unsigned
char
)
temp
;
}
des_fixup_key_parity
(
key
);
gl_des_setkey
(
&
context
,
key
);
des_cbc_cksum
(
&
context
,
buf
,
bufsize
,
key
,
key
);
memset
(
&
context
,
0
,
sizeof
context
);
des_fixup_key_parity
(
key
);
}
static
int
decode64_buf
(
const
char
*
name
,
unsigned
char
**
pbuf
,
size_t
*
psize
)
{
mu_stream_t
str
=
NULL
,
flt
=
NULL
;
size_t
namelen
;
unsigned
char
buf
[
512
];
size_t
size
;
name
++
;
namelen
=
strlen
(
name
)
-
1
;
mu_memory_stream_create
(
&
str
,
NULL
,
MU_STREAM_NO_CHECK
);
mu_filter_create
(
&
flt
,
str
,
"base64"
,
MU_FILTER_DECODE
,
MU_STREAM_READ
|
MU_STREAM_NO_CHECK
);
mu_stream_open
(
str
);
mu_stream_sequential_write
(
str
,
name
,
namelen
);
mu_stream_read
(
flt
,
buf
,
sizeof
buf
,
0
,
&
size
);
mu_stream_destroy
(
&
flt
,
NULL
);
mu_stream_destroy
(
&
str
,
NULL
);
*
pbuf
=
malloc
(
size
);
if
(
!*
pbuf
)
return
1
;
memcpy
(
*
pbuf
,
buf
,
size
);
*
psize
=
size
;
return
0
;
}
struct
ident_info
{
uint32_t
checksum
;
uint16_t
random
;
uint16_t
uid
;
uint32_t
date
;
uint32_t
ip_local
;
uint32_t
ip_remote
;
uint16_t
port_local
;
uint16_t
port_remote
;
};
union
ident_data
{
struct
ident_info
fields
;
unsigned
long
longs
[
6
];
unsigned
char
chars
[
24
];
};
char
*
ident_decrypt
(
const
char
*
file
,
const
char
*
name
)
{
unsigned
char
*
buf
=
NULL
;
size_t
size
=
0
;
int
fd
;
char
keybuf
[
1024
];
union
ident_data
id
;
if
(
decode64_buf
(
name
,
&
buf
,
&
size
))
return
NULL
;
if
(
size
!=
24
)
{
mu_diag_output
(
MU_DIAG_ERROR
,
_
(
"Incorrect length of IDENT DES packet"
));
free
(
buf
);
return
NULL
;
}
fd
=
open
(
file
,
O_RDONLY
);
if
(
fd
<
0
)
{
mu_diag_output
(
MU_DIAG_ERROR
,
_
(
"Cannot open file %s: %s"
),
file
,
mu_strerror
(
errno
));
return
NULL
;
}
while
(
read
(
fd
,
keybuf
,
sizeof
(
keybuf
))
==
sizeof
(
keybuf
))
{
int
i
;
unsigned
char
key
[
8
];
gl_des_ctx
ctx
;
des_string_to_key
(
keybuf
,
sizeof
(
keybuf
),
key
);
gl_des_setkey
(
&
ctx
,
key
);
memcpy
(
id
.
chars
,
buf
,
size
);
gl_des_ecb_decrypt
(
&
ctx
,
(
char
*
)
&
id
.
longs
[
4
],
(
char
*
)
&
id
.
longs
[
4
]);
id
.
longs
[
4
]
^=
id
.
longs
[
2
];
id
.
longs
[
5
]
^=
id
.
longs
[
3
];
gl_des_ecb_decrypt
(
&
ctx
,
(
char
*
)
&
id
.
longs
[
2
],
(
char
*
)
&
id
.
longs
[
2
]);
id
.
longs
[
2
]
^=
id
.
longs
[
0
];
id
.
longs
[
3
]
^=
id
.
longs
[
1
];
gl_des_ecb_decrypt
(
&
ctx
,
(
char
*
)
&
id
.
longs
[
0
],
(
char
*
)
&
id
.
longs
[
0
]);
for
(
i
=
1
;
i
<
6
;
i
++
)
id
.
longs
[
0
]
^=
id
.
longs
[
i
];
if
(
id
.
fields
.
checksum
==
0
)
break
;
}
close
(
fd
);
free
(
buf
);
if
(
id
.
fields
.
checksum
==
0
)
{
uid_t
uid
=
ntohs
(
id
.
fields
.
uid
);
auth_data
=
mu_get_auth_by_uid
(
uid
);
if
(
!
auth_data
)
{
mu_diag_output
(
MU_DIAG_ERROR
,
_
(
"No user with UID %u"
),
uid
);
return
NULL
;
}
return
auth_data
->
name
;
}
else
mu_diag_output
(
MU_DIAG_ERROR
,
_
(
"Failed to decrypt IDENT reply"
));
return
NULL
;
}
static
char
*
do_preauth_ident
(
struct
sockaddr_in
*
pcs
)
{
mu_stream_t
stream
;
char
hostaddr
[
16
];
char
*
p
=
inet_ntoa
(
pcs
->
sin_addr
);
int
rc
;
char
*
buf
=
NULL
;
size_t
size
=
0
;
char
*
name
=
NULL
;
memcpy
(
hostaddr
,
p
,
15
);
hostaddr
[
15
]
=
0
;
rc
=
mu_tcp_stream_create
(
&
stream
,
hostaddr
,
ident_port
,
MU_STREAM_RDWR
|
MU_STREAM_NO_CHECK
);
if
(
rc
)
{
mu_diag_output
(
MU_DIAG_INFO
,
_
(
"Cannot create TCP stream: %s"
),
mu_strerror
(
rc
));
return
NULL
;
}
rc
=
mu_stream_open
(
stream
);
if
(
rc
)
{
mu_diag_output
(
MU_DIAG_INFO
,
_
(
"Cannot open TCP stream to %s:%d: %s"
),
hostaddr
,
ident_port
,
mu_strerror
(
rc
));
return
NULL
;
}
mu_stream_sequential_printf
(
stream
,
"%u , %u
\r\n
"
,
ntohs
(
pcs
->
sin_port
),
mu_gocs_daemon
.
port
);
mu_stream_shutdown
(
stream
,
MU_STREAM_WRITE
);
rc
=
mu_stream_sequential_getline
(
stream
,
&
buf
,
&
size
,
NULL
);
mu_stream_close
(
stream
);
mu_stream_destroy
(
&
stream
,
NULL
);
if
(
rc
)
{
mu_diag_output
(
MU_DIAG_INFO
,
_
(
"Cannot read answer from %s:%d: %s"
),
hostaddr
,
ident_port
,
mu_strerror
(
rc
));
return
NULL
;
}
mu_diag_output
(
MU_DIAG_INFO
,
"Got %s"
,
buf
);
trimcrlf
(
buf
);
name
=
ident_extract_username
(
buf
);
if
(
!
name
)
mu_diag_output
(
MU_DIAG_INFO
,
_
(
"Malformed IDENT response: `%s', from %s:%d"
),
buf
,
hostaddr
,
ident_port
);
else
if
(
is_des_p
(
name
))
{
if
(
!
ident_keyfile
)
{
mu_diag_output
(
MU_DIAG_ERROR
,
_
(
"Keydile not specified in config; "
"use `ident-keyfile FILE'"
));
name
=
NULL
;
}
else
name
=
ident_decrypt
(
ident_keyfile
,
name
);
}
else
if
(
ident_encrypt_only
)
{
mu_diag_output
(
MU_DIAG_ERROR
,
_
(
"Refusing unencrypted ident reply from %s:%d"
),
hostaddr
,
ident_port
);
name
=
NULL
;
}
else
{
mu_diag_output
(
MU_DIAG_INFO
,
"USERNAME %s"
,
name
);
name
=
strdup
(
name
);
}
free
(
buf
);
return
name
;
}
/* External (program) preauth */
static
char
*
do_preauth_program
(
struct
sockaddr_in
*
pcs
)
{
FILE
*
fp
;
char
*
p
=
inet_ntoa
(
pcs
->
sin_addr
);
char
*
cmd
=
0
;
char
*
buf
=
NULL
;
size_t
size
;
ssize_t
rc
;
asprintf
(
&
cmd
,
"%s %s %u %s %u"
,
preauth_program
,
p
,
ntohs
(
pcs
->
sin_port
),
"0.0.0.0"
,
/* FIXME */
mu_gocs_daemon
.
port
);
fp
=
popen
(
cmd
,
"r"
);
free
(
cmd
);
rc
=
getline
(
&
buf
,
&
size
,
fp
);
pclose
(
fp
);
if
(
rc
>
0
)
{
if
(
trimcrlf
(
buf
)
==
0
)
{
free
(
buf
);
return
NULL
;
}
return
buf
;
}
return
NULL
;
}
int
imap4d_preauth_setup
(
int
fd
)
{
struct
sockaddr_in
cs
;
int
len
=
sizeof
cs
;
char
*
username
=
NULL
;
mu_diag_output
(
MU_DIAG_INFO
,
_
(
"Incoming connection opened"
));
if
(
getpeername
(
fd
,
(
struct
sockaddr
*
)
&
cs
,
&
len
)
<
0
)
mu_diag_output
(
MU_DIAG_ERROR
,
_
(
"Cannot obtain IP address of client: %s"
),
strerror
(
errno
));
else
mu_diag_output
(
MU_DIAG_INFO
,
_
(
"Connect from %s"
),
inet_ntoa
(
cs
.
sin_addr
));
auth_data
=
NULL
;
switch
(
preauth_mode
)
{
case
preauth_none
:
return
0
;
case
preauth_stdio
:
username
=
do_preauth_stdio
(
&
cs
);
break
;
case
preauth_ident
:
username
=
do_preauth_ident
(
&
cs
);
break
;
case
preauth_prog
:
username
=
do_preauth_program
(
&
cs
);
break
;
}
if
(
username
)
{
int
rc
;
if
(
auth_data
)
rc
=
imap4d_session_setup0
();
else
{
rc
=
imap4d_session_setup
(
username
);
free
(
username
);
}
if
(
rc
==
0
)
{
state
=
STATE_AUTH
;
return
0
;
}
}
return
preauth_only
;
}
Please
register
or
sign in
to post a comment