File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / gss-auth.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:32:36 2021 UTC (3 years, 3 months ago) by misho
Branches: rsync, MAIN
CVS tags: v3_2_3, HEAD
rsync 3.2.3

    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>