Annotation of embedaddon/rsync/gss-auth.c, revision 1.1.1.1
1.1 misho 1: /*
2: * GSSAPI authentication.
3: *
4: * Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org>
5: * Copyright (C) 2001-2002 Martin Pool <mbp@samba.org>
6: * Copyright (C) 2002-2008 Wayne Davison
7: *
8: * This program is free software; you can redistribute it and/or modify
9: * it under the terms of the GNU General Public License as published by
10: * the Free Software Foundation; either version 3 of the License, or
11: * (at your option) any later version.
12: *
13: * This program is distributed in the hope that it will be useful,
14: * but WITHOUT ANY WARRANTY; without even the implied warranty of
15: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16: * GNU General Public License for more details.
17: *
18: * You should have received a copy of the GNU General Public License along
19: * with this program; if not, visit the http://fsf.org website.
20: */
21:
22: #include "rsync.h"
23:
24: #ifdef GSSAPI_OPTION
25:
26: #define RSYNC_GSS_SERVICE "host"
27:
28: struct init_context_data {
29: gss_cred_id_t initiator_cred_handle;
30: gss_ctx_id_t *context_handle;
31: gss_name_t target_name;
32: gss_OID mech_type;
33: OM_uint32 req_flags;
34: OM_uint32 time_req;
35: gss_channel_bindings_t input_chan_bindings;
36: gss_OID *actual_mech_type;
37: OM_uint32 *ret_flags;
38: OM_uint32 *time_rec;
39: };
40:
41: struct accept_context_data {
42: gss_ctx_id_t *context_handle;
43: gss_cred_id_t acceptor_cred_handle;
44: gss_channel_bindings_t input_chan_bindings;
45: gss_name_t *src_name;
46: gss_OID *mech_type;
47: OM_uint32 *ret_flags;
48: OM_uint32 *time_rec;
49: gss_cred_id_t *delegated_cred_handle;
50: };
51:
52: int auth_gss_client(int fd, const char *host)
53: {
54: gss_ctx_id_t ctxt = GSS_C_NO_CONTEXT;
55: gss_name_t target_name = GSS_C_NO_NAME;
56: struct init_context_data cb_data;
57: char *buffer;
58: int status;
59: OM_uint32 min_stat;
60:
61: buffer = new_array(char, (strlen(host) + 2 + strlen(RSYNC_GSS_SERVICE)));
62:
63: sprintf(buffer, "%s@%s", RSYNC_GSS_SERVICE, host);
64:
65: import_gss_name(&target_name, buffer, GSS_C_NT_HOSTBASED_SERVICE);
66: free(buffer);
67:
68: cb_data.initiator_cred_handle = GSS_C_NO_CREDENTIAL;
69: cb_data.context_handle = &ctxt;
70: cb_data.target_name = target_name;
71: cb_data.mech_type = GSS_C_NO_OID;
72: cb_data.req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
73: cb_data.time_req = 0;
74: cb_data.input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS;
75: cb_data.actual_mech_type = NULL;
76: cb_data.ret_flags = NULL;
77: cb_data.time_rec = NULL;
78:
79: status = do_gss_dialog(fd, fd, 0, &cb_init_sec_context, (void *)&cb_data);
80: if (ctxt != GSS_C_NO_CONTEXT)
81: gss_delete_sec_context(&min_stat, &ctxt, GSS_C_NO_BUFFER);
82: free_gss_name(&target_name);
83:
84: return status;
85: }
86:
87: /*
88: * The call back function for a gss_init_sec_context dialog
89: */
90: OM_uint32 cb_init_sec_context(OM_uint32 *min_statp, gss_buffer_t in_token, gss_buffer_t out_token, void *cb_data)
91: {
92: struct init_context_data *context_data;
93:
94: context_data = (struct init_context_data *) cb_data;
95: return gss_init_sec_context(min_statp, context_data->initiator_cred_handle, context_data->context_handle, context_data->target_name, context_data->mech_type, context_data->req_flags, context_data->time_req, context_data->input_chan_bindings, in_token, context_data->actual_mech_type, out_token, context_data->ret_flags, context_data->time_rec);
96: }
97:
98: /* Possibly negotiate authentication with the client. Use "leader" to
99: * start off the auth if necessary.
100: *
101: * Return NULL if authentication failed. Return "" if anonymous access.
102: * Otherwise return username.
103: */
104: char *auth_gss_server(int fd_in, int fd_out, int module, const char *host, const char *addr, const char *leader)
105: {
106: struct accept_context_data cb_data;
107: gss_cred_id_t server_creds = GSS_C_NO_CREDENTIAL;
108: gss_ctx_id_t context = GSS_C_NO_CONTEXT;
109: OM_uint32 ret_flags;
110: char *users = lp_auth_users(module);
111: OM_uint32 maj_stat, min_stat;
112: gss_name_t server_name = GSS_C_NO_NAME;
113: gss_name_t client_name = GSS_C_NO_NAME;
114: gss_OID doid = GSS_C_NO_OID;
115: char *user = NULL;
116:
117: /* if no auth list then allow anyone in! */
118: if (!users || !*users)
119: return "";
120:
121: import_gss_name(&server_name, "host", GSS_C_NT_HOSTBASED_SERVICE);
122:
123: maj_stat = gss_acquire_cred(&min_stat, server_name, GSS_C_INDEFINITE, GSS_C_NULL_OID_SET, GSS_C_ACCEPT, &server_creds, NULL, NULL);
124: if (maj_stat != GSS_S_COMPLETE) {
125: error_gss(maj_stat, min_stat, "error acquiring credentials on module %s from %s (%s)", lp_name(module), host, addr);
126: return NULL;
127: }
128:
129: io_printf(fd_out, "%s\n", leader);
130:
131: cb_data.context_handle = &context;
132: cb_data.acceptor_cred_handle = server_creds;
133: cb_data.input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS;
134: cb_data.src_name = &client_name;
135: cb_data.mech_type = &doid;
136: cb_data.ret_flags = &ret_flags;
137: cb_data.time_rec = NULL;
138: cb_data.delegated_cred_handle = NULL;
139:
140: if (do_gss_dialog(fd_in, fd_out, -1, &cb_accept_sec_context, (void *)&cb_data) < 0)
141: return NULL;
142:
143: user = get_cn(client_name, doid);
144:
145: free_gss_name(&server_name);
146: free_gss_name(&client_name);
147:
148: return user;
149: }
150:
151: /*
152: * The call back function for a gss_accept_sec_context dialog
153: */
154: OM_uint32 cb_accept_sec_context(OM_uint32 *min_statp, gss_buffer_t in_token, gss_buffer_t out_token, void *cb_data)
155: {
156: struct accept_context_data *context_data;
157:
158: context_data = (struct accept_context_data *) cb_data;
159: return gss_accept_sec_context(min_statp, context_data->context_handle, context_data->acceptor_cred_handle, in_token, context_data->input_chan_bindings, context_data->src_name, context_data->mech_type, out_token, context_data->ret_flags, context_data->time_rec, context_data->delegated_cred_handle);
160: }
161:
162: void free_gss_buffer(gss_buffer_t gss_buffer)
163: {
164: OM_uint32 maj_stat, min_stat;
165:
166: if (gss_buffer->length > 0) {
167: maj_stat = gss_release_buffer(&min_stat, gss_buffer);
168: if (maj_stat != GSS_S_COMPLETE) {
169: error_gss(maj_stat, min_stat, "can't release a buffer");
170: }
171: }
172: }
173:
174: void free_gss_name(gss_name_t *gss_buffer)
175: {
176: OM_uint32 maj_stat, min_stat;
177:
178: if (*gss_buffer != GSS_C_NO_NAME) {
179: maj_stat = gss_release_name(&min_stat, gss_buffer);
180: if (maj_stat != GSS_S_COMPLETE) {
181: error_gss(maj_stat, min_stat, "can't release a name");
182: }
183: }
184: }
185:
186: void import_gss_name(gss_name_t *gss_name, const char *name, gss_OID type)
187: {
188: gss_buffer_desc gssname;
189: OM_uint32 maj_stat, min_stat;
190:
191: gssname.value = strdup(name);
192: gssname.length = strlen(name) +1 ;
193:
194: maj_stat = gss_import_name(&min_stat, &gssname, type, gss_name);
195:
196: if (maj_stat != GSS_S_COMPLETE)
197: error_gss(maj_stat, min_stat, "can't resolve %s", name);
198:
199: free_gss_buffer(&gssname);
200: }
201:
202: char *export_name(const gss_name_t input_name)
203: {
204: OM_uint32 maj_stat, min_stat;
205: gss_buffer_desc exported_name;
206: char *exported;
207: gss_OID name_oid;
208:
209: exported = NULL;
210:
211: maj_stat = gss_display_name(&min_stat, input_name, &exported_name, &name_oid);
212: if (maj_stat != GSS_S_COMPLETE) {
213: error_gss(maj_stat, min_stat, "can't get display name");
214: return NULL;
215: }
216:
217: if (exported_name.length > 0)
218: exported = strdup(exported_name.value);
219:
220: free_gss_buffer(&exported_name);
221:
222: return exported;
223: }
224:
225: void error_gss(OM_uint32 major, OM_uint32 minor, const char *format, ...)
226: {
227: OM_uint32 min_stat;
228: gss_buffer_desc gss_msg = GSS_C_EMPTY_BUFFER;
229: OM_uint32 msg_ctx;
230: va_list ap;
231: char message[BIGPATHBUFLEN];
232:
233: va_start(ap, format);
234: vsnprintf(message, sizeof message, format, ap);
235: va_end(ap);
236:
237: msg_ctx = 0;
238: if (major != GSS_S_FAILURE) /* Don't print unspecified failure, the message is useless */
239: do {
240: gss_display_status(&min_stat, major, GSS_C_GSS_CODE, GSS_C_NULL_OID, &msg_ctx, &gss_msg);
241: rprintf(FERROR, "GSS-API error: %s: %s\n", message, (char *) gss_msg.value);
242: free_gss_buffer(&gss_msg);
243: } while (msg_ctx != 0);
244:
245: if (minor != 0) {
246: do {
247: gss_display_status(&min_stat, minor, GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &gss_msg);
248: rprintf(FERROR, "GSS-API error: %s: %s\n",message, (char *) gss_msg.value);
249: free_gss_buffer(&gss_msg);
250: } while (msg_ctx != 0);
251: }
252: }
253:
254: /*
255: * This function manage a gss dialog
256: * gss tokens are eaten by a call-back function and then send by this function.
257: * Argument to this function can be passed throught the cb_data argument
258: * When told to act as a server, it just begin to wait for a first token before beginning operation
259: * on it
260: */
261: int do_gss_dialog(int fd_in, int fd_out, int isServer, OM_uint32 (*eat_token)(OM_uint32 *,gss_buffer_t, gss_buffer_t, void *), void *cb_data)
262: {
263: OM_uint32 maj_stat, min_stat;
264: gss_buffer_desc in_token = GSS_C_EMPTY_BUFFER;
265: gss_buffer_desc out_token = GSS_C_EMPTY_BUFFER;
266:
267: if (isServer)
268: recv_gss_token(fd_in, &in_token);
269:
270: do {
271: maj_stat = (*eat_token)(&min_stat, &in_token, &out_token, cb_data);
272: free_gss_buffer(&in_token);
273: if (maj_stat != GSS_S_COMPLETE
274: && maj_stat != GSS_S_CONTINUE_NEEDED) {
275: error_gss(maj_stat, min_stat, "error during dialog");
276: return -1;
277: }
278:
279: if (out_token.length != 0) {
280: send_gss_token(fd_out, &out_token);
281: }
282: free_gss_buffer(&out_token);
283:
284: if (maj_stat == GSS_S_CONTINUE_NEEDED) {
285: recv_gss_token(fd_in, &in_token);
286: }
287: } while (maj_stat == GSS_S_CONTINUE_NEEDED);
288:
289: return 0;
290: }
291:
292: char *get_cn(const gss_name_t input_name, const gss_OID mech_type)
293: {
294: OM_uint32 maj_stat, min_stat;
295: gss_name_t output_name;
296: gss_buffer_desc exported_name;
297: char *cn;
298:
299: cn = NULL;
300: maj_stat = gss_canonicalize_name(&min_stat, input_name, mech_type, &output_name);
301: if (maj_stat != GSS_S_COMPLETE) {
302: error_gss(maj_stat, min_stat, "canonizing name");
303: return NULL;
304: }
305:
306: maj_stat = gss_export_name(&min_stat, output_name, &exported_name);
307: if (maj_stat != GSS_S_COMPLETE) {
308: error_gss(maj_stat, min_stat, "canonizing name");
309: return NULL;
310: }
311: if (exported_name.length > 0)
312: cn = strdup(exported_name.value);
313:
314: free_gss_name(&output_name);
315: free_gss_buffer(&exported_name);
316:
317: return cn;
318: }
319:
320: void send_gss_token(int fd, gss_buffer_t token)
321: {
322: write_int(fd, token->length);
323: write_buf(fd, token->value, token->length);
324: }
325:
326: void recv_gss_token(int fd, gss_buffer_t token)
327: {
328: token->length = read_int(fd);
329: if (token->length > 0) {
330: token->value = new_array(char, token->length);
331: read_buf(fd, token->value, token->length);
332: }
333: }
334: #endif /* GSSAPI_OPTION */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>