2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 * Copyright (c) 1985, 1989 Regents of the University of California.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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
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
);
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
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 *);
71 int oldverbose
= verbose
;
72 uchar_t
*out_buf
= NULL
;
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
];
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
,
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
,
105 chan
.application_data
.length
= 0;
106 chan
.application_data
.value
= 0;
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
;
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
);
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
);
138 token_ptr
= GSS_C_NO_BUFFER
;
139 gcontext
= GSS_C_NO_CONTEXT
; /* structure copy */
143 (void) fprintf(stderr
,
144 "calling gss_init_sec_context\n");
146 if (mechstr
&& !mechoid
&&
147 __gss_mech_to_oid(mechstr
, (gss_OID
*)&mechoid
) !=
149 (void) printf("do_auth: %s: not a valid "
150 "security mechanism\n", mechstr
);
153 mechoid
= GSS_C_NULL_OID
;
155 maj_stat
= gss_init_sec_context(&min_stat
,
162 &chan
, /* channel bindings */
164 NULL
, /* ignore mech type */
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 */
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 "
194 maj_stat
= GSS_S_FAILURE
;
197 auth_error
= radix_encode(send_tok
.value
, out_buf
,
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",
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,
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
;
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
;
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
));
244 /* everything worked */
245 token_ptr
= &recv_tok
;
246 recv_tok
.value
= out_buf
;
249 } /* end if (auth_error) */
251 /* get out of loop clean */
253 trial
= n_gss_trials
-1;
254 gss_release_buffer(&min_stat
, &send_tok
);
255 gss_release_name(&min_stat
, &target_name
);
257 } /* end if (send_tok.length != 0) */
259 } while (maj_stat
== GSS_S_CONTINUE_NEEDED
);
262 if (maj_stat
== GSS_S_COMPLETE
)
267 verbose
= oldverbose
;
270 if (maj_stat
== GSS_S_COMPLETE
) {
271 (void) printf("GSSAPI authentication succeeded\n");
273 auth_type
= AUTHTYPE_GSSAPI
;
276 (void) fprintf(stderr
, "GSSAPI authentication failed\n");
279 } /* end if (command...) */
281 /* Other auth types go here ... */
287 * Get the information for the channel structure.
290 get_inet_addr_info(struct sockaddr_in6
*in_ipaddr
, gss_buffer_t in_buffer
)
295 if (in_ipaddr
== NULL
) {
296 in_buffer
->length
= 0;
297 in_buffer
->value
= NULL
;
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
,
310 in_buffer
->length
= length
= sizeof (struct in_addr
);
311 in_buffer
->value
= value
= malloc(length
);
312 memcpy(value
, &in_ipv4addr
, length
);
314 in_buffer
->length
= length
= sizeof (struct in6_addr
);
315 in_buffer
->value
= value
= malloc(length
);
316 memcpy(value
, &(sin6
->sin6_addr
.s6_addr
),
320 in_buffer
->length
= length
= sizeof (struct in_addr
);
321 in_buffer
->value
= value
= malloc(in_buffer
->length
);
323 &((struct sockaddr_in
*)(in_ipaddr
))->sin_addr
,
329 radix_encode(uchar_t
*inbuf
, uchar_t
*outbuf
, size_t buflen
,
330 int *outlen
, int decode
)
338 inbuf
[i
] && inbuf
[i
] != radix_pad
&& (j
< buflen
);
340 if ((p
= strchr(radixN
, inbuf
[i
])) == NULL
)
349 outbuf
[j
] = (D
&15)<<4;
353 outbuf
[j
] = (D
&3)<<6;
359 if (j
== buflen
&& (inbuf
[i
] && inbuf
[i
] != radix_pad
)) {
366 if (strcmp((char *)&inbuf
[i
], "=="))
371 if (strcmp((char *)&inbuf
[i
], "="))
376 for (i
= j
= 0; i
< *outlen
&& j
< buflen
; i
++)
379 outbuf
[j
++] = radixN
[inbuf
[i
]>>2];
383 outbuf
[j
++] = radixN
[c
|inbuf
[i
]>>4];
384 c
= (inbuf
[i
]&15)<<2;
387 outbuf
[j
++] = radixN
[c
|inbuf
[i
]>>6];
388 outbuf
[j
++] = radixN
[inbuf
[i
]&63];
391 if (j
== buflen
&& i
< *outlen
) {
395 outbuf
[j
++] = radixN
[c
];
398 outbuf
[j
++] = radix_pad
;
401 outbuf
[j
++] = radix_pad
;
404 outbuf
[*outlen
= j
] = '\0';
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");