/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * */ /**@CFILE auth_client_ntlm.c NTLM authenticator for SIP client * * @author Pekka Pessi * * @date Created: Wed May 24 21:44:39 EEST 2006 */ #include "config.h" #include #include #include "sofia-sip/auth_ntlm.h" #include "sofia-sip/auth_client.h" #include "sofia-sip/auth_client_plugin.h" #include #include #include #include #include #include #include #include #include #include typedef struct auth_ntlm_client_s { auth_client_t ntlm_client; int ntlm_ncount; char const *ntlm_cnonce; auth_challenge_t ntlm_ac[1]; } auth_ntlm_client_t; static int auc_ntlm_challenge(auth_client_t *ca, msg_auth_t const *ch); static int auc_ntlm_authorization(auth_client_t *ca, su_home_t *h, char const *method, url_t const *url, msg_payload_t const *body, msg_header_t **); auth_client_plugin_t const _ntlm_client_plugin = { sizeof ca_ntlm_plugin, sizeof (auth_ntlm_client_t), "NTLM", auc_ntlm_challenge, auc_ntlm_authorization }; auth_client_plugin_t const * const ntlm_client_plugin = _ntlm_client_plugin; /** Store a ntlm authorization challenge. */ static int auc_ntlm_challenge(auth_client_t *ca, msg_auth_t const *ch) { su_home_t *home = ca->ca_home; auth_ntlm_client_t *ntlm = (auth_ntlm_client_t *)ca; auth_challenge_t ac[1] = {{ sizeof ac }}; int stale; if (auth_ntlm_challenge_get(home, ac, ch->au_params) < 0) goto error; /* Check that we can handle the challenge */ if (!ac->ac_md5 && !ac->ac_md5sess) goto error; if (ac->ac_qop && !ac->ac_auth && !ac->ac_auth_int) goto error; stale = ac->ac_stale || str0cmp(ac->ac_nonce, ntlm->ntlm_ac->ac_nonce); if (ac->ac_qop && (ntlm->ntlm_cnonce == NULL || ac->ac_stale)) { su_guid_t guid[1]; char *cnonce; if (ntlm->ntlm_cnonce != NULL) /* Free the old one if we are updating after stale=true */ su_free(home, (void *)ntlm->ntlm_cnonce); su_guid_generate(guid); ntlm->ntlm_cnonce = cnonce = su_alloc(home, BASE64_SIZE(sizeof(guid)) + 1); base64_e(cnonce, BASE64_SIZE(sizeof(guid)) + 1, guid, sizeof(guid)); ntlm->ntlm_ncount = 0; } auth_ntlm_challenge_free_params(home, ntlm->ntlm_ac); *ntlm->ntlm_ac = *ac; return stale ? 2 : 1; error: auth_ntlm_challenge_free_params(home, ac); return -1; } /**Create a NTLM authorization header. * * Creates a ntlm authorization header from username @a user and password * @a pass, client nonce @a cnonce, client nonce count @a nc, request method * @a method, request URI @a uri and message body @a data. The authorization * header type is determined by @a hc - it can be either * sip_authorization_class or sip_proxy_authorization_class, as well as * http_authorization_class or http_proxy_authorization_class. * * @param home memory home used to allocate memory for the new header * @param hc header class for the header to be created * @param user user name * @param pass password * @param ac challenge structure * @param cnonce client nonce * @param nc client nonce count * @param method request method * @param uri request uri * @param data message body * @param dlen length of message body * * @return * Returns a pointer to newly created authorization header, or NULL upon an * error. */ int auc_ntlm_authorization(auth_client_t *ca, su_home_t *home, char const *method, url_t const *url, msg_payload_t const *body, msg_header_t **return_headers) { auth_ntlm_client_t *ntlm = (auth_ntlm_client_t *)ca; msg_hclass_t *hc = ca->ca_credential_class; char const *user = ca->ca_user; char const *pass = ca->ca_pass; auth_challenge_t const *ac = ntlm->ntlm_ac; char const *cnonce = ntlm->ntlm_cnonce; unsigned nc = ++ntlm->ntlm_ncount; char *uri = url_as_string(home, url); void const *data = body ? body->pl_data : ""; int dlen = body ? body->pl_len : 0; msg_header_t *h; auth_hexmd5_t sessionkey, response; auth_response_t ar[1] = {{ 0 }}; char ncount[17]; ar->ar_size = sizeof(ar); ar->ar_username = user; ar->ar_realm = ac->ac_realm; ar->ar_nonce = ac->ac_nonce; ar->ar_algorithm = NULL; ar->ar_md5 = ac->ac_md5; ar->ar_md5sess = ac->ac_md5sess; ar->ar_opaque = ac->ac_opaque; ar->ar_qop = NULL; ar->ar_auth = ac->ac_auth; ar->ar_auth_int = ac->ac_auth_int; ar->ar_uri = uri; /* If there is no qop, we MUST NOT include cnonce or nc */ if (!ar->ar_auth && !ar->ar_auth_int) cnonce = NULL; if (cnonce) { snprintf(ncount, sizeof(ncount), "%08x", nc); ar->ar_cnonce = cnonce; ar->ar_nc = ncount; } auth_ntlm_sessionkey(ar, sessionkey, pass); auth_ntlm_response(ar, response, sessionkey, method, data, dlen); h = msg_header_format(home, hc, "NTLM " "username=\"%s\", " "realm=\"%s\", " "nonce=\"%s" "%s%s" "%s%s" "%s%s, " "uri=\"%s\", " "response=\"%s\"" "%s%s" "%s%s", ar->ar_username, ar->ar_realm, ar->ar_nonce, cnonce ? "\", cnonce=\"" : "", cnonce ? cnonce : "", ar->ar_opaque ? "\", opaque=\"" : "", ar->ar_opaque ? ar->ar_opaque : "", ar->ar_algorithm ? "\", algorithm=" : "", ar->ar_algorithm ? ar->ar_algorithm : "", ar->ar_uri, response, ar->ar_auth || ar->ar_auth_int ? ", qop=" : "", ar->ar_auth_int ? "auth-int" : (ar->ar_auth ? "auth" : ""), cnonce ? ", nc=" : "", cnonce ? ncount : ""); su_free(home, uri); if (!h) return -1; *return_headers = h; return 0; }