2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
6 #pragma ident "%Z%%M% %I% %E% SMI"
9 * Copyright (c) 1985, 1989 Regents of the University of California.
10 * All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 #include <sys/types.h>
43 #include <gssapi/gssapi.h>
44 #include <gssapi/gssapi_ext.h>
46 int auth_type
; /* Authentication succeeded? If so, what type? */
48 char *radix_error(int);
49 static void get_inet_addr_info(struct sockaddr_in6
*, gss_buffer_t
);
52 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
53 static char radix_pad
= '=';
56 * authenticate the user, if auth_type is AUTHTYPE_NONE
58 * Returns: 0 if there is no auth type
64 gss_ctx_id_t gcontext
; /* global gss security context */
65 static const char *gss_trials
[] = { "ftp", "host" };
66 /* the number of elements in gss_trials array */
67 static const int n_gss_trials
= sizeof (gss_trials
)/sizeof (char *);
73 int oldverbose
= verbose
;
74 uchar_t
*out_buf
= NULL
;
78 if (auth_type
!= AUTHTYPE_NONE
)
79 return (1); /* auth already succeeded */
81 /* Other auth types go here ... */
83 if (command("AUTH %s", "GSSAPI") == CONTINUE
) {
84 OM_uint32 maj_stat
, min_stat
;
85 gss_name_t target_name
;
86 gss_buffer_desc send_tok
, recv_tok
, *token_ptr
;
87 gss_buffer_desc temp_buf
;
88 char stbuf
[FTPBUFSIZ
];
91 struct gss_channel_bindings_struct chan
;
93 get_inet_addr_info(&myctladdr
, &temp_buf
);
94 chan
.initiator_addrtype
= GSS_C_AF_INET
; /* OM_uint32 */
95 chan
.initiator_address
.length
= temp_buf
.length
;
96 chan
.initiator_address
.value
= malloc(temp_buf
.length
);
97 memcpy(chan
.initiator_address
.value
, temp_buf
.value
,
100 get_inet_addr_info(&remctladdr
, &temp_buf
);
101 chan
.acceptor_addrtype
= GSS_C_AF_INET
; /* OM_uint32 */
102 chan
.acceptor_address
.length
= temp_buf
.length
;
103 chan
.acceptor_address
.value
= malloc(temp_buf
.length
);
104 memcpy(chan
.acceptor_address
.value
, temp_buf
.value
,
107 chan
.application_data
.length
= 0;
108 chan
.application_data
.value
= 0;
111 (void) printf("GSSAPI accepted as authentication type\n");
113 /* set the forward flag */
114 req_flags
= GSS_C_MUTUAL_FLAG
| GSS_C_REPLAY_FLAG
;
117 req_flags
|= GSS_C_DELEG_FLAG
;
119 /* blob from gss-client */
120 for (trial
= 0; trial
< n_gss_trials
; trial
++) {
121 /* ftp@hostname first, then host@hostname */
122 /* the V5 GSSAPI binding canonicalizes this for us... */
123 (void) snprintf(stbuf
, FTPBUFSIZ
, "%s@%s",
124 gss_trials
[trial
], hostname
);
126 (void) fprintf(stderr
,
127 "Trying to authenticate to <%s>\n", stbuf
);
129 send_tok
.value
= stbuf
;
130 send_tok
.length
= strlen(stbuf
) + 1;
131 maj_stat
= gss_import_name(&min_stat
, &send_tok
,
132 GSS_C_NT_HOSTBASED_SERVICE
, &target_name
);
134 if (maj_stat
!= GSS_S_COMPLETE
) {
135 user_gss_error(maj_stat
, min_stat
, "parsing name");
136 (void) fprintf(stderr
, "name parsed <%s>\n", stbuf
);
140 token_ptr
= GSS_C_NO_BUFFER
;
141 gcontext
= GSS_C_NO_CONTEXT
; /* structure copy */
145 (void) fprintf(stderr
,
146 "calling gss_init_sec_context\n");
148 if (mechstr
&& !mechoid
&&
149 __gss_mech_to_oid(mechstr
, (gss_OID
*)&mechoid
) !=
151 (void) printf("do_auth: %s: not a valid "
152 "security mechanism\n", mechstr
);
155 mechoid
= GSS_C_NULL_OID
;
157 maj_stat
= gss_init_sec_context(&min_stat
,
164 &chan
, /* channel bindings */
166 NULL
, /* ignore mech type */
168 NULL
, /* ignore ret_flags */
169 NULL
); /* ignore time_rec */
171 if (maj_stat
!= GSS_S_COMPLETE
&&
172 maj_stat
!= GSS_S_CONTINUE_NEEDED
) {
174 /* return an error if this is NOT the ftp ticket */
175 if (strcmp(gss_trials
[trial
], "ftp"))
176 user_gss_error(maj_stat
, min_stat
,
177 "initializing context");
179 (void) gss_release_name(&min_stat
, &target_name
);
180 /* could just be that we missed on the service name */
185 if (send_tok
.length
!= 0) {
186 int len
= send_tok
.length
;
187 reply_parse
= "ADAT="; /* for command() later */
188 oldverbose
= verbose
;
189 verbose
= (trial
== n_gss_trials
-1)?0:-1;
191 outlen
= ENCODELEN(send_tok
.length
);
192 out_buf
= (uchar_t
*)malloc(outlen
);
193 if (out_buf
== NULL
) {
194 (void) fprintf(stderr
, "memory error allocating "
196 maj_stat
= GSS_S_FAILURE
;
199 auth_error
= radix_encode(send_tok
.value
, out_buf
,
203 (void) fprintf(stderr
, "Base 64 encoding failed: %s\n",
204 radix_error(auth_error
));
205 } else if ((comcode
= command("ADAT %s", out_buf
))
206 != COMPLETE
/* && comcode != 3 (335)*/) {
208 if (trial
== n_gss_trials
-1) {
209 (void) fprintf(stderr
, "GSSAPI ADAT failed (%d)\n",
212 /* force out of loop */
213 maj_stat
= GSS_S_FAILURE
;
217 * backoff to the v1 gssapi is still possible.
218 * Send a new AUTH command. If that fails,
221 if (command("AUTH %s", "GSSAPI") != CONTINUE
) {
222 (void) fprintf(stderr
,
223 "GSSAPI ADAT failed, AUTH restart failed\n");
224 /* force out of loop */
225 maj_stat
= GSS_S_FAILURE
;
229 } else if (!reply_parse
) {
230 (void) fprintf(stderr
,
231 "No authentication data received from server\n");
232 if (maj_stat
== GSS_S_COMPLETE
) {
233 (void) fprintf(stderr
,
234 "...but no more was needed\n");
235 goto gss_complete_loop
;
237 user_gss_error(maj_stat
, min_stat
, "no reply.");
238 goto gss_complete_loop
;
240 } else if (auth_error
= radix_encode((uchar_t
*)
241 reply_parse
, out_buf
, outlen
, &i
, 1)) {
242 (void) fprintf(stderr
,
243 "Base 64 decoding failed: %s\n",
244 radix_error(auth_error
));
246 /* everything worked */
247 token_ptr
= &recv_tok
;
248 recv_tok
.value
= out_buf
;
251 } /* end if (auth_error) */
253 /* get out of loop clean */
255 trial
= n_gss_trials
-1;
256 gss_release_buffer(&min_stat
, &send_tok
);
257 gss_release_name(&min_stat
, &target_name
);
259 } /* end if (send_tok.length != 0) */
261 } while (maj_stat
== GSS_S_CONTINUE_NEEDED
);
264 if (maj_stat
== GSS_S_COMPLETE
)
269 verbose
= oldverbose
;
273 if (maj_stat
== GSS_S_COMPLETE
) {
274 (void) printf("GSSAPI authentication succeeded\n");
276 auth_type
= AUTHTYPE_GSSAPI
;
279 (void) fprintf(stderr
, "GSSAPI authentication failed\n");
282 } /* end if (command...) */
284 /* Other auth types go here ... */
290 * Get the information for the channel structure.
293 get_inet_addr_info(struct sockaddr_in6
*in_ipaddr
, gss_buffer_t in_buffer
)
298 if (in_ipaddr
== NULL
) {
299 in_buffer
->length
= 0;
300 in_buffer
->value
= NULL
;
304 /* get the initiator address.value and address.length */
306 if (in_ipaddr
->sin6_family
== AF_INET6
) {
307 struct in_addr in_ipv4addr
;
308 struct sockaddr_in6
*sin6
=
309 (struct sockaddr_in6
*)in_ipaddr
;
310 if (IN6_IS_ADDR_V4MAPPED(&sin6
->sin6_addr
)) {
311 IN6_V4MAPPED_TO_INADDR(&sin6
->sin6_addr
,
313 in_buffer
->length
= length
= sizeof (struct in_addr
);
314 in_buffer
->value
= value
= malloc(length
);
315 memcpy(value
, &in_ipv4addr
, length
);
317 in_buffer
->length
= length
= sizeof (struct in6_addr
);
318 in_buffer
->value
= value
= malloc(length
);
319 memcpy(value
, &(sin6
->sin6_addr
.s6_addr
),
323 in_buffer
->length
= length
= sizeof (struct in_addr
);
324 in_buffer
->value
= value
= malloc(in_buffer
->length
);
326 &((struct sockaddr_in
*)(in_ipaddr
))->sin_addr
,
332 radix_encode(uchar_t
*inbuf
, uchar_t
*outbuf
, size_t buflen
,
333 int *outlen
, int decode
)
341 inbuf
[i
] && inbuf
[i
] != radix_pad
&& (j
< buflen
);
343 if ((p
= strchr(radixN
, inbuf
[i
])) == NULL
)
352 outbuf
[j
] = (D
&15)<<4;
356 outbuf
[j
] = (D
&3)<<6;
362 if (j
== buflen
&& (inbuf
[i
] && inbuf
[i
] != radix_pad
)) {
369 if (strcmp((char *)&inbuf
[i
], "=="))
374 if (strcmp((char *)&inbuf
[i
], "="))
379 for (i
= j
= 0; i
< *outlen
&& j
< buflen
; i
++)
382 outbuf
[j
++] = radixN
[inbuf
[i
]>>2];
386 outbuf
[j
++] = radixN
[c
|inbuf
[i
]>>4];
387 c
= (inbuf
[i
]&15)<<2;
390 outbuf
[j
++] = radixN
[c
|inbuf
[i
]>>6];
391 outbuf
[j
++] = radixN
[inbuf
[i
]&63];
394 if (j
== buflen
&& i
< *outlen
) {
398 outbuf
[j
++] = radixN
[c
];
401 outbuf
[j
++] = radix_pad
;
404 outbuf
[j
++] = radix_pad
;
407 outbuf
[*outlen
= j
] = '\0';
416 case 0: return ("Success");
417 case 1: return ("Bad character in encoding");
418 case 2: return ("Encoding not properly padded");
419 case 3: return ("Decoded # of bits not a multiple of 8");
420 case 4: return ("Buffer size error");
421 default: return ("Unknown error");