Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F120838099
mupdate-client.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
21 KB
Referenced Files
None
Subscribers
None
mupdate-client.c
View Options
/* mupdate-client.c -- cyrus murder database clients
*
* $Id: mupdate-client.c,v 1.32 2002/04/05 19:52:27 rjs3 Exp $
* Copyright (c) 2001 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 other legal
* details, please contact
* Office of Technology Transfer
* Carnegie Mellon University
* 5000 Forbes Avenue
* Pittsburgh, PA 15213-3890
* (412) 268-4387, fax: (412) 268-7395
* tech-transfer@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
<errno.h>
#include
<string.h>
#include
<signal.h>
#include
<ctype.h>
#include
<sasl/sasl.h>
#include
<sasl/saslutil.h>
#include
<syslog.h>
#ifdef __STDC__
#include
<stdarg.h>
#else
#include
<varargs.h>
#endif
#ifdef HAVE_UNISTD_H
#include
<unistd.h>
#endif
#include
<sys/types.h>
#include
<sys/time.h>
#include
<netinet/in.h>
#ifdef HAVE_SYS_SELECT_H
#include
<sys/select.h>
#endif
#include
"prot.h"
#include
"xmalloc.h"
#include
"imapconf.h"
#include
"assert.h"
#include
"imparse.h"
#include
"iptostring.h"
#include
"mupdate.h"
#include
"mupdate_err.h"
#include
"exitcodes.h"
const
char
service_name
[]
=
"mupdate"
;
extern
sasl_callback_t
*
mysasl_callbacks
(
const
char
*
username
,
const
char
*
authname
,
const
char
*
realm
,
const
char
*
password
);
extern
void
free_callbacks
(
sasl_callback_t
*
in
);
static
sasl_security_properties_t
*
make_secprops
(
int
min
,
int
max
)
{
sasl_security_properties_t
*
ret
=
(
sasl_security_properties_t
*
)
xzmalloc
(
sizeof
(
sasl_security_properties_t
));
ret
->
maxbufsize
=
PROT_BUFSIZE
;
ret
->
min_ssf
=
config_getint
(
"sasl_minimum_layer"
,
min
);
ret
->
max_ssf
=
config_getint
(
"sasl_maximum_layer"
,
max
);
return
ret
;
}
static
int
mupdate_authenticate
(
mupdate_handle
*
h
,
const
char
*
mechlist
)
{
int
saslresult
;
sasl_security_properties_t
*
secprops
=
NULL
;
socklen_t
addrsize
;
struct
sockaddr_in
saddr_l
;
struct
sockaddr_in
saddr_r
;
char
localip
[
60
],
remoteip
[
60
];
const
char
*
out
;
unsigned
int
outlen
;
const
char
*
mechusing
;
int
ch
;
char
buf
[
4096
];
/* Why do this again? */
if
(
h
->
saslcompleted
)
{
return
1
;
}
secprops
=
make_secprops
(
0
,
256
);
if
(
!
secprops
)
return
1
;
saslresult
=
sasl_setprop
(
h
->
saslconn
,
SASL_SEC_PROPS
,
secprops
);
if
(
saslresult
!=
SASL_OK
)
return
1
;
free
(
secprops
);
addrsize
=
sizeof
(
struct
sockaddr_in
);
if
(
getpeername
(
h
->
sock
,(
struct
sockaddr
*
)
&
saddr_r
,
&
addrsize
)
!=
0
)
return
1
;
addrsize
=
sizeof
(
struct
sockaddr_in
);
if
(
getsockname
(
h
->
sock
,(
struct
sockaddr
*
)
&
saddr_l
,
&
addrsize
)
!=
0
)
return
1
;
if
(
iptostring
((
const
struct
sockaddr
*
)
&
saddr_l
,
sizeof
(
struct
sockaddr_in
),
localip
,
60
)
!=
0
)
return
1
;
if
(
iptostring
((
const
struct
sockaddr
*
)
&
saddr_r
,
sizeof
(
struct
sockaddr_in
),
remoteip
,
60
)
!=
0
)
return
1
;
saslresult
=
sasl_setprop
(
h
->
saslconn
,
SASL_IPREMOTEPORT
,
remoteip
);
if
(
saslresult
!=
SASL_OK
)
return
1
;
saslresult
=
sasl_setprop
(
h
->
saslconn
,
SASL_IPLOCALPORT
,
localip
);
if
(
saslresult
!=
SASL_OK
)
return
1
;
/* We shouldn't get sasl_interact's,
* because we provide explicit callbacks */
saslresult
=
sasl_client_start
(
h
->
saslconn
,
mechlist
,
NULL
,
&
out
,
&
outlen
,
&
mechusing
);
if
(
saslresult
!=
SASL_OK
&&
saslresult
!=
SASL_CONTINUE
)
return
1
;
if
(
out
)
{
int
r
=
sasl_encode64
(
out
,
outlen
,
buf
,
sizeof
(
buf
),
NULL
);
if
(
r
!=
SASL_OK
)
return
1
;
/* it's always ok to send the mechname quoted */
prot_printf
(
h
->
pout
,
"A01 AUTHENTICATE
\"
%s
\"
{%d+}
\r\n
%s
\r\n
"
,
mechusing
,
strlen
(
buf
),
buf
);
}
else
{
prot_printf
(
h
->
pout
,
"A01 AUTHENTICATE
\"
%s
\"\r\n
"
,
mechusing
);
}
while
(
saslresult
==
SASL_CONTINUE
)
{
char
*
p
,
*
in
;
unsigned
int
len
,
inlen
;
if
(
!
prot_fgets
(
buf
,
sizeof
(
buf
)
-1
,
h
->
pin
))
{
/* Connection Dropped */
return
1
;
}
p
=
buf
+
strlen
(
buf
)
-
1
;
if
(
p
>=
buf
&&
*
p
==
'\n'
)
*
p
--
=
'\0'
;
if
(
p
>=
buf
&&
*
p
==
'\r'
)
*
p
--
=
'\0'
;
len
=
strlen
(
buf
);
in
=
xmalloc
(
len
);
saslresult
=
sasl_decode64
(
buf
,
len
,
in
,
len
,
&
inlen
);
if
(
saslresult
!=
SASL_OK
)
{
free
(
in
);
/* CANCEL */
syslog
(
LOG_ERR
,
"couldn't base64 decode: aborted authentication"
);
/* If we haven't already canceled due to bad authentication,
* then we should */
if
(
strncmp
(
buf
,
"A01 NO "
,
7
))
prot_printf
(
h
->
pout
,
"*"
);
else
{
syslog
(
LOG_ERR
,
"Authentication to master failed (%s)"
,
buf
+
7
);
}
return
1
;
}
saslresult
=
sasl_client_step
(
h
->
saslconn
,
in
,
inlen
,
NULL
,
&
out
,
&
outlen
);
free
(
in
);
if
((
saslresult
==
SASL_OK
||
saslresult
==
SASL_CONTINUE
)
&&
out
)
{
int
r
=
sasl_encode64
(
out
,
outlen
,
buf
,
sizeof
(
buf
),
NULL
);
if
(
r
!=
SASL_OK
)
return
1
;
prot_printf
(
h
->
pout
,
"%s
\r\n
"
,
buf
);
}
}
if
(
saslresult
!=
SASL_OK
)
{
syslog
(
LOG_ERR
,
"bad authentication: %s"
,
sasl_errdetail
(
h
->
saslconn
));
prot_printf
(
h
->
pout
,
"*"
);
return
1
;
}
/* Check Result */
ch
=
getword
(
h
->
pin
,
&
(
h
->
tag
));
if
(
ch
!=
' '
)
return
1
;
/* need an OK or NO */
ch
=
getword
(
h
->
pin
,
&
(
h
->
cmd
));
if
(
!
strncmp
(
h
->
cmd
.
s
,
"NO"
,
2
))
{
if
(
ch
!=
' '
)
return
1
;
/* no reason really necessary, but we failed */
ch
=
getstring
(
h
->
pin
,
h
->
pout
,
&
(
h
->
arg1
));
syslog
(
LOG_ERR
,
"authentication failed: %s"
,
h
->
arg1
.
s
);
return
1
;
}
prot_setsasl
(
h
->
pin
,
h
->
saslconn
);
prot_setsasl
(
h
->
pout
,
h
->
saslconn
);
h
->
saslcompleted
=
1
;
return
0
;
/* SUCCESS */
}
int
mupdate_connect
(
const
char
*
server
,
const
char
*
port
,
mupdate_handle
**
handle
,
sasl_callback_t
*
cbs
)
{
mupdate_handle
*
h
=
NULL
;
int
local_cbs
=
0
;
struct
hostent
*
hp
;
struct
servent
*
sp
;
struct
sockaddr_in
addr
;
int
s
,
saslresult
;
char
buf
[
4096
];
char
*
mechlist
=
NULL
;
if
(
!
handle
)
return
MUPDATE_BADPARAM
;
/* open connection to 'server' */
if
(
!
server
)
{
server
=
config_getstring
(
"mupdate_server"
,
NULL
);
if
(
server
==
NULL
)
{
fatal
(
"couldn't get mupdate server name"
,
EC_UNAVAILABLE
);
}
}
if
(
!
port
)
{
port
=
config_getstring
(
"mupdate_port"
,
NULL
);
}
hp
=
gethostbyname
(
server
);
if
(
!
hp
)
{
syslog
(
LOG_ERR
,
"mupdate-client: gethostbyname %s failed: %m"
,
server
);
return
MUPDATE_NOCONN
;
}
s
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
);
if
(
s
==
-1
)
{
syslog
(
LOG_ERR
,
"mupdate-client: socket(): %m"
);
return
MUPDATE_NOCONN
;
}
addr
.
sin_family
=
AF_INET
;
memcpy
(
&
addr
.
sin_addr
,
hp
->
h_addr
,
sizeof
(
addr
.
sin_addr
));
if
(
port
&&
imparse_isnumber
(
port
))
{
addr
.
sin_port
=
htons
(
atoi
(
port
));
}
else
if
(
port
)
{
sp
=
getservbyname
(
port
,
"tcp"
);
if
(
!
sp
)
{
syslog
(
LOG_ERR
,
"mupdate-client: getservbyname(tcp, %s): %m"
,
port
);
}
addr
.
sin_port
=
sp
->
s_port
;
}
else
if
((
sp
=
getservbyname
(
"mupdate"
,
"tcp"
))
!=
NULL
)
{
addr
.
sin_port
=
sp
->
s_port
;
}
else
{
addr
.
sin_port
=
htons
(
2004
);
}
if
(
connect
(
s
,
(
struct
sockaddr
*
)
&
addr
,
sizeof
(
addr
))
==
-1
)
{
syslog
(
LOG_ERR
,
"mupdate-client: connect(%s): %m"
,
server
);
return
MUPDATE_NOCONN
;
}
h
=
xzmalloc
(
sizeof
(
mupdate_handle
));
*
handle
=
h
;
h
->
sock
=
s
;
if
(
!
cbs
)
{
local_cbs
=
1
;
cbs
=
mysasl_callbacks
(
config_getstring
(
"mupdate_username"
,
""
),
config_getstring
(
"mupdate_authname"
,
NULL
),
config_getstring
(
"mupdate_realm"
,
NULL
),
config_getstring
(
"mupdate_password"
,
NULL
));
}
saslresult
=
sasl_client_new
(
service_name
,
server
,
NULL
,
NULL
,
cbs
,
0
,
&
(
h
->
saslconn
));
/* create protstream */
h
->
pin
=
prot_new
(
h
->
sock
,
0
);
h
->
pout
=
prot_new
(
h
->
sock
,
1
);
prot_setflushonread
(
h
->
pin
,
h
->
pout
);
prot_settimeout
(
h
->
pin
,
30
*
60
);
/* Read the mechlist & other capabilities */
while
(
1
)
{
if
(
!
prot_fgets
(
buf
,
sizeof
(
buf
)
-1
,
h
->
pin
))
{
goto
noconn
;
}
if
(
!
strncmp
(
buf
,
"* AUTH"
,
6
))
{
mechlist
=
xstrdup
(
buf
+
6
);
}
else
if
(
!
strncmp
(
buf
,
"* OK MUPDATE"
,
12
))
{
break
;
}
}
if
(
!
mechlist
)
{
syslog
(
LOG_ERR
,
"no AUTH banner from remote"
);
mupdate_disconnect
(
handle
);
free_callbacks
(
cbs
);
return
MUPDATE_NOAUTH
;
}
if
(
mupdate_authenticate
(
h
,
mechlist
))
{
syslog
(
LOG_ERR
,
"authentication to remote mupdate server failed"
);
free
(
mechlist
);
mupdate_disconnect
(
handle
);
free_callbacks
(
cbs
);
return
MUPDATE_NOAUTH
;
}
free
(
mechlist
);
/* xxx unclear that this is correct, but it prevents a memory leak */
if
(
local_cbs
)
free_callbacks
(
cbs
);
/* SUCCESS */
return
0
;
noconn
:
if
(
mechlist
)
free
(
mechlist
);
syslog
(
LOG_ERR
,
"mupdate-client: connection to server closed: %s"
,
prot_error
(
h
->
pin
));
mupdate_disconnect
(
handle
);
return
MUPDATE_NOCONN
;
}
void
mupdate_disconnect
(
mupdate_handle
**
hp
)
{
mupdate_handle
*
h
;
if
(
!
hp
||
!
(
*
hp
))
return
;
h
=
*
hp
;
if
(
h
->
pout
)
{
prot_printf
(
h
->
pout
,
"L01 LOGOUT
\r\n
"
);
prot_flush
(
h
->
pout
);
}
freebuf
(
&
(
h
->
tag
));
freebuf
(
&
(
h
->
cmd
));
freebuf
(
&
(
h
->
arg1
));
freebuf
(
&
(
h
->
arg2
));
freebuf
(
&
(
h
->
arg3
));
if
(
h
->
pin
)
prot_free
(
h
->
pin
);
if
(
h
->
pout
)
prot_free
(
h
->
pout
);
sasl_dispose
(
&
(
h
->
saslconn
));
close
(
h
->
sock
);
if
(
h
->
acl_buf
)
free
(
h
->
acl_buf
);
free
(
h
);
*
hp
=
NULL
;
}
/* We're really only looking for an OK or NO or BAD here */
static
int
mupdate_scarf_one
(
struct
mupdate_mailboxdata
*
mdata
__attribute__
((
unused
)),
const
char
*
cmd
,
void
*
context
)
{
int
*
called
=
context
;
if
(
*
called
)
{
/* Only want to be called once per command */
return
-1
;
}
*
called
=
1
;
/*only accept OK, NO and BAD */
if
(
strncmp
(
cmd
,
"OK"
,
2
))
{
return
0
;
}
else
if
(
strncmp
(
cmd
,
"NO"
,
2
)
||
strncmp
(
cmd
,
"BAD"
,
3
))
{
return
-1
;
}
else
{
return
1
;
}
}
int
mupdate_activate
(
mupdate_handle
*
handle
,
const
char
*
mailbox
,
const
char
*
server
,
const
char
*
acl
)
{
int
ret
;
int
called
=
0
;
enum
mupdate_cmd_response
response
;
if
(
!
handle
)
return
MUPDATE_BADPARAM
;
if
(
!
mailbox
||
!
server
||
!
acl
)
return
MUPDATE_BADPARAM
;
if
(
!
handle
->
saslcompleted
)
return
MUPDATE_NOAUTH
;
prot_printf
(
handle
->
pout
,
"X%u ACTIVATE {%d+}
\r\n
%s {%d+}
\r\n
%s {%d+}
\r\n
%s
\r\n
"
,
handle
->
tagn
++
,
strlen
(
mailbox
),
mailbox
,
strlen
(
server
),
server
,
strlen
(
acl
),
acl
);
ret
=
mupdate_scarf
(
handle
,
mupdate_scarf_one
,
&
called
,
1
,
&
response
);
if
(
ret
)
{
return
ret
;
}
else
if
(
response
!=
MUPDATE_OK
)
{
return
MUPDATE_FAIL
;
}
else
{
return
0
;
}
}
int
mupdate_reserve
(
mupdate_handle
*
handle
,
const
char
*
mailbox
,
const
char
*
server
)
{
int
ret
;
int
called
=
0
;
enum
mupdate_cmd_response
response
;
if
(
!
handle
)
return
MUPDATE_BADPARAM
;
if
(
!
mailbox
||
!
server
)
return
MUPDATE_BADPARAM
;
if
(
!
handle
->
saslcompleted
)
return
MUPDATE_NOAUTH
;
prot_printf
(
handle
->
pout
,
"X%u RESERVE {%d+}
\r\n
%s {%d+}
\r\n
%s
\r\n
"
,
handle
->
tagn
++
,
strlen
(
mailbox
),
mailbox
,
strlen
(
server
),
server
);
ret
=
mupdate_scarf
(
handle
,
mupdate_scarf_one
,
&
called
,
1
,
&
response
);
if
(
ret
)
{
return
ret
;
}
else
if
(
response
!=
MUPDATE_OK
)
{
return
MUPDATE_FAIL_RESERVE
;
}
else
{
return
0
;
}
}
int
mupdate_deactivate
(
mupdate_handle
*
handle
,
const
char
*
mailbox
,
const
char
*
server
)
{
int
ret
;
int
called
=
0
;
enum
mupdate_cmd_response
response
;
if
(
!
handle
)
return
MUPDATE_BADPARAM
;
if
(
!
mailbox
||
!
server
)
return
MUPDATE_BADPARAM
;
if
(
!
handle
->
saslcompleted
)
return
MUPDATE_NOAUTH
;
prot_printf
(
handle
->
pout
,
"X%u DEACTIVATE {%d+}
\r\n
%s {%d+}
\r\n
%s
\r\n
"
,
handle
->
tagn
++
,
strlen
(
mailbox
),
mailbox
,
strlen
(
server
),
server
);
ret
=
mupdate_scarf
(
handle
,
mupdate_scarf_one
,
&
called
,
1
,
&
response
);
if
(
ret
)
{
return
ret
;
}
else
if
(
response
!=
MUPDATE_OK
)
{
return
MUPDATE_FAIL_RESERVE
;
}
else
{
return
0
;
}
}
int
mupdate_delete
(
mupdate_handle
*
handle
,
const
char
*
mailbox
)
{
int
ret
;
int
called
=
0
;
enum
mupdate_cmd_response
response
;
if
(
!
handle
)
return
MUPDATE_BADPARAM
;
if
(
!
mailbox
)
return
MUPDATE_BADPARAM
;
if
(
!
handle
->
saslcompleted
)
return
MUPDATE_NOAUTH
;
prot_printf
(
handle
->
pout
,
"X%u DELETE {%d+}
\r\n
%s
\r\n
"
,
handle
->
tagn
++
,
strlen
(
mailbox
),
mailbox
);
ret
=
mupdate_scarf
(
handle
,
mupdate_scarf_one
,
&
called
,
1
,
&
response
);
if
(
ret
)
{
return
ret
;
}
else
if
(
response
!=
MUPDATE_OK
)
{
return
MUPDATE_FAIL
;
}
else
{
return
0
;
}
}
static
int
mupdate_find_cb
(
struct
mupdate_mailboxdata
*
mdata
,
const
char
*
cmd
,
void
*
context
)
{
struct
mupdate_handle_s
*
h
=
(
struct
mupdate_handle_s
*
)
context
;
if
(
!
h
||
!
cmd
||
!
mdata
)
return
1
;
/* coyp the data to the handle storage */
/* xxx why can't we just point to the 'mdata' buffers? */
strlcpy
(
h
->
mailbox_buf
,
mdata
->
mailbox
,
MAX_MAILBOX_NAME
);
strlcpy
(
h
->
server_buf
,
mdata
->
server
,
MAX_MAILBOX_NAME
);
if
(
!
strncmp
(
cmd
,
"MAILBOX"
,
7
))
{
int
len
=
strlen
(
mdata
->
acl
)
+
1
;
h
->
mailboxdata_buf
.
t
=
ACTIVE
;
if
(
len
>
h
->
acl_buf_len
)
{
/* we want to at least double the buffer */
if
(
len
<
2
*
h
->
acl_buf_len
)
{
len
=
2
*
h
->
acl_buf_len
;
}
h
->
acl_buf
=
xrealloc
(
h
->
acl_buf
,
len
);
strcpy
(
h
->
acl_buf
,
mdata
->
acl
);
}
}
else
if
(
!
strncmp
(
cmd
,
"RESERVE"
,
7
))
{
h
->
mailboxdata_buf
.
t
=
RESERVE
;
if
(
!
h
->
acl_buf
)
{
h
->
acl_buf
=
xstrdup
(
""
);
h
->
acl_buf_len
=
1
;
}
else
{
h
->
acl_buf
[
0
]
=
'\0'
;
}
}
else
{
/* Bad command */
return
1
;
}
h
->
mailboxdata_buf
.
mailbox
=
h
->
mailbox_buf
;
h
->
mailboxdata_buf
.
server
=
h
->
server_buf
;
h
->
mailboxdata_buf
.
acl
=
h
->
acl_buf
;
return
0
;
}
int
mupdate_find
(
mupdate_handle
*
handle
,
const
char
*
mailbox
,
struct
mupdate_mailboxdata
**
target
)
{
int
ret
;
enum
mupdate_cmd_response
response
;
if
(
!
handle
||
!
mailbox
||
!
target
)
return
MUPDATE_BADPARAM
;
prot_printf
(
handle
->
pout
,
"X%u FIND {%d+}
\r\n
%s
\r\n
"
,
handle
->
tagn
++
,
strlen
(
mailbox
),
mailbox
);
memset
(
&
(
handle
->
mailboxdata_buf
),
0
,
sizeof
(
handle
->
mailboxdata_buf
));
ret
=
mupdate_scarf
(
handle
,
mupdate_find_cb
,
handle
,
1
,
&
response
);
/* note that the response is still OK even if there was no data returned,
* so we have to make sure we actually filled in the data too */
if
(
!
ret
&&
response
==
MUPDATE_OK
&&
handle
->
mailboxdata_buf
.
mailbox
)
{
*
target
=
&
(
handle
->
mailboxdata_buf
);
return
0
;
}
else
if
(
!
ret
&&
response
==
MUPDATE_OK
)
{
/* it looked okay, but we didn't get a mailbox */
*
target
=
NULL
;
return
MUPDATE_MAILBOX_UNKNOWN
;
}
else
{
/* Something Bad happened */
*
target
=
NULL
;
return
ret
?
ret
:
MUPDATE_FAIL
;
}
}
int
mupdate_list
(
mupdate_handle
*
handle
,
mupdate_callback
callback
,
const
char
*
prefix
,
void
*
context
)
{
int
ret
;
enum
mupdate_cmd_response
response
;
if
(
!
handle
||
!
callback
)
return
MUPDATE_BADPARAM
;
if
(
prefix
)
{
prot_printf
(
handle
->
pout
,
"X%u LIST {%d+}
\r\n
%s
\r\n
"
,
handle
->
tagn
++
,
strlen
(
prefix
),
prefix
);
}
else
{
prot_printf
(
handle
->
pout
,
"X%u LIST
\r\n
"
,
handle
->
tagn
++
);
}
ret
=
mupdate_scarf
(
handle
,
callback
,
context
,
1
,
&
response
);
if
(
ret
)
{
return
ret
;
}
else
if
(
response
!=
MUPDATE_OK
)
{
return
MUPDATE_FAIL
;
}
else
{
return
0
;
}
}
int
mupdate_noop
(
mupdate_handle
*
handle
,
mupdate_callback
callback
,
void
*
context
)
{
int
ret
;
enum
mupdate_cmd_response
response
;
if
(
!
handle
||
!
callback
)
return
MUPDATE_BADPARAM
;
prot_printf
(
handle
->
pout
,
"X%u NOOP
\r\n
"
,
handle
->
tagn
++
);
ret
=
mupdate_scarf
(
handle
,
callback
,
context
,
1
,
&
response
);
if
(
!
ret
&&
response
==
MUPDATE_OK
)
{
return
0
;
}
else
{
return
ret
?
ret
:
MUPDATE_FAIL
;
}
}
#define CHECKNEWLINE(c, ch) do { if ((ch) == '\r') (ch)=prot_getc((c)->pin); \
if ((ch) != '\n') { syslog(LOG_ERR, \
"extra arguments recieved, aborting connection");\
r = MUPDATE_PROTOCOL_ERROR;\
goto done; }} while(0)
/* Scarf up the incoming data and perform the requested operations */
int
mupdate_scarf
(
mupdate_handle
*
handle
,
mupdate_callback
callback
,
void
*
context
,
int
wait_for_ok
,
enum
mupdate_cmd_response
*
response
)
{
struct
mupdate_mailboxdata
box
;
int
r
=
0
;
if
(
!
handle
||
!
callback
)
return
MUPDATE_BADPARAM
;
/* keep going while we have input or if we're waiting for an OK */
while
(
!
r
)
{
int
ch
;
unsigned
char
*
p
;
if
(
wait_for_ok
)
{
prot_BLOCK
(
handle
->
pin
);
}
else
{
prot_NONBLOCK
(
handle
->
pin
);
}
ch
=
getword
(
handle
->
pin
,
&
(
handle
->
tag
));
if
(
ch
==
EOF
&&
errno
==
EAGAIN
)
{
/* this was just "no input" we return 0 */
goto
done
;
}
else
if
(
ch
==
EOF
)
{
/* this was a fatal error */
r
=
MUPDATE_NOCONN
;
goto
done
;
}
/* set it blocking so we don't get half a line */
prot_BLOCK
(
handle
->
pin
);
if
(
ch
!=
' '
)
{
/* We always have a command */
syslog
(
LOG_ERR
,
"Protocol error from master: no tag"
);
r
=
MUPDATE_PROTOCOL_ERROR
;
goto
done
;
}
ch
=
getword
(
handle
->
pin
,
&
(
handle
->
cmd
));
if
(
ch
!=
' '
)
{
/* We always have an argument */
syslog
(
LOG_ERR
,
"Protocol error from master: no keyword"
);
r
=
MUPDATE_PROTOCOL_ERROR
;
break
;
}
if
(
islower
((
unsigned
char
)
handle
->
cmd
.
s
[
0
]))
{
handle
->
cmd
.
s
[
0
]
=
toupper
((
unsigned
char
)
handle
->
cmd
.
s
[
0
]);
}
for
(
p
=
&
(
handle
->
cmd
.
s
[
1
]);
*
p
;
p
++
)
{
if
(
islower
((
unsigned
char
)
*
p
))
*
p
=
toupper
((
unsigned
char
)
*
p
);
}
switch
(
handle
->
cmd
.
s
[
0
])
{
case
'B'
:
if
(
!
strncmp
(
handle
->
cmd
.
s
,
"BAD"
,
6
))
{
ch
=
getstring
(
handle
->
pin
,
handle
->
pout
,
&
(
handle
->
arg1
));
CHECKNEWLINE
(
handle
,
ch
);
syslog
(
LOG_DEBUG
,
"mupdate BAD response: %s"
,
handle
->
arg1
.
s
);
if
(
wait_for_ok
&&
response
)
{
*
response
=
MUPDATE_BAD
;
}
goto
done
;
}
goto
badcmd
;
case
'D'
:
if
(
!
strncmp
(
handle
->
cmd
.
s
,
"DELETE"
,
6
))
{
ch
=
getstring
(
handle
->
pin
,
handle
->
pout
,
&
(
handle
->
arg1
));
CHECKNEWLINE
(
handle
,
ch
);
memset
(
&
box
,
0
,
sizeof
(
box
));
box
.
mailbox
=
handle
->
arg1
.
s
;
/* Handle delete command */
r
=
callback
(
&
box
,
handle
->
cmd
.
s
,
context
);
if
(
r
)
{
syslog
(
LOG_ERR
,
"error deleting mailbox: callback returned %d"
,
r
);
goto
done
;
}
break
;
}
goto
badcmd
;
case
'M'
:
if
(
!
strncmp
(
handle
->
cmd
.
s
,
"MAILBOX"
,
7
))
{
/* Mailbox Name */
ch
=
getstring
(
handle
->
pin
,
handle
->
pout
,
&
(
handle
->
arg1
));
if
(
ch
!=
' '
)
{
r
=
MUPDATE_PROTOCOL_ERROR
;
goto
done
;
}
/* Server */
ch
=
getstring
(
handle
->
pin
,
handle
->
pout
,
&
(
handle
->
arg2
));
if
(
ch
!=
' '
)
{
r
=
MUPDATE_PROTOCOL_ERROR
;
goto
done
;
}
/* ACL */
ch
=
getstring
(
handle
->
pin
,
handle
->
pout
,
&
(
handle
->
arg3
));
CHECKNEWLINE
(
handle
,
ch
);
/* Handle mailbox command */
memset
(
&
box
,
0
,
sizeof
(
box
));
box
.
mailbox
=
handle
->
arg1
.
s
;
box
.
server
=
handle
->
arg2
.
s
;
box
.
acl
=
handle
->
arg3
.
s
;
r
=
callback
(
&
box
,
handle
->
cmd
.
s
,
context
);
if
(
r
)
{
/* callback error ? */
syslog
(
LOG_ERR
,
"error activating mailbox: callback returned %d"
,
r
);
goto
done
;
}
break
;
}
goto
badcmd
;
case
'N'
:
if
(
!
strncmp
(
handle
->
cmd
.
s
,
"NO"
,
6
))
{
ch
=
getstring
(
handle
->
pin
,
handle
->
pout
,
&
(
handle
->
arg1
));
CHECKNEWLINE
(
handle
,
ch
);
syslog
(
LOG_DEBUG
,
"mupdate NO response: %s"
,
handle
->
arg1
.
s
);
if
(
wait_for_ok
)
{
if
(
response
)
*
response
=
MUPDATE_NO
;
goto
done
;
}
break
;
}
goto
badcmd
;
case
'O'
:
if
(
!
strncmp
(
handle
->
cmd
.
s
,
"OK"
,
2
))
{
/* It's all good, grab the attached string and move on */
ch
=
getstring
(
handle
->
pin
,
handle
->
pout
,
&
(
handle
->
arg1
));
CHECKNEWLINE
(
handle
,
ch
);
if
(
wait_for_ok
)
{
if
(
response
)
*
response
=
MUPDATE_OK
;
goto
done
;
}
break
;
}
goto
badcmd
;
case
'R'
:
if
(
!
strncmp
(
handle
->
cmd
.
s
,
"RESERVE"
,
7
))
{
/* Mailbox Name */
ch
=
getstring
(
handle
->
pin
,
handle
->
pout
,
&
(
handle
->
arg1
));
if
(
ch
!=
' '
)
{
r
=
MUPDATE_PROTOCOL_ERROR
;
goto
done
;
}
/* Server */
ch
=
getstring
(
handle
->
pin
,
handle
->
pout
,
&
(
handle
->
arg2
));
CHECKNEWLINE
(
handle
,
ch
);
/* Handle reserve command */
memset
(
&
box
,
0
,
sizeof
(
box
));
box
.
mailbox
=
handle
->
arg1
.
s
;
box
.
server
=
handle
->
arg2
.
s
;
r
=
callback
(
&
box
,
handle
->
cmd
.
s
,
context
);
if
(
r
)
{
/* callback error ? */
syslog
(
LOG_ERR
,
"error reserving mailbox: callback returned %d"
,
r
);
goto
done
;
}
break
;
}
goto
badcmd
;
default
:
badcmd
:
/* Bad Command */
syslog
(
LOG_ERR
,
"bad/unexpected command from master: %s"
,
handle
->
cmd
.
s
);
r
=
MUPDATE_PROTOCOL_ERROR
;
goto
done
;
}
}
done
:
/* reset blocking */
prot_NONBLOCK
(
handle
->
pin
);
return
r
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Fri, Apr 24, 1:54 PM (5 d, 3 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18863045
Default Alt Text
mupdate-client.c (21 KB)
Attached To
Mode
R111 cyrus-imapd
Attached
Detach File
Event Timeline