Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F120836813
global.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
29 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.
*
* $Id: global.c,v 1.35 2010/04/22 17:29:53 murch Exp $
*/
#include
<config.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#include
<ctype.h>
#include
<syslog.h>
#include
<sys/statvfs.h>
#include
<sys/types.h>
#include
<netinet/in.h>
#include
<sys/stat.h>
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#include
<errno.h>
#include
"acl.h"
#include
"cyrusdb.h"
#include
"exitcodes.h"
#include
"gmtoff.h"
#include
"hash.h"
#include
"imap_err.h"
#include
"global.h"
#include
"libconfig.h"
#include
"libcyr_cfg.h"
#include
"mboxlist.h"
#include
"mkgmtime.h"
#include
"mupdate_err.h"
#include
"mutex.h"
#include
"prot.h"
/* for PROT_BUFSIZE */
#include
"userdeny.h"
#include
"util.h"
#include
"xmalloc.h"
#include
"xstrlcpy.h"
#include
"xstrlcat.h"
static
enum
{
NOT_RUNNING
=
0
,
RUNNING
=
1
,
DONE
=
2
}
cyrus_init_run
=
NOT_RUNNING
;
static
int
cyrus_init_nodb
=
0
;
int
in_shutdown
=
0
;
int
config_fulldirhash
;
/* 0 */
int
config_implicitrights
;
/* "lkxa" */
unsigned
long
config_metapartition_files
;
/* 0 */
struct
cyrusdb_backend
*
config_mboxlist_db
;
struct
cyrusdb_backend
*
config_quota_db
;
struct
cyrusdb_backend
*
config_subscription_db
;
struct
cyrusdb_backend
*
config_annotation_db
;
struct
cyrusdb_backend
*
config_seenstate_db
;
struct
cyrusdb_backend
*
config_mboxkey_db
;
struct
cyrusdb_backend
*
config_duplicate_db
;
struct
cyrusdb_backend
*
config_tlscache_db
;
struct
cyrusdb_backend
*
config_ptscache_db
;
struct
cyrusdb_backend
*
config_statuscache_db
;
struct
cyrusdb_backend
*
config_userdeny_db
;
#define MAX_SESSIONID_SIZE 256
char
session_id_buf
[
MAX_SESSIONID_SIZE
];
int
session_id_time
=
0
;
int
session_id_count
=
0
;
/* Called before a cyrus application starts (but after command line parameters
* are read) */
int
cyrus_init
(
const
char
*
alt_config
,
const
char
*
ident
,
unsigned
flags
)
{
char
*
p
;
const
char
*
val
;
const
char
*
prefix
;
int
umaskval
=
0
;
if
(
cyrus_init_run
!=
NOT_RUNNING
)
{
fatal
(
"cyrus_init called twice!"
,
EC_CONFIG
);
}
else
{
cyrus_init_run
=
RUNNING
;
}
cyrus_init_nodb
=
(
flags
&
CYRUSINIT_NODB
);
initialize_imap_error_table
();
initialize_mupd_error_table
();
if
(
!
ident
)
fatal
(
"service name was not specified to cyrus_init"
,
EC_CONFIG
);
config_ident
=
ident
;
/* xxx we lose here since we can't have the prefix until we load the
* config file */
openlog
(
config_ident
,
LOG_PID
,
SYSLOG_FACILITY
);
/* Load configuration file. This will set config_dir when it finds it */
config_read
(
alt_config
);
prefix
=
config_getstring
(
IMAPOPT_SYSLOG_PREFIX
);
/* Reopen the log with the new prefix, if needed */
if
(
prefix
)
{
int
size
=
strlen
(
prefix
)
+
1
+
strlen
(
ident
)
+
1
;
char
*
ident_buf
=
xmalloc
(
size
);
strlcpy
(
ident_buf
,
prefix
,
size
);
strlcat
(
ident_buf
,
"/"
,
size
);
strlcat
(
ident_buf
,
ident
,
size
);
closelog
();
openlog
(
ident_buf
,
LOG_PID
,
SYSLOG_FACILITY
);
/* don't free the openlog() string! */
}
/* 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"
,
EC_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 */
config_implicitrights
=
cyrus_acl_strtomask
(
config_getstring
(
IMAPOPT_IMPLICIT_OWNER_RIGHTS
));
config_metapartition_files
=
config_getbitfield
(
IMAPOPT_METAPARTITION_FILES
);
if
(
!
cyrus_init_nodb
)
{
/* lookup the database backends */
config_mboxlist_db
=
cyrusdb_fromname
(
config_getstring
(
IMAPOPT_MBOXLIST_DB
));
config_quota_db
=
cyrusdb_fromname
(
config_getstring
(
IMAPOPT_QUOTA_DB
));
config_subscription_db
=
cyrusdb_fromname
(
config_getstring
(
IMAPOPT_SUBSCRIPTION_DB
));
config_annotation_db
=
cyrusdb_fromname
(
config_getstring
(
IMAPOPT_ANNOTATION_DB
));
config_seenstate_db
=
cyrusdb_fromname
(
config_getstring
(
IMAPOPT_SEENSTATE_DB
));
config_mboxkey_db
=
cyrusdb_fromname
(
config_getstring
(
IMAPOPT_MBOXKEY_DB
));
config_duplicate_db
=
cyrusdb_fromname
(
config_getstring
(
IMAPOPT_DUPLICATE_DB
));
config_tlscache_db
=
cyrusdb_fromname
(
config_getstring
(
IMAPOPT_TLSCACHE_DB
));
config_ptscache_db
=
cyrusdb_fromname
(
config_getstring
(
IMAPOPT_PTSCACHE_DB
));
config_statuscache_db
=
cyrusdb_fromname
(
config_getstring
(
IMAPOPT_STATUSCACHE_DB
));
config_userdeny_db
=
cyrusdb_fromname
(
config_getstring
(
IMAPOPT_USERDENY_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_PTLOADER_SOCK
,
config_getstring
(
IMAPOPT_PTLOADER_SOCK
));
libcyrus_config_setswitch
(
CYRUSOPT_VIRTDOMAINS
,
config_getenum
(
IMAPOPT_VIRTDOMAINS
));
libcyrus_config_setint
(
CYRUSOPT_BERKELEY_CACHESIZE
,
config_getint
(
IMAPOPT_BERKELEY_CACHESIZE
));
libcyrus_config_setstring
(
CYRUSOPT_AUTH_MECH
,
config_getstring
(
IMAPOPT_AUTH_MECH
));
libcyrus_config_setint
(
CYRUSOPT_BERKELEY_LOCKS_MAX
,
config_getint
(
IMAPOPT_BERKELEY_LOCKS_MAX
));
libcyrus_config_setint
(
CYRUSOPT_BERKELEY_TXNS_MAX
,
config_getint
(
IMAPOPT_BERKELEY_TXNS_MAX
));
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
));
/* Not until all configuration parameters are set! */
libcyrus_init
();
}
return
0
;
}
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)"
,
EC_SOFTWARE
);
}
if
(
server
&&
sasl_server_init
(
callbacks
,
"Cyrus"
))
{
fatal
(
"could not init sasl (server)"
,
EC_SOFTWARE
);
}
}
/* this is a wrapper to call the cyrus configuration from SASL */
int
mysasl_config
(
void
*
context
__attribute__
((
unused
)),
const
char
*
plugin_name
,
const
char
*
option
,
const
char
**
result
,
unsigned
*
len
)
{
char
opt
[
1024
];
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 */
strlcpy
(
opt
,
"sasl_"
,
sizeof
(
opt
));
strlcat
(
opt
,
plugin_name
,
sizeof
(
opt
));
strlcat
(
opt
,
"_"
,
sizeof
(
opt
));
strlcat
(
opt
,
option
,
sizeof
(
opt
));
*
result
=
config_getoverflowstring
(
opt
,
NULL
);
}
if
(
*
result
==
NULL
)
{
/* try without the plugin name */
strlcpy
(
opt
,
"sasl_"
,
sizeof
(
opt
));
strlcat
(
opt
,
option
,
sizeof
(
opt
));
*
result
=
config_getoverflowstring
(
opt
,
NULL
);
}
}
if
(
*
result
!=
NULL
)
{
if
(
len
)
{
*
len
=
strlen
(
*
result
);
}
return
SASL_OK
;
}
return
SASL_FAIL
;
}
/* This creates a structure that defines the allowable
* security properties
*/
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' */
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). */
char
*
canonify_userid
(
char
*
user
,
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
);
}
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
)
{
char
*
canonuser
=
NULL
;
if
(
ulen
+
1
>
out_max
)
{
sasl_seterror
(
conn
,
0
,
"buffer overflow while canonicalizing"
);
return
SASL_BUFOVER
;
}
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
;
}
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
*
user
,
struct
auth_state
*
authstate
)
{
struct
namespace
namespace
;
struct
mboxlist_entry
mbentry
;
char
bufuser
[
MAX_MAILBOX_BUFFER
],
inboxname
[
MAX_MAILBOX_BUFFER
];
int
r
;
/* Set namespace */
if
((
r
=
mboxname_init_namespace
(
&
namespace
,
0
))
!=
0
)
{
syslog
(
LOG_ERR
,
"%s"
,
error_message
(
r
));
fatal
(
error_message
(
r
),
EC_CONFIG
);
}
strlcpy
(
bufuser
,
user
,
sizeof
(
bufuser
));
/* Translate any separators in userid */
mboxname_hiersep_tointernal
(
&
namespace
,
bufuser
,
config_virtdomains
?
strcspn
(
bufuser
,
"@"
)
:
0
);
if
(
!
r
)
r
=
(
*
namespace
.
mboxname_tointernal
)(
&
namespace
,
"INBOX"
,
bufuser
,
inboxname
);
if
(
r
||
!
authstate
||
mboxlist_lookup
(
inboxname
,
&
mbentry
,
NULL
))
{
r
=
0
;
/* Failed so assume no proxy access */
}
else
{
r
=
(
cyrus_acl_myrights
(
authstate
,
mbentry
.
acl
)
&
ACL_ADMIN
)
!=
0
;
}
return
r
;
}
/* should we allow users to proxy? return SASL_OK if yes,
SASL_BADAUTH otherwise */
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
;
}
static
const
char
*
const
monthname
[
12
]
=
{
"Jan"
,
"Feb"
,
"Mar"
,
"Apr"
,
"May"
,
"Jun"
,
"Jul"
,
"Aug"
,
"Sep"
,
"Oct"
,
"Nov"
,
"Dec"
};
/* Convert a time_t date to an IMAP-style date
* datebuf needs to be >= 30 bytes */
void
cyrus_ctime
(
time_t
date
,
char
*
datebuf
)
{
struct
tm
*
tm
=
localtime
(
&
date
);
long
gmtoff
=
gmtoff_of
(
tm
,
date
);
int
gmtnegative
=
0
;
assert
(
date
>
0
);
assert
(
tm
->
tm_year
>=
69
);
if
(
gmtoff
<
0
)
{
gmtoff
=
-
gmtoff
;
gmtnegative
=
1
;
}
gmtoff
/=
60
;
sprintf
(
datebuf
,
"%2u-%s-%u %.2u:%.2u:%.2u %c%.2lu%.2lu"
,
tm
->
tm_mday
,
monthname
[
tm
->
tm_mon
],
tm
->
tm_year
+
1900
,
tm
->
tm_hour
,
tm
->
tm_min
,
tm
->
tm_sec
,
gmtnegative
?
'-'
:
'+'
,
gmtoff
/
60
,
gmtoff
%
60
);
}
/*
* Parse a string in IMAP date-time format (and some more
* obscure legacy formats too) to a time_t. Parses both
* date and time parts.
*
* Specific formats accepted are listed below. Note that only
* the first two are compliant with RFC3501, the remainder
* are legacy formats. Note that the " quotes are not part
* of the format, they're just used in this comment to show
* where the leading spaces are.
*
* "dd-mmm-yyyy HH:MM:SS zzzzz"
* " d-mmm-yyyy HH:MM:SS zzzzz"
* "dd-mmm-yy HH:MM:SS-z"
* " d-mmm-yy HH:MM:SS-z"
* "dd-mmm-yy HH:MM:SS-zz"
* " d-mmm-yy HH:MM:SS-zz"
* "dd-mmm-yy HH:MM:SS-zzz"
* " d-mmm-yy HH:MM:SS-zzz"
*
* where:
* dd is the day-of-month between 1 and 31 inclusive.
* mmm is the three-letter abbreviation for the English
* month name (case insensitive).
* yy is the 2 digit year, between 00 (the year 1900)
* and 99 (the year 1999) inclusive.
* yyyy is the 4 digit year, between 1900 and disaster
* (31b time_t wrapping in 2038 is not handled, sorry).
* HH is the hour, zero padded, between 00 and 23 inclusive.
* MM is the minute, zero padded, between 00 and 59 inclusive.
* MM is the second, zero padded, between 00 and 60 inclusive
* (to account for leap seconds).
* z is a US military style single character time zone.
* A (Alpha) is +0100 ... I (India) is +0900
* J (Juliet) is not defined
* K (Kilo) is +1000 ... M (Mike) is +1200
* N (November) is -0100 ... Y (Yankee) is -1200
* Z (Zulu) is UTC
* zz is the case-insensitive string "UT", denoting UTC time.
* zzz is a three-character case insensitive North American
* time zone name, one of the following (listed with the
* UTC offsets and comments):
* AST -0400 Atlantic Standard Time
* ADT -0300 Atlantic Daylight Time
* EST -0500 Eastern Standard Time
* EDT -0400 Eastern Daylight Time
* CST -0600 Central Standard Time
* CDT -0500 Central Daylight Time
* MST -0700 Mountain Standard Time
* MDT -0600 Mountain Daylight Time
* PST -0800 Pacific Standard Time
* PDT -0700 Pacific Daylight Time
* YST -0900 Yukon Standard Time
* (Obsolete, now AKST = Alaska S.T.)
* YDT -0800 Yukon Daylight Time
* (Obsolete, now AKDT = Alaska D.T.)
* HST -1000 Hawaiian Standard Time
* (Obsolete, now HAST = Hawaiian/Aleutian S.T.)
* HDT -0900 Hawaiian Daylight Time
* (Obsolete, now HADT = Hawaiian/Aleutian D.T.)
* BST -1100 Used in American Samoa & Midway Island
* (Obsolete, now SST = Samoa S.T.)
* BDT -1000 Nonsensical, standard time is used
* all year around in the SST territories.
* zzzzz is an numeric time zone offset in the form +HHMM
* or -HMMM.
*
* Returns: 0 on success, or a negative errno on error.
*/
int
cyrus_parsetime
(
const
char
*
s
,
time_t
*
date
)
{
static
const
int
max_monthdays
[
12
]
=
{
31
,
29
,
31
,
30
,
31
,
30
,
31
,
31
,
30
,
31
,
30
,
31
};
int
c
;
struct
tm
tm
;
int
old_format
=
0
;
char
month
[
4
],
zone
[
4
],
*
p
;
time_t
tmp_gmtime
;
int
zone_off
;
/* timezone offset in minutes */
memset
(
&
tm
,
0
,
sizeof
tm
);
/* Day of month */
c
=
*
s
++
;
if
(
c
==
' '
)
c
=
'0'
;
else
if
(
!
isdigit
(
c
))
goto
baddate
;
tm
.
tm_mday
=
c
-
'0'
;
c
=
*
s
++
;
if
(
isdigit
(
c
))
{
tm
.
tm_mday
=
tm
.
tm_mday
*
10
+
c
-
'0'
;
c
=
*
s
++
;
if
(
tm
.
tm_mday
<=
0
||
tm
.
tm_mday
>
31
)
goto
baddate
;
}
if
(
c
!=
'-'
)
goto
baddate
;
c
=
*
s
++
;
/* Month name */
if
(
!
isalpha
(
c
))
goto
baddate
;
month
[
0
]
=
c
;
c
=
*
s
++
;
if
(
!
isalpha
(
c
))
goto
baddate
;
month
[
1
]
=
c
;
c
=
*
s
++
;
if
(
!
isalpha
(
c
))
goto
baddate
;
month
[
2
]
=
c
;
c
=
*
s
++
;
month
[
3
]
=
'\0'
;
for
(
tm
.
tm_mon
=
0
;
tm
.
tm_mon
<
12
;
tm
.
tm_mon
++
)
{
if
(
!
strcasecmp
(
month
,
monthname
[
tm
.
tm_mon
]))
break
;
}
if
(
tm
.
tm_mon
==
12
)
goto
baddate
;
/* This works fine in leap years but allows false
* negatives in the non-leap years. */
if
(
tm
.
tm_mday
>
max_monthdays
[
tm
.
tm_mon
])
goto
baddate
;
if
(
c
!=
'-'
)
goto
baddate
;
c
=
*
s
++
;
/* Year */
if
(
!
isdigit
(
c
))
goto
baddate
;
tm
.
tm_year
=
c
-
'0'
;
c
=
*
s
++
;
if
(
!
isdigit
(
c
))
goto
baddate
;
tm
.
tm_year
=
tm
.
tm_year
*
10
+
c
-
'0'
;
c
=
*
s
++
;
if
(
isdigit
(
c
))
{
if
(
tm
.
tm_year
<
19
)
goto
baddate
;
tm
.
tm_year
-=
19
;
tm
.
tm_year
=
tm
.
tm_year
*
10
+
c
-
'0'
;
c
=
*
s
++
;
if
(
!
isdigit
(
c
))
goto
baddate
;
tm
.
tm_year
=
tm
.
tm_year
*
10
+
c
-
'0'
;
c
=
*
s
++
;
}
else
old_format
++
;
/* Hour */
if
(
c
!=
' '
)
goto
baddate
;
c
=
*
s
++
;
if
(
!
isdigit
(
c
))
goto
baddate
;
tm
.
tm_hour
=
c
-
'0'
;
c
=
*
s
++
;
if
(
!
isdigit
(
c
))
goto
baddate
;
tm
.
tm_hour
=
tm
.
tm_hour
*
10
+
c
-
'0'
;
c
=
*
s
++
;
if
(
tm
.
tm_hour
>
23
)
goto
baddate
;
/* Minute */
if
(
c
!=
':'
)
goto
baddate
;
c
=
*
s
++
;
if
(
!
isdigit
(
c
))
goto
baddate
;
tm
.
tm_min
=
c
-
'0'
;
c
=
*
s
++
;
if
(
!
isdigit
(
c
))
goto
baddate
;
tm
.
tm_min
=
tm
.
tm_min
*
10
+
c
-
'0'
;
c
=
*
s
++
;
if
(
tm
.
tm_min
>
59
)
goto
baddate
;
/* Second */
if
(
c
!=
':'
)
goto
baddate
;
c
=
*
s
++
;
if
(
!
isdigit
(
c
))
goto
baddate
;
tm
.
tm_sec
=
c
-
'0'
;
c
=
*
s
++
;
if
(
!
isdigit
(
c
))
goto
baddate
;
tm
.
tm_sec
=
tm
.
tm_sec
*
10
+
c
-
'0'
;
c
=
*
s
++
;
if
(
tm
.
tm_min
>
60
)
goto
baddate
;
/* Time zone */
if
(
old_format
)
{
if
(
c
!=
'-'
)
goto
baddate
;
c
=
*
s
++
;
if
(
!
isalpha
(
c
))
goto
baddate
;
zone
[
0
]
=
c
;
c
=
*
s
++
;
if
(
c
==
'\0'
)
{
/* Military (single-char) zones */
zone
[
1
]
=
'\0'
;
lcase
(
zone
);
if
(
zone
[
0
]
<=
'i'
)
{
zone_off
=
(
zone
[
0
]
-
'a'
+
1
)
*
60
;
}
else
if
(
zone
[
0
]
==
'j'
)
{
goto
baddate
;
}
else
if
(
zone
[
0
]
<=
'm'
)
{
zone_off
=
(
zone
[
0
]
-
'k'
+
10
)
*
60
;
}
else
if
(
zone
[
0
]
<
'z'
)
{
zone_off
=
(
'm'
-
zone
[
0
])
*
60
;
}
else
/* 'z' */
zone_off
=
0
;
}
else
{
/* UT (universal time) */
zone
[
1
]
=
c
;
c
=
*
s
++
;
if
(
c
==
'\0'
)
{
zone
[
2
]
=
'\0'
;
lcase
(
zone
);
if
(
!
strcmp
(
zone
,
"ut"
))
goto
baddate
;
zone_off
=
0
;
}
else
{
/* 3-char time zone */
zone
[
2
]
=
c
;
c
=
*
s
++
;
if
(
c
!=
'\0'
)
goto
baddate
;
zone
[
3
]
=
'\0'
;
lcase
(
zone
);
p
=
strchr
(
"aecmpyhb"
,
zone
[
0
]);
if
(
c
!=
'\0'
||
zone
[
2
]
!=
't'
||
!
p
)
goto
baddate
;
zone_off
=
(
strlen
(
p
)
-
12
)
*
60
;
if
(
zone
[
1
]
==
'd'
)
zone_off
+=
60
;
else
if
(
zone
[
1
]
!=
's'
)
goto
baddate
;
}
}
}
else
{
if
(
c
!=
' '
)
goto
baddate
;
c
=
*
s
++
;
if
(
c
!=
'+'
&&
c
!=
'-'
)
goto
baddate
;
zone
[
0
]
=
c
;
c
=
*
s
++
;
if
(
!
isdigit
(
c
))
goto
baddate
;
zone_off
=
c
-
'0'
;
c
=
*
s
++
;
if
(
!
isdigit
(
c
))
goto
baddate
;
zone_off
=
zone_off
*
10
+
c
-
'0'
;
c
=
*
s
++
;
if
(
!
isdigit
(
c
))
goto
baddate
;
zone_off
=
zone_off
*
6
+
c
-
'0'
;
c
=
*
s
++
;
if
(
!
isdigit
(
c
))
goto
baddate
;
zone_off
=
zone_off
*
10
+
c
-
'0'
;
if
(
zone
[
0
]
==
'-'
)
zone_off
=
-
zone_off
;
c
=
*
s
++
;
if
(
c
!=
'\0'
)
goto
baddate
;
}
tm
.
tm_isdst
=
-1
;
tmp_gmtime
=
mkgmtime
(
&
tm
);
if
(
tmp_gmtime
==
-1
)
goto
baddate
;
*
date
=
tmp_gmtime
-
zone_off
*
60
;
return
0
;
baddate
:
return
-
EINVAL
;
}
/* call before a cyrus application exits */
void
cyrus_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.
*/
int
shutdown_file
(
char
*
buf
,
int
size
)
{
FILE
*
f
;
static
char
shutdownfilename
[
1024
]
=
""
;
char
*
p
;
if
(
!
shutdownfilename
[
0
])
snprintf
(
shutdownfilename
,
sizeof
(
shutdownfilename
),
"%s/msg/shutdown"
,
config_dir
);
f
=
fopen
(
shutdownfilename
,
"r"
);
if
(
!
f
)
return
0
;
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
;
}
struct
part_stats
{
char
name
[
MAX_PARTITION_LEN
+
1
];
/* name of part with most space */
unsigned
long
avail
;
/* 1k free blocks on freeest part */
unsigned
long
tavail
;
/* total 1k free blocks on server */
unsigned
long
fsid
[
512
];
/* array of file system IDs */
unsigned
nfsid
;
/* number of file system IDs */
};
/*
* config_foreachoverflowstring() callback which finds spool partition
* with the most available space and totals the space available on
* all partitions.
*/
static
void
get_part_stats
(
const
char
*
key
,
const
char
*
val
,
void
*
rock
)
{
struct
part_stats
*
stats
=
(
struct
part_stats
*
)
rock
;
struct
statvfs
s
;
unsigned
long
avail
;
unsigned
i
;
/* not a partition-* config option */
if
(
strncmp
(
"partition-"
,
key
,
10
))
return
;
/* can't stat the given path */
if
(
statvfs
(
val
,
&
s
))
return
;
/* eliminate duplicate filesystems */
for
(
i
=
0
;
i
<
stats
->
nfsid
;
i
++
)
{
if
(
s
.
f_fsid
==
stats
->
fsid
[
i
])
return
;
}
stats
->
fsid
[
stats
->
nfsid
++
]
=
s
.
f_fsid
;
/* calculate avail space in 1k blocks */
avail
=
(
unsigned
long
)
(
s
.
f_bavail
*
(
s
.
f_frsize
/
1024.0
));
/* add to total */
stats
->
tavail
+=
avail
;
if
(
avail
>
stats
->
avail
)
{
/* this part has the most avail space */
stats
->
avail
=
avail
;
strlcpy
(
stats
->
name
,
key
+
10
,
MAX_PARTITION_LEN
);
}
}
/*
* Returns the name of the spool partition with the most available space.
* Optionally returns the total amount of available space on the server
* (all partitions) in 1k blocks.
*/
char
*
find_free_partition
(
unsigned
long
*
tavail
)
{
static
struct
part_stats
stats
;
memset
(
&
stats
,
0
,
sizeof
(
struct
part_stats
));
config_foreachoverflowstring
(
get_part_stats
,
&
stats
);
if
(
tavail
)
*
tavail
=
stats
.
tavail
;
return
stats
.
name
;
}
/* Set up the Session ID Buffer */
void
session_new_id
()
{
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
;
snprintf
(
session_id_buf
,
MAX_SESSIONID_SIZE
,
"%.128s-%d-%d-%d"
,
base
,
getpid
(),
session_id_time
,
session_id_count
);
}
/* Return the session id */
const
char
*
session_id
()
{
if
(
!
session_id_count
)
session_new_id
();
return
(
const
char
*
)
session_id_buf
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Fri, Apr 24, 1:36 PM (8 h, 23 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18879498
Default Alt Text
global.c (29 KB)
Attached To
Mode
R111 cyrus-imapd
Attached
Detach File
Event Timeline