libsmb/spnego.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003 
00004    RFC2478 Compliant SPNEGO implementation
00005 
00006    Copyright (C) Jim McDonough <jmcd@us.ibm.com>   2003
00007 
00008    This program is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 2 of the License, or
00011    (at your option) any later version.
00012    
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017 
00018    
00019    You should have received a copy of the GNU General Public License
00020    along with this program; if not, write to the Free Software
00021    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00022 */
00023 
00024 #include "includes.h"
00025 
00026 #undef DBGC_CLASS
00027 #define DBGC_CLASS DBGC_AUTH
00028 
00029 static BOOL read_negTokenInit(ASN1_DATA *asn1, negTokenInit_t *token)
00030 {
00031         ZERO_STRUCTP(token);
00032 
00033         asn1_start_tag(asn1, ASN1_CONTEXT(0));
00034         asn1_start_tag(asn1, ASN1_SEQUENCE(0));
00035 
00036         while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) {
00037                 int i;
00038 
00039                 switch (asn1->data[asn1->ofs]) {
00040                 /* Read mechTypes */
00041                 case ASN1_CONTEXT(0):
00042                         asn1_start_tag(asn1, ASN1_CONTEXT(0));
00043                         asn1_start_tag(asn1, ASN1_SEQUENCE(0));
00044 
00045                         token->mechTypes = SMB_MALLOC_P(const char *);
00046                         for (i = 0; !asn1->has_error &&
00047                                      0 < asn1_tag_remaining(asn1); i++) {
00048                                 char *p_oid = NULL;
00049                                 token->mechTypes = 
00050                                         SMB_REALLOC_ARRAY(token->mechTypes, const char *, i + 2);
00051                                 if (!token->mechTypes) {
00052                                         asn1->has_error = True;
00053                                         return False;
00054                                 }
00055                                 asn1_read_OID(asn1, &p_oid);
00056                                 token->mechTypes[i] = p_oid;
00057                         }
00058                         token->mechTypes[i] = NULL;
00059                         
00060                         asn1_end_tag(asn1);
00061                         asn1_end_tag(asn1);
00062                         break;
00063                 /* Read reqFlags */
00064                 case ASN1_CONTEXT(1):
00065                         asn1_start_tag(asn1, ASN1_CONTEXT(1));
00066                         asn1_read_Integer(asn1, &token->reqFlags);
00067                         token->reqFlags |= SPNEGO_REQ_FLAG;
00068                         asn1_end_tag(asn1);
00069                         break;
00070                 /* Read mechToken */
00071                 case ASN1_CONTEXT(2):
00072                         asn1_start_tag(asn1, ASN1_CONTEXT(2));
00073                         asn1_read_OctetString(asn1, &token->mechToken);
00074                         asn1_end_tag(asn1);
00075                         break;
00076                 /* Read mecListMIC */
00077                 case ASN1_CONTEXT(3):
00078                         asn1_start_tag(asn1, ASN1_CONTEXT(3));
00079                         if (asn1->data[asn1->ofs] == ASN1_OCTET_STRING) {
00080                                 asn1_read_OctetString(asn1,
00081                                                       &token->mechListMIC);
00082                         } else {
00083                                 /* RFC 2478 says we have an Octet String here,
00084                                    but W2k sends something different... */
00085                                 char *mechListMIC;
00086                                 asn1_push_tag(asn1, ASN1_SEQUENCE(0));
00087                                 asn1_push_tag(asn1, ASN1_CONTEXT(0));
00088                                 asn1_read_GeneralString(asn1, &mechListMIC);
00089                                 asn1_pop_tag(asn1);
00090                                 asn1_pop_tag(asn1);
00091 
00092                                 token->mechListMIC =
00093                                         data_blob(mechListMIC, strlen(mechListMIC));
00094                                 SAFE_FREE(mechListMIC);
00095                         }
00096                         asn1_end_tag(asn1);
00097                         break;
00098                 default:
00099                         asn1->has_error = True;
00100                         break;
00101                 }
00102         }
00103 
00104         asn1_end_tag(asn1);
00105         asn1_end_tag(asn1);
00106 
00107         return !asn1->has_error;
00108 }
00109 
00110 static BOOL write_negTokenInit(ASN1_DATA *asn1, negTokenInit_t *token)
00111 {
00112         asn1_push_tag(asn1, ASN1_CONTEXT(0));
00113         asn1_push_tag(asn1, ASN1_SEQUENCE(0));
00114 
00115         /* Write mechTypes */
00116         if (token->mechTypes && *token->mechTypes) {
00117                 int i;
00118 
00119                 asn1_push_tag(asn1, ASN1_CONTEXT(0));
00120                 asn1_push_tag(asn1, ASN1_SEQUENCE(0));
00121                 for (i = 0; token->mechTypes[i]; i++) {
00122                         asn1_write_OID(asn1, token->mechTypes[i]);
00123                 }
00124                 asn1_pop_tag(asn1);
00125                 asn1_pop_tag(asn1);
00126         }
00127 
00128         /* write reqFlags */
00129         if (token->reqFlags & SPNEGO_REQ_FLAG) {
00130                 int flags = token->reqFlags & ~SPNEGO_REQ_FLAG;
00131 
00132                 asn1_push_tag(asn1, ASN1_CONTEXT(1));
00133                 asn1_write_Integer(asn1, flags);
00134                 asn1_pop_tag(asn1);
00135         }
00136 
00137         /* write mechToken */
00138         if (token->mechToken.data) {
00139                 asn1_push_tag(asn1, ASN1_CONTEXT(2));
00140                 asn1_write_OctetString(asn1, token->mechToken.data,
00141                                        token->mechToken.length);
00142                 asn1_pop_tag(asn1);
00143         }
00144 
00145         /* write mechListMIC */
00146         if (token->mechListMIC.data) {
00147                 asn1_push_tag(asn1, ASN1_CONTEXT(3));
00148 #if 0
00149                 /* This is what RFC 2478 says ... */
00150                 asn1_write_OctetString(asn1, token->mechListMIC.data,
00151                                        token->mechListMIC.length);
00152 #else
00153                 /* ... but unfortunately this is what Windows
00154                    sends/expects */
00155                 asn1_push_tag(asn1, ASN1_SEQUENCE(0));
00156                 asn1_push_tag(asn1, ASN1_CONTEXT(0));
00157                 asn1_push_tag(asn1, ASN1_GENERAL_STRING);
00158                 asn1_write(asn1, token->mechListMIC.data,
00159                            token->mechListMIC.length);
00160                 asn1_pop_tag(asn1);
00161                 asn1_pop_tag(asn1);
00162                 asn1_pop_tag(asn1);
00163 #endif          
00164                 asn1_pop_tag(asn1);
00165         }
00166 
00167         asn1_pop_tag(asn1);
00168         asn1_pop_tag(asn1);
00169 
00170         return !asn1->has_error;
00171 }
00172 
00173 static BOOL read_negTokenTarg(ASN1_DATA *asn1, negTokenTarg_t *token)
00174 {
00175         ZERO_STRUCTP(token);
00176 
00177         asn1_start_tag(asn1, ASN1_CONTEXT(1));
00178         asn1_start_tag(asn1, ASN1_SEQUENCE(0));
00179 
00180         while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) {
00181                 switch (asn1->data[asn1->ofs]) {
00182                 case ASN1_CONTEXT(0):
00183                         asn1_start_tag(asn1, ASN1_CONTEXT(0));
00184                         asn1_start_tag(asn1, ASN1_ENUMERATED);
00185                         asn1_read_uint8(asn1, &token->negResult);
00186                         asn1_end_tag(asn1);
00187                         asn1_end_tag(asn1);
00188                         break;
00189                 case ASN1_CONTEXT(1):
00190                         asn1_start_tag(asn1, ASN1_CONTEXT(1));
00191                         asn1_read_OID(asn1, &token->supportedMech);
00192                         asn1_end_tag(asn1);
00193                         break;
00194                 case ASN1_CONTEXT(2):
00195                         asn1_start_tag(asn1, ASN1_CONTEXT(2));
00196                         asn1_read_OctetString(asn1, &token->responseToken);
00197                         asn1_end_tag(asn1);
00198                         break;
00199                 case ASN1_CONTEXT(3):
00200                         asn1_start_tag(asn1, ASN1_CONTEXT(3));
00201                         asn1_read_OctetString(asn1, &token->mechListMIC);
00202                         asn1_end_tag(asn1);
00203                         break;
00204                 default:
00205                         asn1->has_error = True;
00206                         break;
00207                 }
00208         }
00209 
00210         asn1_end_tag(asn1);
00211         asn1_end_tag(asn1);
00212 
00213         return !asn1->has_error;
00214 }
00215 
00216 static BOOL write_negTokenTarg(ASN1_DATA *asn1, negTokenTarg_t *token)
00217 {
00218         asn1_push_tag(asn1, ASN1_CONTEXT(1));
00219         asn1_push_tag(asn1, ASN1_SEQUENCE(0));
00220 
00221         asn1_push_tag(asn1, ASN1_CONTEXT(0));
00222         asn1_write_enumerated(asn1, token->negResult);
00223         asn1_pop_tag(asn1);
00224 
00225         if (token->supportedMech) {
00226                 asn1_push_tag(asn1, ASN1_CONTEXT(1));
00227                 asn1_write_OID(asn1, token->supportedMech);
00228                 asn1_pop_tag(asn1);
00229         }
00230 
00231         if (token->responseToken.data) {
00232                 asn1_push_tag(asn1, ASN1_CONTEXT(2));
00233                 asn1_write_OctetString(asn1, token->responseToken.data,
00234                                        token->responseToken.length);
00235                 asn1_pop_tag(asn1);
00236         }
00237 
00238         if (token->mechListMIC.data) {
00239                 asn1_push_tag(asn1, ASN1_CONTEXT(3));
00240                 asn1_write_OctetString(asn1, token->mechListMIC.data,
00241                                       token->mechListMIC.length);
00242                 asn1_pop_tag(asn1);
00243         }
00244 
00245         asn1_pop_tag(asn1);
00246         asn1_pop_tag(asn1);
00247 
00248         return !asn1->has_error;
00249 }
00250 
00251 ssize_t read_spnego_data(DATA_BLOB data, SPNEGO_DATA *token)
00252 {
00253         ASN1_DATA asn1;
00254         ssize_t ret = -1;
00255 
00256         ZERO_STRUCTP(token);
00257         ZERO_STRUCT(asn1);
00258         asn1_load(&asn1, data);
00259 
00260         switch (asn1.data[asn1.ofs]) {
00261         case ASN1_APPLICATION(0):
00262                 asn1_start_tag(&asn1, ASN1_APPLICATION(0));
00263                 asn1_check_OID(&asn1, OID_SPNEGO);
00264                 if (read_negTokenInit(&asn1, &token->negTokenInit)) {
00265                         token->type = SPNEGO_NEG_TOKEN_INIT;
00266                 }
00267                 asn1_end_tag(&asn1);
00268                 break;
00269         case ASN1_CONTEXT(1):
00270                 if (read_negTokenTarg(&asn1, &token->negTokenTarg)) {
00271                         token->type = SPNEGO_NEG_TOKEN_TARG;
00272                 }
00273                 break;
00274         default:
00275                 break;
00276         }
00277 
00278         if (!asn1.has_error) ret = asn1.ofs;
00279         asn1_free(&asn1);
00280 
00281         return ret;
00282 }
00283 
00284 ssize_t write_spnego_data(DATA_BLOB *blob, SPNEGO_DATA *spnego)
00285 {
00286         ASN1_DATA asn1;
00287         ssize_t ret = -1;
00288 
00289         ZERO_STRUCT(asn1);
00290 
00291         switch (spnego->type) {
00292         case SPNEGO_NEG_TOKEN_INIT:
00293                 asn1_push_tag(&asn1, ASN1_APPLICATION(0));
00294                 asn1_write_OID(&asn1, OID_SPNEGO);
00295                 write_negTokenInit(&asn1, &spnego->negTokenInit);
00296                 asn1_pop_tag(&asn1);
00297                 break;
00298         case SPNEGO_NEG_TOKEN_TARG:
00299                 write_negTokenTarg(&asn1, &spnego->negTokenTarg);
00300                 break;
00301         default:
00302                 asn1.has_error = True;
00303                 break;
00304         }
00305 
00306         if (!asn1.has_error) {
00307                 *blob = data_blob(asn1.data, asn1.length);
00308                 ret = asn1.ofs;
00309         }
00310         asn1_free(&asn1);
00311 
00312         return ret;
00313 }
00314 
00315 BOOL free_spnego_data(SPNEGO_DATA *spnego)
00316 {
00317         BOOL ret = True;
00318 
00319         if (!spnego) goto out;
00320 
00321         switch(spnego->type) {
00322         case SPNEGO_NEG_TOKEN_INIT:
00323                 if (spnego->negTokenInit.mechTypes) {
00324                         int i;
00325                         for (i = 0; spnego->negTokenInit.mechTypes[i]; i++) {
00326                                 free(CONST_DISCARD(char *,spnego->negTokenInit.mechTypes[i]));
00327                         }
00328                         free(spnego->negTokenInit.mechTypes);
00329                 }
00330                 data_blob_free(&spnego->negTokenInit.mechToken);
00331                 data_blob_free(&spnego->negTokenInit.mechListMIC);
00332                 break;
00333         case SPNEGO_NEG_TOKEN_TARG:
00334                 if (spnego->negTokenTarg.supportedMech) {
00335                         free(spnego->negTokenTarg.supportedMech);
00336                 }
00337                 data_blob_free(&spnego->negTokenTarg.responseToken);
00338                 data_blob_free(&spnego->negTokenTarg.mechListMIC);
00339                 break;
00340         default:
00341                 ret = False;
00342                 break;
00343         }
00344         ZERO_STRUCTP(spnego);
00345 out:
00346         return ret;
00347 }

Sambaに対してSat Aug 29 21:23:06 2009に生成されました。  doxygen 1.4.7