Annotation of embedaddon/rsync/gss-auth.c, revision 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>