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>