Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117879785
global.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
34 KB
Referenced Files
None
Subscribers
None
global.c
View Options
/* global.c -- Configuration routines
*
* 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.
*/
#include
<config.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#include
<ctype.h>
#include
<sysexits.h>
#include
<syslog.h>
#include
<sys/statvfs.h>
#include
<sys/types.h>
#include
<netinet/in.h>
#include
<sys/stat.h>
#ifdef HAVE_SSL
#include
<openssl/rand.h>
#endif
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#include
"acl.h"
#include
"assert.h"
#include
"charset.h"
#include
"cyr_lock.h"
#include
"gmtoff.h"
#include
"iptostring.h"
#include
"global.h"
#include
"libconfig.h"
#include
"libcyr_cfg.h"
#include
"mboxlist.h"
#include
"mutex.h"
#include
"prot.h"
/* for PROT_BUFSIZE */
#include
"strarray.h"
#include
"userdeny.h"
#include
"util.h"
#include
"xmalloc.h"
#include
"xstrlcat.h"
#include
"xstrlcpy.h"
/* generated headers are not necessarily in current directory */
#include
"imap/imap_err.h"
#include
"imap/mupdate_err.h"
static
enum
{
NOT_RUNNING
=
0
,
RUNNING
=
1
,
DONE
=
2
}
cyrus_init_run
=
NOT_RUNNING
;
static
int
cyrus_init_nodb
=
0
;
EXPORTED
int
in_shutdown
=
0
;
EXPORTED
int
config_fulldirhash
;
/* 0 */
EXPORTED
int
config_implicitrights
;
/* "lkxa" */
EXPORTED
unsigned
long
config_metapartition_files
;
/* 0 */
EXPORTED
const
char
*
config_mboxlist_db
;
EXPORTED
const
char
*
config_quota_db
;
EXPORTED
const
char
*
config_subscription_db
;
EXPORTED
const
char
*
config_annotation_db
;
EXPORTED
const
char
*
config_seenstate_db
;
HIDDEN
const
char
*
config_mboxkey_db
;
EXPORTED
const
char
*
config_duplicate_db
;
EXPORTED
const
char
*
config_tls_sessions_db
;
EXPORTED
const
char
*
config_ptscache_db
;
EXPORTED
const
char
*
config_statuscache_db
;
HIDDEN
const
char
*
config_userdeny_db
;
EXPORTED
const
char
*
config_zoneinfo_db
;
EXPORTED
const
char
*
config_conversations_db
;
EXPORTED
const
char
*
config_backup_db
;
EXPORTED
int
charset_flags
;
EXPORTED
int
charset_snippet_flags
;
static
char
session_id_buf
[
MAX_SESSIONID_SIZE
];
static
int
session_id_time
=
0
;
static
int
session_id_count
=
0
;
static
strarray_t
*
suppressed_capabilities
=
NULL
;
static
int
get_facility
(
const
char
*
name
)
{
if
(
!
strcasecmp
(
name
,
"DAEMON"
))
return
LOG_DAEMON
;
if
(
!
strcasecmp
(
name
,
"MAIL"
))
return
LOG_MAIL
;
if
(
!
strcasecmp
(
name
,
"NEWS"
))
return
LOG_NEWS
;
if
(
!
strcasecmp
(
name
,
"USER"
))
return
LOG_USER
;
if
(
!
strcasecmp
(
name
,
"LOCAL0"
))
return
LOG_LOCAL0
;
if
(
!
strcasecmp
(
name
,
"LOCAL1"
))
return
LOG_LOCAL1
;
if
(
!
strcasecmp
(
name
,
"LOCAL2"
))
return
LOG_LOCAL2
;
if
(
!
strcasecmp
(
name
,
"LOCAL3"
))
return
LOG_LOCAL3
;
if
(
!
strcasecmp
(
name
,
"LOCAL4"
))
return
LOG_LOCAL4
;
if
(
!
strcasecmp
(
name
,
"LOCAL5"
))
return
LOG_LOCAL5
;
if
(
!
strcasecmp
(
name
,
"LOCAL6"
))
return
LOG_LOCAL6
;
if
(
!
strcasecmp
(
name
,
"LOCAL7"
))
return
LOG_LOCAL7
;
/* fall back to the default. This will work because we already have
this log open when we call out */
syslog
(
LOG_ERR
,
"config error: syslog name %s not recognised"
,
name
);
return
SYSLOG_FACILITY
;
}
struct
cyrus_module
{
void
(
*
done
)(
void
*
rock
);
void
*
rock
;
};
static
ptrarray_t
cyrus_modules
=
PTRARRAY_INITIALIZER
;
EXPORTED
void
cyrus_modules_add
(
void
(
*
done
)(
void
*
),
void
*
rock
)
{
struct
cyrus_module
*
cm
=
xmalloc
(
sizeof
(
struct
cyrus_module
));
cm
->
done
=
done
;
cm
->
rock
=
rock
;
ptrarray_append
(
&
cyrus_modules
,
cm
);
}
static
void
cyrus_modules_done
()
{
struct
cyrus_module
*
cm
;
while
((
cm
=
ptrarray_pop
(
&
cyrus_modules
)))
{
cm
->
done
(
cm
->
rock
);
free
(
cm
);
}
}
/* Called before a cyrus application starts (but after command line parameters
* are read) */
EXPORTED
int
cyrus_init
(
const
char
*
alt_config
,
const
char
*
ident
,
unsigned
flags
,
int
config_need_data
)
{
char
*
p
;
const
char
*
val
;
const
char
*
prefix
;
int
umaskval
=
0
;
int
syslog_opts
=
LOG_PID
;
const
char
*
facility
;
if
(
cyrus_init_run
!=
NOT_RUNNING
)
{
fatal
(
"cyrus_init called twice!"
,
EX_CONFIG
);
}
else
{
cyrus_init_run
=
RUNNING
;
}
cyrus_init_nodb
=
(
flags
&
CYRUSINIT_NODB
);
#ifdef LOG_PERROR
if
((
flags
&
CYRUSINIT_PERROR
))
syslog_opts
|=
LOG_PERROR
;
#endif
initialize_imap_error_table
();
initialize_mupd_error_table
();
/* various things can run our commands with only two file descriptors, e.g. old strace on FreeBSD,
* or IPC::Run from Perl. Make sure we don't accidentally reuse low FD numbers */
while
(
1
)
{
int
fd
=
open
(
"/dev/null"
,
0
);
if
(
fd
==
-1
)
fatal
(
"can't open /dev/null"
,
EX_SOFTWARE
);
if
(
fd
>=
3
)
{
close
(
fd
);
break
;
}
}
if
(
!
ident
)
fatal
(
"service name was not specified to cyrus_init"
,
EX_CONFIG
);
config_ident
=
ident
;
/* xxx we lose here since we can't have the prefix until we load the
* config file */
openlog
(
config_ident
,
syslog_opts
,
SYSLOG_FACILITY
);
/* Load configuration file. This will set config_dir when it finds it */
config_read
(
alt_config
,
config_need_data
);
/* changed user if needed */
if
((
geteuid
())
==
0
&&
(
become_cyrus
(
/*is_master*/
0
)
!=
0
))
{
fatal
(
"must run as the Cyrus user"
,
EX_USAGE
);
}
prefix
=
config_getstring
(
IMAPOPT_SYSLOG_PREFIX
);
facility
=
config_getstring
(
IMAPOPT_SYSLOG_FACILITY
);
/* Reopen the log with the new prefix, if needed */
if
(
prefix
||
facility
)
{
char
*
ident_buf
;
int
facnum
=
facility
?
get_facility
(
facility
)
:
SYSLOG_FACILITY
;
if
(
prefix
)
ident_buf
=
strconcat
(
prefix
,
"/"
,
ident
,
(
char
*
)
NULL
);
else
ident_buf
=
xstrdup
(
ident
);
closelog
();
openlog
(
ident_buf
,
syslog_opts
,
facnum
);
/* don't free the openlog() string! */
}
/* allow debug logging */
if
(
!
config_debug
)
setlogmask
(
~
LOG_MASK
(
LOG_DEBUG
));
/* Look up default partition */
config_defpartition
=
config_getstring
(
IMAPOPT_DEFAULTPARTITION
);
for
(
p
=
(
char
*
)
config_defpartition
;
p
&&
*
p
;
p
++
)
{
if
(
!
Uisalnum
(
*
p
))
fatal
(
"defaultpartition option contains non-alphanumeric character"
,
EX_CONFIG
);
if
(
Uisupper
(
*
p
))
*
p
=
tolower
((
unsigned
char
)
*
p
);
}
/* Look up umask */
val
=
config_getstring
(
IMAPOPT_UMASK
);
while
(
*
val
)
{
if
(
*
val
>=
'0'
&&
*
val
<=
'7'
)
umaskval
=
umaskval
*
8
+
*
val
-
'0'
;
val
++
;
}
umask
(
umaskval
);
config_fulldirhash
=
config_getswitch
(
IMAPOPT_FULLDIRHASH
);
/* look up and canonify the implicit rights of mailbox owners */
cyrus_acl_strtomask
(
config_getstring
(
IMAPOPT_IMPLICIT_OWNER_RIGHTS
),
&
config_implicitrights
);
/* XXX and if strtomask fails? */
config_metapartition_files
=
config_getbitfield
(
IMAPOPT_METAPARTITION_FILES
);
val
=
config_getstring
(
IMAPOPT_SUPPRESS_CAPABILITIES
);
if
(
val
)
suppressed_capabilities
=
strarray_split
(
val
,
NULL
,
0
);
if
(
config_getswitch
(
IMAPOPT_SEARCH_SKIPDIACRIT
))
charset_flags
|=
CHARSET_SKIPDIACRIT
;
switch
(
config_getenum
(
IMAPOPT_SEARCH_WHITESPACE
))
{
case
IMAP_ENUM_SEARCH_WHITESPACE_MERGE
:
charset_flags
|=
CHARSET_MERGESPACE
;
break
;
case
IMAP_ENUM_SEARCH_WHITESPACE_SKIP
:
charset_flags
|=
CHARSET_SKIPSPACE
;
break
;
default
:
break
;
}
if
(
config_getswitch
(
IMAPOPT_SEARCH_SKIPHTML
))
charset_flags
|=
CHARSET_SKIPHTML
;
if
(
config_getswitch
(
IMAPOPT_RFC2047_UTF8
))
charset_flags
|=
CHARSET_MIME_UTF8
;
/* Set snippet conversion flags. */
charset_snippet_flags
=
CHARSET_KEEPCASE
;
if
(
config_getenum
(
IMAPOPT_SEARCH_ENGINE
)
!=
IMAP_ENUM_SEARCH_ENGINE_XAPIAN
)
{
/* All search engines other than Xapian require escaped HTML */
charset_snippet_flags
|=
CHARSET_ESCAPEHTML
;
}
if
(
!
cyrus_init_nodb
)
{
/* lookup the database backends */
config_mboxlist_db
=
config_getstring
(
IMAPOPT_MBOXLIST_DB
);
config_quota_db
=
config_getstring
(
IMAPOPT_QUOTA_DB
);
config_subscription_db
=
config_getstring
(
IMAPOPT_SUBSCRIPTION_DB
);
config_annotation_db
=
config_getstring
(
IMAPOPT_ANNOTATION_DB
);
config_seenstate_db
=
config_getstring
(
IMAPOPT_SEENSTATE_DB
);
config_mboxkey_db
=
config_getstring
(
IMAPOPT_MBOXKEY_DB
);
config_duplicate_db
=
config_getstring
(
IMAPOPT_DUPLICATE_DB
);
config_tls_sessions_db
=
config_getstring
(
IMAPOPT_TLS_SESSIONS_DB
);
config_ptscache_db
=
config_getstring
(
IMAPOPT_PTSCACHE_DB
);
config_statuscache_db
=
config_getstring
(
IMAPOPT_STATUSCACHE_DB
);
config_userdeny_db
=
config_getstring
(
IMAPOPT_USERDENY_DB
);
config_zoneinfo_db
=
config_getstring
(
IMAPOPT_ZONEINFO_DB
);
config_conversations_db
=
config_getstring
(
IMAPOPT_CONVERSATIONS_DB
);
config_backup_db
=
config_getstring
(
IMAPOPT_BACKUP_DB
);
/* configure libcyrus as needed */
libcyrus_config_setstring
(
CYRUSOPT_CONFIG_DIR
,
config_dir
);
libcyrus_config_setswitch
(
CYRUSOPT_AUTH_UNIX_GROUP_ENABLE
,
config_getswitch
(
IMAPOPT_UNIX_GROUP_ENABLE
));
libcyrus_config_setswitch
(
CYRUSOPT_USERNAME_TOLOWER
,
config_getswitch
(
IMAPOPT_USERNAME_TOLOWER
));
libcyrus_config_setswitch
(
CYRUSOPT_SKIPLIST_UNSAFE
,
config_getswitch
(
IMAPOPT_SKIPLIST_UNSAFE
));
libcyrus_config_setstring
(
CYRUSOPT_TEMP_PATH
,
config_getstring
(
IMAPOPT_TEMP_PATH
));
libcyrus_config_setint
(
CYRUSOPT_PTS_CACHE_TIMEOUT
,
config_getint
(
IMAPOPT_PTSCACHE_TIMEOUT
));
libcyrus_config_setswitch
(
CYRUSOPT_FULLDIRHASH
,
config_getswitch
(
IMAPOPT_FULLDIRHASH
));
libcyrus_config_setstring
(
CYRUSOPT_PTSCACHE_DB
,
config_getstring
(
IMAPOPT_PTSCACHE_DB
));
libcyrus_config_setstring
(
CYRUSOPT_PTSCACHE_DB_PATH
,
config_getstring
(
IMAPOPT_PTSCACHE_DB_PATH
));
libcyrus_config_setstring
(
CYRUSOPT_PTLOADER_SOCK
,
config_getstring
(
IMAPOPT_PTLOADER_SOCK
));
libcyrus_config_setswitch
(
CYRUSOPT_VIRTDOMAINS
,
config_getenum
(
IMAPOPT_VIRTDOMAINS
));
libcyrus_config_setstring
(
CYRUSOPT_AUTH_MECH
,
config_getstring
(
IMAPOPT_AUTH_MECH
));
libcyrus_config_setstring
(
CYRUSOPT_DELETERIGHT
,
config_getstring
(
IMAPOPT_DELETERIGHT
));
libcyrus_config_setstring
(
CYRUSOPT_SQL_DATABASE
,
config_getstring
(
IMAPOPT_SQL_DATABASE
));
libcyrus_config_setstring
(
CYRUSOPT_SQL_ENGINE
,
config_getstring
(
IMAPOPT_SQL_ENGINE
));
libcyrus_config_setstring
(
CYRUSOPT_SQL_HOSTNAMES
,
config_getstring
(
IMAPOPT_SQL_HOSTNAMES
));
libcyrus_config_setstring
(
CYRUSOPT_SQL_USER
,
config_getstring
(
IMAPOPT_SQL_USER
));
libcyrus_config_setstring
(
CYRUSOPT_SQL_PASSWD
,
config_getstring
(
IMAPOPT_SQL_PASSWD
));
libcyrus_config_setswitch
(
CYRUSOPT_SQL_USESSL
,
config_getswitch
(
IMAPOPT_SQL_USESSL
));
libcyrus_config_setswitch
(
CYRUSOPT_SKIPLIST_ALWAYS_CHECKPOINT
,
config_getswitch
(
IMAPOPT_SKIPLIST_ALWAYS_CHECKPOINT
));
/* Not until all configuration parameters are set! */
libcyrus_init
();
}
/* debug lock timing */
const
char
*
locktime
=
config_getstring
(
IMAPOPT_LOCK_DEBUGTIME
);
if
(
locktime
)
{
debug_locks_longer_than
=
atof
(
locktime
);
}
return
0
;
}
EXPORTED
void
global_sasl_init
(
int
client
,
int
server
,
const
sasl_callback_t
*
callbacks
)
{
static
int
called_already
=
0
;
assert
(
client
||
server
);
assert
(
!
called_already
);
called_already
=
1
;
/* set the SASL allocation functions */
sasl_set_alloc
((
sasl_malloc_t
*
)
&
xmalloc
,
(
sasl_calloc_t
*
)
&
xcalloc
,
(
sasl_realloc_t
*
)
&
xrealloc
,
(
sasl_free_t
*
)
&
free
);
/* set the SASL mutex functions */
sasl_set_mutex
((
sasl_mutex_alloc_t
*
)
&
cyrus_mutex_alloc
,
(
sasl_mutex_lock_t
*
)
&
cyrus_mutex_lock
,
(
sasl_mutex_unlock_t
*
)
&
cyrus_mutex_unlock
,
(
sasl_mutex_free_t
*
)
&
cyrus_mutex_free
);
if
(
client
&&
sasl_client_init
(
callbacks
))
{
fatal
(
"could not init sasl (client)"
,
EX_SOFTWARE
);
}
if
(
server
&&
sasl_server_init
(
callbacks
,
"Cyrus"
))
{
fatal
(
"could not init sasl (server)"
,
EX_SOFTWARE
);
}
}
/* this is a wrapper to call the cyrus configuration from SASL */
EXPORTED
int
mysasl_config
(
void
*
context
__attribute__
((
unused
)),
const
char
*
plugin_name
,
const
char
*
option
,
const
char
**
result
,
unsigned
*
len
)
{
if
(
!
strcmp
(
option
,
"srvtab"
))
{
/* we don't transform srvtab! */
*
result
=
config_getstring
(
IMAPOPT_SRVTAB
);
}
else
{
*
result
=
NULL
;
if
(
plugin_name
)
{
/* first try it with the plugin name */
char
*
opt
=
strconcat
(
"sasl_"
,
plugin_name
,
"_"
,
option
,
(
char
*
)
NULL
);
*
result
=
config_getoverflowstring
(
opt
,
NULL
);
free
(
opt
);
}
if
(
*
result
==
NULL
)
{
/* try without the plugin name */
char
*
opt
=
strconcat
(
"sasl_"
,
option
,
(
char
*
)
NULL
);
*
result
=
config_getoverflowstring
(
opt
,
NULL
);
free
(
opt
);
}
}
if
(
*
result
!=
NULL
)
{
if
(
len
)
{
*
len
=
strlen
(
*
result
);
}
return
SASL_OK
;
}
return
SASL_FAIL
;
}
/* This creates a structure that defines the allowable
* security properties
*/
EXPORTED
sasl_security_properties_t
*
mysasl_secprops
(
int
flags
)
{
static
sasl_security_properties_t
ret
;
ret
.
maxbufsize
=
PROT_BUFSIZE
;
ret
.
min_ssf
=
config_getint
(
IMAPOPT_SASL_MINIMUM_LAYER
);
/* minimum allowable security strength */
ret
.
max_ssf
=
config_getint
(
IMAPOPT_SASL_MAXIMUM_LAYER
);
/* maximum allowable security strength */
ret
.
security_flags
=
flags
;
if
(
!
config_getswitch
(
IMAPOPT_ALLOWPLAINTEXT
))
{
ret
.
security_flags
|=
SASL_SEC_NOPLAINTEXT
;
}
if
(
!
config_getswitch
(
IMAPOPT_ALLOWANONYMOUSLOGIN
))
{
ret
.
security_flags
|=
SASL_SEC_NOANONYMOUS
;
}
ret
.
property_names
=
NULL
;
ret
.
property_values
=
NULL
;
return
&
ret
;
}
/* true if 'authstate' is in 'opt' */
EXPORTED
int
global_authisa
(
struct
auth_state
*
authstate
,
enum
imapopt
opt
)
{
char
buf
[
1024
];
const
char
*
val
=
config_getstring
(
opt
);
size_t
len
;
/* Is the option defined? */
if
(
!
val
)
return
0
;
while
(
*
val
)
{
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
(
auth_memberof
(
authstate
,
buf
))
{
return
1
;
}
val
=
p
;
while
(
*
val
&&
Uisspace
(
*
val
))
val
++
;
}
return
0
;
}
/* Note: This function is not idempotent! Only call it once for a given ID
* or you will be unhappy (think IP hosting). */
EXPORTED
const
char
*
canonify_userid
(
char
*
user
,
const
char
*
loginid
,
int
*
domain_from_ip
)
{
char
*
domain
=
NULL
;
int
len
=
strlen
(
user
);
char
buf
[
81
];
/* check for domain */
if
(
config_virtdomains
&&
((
domain
=
strrchr
(
user
,
'@'
))
||
(
domain
=
strrchr
(
user
,
'%'
))))
{
*
domain
=
'@'
;
len
=
domain
-
user
;
}
/* check for global identifiers */
if
(
is_userid_anonymous
(
user
))
{
return
"anonymous"
;
}
else
if
((
len
==
7
&&
strncasecmp
(
user
,
"anybody"
,
len
)
==
0
)
||
(
len
==
6
&&
strncasecmp
(
user
,
"anyone"
,
len
)
==
0
))
{
return
"anyone"
;
}
if
(
config_virtdomains
)
{
if
(
domain
)
{
if
(
config_defdomain
&&
!
strcasecmp
(
config_defdomain
,
domain
+
1
))
{
*
domain
=
'\0'
;
/* trim the default domain */
}
}
else
if
(
loginid
)
{
/* used for LISTRIGHTS */
if
((
domain
=
strrchr
(
loginid
,
'@'
)))
{
/* append the domain from the login id */
snprintf
(
buf
,
sizeof
(
buf
),
"%s@%s"
,
user
,
domain
+
1
);
user
=
buf
;
}
}
else
if
(
config_virtdomains
!=
IMAP_ENUM_VIRTDOMAINS_USERID
)
{
socklen_t
salen
;
int
error
;
struct
sockaddr_storage
localaddr
;
char
hbuf
[
NI_MAXHOST
];
salen
=
sizeof
(
localaddr
);
if
(
getsockname
(
0
,
(
struct
sockaddr
*
)
&
localaddr
,
&
salen
)
==
0
)
{
error
=
getnameinfo
((
struct
sockaddr
*
)
&
localaddr
,
salen
,
hbuf
,
sizeof
(
hbuf
),
NULL
,
0
,
NI_NAMEREQD
);
if
(
error
==
0
&&
(
domain
=
strchr
(
hbuf
,
'.'
))
&&
!
(
config_defdomain
&&
!
strcasecmp
(
config_defdomain
,
domain
+
1
)))
{
/* append the domain from our IP */
snprintf
(
buf
,
sizeof
(
buf
),
"%s@%s"
,
user
,
domain
+
1
);
user
=
buf
;
if
(
domain_from_ip
)
*
domain_from_ip
=
1
;
}
}
}
}
return
auth_canonifyid
(
user
,
0
);
}
EXPORTED
int
mysasl_canon_user
(
sasl_conn_t
*
conn
,
void
*
context
,
const
char
*
user
,
unsigned
ulen
,
unsigned
flags
__attribute__
((
unused
)),
const
char
*
user_realm
__attribute__
((
unused
)),
char
*
out
,
unsigned
out_max
,
unsigned
*
out_ulen
)
{
const
char
*
canonuser
=
NULL
;
if
(
ulen
+
1
>
out_max
)
{
sasl_seterror
(
conn
,
0
,
"buffer overflow while canonicalizing"
);
return
SASL_BUFOVER
;
}
if
(
out
!=
user
)
{
/* There are some paths through libsasl which result in our
* being called with parameters 'user' and 'out' being the
* same buffer. We can handle that case just fine, but this
* memcpy() is redundant and causes a warning in Valgrind. */
memcpy
(
out
,
user
,
ulen
);
}
out
[
ulen
]
=
'\0'
;
canonuser
=
canonify_userid
(
out
,
NULL
,
(
int
*
)
context
);
if
(
!
canonuser
)
{
sasl_seterror
(
conn
,
0
,
"bad userid authenticated"
);
return
SASL_BADAUTH
;
}
*
out_ulen
=
strlen
(
canonuser
);
if
(
*
out_ulen
>=
out_max
)
{
sasl_seterror
(
conn
,
0
,
"buffer overflow while canonicalizing"
);
return
SASL_BUFOVER
;
}
strcpy
(
out
,
canonuser
);
return
SASL_OK
;
}
EXPORTED
int
is_userid_anonymous
(
const
char
*
user
)
{
int
len
=
strlen
(
user
);
const
char
*
domain
;
assert
(
user
);
/* check for domain */
if
(
config_virtdomains
&&
((
domain
=
strrchr
(
user
,
'@'
))
||
(
domain
=
strrchr
(
user
,
'%'
))))
{
len
=
domain
-
user
;
}
/* check if we are anonymous */
if
(
len
==
9
&&
strncasecmp
(
user
,
"anonymous"
,
len
)
==
0
)
{
return
1
;
}
else
{
return
0
;
}
}
/*
* acl_ok() checks to see if the the inbox for 'user' grants the 'a'
* right to 'authstate'. Returns 1 if so, 0 if not.
*/
/* Note that we do not determine if the mailbox is remote or not */
static
int
acl_ok
(
const
char
*
userid
,
struct
auth_state
*
authstate
)
{
mbentry_t
*
mbentry
=
NULL
;
char
*
inbox
=
mboxname_user_mbox
(
userid
,
NULL
);
int
r
=
0
;
if
(
authstate
&&
!
mboxlist_lookup
(
inbox
,
&
mbentry
,
NULL
))
{
r
=
(
cyrus_acl_myrights
(
authstate
,
mbentry
->
acl
)
&
ACL_ADMIN
)
!=
0
;
}
mboxlist_entry_free
(
&
mbentry
);
free
(
inbox
);
return
r
;
}
/* should we allow users to proxy? return SASL_OK if yes,
SASL_BADAUTH otherwise */
EXPORTED
int
mysasl_proxy_policy
(
sasl_conn_t
*
conn
,
void
*
context
,
const
char
*
requested_user
,
unsigned
rlen
,
const
char
*
auth_identity
,
unsigned
alen
,
const
char
*
def_realm
__attribute__
((
unused
)),
unsigned
urlen
__attribute__
((
unused
)),
struct
propctx
*
propctx
__attribute__
((
unused
)))
{
struct
proxy_context
*
ctx
=
(
struct
proxy_context
*
)
context
;
const
char
*
val
=
config_getstring
(
IMAPOPT_LOGINREALMS
);
struct
auth_state
*
authstate
;
int
userisadmin
=
0
;
char
*
realm
;
/* check if remote realm */
if
((
!
config_virtdomains
||
*
val
)
&&
(
realm
=
strchr
(
auth_identity
,
'@'
))
!=
NULL
)
{
realm
++
;
while
(
*
val
)
{
if
(
!
strncasecmp
(
val
,
realm
,
strlen
(
realm
))
&&
(
!
val
[
strlen
(
realm
)]
||
Uisspace
(
val
[
strlen
(
realm
)])))
{
break
;
}
/* not this realm, try next one */
while
(
*
val
&&
!
Uisspace
(
*
val
))
val
++
;
while
(
*
val
&&
Uisspace
(
*
val
))
val
++
;
}
if
(
!*
val
)
{
sasl_seterror
(
conn
,
0
,
"cross-realm login %s denied"
,
auth_identity
);
return
SASL_BADAUTH
;
}
}
authstate
=
auth_newstate
(
auth_identity
);
/* ok, is auth_identity an admin? */
userisadmin
=
global_authisa
(
authstate
,
IMAPOPT_ADMINS
);
if
(
!
ctx
)
{
/* for now only admins are allowed */
auth_freestate
(
authstate
);
if
(
!
userisadmin
)
{
syslog
(
LOG_ERR
,
"%s is not an admin"
,
auth_identity
);
sasl_seterror
(
conn
,
SASL_NOLOG
,
"only admins may authenticate"
);
return
SASL_BADAUTH
;
}
return
SASL_OK
;
}
/* is requested_user denied access? authenticated admins are exempt */
if
(
!
userisadmin
&&
userdeny
(
requested_user
,
config_ident
,
NULL
,
0
))
{
syslog
(
LOG_ERR
,
"user '%s' denied access to service '%s'"
,
requested_user
,
config_ident
);
sasl_seterror
(
conn
,
SASL_NOLOG
,
"user '%s' is denied access to service '%s'"
,
requested_user
,
config_ident
);
auth_freestate
(
authstate
);
return
SASL_NOAUTHZ
;
}
if
(
alen
!=
rlen
||
strncmp
(
auth_identity
,
requested_user
,
alen
))
{
/* we want to authenticate as a different user; we'll allow this
if we're an admin or if we've allowed ACL proxy logins */
int
use_acl
=
ctx
->
use_acl
&&
config_getswitch
(
IMAPOPT_LOGINUSEACL
);
if
(
userisadmin
||
(
use_acl
&&
acl_ok
(
requested_user
,
authstate
))
||
(
ctx
->
proxy_servers
&&
global_authisa
(
authstate
,
IMAPOPT_PROXYSERVERS
)))
{
/* proxy ok! */
userisadmin
=
0
;
/* no longer admin */
auth_freestate
(
authstate
);
authstate
=
auth_newstate
(
requested_user
);
/* are we a proxy admin? */
if
(
ctx
->
userisproxyadmin
)
*
(
ctx
->
userisproxyadmin
)
=
global_authisa
(
authstate
,
IMAPOPT_ADMINS
);
}
else
{
sasl_seterror
(
conn
,
0
,
"user %s is not allowed to proxy"
,
auth_identity
);
auth_freestate
(
authstate
);
return
SASL_BADAUTH
;
}
}
if
(
ctx
->
authstate
)
*
(
ctx
->
authstate
)
=
authstate
;
else
auth_freestate
(
authstate
);
if
(
ctx
->
userisadmin
)
*
(
ctx
->
userisadmin
)
=
userisadmin
;
return
SASL_OK
;
}
/* call before a cyrus application exits */
EXPORTED
void
cyrus_done
(
void
)
{
cyrus_modules_done
();
if
(
cyrus_init_run
!=
RUNNING
)
return
;
cyrus_init_run
=
DONE
;
if
(
!
cyrus_init_nodb
)
libcyrus_done
();
}
/*
* Returns 1 if we have a shutdown file, with the first line in buf.
* Otherwise returns 0, and the contents of buf is undefined.
*/
EXPORTED
int
shutdown_file
(
char
*
buf
,
int
size
)
{
FILE
*
f
;
static
char
*
shutdownfilename
=
NULL
,
*
suffix
;
char
*
p
;
char
tmpbuf
[
1024
];
if
(
!
shutdownfilename
)
{
/* Create system shutdownfile name */
struct
buf
buf
=
BUF_INITIALIZER
;
size_t
system_len
;
buf_printf
(
&
buf
,
"%s/msg/shutdown"
,
config_dir
);
system_len
=
buf_len
(
&
buf
);
/* Add per-service suffix */
buf_printf
(
&
buf
,
".%s"
,
config_ident
);
shutdownfilename
=
buf_release
(
&
buf
);
suffix
=
shutdownfilename
+
system_len
;
}
/* Try per-service shutdown file */
f
=
fopen
(
shutdownfilename
,
"r"
);
if
(
!
f
)
{
/* Trim per-service suffix and try system shutdownfile */
*
suffix
=
'\0'
;
f
=
fopen
(
shutdownfilename
,
"r"
);
if
(
!
f
)
{
/* Restore per-service suffix */
*
suffix
=
'.'
;
return
0
;
}
}
free
(
shutdownfilename
);
if
(
!
buf
)
{
buf
=
tmpbuf
;
size
=
sizeof
(
tmpbuf
);
}
if
(
!
fgets
(
buf
,
size
,
f
))
{
*
buf
=
'\0'
;
syslog
(
LOG_DEBUG
,
"Shutdown file exists with no contents"
);
}
else
{
if
((
p
=
strchr
(
buf
,
'\r'
))
!=
NULL
)
*
p
=
0
;
if
((
p
=
strchr
(
buf
,
'\n'
))
!=
NULL
)
*
p
=
0
;
syslog
(
LOG_DEBUG
,
"Shutdown file: %s, closing connection"
,
buf
);
}
fclose
(
f
);
return
1
;
}
/* Set up the Session ID Buffer */
EXPORTED
void
session_new_id
(
void
)
{
const
char
*
base
;
int
now
=
time
(
NULL
);
if
(
now
!=
session_id_time
)
{
session_id_time
=
now
;
session_id_count
=
0
;
}
++
session_id_count
;
base
=
config_getstring
(
IMAPOPT_SYSLOG_PREFIX
);
if
(
!
base
)
base
=
config_servername
;
#ifdef HAVE_SSL
unsigned
long
long
random
;
RAND_bytes
((
unsigned
char
*
)
&
random
,
sizeof
(
random
));
snprintf
(
session_id_buf
,
MAX_SESSIONID_SIZE
,
"%.128s-%d-%d-%d-%llu"
,
base
,
session_id_time
,
getpid
(),
session_id_count
,
random
);
#else
snprintf
(
session_id_buf
,
MAX_SESSIONID_SIZE
,
"%.128s-%d-%d-%d"
,
base
,
session_id_time
,
getpid
(),
session_id_count
);
#endif
}
/* Return the session id */
EXPORTED
const
char
*
session_id
(
void
)
{
if
(
!
session_id_count
)
session_new_id
();
return
(
const
char
*
)
session_id_buf
;
}
/* parse sessionid out of protocol answers */
EXPORTED
void
parse_sessionid
(
const
char
*
str
,
char
*
sessionid
)
{
char
*
sp
,
*
ep
;
int
len
;
if
((
str
)
&&
(
sp
=
strstr
(
str
,
"SESSIONID=<"
))
&&
(
ep
=
strchr
(
sp
,
'>'
)))
{
sp
+=
11
;
len
=
ep
-
sp
;
if
(
len
<
MAX_SESSIONID_SIZE
)
{
strncpy
(
sessionid
,
sp
,
len
);
ep
=
sessionid
+
len
;
*
ep
=
'\0'
;
}
else
strcpy
(
sessionid
,
"invalid"
);
}
else
strcpy
(
sessionid
,
"unknown"
);
}
EXPORTED
int
capa_is_disabled
(
const
char
*
str
)
{
if
(
!
suppressed_capabilities
)
return
0
;
return
(
strarray_find_case
(
suppressed_capabilities
,
str
,
0
)
>=
0
);
}
/* Find a message-id looking thingy in a string. Returns a pointer to the
* alloc'd id and the remaining string is returned in the **loc parameter.
*
* This is a poor-man's way of finding the message-id. We simply look for
* any string having the format "< ... @ ... >" and assume that the mail
* client created a properly formatted message-id.
*/
#define MSGID_SPECIALS "<> @\\"
EXPORTED
char
*
find_msgid
(
char
*
str
,
char
**
rem
)
{
char
*
msgid
,
*
src
,
*
dst
,
*
cp
;
if
(
!
str
)
return
NULL
;
msgid
=
NULL
;
src
=
str
;
/* find the start of a msgid (don't go past the end of the header) */
while
((
cp
=
src
=
strpbrk
(
src
,
"<
\r
"
))
!=
NULL
)
{
/* check for fold or end of header
*
* Per RFC 2822 section 2.2.3, a long header may be folded by
* inserting CRLF before any WSP (SP and HTAB, per section 2.2.2).
* Any other CRLF is the end of the header.
*/
if
(
*
cp
++
==
'\r'
)
{
if
(
*
cp
++
==
'\n'
&&
!
(
*
cp
==
' '
||
*
cp
==
'\t'
))
{
/* end of header, we're done */
break
;
}
/* skip fold (or junk) */
src
++
;
continue
;
}
/* see if we have (and skip) a quoted localpart */
if
(
*
cp
==
'\"'
)
{
/* find the endquote, making sure it isn't escaped */
do
{
++
cp
;
cp
=
strchr
(
cp
,
'\"'
);
}
while
(
cp
&&
*
(
cp
-1
)
==
'\\'
);
/* no endquote, so bail */
if
(
!
cp
)
{
src
++
;
continue
;
}
}
/* find the end of the msgid */
if
((
cp
=
strchr
(
cp
,
'>'
))
==
NULL
)
return
NULL
;
/* alloc space for the msgid */
dst
=
msgid
=
(
char
*
)
xrealloc
(
msgid
,
cp
-
src
+
2
);
*
dst
++
=
*
src
++
;
/* quoted string */
if
(
*
src
==
'\"'
)
{
src
++
;
while
(
*
src
!=
'\"'
)
{
if
(
*
src
==
'\\'
)
{
src
++
;
}
*
dst
++
=
*
src
++
;
}
src
++
;
}
/* atom */
else
{
while
(
!
strchr
(
MSGID_SPECIALS
,
*
src
))
*
dst
++
=
*
src
++
;
}
if
(
*
src
!=
'@'
||
*
(
dst
-1
)
==
'<'
)
continue
;
*
dst
++
=
*
src
++
;
/* domain atom */
while
(
!
strchr
(
MSGID_SPECIALS
,
*
src
))
*
dst
++
=
*
src
++
;
if
(
*
src
!=
'>'
||
*
(
dst
-1
)
==
'@'
)
continue
;
*
dst
++
=
*
src
++
;
*
dst
=
'\0'
;
if
(
rem
)
*
rem
=
src
;
return
msgid
;
}
if
(
msgid
)
free
(
msgid
);
return
NULL
;
}
/*
* Get name of client host on socket 's'.
* Also returns local IP port and remote IP port on inet connections.
*/
EXPORTED
const
char
*
get_clienthost
(
int
s
,
const
char
**
localip
,
const
char
**
remoteip
)
{
#define IPBUF_SIZE (NI_MAXHOST+NI_MAXSERV+2)
socklen_t
salen
;
struct
sockaddr_storage
localaddr
,
remoteaddr
;
struct
sockaddr
*
localsock
=
(
struct
sockaddr
*
)
&
localaddr
;
struct
sockaddr
*
remotesock
=
(
struct
sockaddr
*
)
&
remoteaddr
;
static
struct
buf
clientbuf
=
BUF_INITIALIZER
;
static
char
lipbuf
[
IPBUF_SIZE
],
ripbuf
[
IPBUF_SIZE
];
char
hbuf
[
NI_MAXHOST
];
int
niflags
;
buf_reset
(
&
clientbuf
);
*
localip
=
*
remoteip
=
NULL
;
/* determine who we're talking to */
salen
=
sizeof
(
struct
sockaddr_storage
);
if
(
getpeername
(
s
,
remotesock
,
&
salen
)
==
0
&&
(
remotesock
->
sa_family
==
AF_INET
||
remotesock
->
sa_family
==
AF_INET6
))
{
/* connected to an internet socket */
if
(
getnameinfo
(
remotesock
,
salen
,
hbuf
,
sizeof
(
hbuf
),
NULL
,
0
,
NI_NAMEREQD
)
==
0
)
{
buf_printf
(
&
clientbuf
,
"%s "
,
hbuf
);
}
niflags
=
NI_NUMERICHOST
;
#ifdef NI_WITHSCOPEID
if
(
remotesock
->
sa_family
==
AF_INET6
)
niflags
|=
NI_WITHSCOPEID
;
#endif
if
(
getnameinfo
(
remotesock
,
salen
,
hbuf
,
sizeof
(
hbuf
),
NULL
,
0
,
niflags
)
!=
0
)
{
strlcpy
(
hbuf
,
"unknown"
,
sizeof
(
hbuf
));
}
buf_printf
(
&
clientbuf
,
"[%s]"
,
hbuf
);
salen
=
sizeof
(
struct
sockaddr_storage
);
if
(
getsockname
(
s
,
localsock
,
&
salen
)
==
0
)
{
/* set the ip addresses here */
if
(
iptostring
(
localsock
,
salen
,
lipbuf
,
sizeof
(
lipbuf
))
==
0
)
{
*
localip
=
lipbuf
;
}
if
(
iptostring
(
remotesock
,
salen
,
ripbuf
,
sizeof
(
ripbuf
))
==
0
)
{
*
remoteip
=
ripbuf
;
}
}
else
{
fatal
(
"can't get local addr"
,
EX_SOFTWARE
);
}
}
else
{
/* we're not connected to a internet socket! */
buf_setcstr
(
&
clientbuf
,
UNIX_SOCKET
);
}
return
buf_cstring
(
&
clientbuf
);
}
EXPORTED
int
cmd_cancelled
(
int
insearch
)
{
if
(
signals_cancelled
())
return
IMAP_CANCELLED
;
if
(
insearch
&&
cmdtime_checksearch
())
return
IMAP_SEARCH_SLOW
;
return
0
;
}
EXPORTED
void
saslprops_reset
(
struct
saslprops_t
*
saslprops
)
{
buf_reset
(
&
saslprops
->
iplocalport
);
buf_reset
(
&
saslprops
->
ipremoteport
);
buf_reset
(
&
saslprops
->
authid
);
saslprops
->
ssf
=
0
;
saslprops
->
cbinding
.
name
=
NULL
;
}
EXPORTED
void
saslprops_free
(
struct
saslprops_t
*
saslprops
)
{
buf_free
(
&
saslprops
->
iplocalport
);
buf_free
(
&
saslprops
->
ipremoteport
);
buf_free
(
&
saslprops
->
authid
);
}
EXPORTED
int
saslprops_set_tls
(
struct
saslprops_t
*
saslprops
,
sasl_conn_t
*
saslconn
)
{
int
r
;
r
=
sasl_setprop
(
saslconn
,
SASL_SSF_EXTERNAL
,
&
saslprops
->
ssf
);
if
(
r
!=
SASL_OK
)
{
syslog
(
LOG_NOTICE
,
"sasl_setprop(SSF_EXTERNAL) failed"
);
return
r
;
}
r
=
sasl_setprop
(
saslconn
,
SASL_AUTH_EXTERNAL
,
buf_cstringnull
(
&
saslprops
->
authid
));
if
(
r
!=
SASL_OK
)
{
syslog
(
LOG_NOTICE
,
"sasl_setprop(AUTH_EXTERNAL) failed"
);
return
r
;
}
if
(
saslprops
->
cbinding
.
name
)
{
r
=
sasl_setprop
(
saslconn
,
SASL_CHANNEL_BINDING
,
&
saslprops
->
cbinding
);
if
(
r
!=
SASL_OK
)
{
syslog
(
LOG_NOTICE
,
"sasl_setprop(CHANNEL_BINDING) failed"
);
return
r
;
}
}
return
SASL_OK
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sun, Apr 5, 11:08 PM (1 w, 6 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18831513
Default Alt Text
global.c (34 KB)
Attached To
Mode
R111 cyrus-imapd
Attached
Detach File
Event Timeline