1package CyrusSasl;
2
3import javax.security.auth.callback.*;
4import java.io.*;
5
6public class GenericClient extends GenericCommon implements SaslClient
7{
8
9    private byte[]initial_response;
10    private String mechanism;
11    private boolean hasinitresp;
12    private javax.security.auth.callback.CallbackHandler cbh;
13
14    GenericClient(int cptr, String mechlist,
15		  java.util.Hashtable props,
16		  javax.security.auth.callback.CallbackHandler cbh)
17    {
18	ptr=cptr;
19	this.cbh = cbh;
20
21	/* set properties */
22	super.setcommonproperties(props);
23
24	initial_response = jni_sasl_client_start(cptr, mechlist);
25    }
26
27    private native byte[] jni_sasl_client_start(int ptr,
28						String mechlist);
29
30    /**
31     * Perform a step. start() must have been preformed succesfully
32     * before this step() can be called. A client should call this
33     * method until it receives notification from the server that
34     * authentication is complete. Any protocol specific decoding (such
35     * as base64 decoding) must be done before calling step(). The
36     * return byte array should be encoded by the protocol specific
37     * method then sent to the server
38     *
39     * @param challenge byte[] from server (must be protocol specific decode before)
40     * @exception saslException sasl exception
41     * @return the byte[] you should send to the server */
42
43    public byte[] evaluateChallenge(byte[] challenge) throws SaslException
44    {
45	/* xxx this should check for empty challenge & existing initial
46	   sasl challenge */
47	byte[] out=null;
48
49	if (complete && challenge == null) {
50	    /* we're already done and there's no challenge */
51	    return null;
52	}
53
54	if (challenge==null) {
55	    out=jni_sasl_client_step(ptr, null, 0);
56	} else {
57	    out=jni_sasl_client_step(ptr, challenge, challenge.length);
58	}
59
60	return out;
61    }
62
63    private native byte[] jni_sasl_client_step(int ptr,
64					       byte[] in,
65					       int inlen);
66
67
68    public boolean hasInitialResponse()
69    {
70	return hasinitresp;
71    }
72
73    /**
74     * Use this method to obtain the name of the mechanism being
75     * negotiated with the server. After giving start() a list of
76     * mechanisms one will be chosen. Use this method to determine which
77     * one if being used if any.
78     *
79     * @return the mechanism currently negotiated or already negotiated */
80
81    public String getMechanismName()
82    {
83	return mechanism;
84    }
85
86    /* called from C layer */
87    private void callback_setmechanism(String mech, int initresp)
88    {
89	mechanism = mech;
90	hasinitresp = initresp != 0;
91    }
92
93    private String userid;
94    private String authid;
95    private String password;
96    private String realm;
97
98    private void do_callbacks(int wantuid, int wantaid, int wantpass, int wantrealm) throws SaslException
99    {
100	int numcb = wantuid+wantaid+wantpass+wantrealm;
101
102	Callback[] cbs = new Callback[numcb];
103	int pos = 0;
104
105	NameCallback nc = null;
106	NameCallback nc2 = null;
107	PasswordCallback pc = null;
108	RealmCallback rc = null;
109
110	if (wantuid==1) {
111	    nc = new NameCallback("Please enter your authorization id");
112	    cbs[pos] = nc;
113	    pos++;
114	}
115
116	if (wantaid==1) {
117	    nc2 = new NameCallback("Please enter your authentication id");
118	    cbs[pos] = nc2;
119	    pos++;
120	}
121
122	if (wantpass==1) {
123	    pc = new PasswordCallback("Please enter your password", false);
124	    cbs[pos] = pc;
125	    pos++;
126	}
127
128	if (wantrealm==1) {
129	    rc = new RealmCallback("Please enter your realm");
130	    cbs[pos] = rc;
131	    pos++;
132	}
133
134	try {
135	    cbh.handle(cbs);
136	} catch (UnsupportedCallbackException e) {
137	    throw new SaslException("Unsupported callback",null);
138	} catch (IOException e) {
139	    throw new SaslException("IO exception",null);
140	}
141
142	if (nc!=null) {
143	    this.userid = nc.getName();
144	}
145	if (nc2!=null) {
146	    this.authid = nc2.getName();
147	}
148	if (pc!=null) {
149	    this.password = new String(pc.getPassword());
150	}
151	if (rc!=null) {
152	    this.realm = rc.getRealm();
153	}
154    }
155
156    private String get_userid(int a)
157    {
158	return userid;
159    }
160    private String get_authid(int a)
161    {
162	return authid;
163    }
164    private String get_password(int a)
165    {
166	return password;
167    }
168    private String get_realm(int a)
169    {
170	return realm;
171    }
172
173    public InputStream getInputStream(InputStream source) throws IOException
174    {
175	if (getSecurity() > 0) {
176	    return new SaslInputStream(source,this);
177	} else {
178	    // no security layer, no indirection needed
179	    return source;
180	}
181    }
182
183    public OutputStream getOutputStream(OutputStream dest) throws IOException
184    {
185	if (getSecurity() > 0) {
186	    return new SaslOutputStream(dest,this);
187	} else {
188	    // no security layer, no indirection needed
189	    return dest;
190	}
191    }
192
193    public byte[] createInitialResponse(){
194	/* xxx this is deprecated */
195	return initial_response;
196    }
197}
198