dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.bin / ftp / auth.c
blobd17d46673b4a57de817c5866d798bbbf2a336201
1 /*
2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 /*
7 * Copyright (c) 1985, 1989 Regents of the University of California.
8 * All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
39 #include "ftp_var.h"
40 #include <sys/types.h>
41 #include <gssapi/gssapi.h>
42 #include <gssapi/gssapi_ext.h>
44 int auth_type; /* Authentication succeeded? If so, what type? */
46 char *radix_error(int);
47 static void get_inet_addr_info(struct sockaddr_in6 *, gss_buffer_t);
49 static char *radixN =
50 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
51 static char radix_pad = '=';
54 * authenticate the user, if auth_type is AUTHTYPE_NONE
56 * Returns: 0 if there is no auth type
57 * 1 if success
58 * 2 if failure
61 gss_OID mechoid;
62 gss_ctx_id_t gcontext; /* global gss security context */
63 static const char *gss_trials[] = { "ftp", "host" };
64 /* the number of elements in gss_trials array */
65 static const int n_gss_trials = sizeof (gss_trials)/sizeof (char *);
66 char *reply_parse;
68 int
69 do_auth(void)
71 int oldverbose = verbose;
72 uchar_t *out_buf = NULL;
73 size_t outlen;
74 int i;
76 if (auth_type != AUTHTYPE_NONE)
77 return (1); /* auth already succeeded */
79 /* Other auth types go here ... */
81 if (command("AUTH %s", "GSSAPI") == CONTINUE) {
82 OM_uint32 maj_stat, min_stat;
83 gss_name_t target_name;
84 gss_buffer_desc send_tok, recv_tok, *token_ptr;
85 gss_buffer_desc temp_buf;
86 char stbuf[FTPBUFSIZ];
87 int comcode, trial;
88 int req_flags;
89 struct gss_channel_bindings_struct chan;
91 get_inet_addr_info(&myctladdr, &temp_buf);
92 chan.initiator_addrtype = GSS_C_AF_INET; /* OM_uint32 */
93 chan.initiator_address.length = temp_buf.length;
94 chan.initiator_address.value = malloc(temp_buf.length);
95 memcpy(chan.initiator_address.value, temp_buf.value,
96 temp_buf.length);
98 get_inet_addr_info(&remctladdr, &temp_buf);
99 chan.acceptor_addrtype = GSS_C_AF_INET; /* OM_uint32 */
100 chan.acceptor_address.length = temp_buf.length;
101 chan.acceptor_address.value = malloc(temp_buf.length);
102 memcpy(chan.acceptor_address.value, temp_buf.value,
103 temp_buf.length);
105 chan.application_data.length = 0;
106 chan.application_data.value = 0;
108 if (verbose)
109 (void) printf("GSSAPI accepted as authentication type\n");
111 /* set the forward flag */
112 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
114 if (fflag)
115 req_flags |= GSS_C_DELEG_FLAG;
117 /* blob from gss-client */
118 for (trial = 0; trial < n_gss_trials; trial++) {
119 /* ftp@hostname first, then host@hostname */
120 /* the V5 GSSAPI binding canonicalizes this for us... */
121 (void) snprintf(stbuf, FTPBUFSIZ, "%s@%s",
122 gss_trials[trial], hostname);
123 if (debug)
124 (void) fprintf(stderr,
125 "Trying to authenticate to <%s>\n", stbuf);
127 send_tok.value = stbuf;
128 send_tok.length = strlen(stbuf) + 1;
129 maj_stat = gss_import_name(&min_stat, &send_tok,
130 GSS_C_NT_HOSTBASED_SERVICE, &target_name);
132 if (maj_stat != GSS_S_COMPLETE) {
133 user_gss_error(maj_stat, min_stat, "parsing name");
134 (void) fprintf(stderr, "name parsed <%s>\n", stbuf);
135 continue;
138 token_ptr = GSS_C_NO_BUFFER;
139 gcontext = GSS_C_NO_CONTEXT; /* structure copy */
141 do {
142 if (debug)
143 (void) fprintf(stderr,
144 "calling gss_init_sec_context\n");
146 if (mechstr && !mechoid &&
147 __gss_mech_to_oid(mechstr, (gss_OID*)&mechoid) !=
148 GSS_S_COMPLETE)
149 (void) printf("do_auth: %s: not a valid "
150 "security mechanism\n", mechstr);
152 if (!mechoid)
153 mechoid = GSS_C_NULL_OID;
155 maj_stat = gss_init_sec_context(&min_stat,
156 GSS_C_NO_CREDENTIAL,
157 &gcontext,
158 target_name,
159 mechoid,
160 req_flags,
162 &chan, /* channel bindings */
163 token_ptr,
164 NULL, /* ignore mech type */
165 &send_tok,
166 NULL, /* ignore ret_flags */
167 NULL); /* ignore time_rec */
169 if (maj_stat != GSS_S_COMPLETE &&
170 maj_stat != GSS_S_CONTINUE_NEEDED) {
172 /* return an error if this is NOT the ftp ticket */
173 if (strcmp(gss_trials[trial], "ftp"))
174 user_gss_error(maj_stat, min_stat,
175 "initializing context");
177 (void) gss_release_name(&min_stat, &target_name);
178 /* could just be that we missed on the service name */
179 goto outer_loop;
183 if (send_tok.length != 0) {
184 int len = send_tok.length;
185 reply_parse = "ADAT="; /* for command() later */
186 oldverbose = verbose;
187 verbose = (trial == n_gss_trials-1)?0:-1;
189 outlen = ENCODELEN(send_tok.length);
190 out_buf = (uchar_t *)malloc(outlen);
191 if (out_buf == NULL) {
192 (void) fprintf(stderr, "memory error allocating "
193 "auth buffer\n");
194 maj_stat = GSS_S_FAILURE;
195 goto outer_loop;
197 auth_error = radix_encode(send_tok.value, out_buf,
198 outlen, &len, 0);
200 if (auth_error) {
201 (void) fprintf(stderr, "Base 64 encoding failed: %s\n",
202 radix_error(auth_error));
203 } else if ((comcode = command("ADAT %s", out_buf))
204 != COMPLETE /* && comcode != 3 (335)*/) {
206 if (trial == n_gss_trials-1) {
207 (void) fprintf(stderr, "GSSAPI ADAT failed (%d)\n",
208 comcode);
210 /* force out of loop */
211 maj_stat = GSS_S_FAILURE;
215 * backoff to the v1 gssapi is still possible.
216 * Send a new AUTH command. If that fails,
217 * terminate the loop
219 if (command("AUTH %s", "GSSAPI") != CONTINUE) {
220 (void) fprintf(stderr,
221 "GSSAPI ADAT failed, AUTH restart failed\n");
222 /* force out of loop */
223 maj_stat = GSS_S_FAILURE;
226 goto outer_loop;
227 } else if (!reply_parse) {
228 (void) fprintf(stderr,
229 "No authentication data received from server\n");
230 if (maj_stat == GSS_S_COMPLETE) {
231 (void) fprintf(stderr,
232 "...but no more was needed\n");
233 goto gss_complete_loop;
234 } else {
235 user_gss_error(maj_stat, min_stat, "no reply.");
236 goto gss_complete_loop;
238 } else if (auth_error = radix_encode((uchar_t *)
239 reply_parse, out_buf, outlen, &i, 1)) {
240 (void) fprintf(stderr,
241 "Base 64 decoding failed: %s\n",
242 radix_error(auth_error));
243 } else {
244 /* everything worked */
245 token_ptr = &recv_tok;
246 recv_tok.value = out_buf;
247 recv_tok.length = i;
248 continue;
249 } /* end if (auth_error) */
251 /* get out of loop clean */
252 gss_complete_loop:
253 trial = n_gss_trials-1;
254 gss_release_buffer(&min_stat, &send_tok);
255 gss_release_name(&min_stat, &target_name);
256 goto outer_loop;
257 } /* end if (send_tok.length != 0) */
259 } while (maj_stat == GSS_S_CONTINUE_NEEDED);
261 outer_loop:
262 if (maj_stat == GSS_S_COMPLETE)
263 break;
265 } /* end for loop */
267 verbose = oldverbose;
268 free(out_buf);
270 if (maj_stat == GSS_S_COMPLETE) {
271 (void) printf("GSSAPI authentication succeeded\n");
272 reply_parse = NULL;
273 auth_type = AUTHTYPE_GSSAPI;
274 return (1);
275 } else {
276 (void) fprintf(stderr, "GSSAPI authentication failed\n");
277 reply_parse = NULL;
279 } /* end if (command...) */
281 /* Other auth types go here ... */
283 return (0);
287 * Get the information for the channel structure.
289 void
290 get_inet_addr_info(struct sockaddr_in6 *in_ipaddr, gss_buffer_t in_buffer)
292 size_t length;
293 char *value;
295 if (in_ipaddr == NULL) {
296 in_buffer->length = 0;
297 in_buffer->value = NULL;
298 return;
301 /* get the initiator address.value and address.length */
303 if (in_ipaddr->sin6_family == AF_INET6) {
304 struct in_addr in_ipv4addr;
305 struct sockaddr_in6 *sin6 =
306 (struct sockaddr_in6 *)in_ipaddr;
307 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
308 IN6_V4MAPPED_TO_INADDR(&sin6->sin6_addr,
309 &in_ipv4addr);
310 in_buffer->length = length = sizeof (struct in_addr);
311 in_buffer->value = value = malloc(length);
312 memcpy(value, &in_ipv4addr, length);
313 } else {
314 in_buffer->length = length = sizeof (struct in6_addr);
315 in_buffer->value = value = malloc(length);
316 memcpy(value, &(sin6->sin6_addr.s6_addr),
317 length);
319 } else {
320 in_buffer->length = length = sizeof (struct in_addr);
321 in_buffer->value = value = malloc(in_buffer->length);
322 memcpy(value,
323 &((struct sockaddr_in *)(in_ipaddr))->sin_addr,
324 length);
329 radix_encode(uchar_t *inbuf, uchar_t *outbuf, size_t buflen,
330 int *outlen, int decode)
332 int i, j, D;
333 char *p;
334 uchar_t c;
336 if (decode) {
337 for (i = j = 0;
338 inbuf[i] && inbuf[i] != radix_pad && (j < buflen);
339 i++) {
340 if ((p = strchr(radixN, inbuf[i])) == NULL)
341 return (1);
342 D = p - radixN;
343 switch (i&3) {
344 case 0:
345 outbuf[j] = D<<2;
346 break;
347 case 1:
348 outbuf[j++] |= D>>4;
349 outbuf[j] = (D&15)<<4;
350 break;
351 case 2:
352 outbuf[j++] |= D>>2;
353 outbuf[j] = (D&3)<<6;
354 break;
355 case 3:
356 outbuf[j++] |= D;
359 if (j == buflen && (inbuf[i] && inbuf[i] != radix_pad)) {
360 return (4);
362 switch (i&3) {
363 case 1: return (3);
364 case 2: if (D&15)
365 return (3);
366 if (strcmp((char *)&inbuf[i], "=="))
367 return (2);
368 break;
369 case 3: if (D&3)
370 return (3);
371 if (strcmp((char *)&inbuf[i], "="))
372 return (2);
374 *outlen = j;
375 } else {
376 for (i = j = 0; i < *outlen && j < buflen; i++)
377 switch (i%3) {
378 case 0:
379 outbuf[j++] = radixN[inbuf[i]>>2];
380 c = (inbuf[i]&3)<<4;
381 break;
382 case 1:
383 outbuf[j++] = radixN[c|inbuf[i]>>4];
384 c = (inbuf[i]&15)<<2;
385 break;
386 case 2:
387 outbuf[j++] = radixN[c|inbuf[i]>>6];
388 outbuf[j++] = radixN[inbuf[i]&63];
389 c = 0;
391 if (j == buflen && i < *outlen) {
392 return (4);
394 if (i%3)
395 outbuf[j++] = radixN[c];
396 switch (i%3) {
397 case 1:
398 outbuf[j++] = radix_pad;
399 /* FALLTHROUGH */
400 case 2:
401 outbuf[j++] = radix_pad;
402 break;
404 outbuf[*outlen = j] = '\0';
406 return (0);
409 char *
410 radix_error(int e)
412 switch (e) {
413 case 0: return ("Success");
414 case 1: return ("Bad character in encoding");
415 case 2: return ("Encoding not properly padded");
416 case 3: return ("Decoded # of bits not a multiple of 8");
417 case 4: return ("Buffer size error");
418 default: return ("Unknown error");