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>