Imported Upstream version 1.6.8p5
[debian/sudo] / auth / kerb5.c
index 1992c1dd6c7c985bd896ef7e57197b5c58c2b0b3..9723020ceebe71028e83c11152732bc6840220a0 100644 (file)
@@ -1,38 +1,24 @@
 /*
- * Copyright (c) 1999, 2001 Todd C. Miller <Todd.Miller@courtesan.com>
- * All rights reserved.
+ * Copyright (c) 1999,2001,2003-2004 Todd C. Miller <Todd.Miller@courtesan.com>
  *
- * This code is derived from software contributed by Frank Cusack
- * <fcusack@fcusack.com>.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * 4. Products derived from this software may not be called "Sudo" nor
- *    may "Sudo" appear in their names without specific prior written
- *    permission from the author.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
  */
 
 #include "config.h"
 #include "sudo_auth.h"
 
 #ifndef lint
-static const char rcsid[] = "$Sudo: kerb5.c,v 1.11 2001/12/14 19:52:53 millert Exp $";
+static const char rcsid[] = "$Sudo: kerb5.c,v 1.23 2004/06/07 00:02:56 millert Exp $";
 #endif /* lint */
 
+#ifdef HAVE_HEIMDAL
+# define extract_name(c, p)            krb5_principal_get_comp_string(c, p, 0)
+# define krb5_free_data_contents(c, d) krb5_data_free(d)
+# define ENCTYPE_DES_CBC_MD5           ETYPE_DES_CBC_MD5       /* XXX */
+#else
+# define extract_name(c, p)            (krb5_princ_component(c, p, 1)->data)
+#endif
+
 static int verify_krb_v5_tgt __P((krb5_context, krb5_ccache, char *));
 static struct _sudo_krb5_data {
     krb5_context       sudo_context;
@@ -76,7 +70,7 @@ static struct _sudo_krb5_data {
 } sudo_krb5_data = { NULL, NULL, NULL };
 typedef struct _sudo_krb5_data *sudo_krb5_datap;
 
-extern krb5_cc_ops krb5_mcc_ops;
+extern const krb5_cc_ops krb5_mcc_ops;
 
 int
 kerb5_init(pw, promptp, auth)
@@ -93,17 +87,13 @@ kerb5_init(pw, promptp, auth)
 
     auth->data = (VOID *) &sudo_krb5_data; /* Stash all our data here */
 
-    if (error = krb5_init_context(&(sudo_krb5_data.sudo_context))) {
-       log_error(NO_EXIT|NO_MAIL, 
-                 "%s: unable to initialize context: %s", auth->name,
-                 error_message(error));
+    if ((error = krb5_init_context(&(sudo_krb5_data.sudo_context))))
        return(AUTH_FAILURE);
-    }
     sudo_context = sudo_krb5_data.sudo_context;
 
-    if (error = krb5_parse_name(sudo_context, pw->pw_name,
-       &(sudo_krb5_data.princ))) {
-       log_error(NO_EXIT|NO_MAIL, 
+    if ((error = krb5_parse_name(sudo_context, pw->pw_name,
+       &(sudo_krb5_data.princ)))) {
+       log_error(NO_EXIT|NO_MAIL,
                  "%s: unable to parse '%s': %s", auth->name, pw->pw_name,
                  error_message(error));
        return(AUTH_FAILURE);
@@ -115,7 +105,7 @@ kerb5_init(pw, promptp, auth)
      * The API does not currently provide this unless the auth is standalone.
      */
 #if 1
-    if (error = krb5_unparse_name(sudo_context, princ, &pname)) {
+    if ((error = krb5_unparse_name(sudo_context, princ, &pname))) {
        log_error(NO_EXIT|NO_MAIL,
                  "%s: unable to unparse princ ('%s'): %s", auth->name,
                  pw->pw_name, error_message(error));
@@ -130,9 +120,9 @@ kerb5_init(pw, promptp, auth)
 #endif
 
     /* For CNS compatibility */
-    if (error = krb5_cc_register(sudo_context, &krb5_mcc_ops, FALSE)) {
+    if ((error = krb5_cc_register(sudo_context, &krb5_mcc_ops, FALSE))) {
        if (error != KRB5_CC_TYPE_EXISTS) {
-           log_error(NO_EXIT|NO_MAIL, 
+           log_error(NO_EXIT|NO_MAIL,
                      "%s: unable to use Memory ccache: %s", auth->name,
                      error_message(error));
            return(AUTH_FAILURE);
@@ -141,17 +131,17 @@ kerb5_init(pw, promptp, auth)
 
     (void) snprintf(cache_name, sizeof(cache_name), "MEMORY:sudocc_%ld",
                    (long) getpid());
-    if (error = krb5_cc_resolve(sudo_context, cache_name,
-       &(sudo_krb5_data.ccache))) {
-       log_error(NO_EXIT|NO_MAIL, 
+    if ((error = krb5_cc_resolve(sudo_context, cache_name,
+       &(sudo_krb5_data.ccache)))) {
+       log_error(NO_EXIT|NO_MAIL,
                  "%s: unable to resolve ccache: %s", auth->name,
                  error_message(error));
        return(AUTH_FAILURE);
     }
     ccache = sudo_krb5_data.ccache;
 
-    if (error = krb5_cc_initialize(sudo_context, ccache, princ)) {
-       log_error(NO_EXIT|NO_MAIL, 
+    if ((error = krb5_cc_initialize(sudo_context, ccache, princ))) {
+       log_error(NO_EXIT|NO_MAIL,
                  "%s: unable to initialize ccache: %s", auth->name,
                  error_message(error));
        return(AUTH_FAILURE);
@@ -172,7 +162,6 @@ kerb5_verify(pw, pass, auth)
     krb5_creds         creds;
     krb5_error_code    error;
     krb5_get_init_creds_opt opts;
-    char               cache_name[64];
 
     sudo_context = ((sudo_krb5_datap) auth->data)->sudo_context;
     princ = ((sudo_krb5_datap) auth->data)->princ;
@@ -182,21 +171,21 @@ kerb5_verify(pw, pass, auth)
     krb5_get_init_creds_opt_init(&opts);
 
     /* Note that we always obtain a new TGT to verify the user */
-    if (error = krb5_get_init_creds_password(sudo_context, &creds, princ,
+    if ((error = krb5_get_init_creds_password(sudo_context, &creds, princ,
                                             pass, krb5_prompter_posix,
-                                            NULL, 0, NULL, &opts)) {
+                                            NULL, 0, NULL, &opts))) {
        if (error == KRB5KRB_AP_ERR_BAD_INTEGRITY) /* Bad password */
            return(AUTH_FAILURE);
        /* Some other error */
-       log_error(NO_EXIT|NO_MAIL, 
+       log_error(NO_EXIT|NO_MAIL,
                  "%s: unable to get credentials: %s", auth->name,
                  error_message(error));
        return(AUTH_FAILURE);
     }
 
     /* Stash the TGT so we can verify it. */
-    if (error = krb5_cc_store_cred(sudo_context, ccache, &creds)) {
-       log_error(NO_EXIT|NO_MAIL, 
+    if ((error = krb5_cc_store_cred(sudo_context, ccache, &creds))) {
+       log_error(NO_EXIT|NO_MAIL,
                  "%s: unable to store credentials: %s", auth->name,
                  error_message(error));
     } else {
@@ -263,26 +252,24 @@ verify_krb_v5_tgt(sudo_context, ccache, auth_name)
      * Get the server principal for the local host.
      * (Use defaults of "host" and canonicalized local name.)
      */
-    if (error = krb5_sname_to_principal(sudo_context, NULL, NULL,
-                                       KRB5_NT_SRV_HST, &princ)) {
-       log_error(NO_EXIT|NO_MAIL, 
+    if ((error = krb5_sname_to_principal(sudo_context, NULL, NULL,
+                                       KRB5_NT_SRV_HST, &princ))) {
+       log_error(NO_EXIT|NO_MAIL,
                  "%s: unable to get host principal: %s", auth_name,
                  error_message(error));
        return(-1);
     }
 
     /* Extract the name directly. Yow. */
-    strncpy(phost, krb5_princ_component(sudo_context, princ, 1)->data,
-           sizeof(phost) - 1);
-    phost[sizeof(phost) - 1] = '\0';
+    strlcpy(phost, extract_name(sudo_context, princ), sizeof(phost));
 
     /*
      * Do we have host/<host> keys?
      * (use default keytab, kvno IGNORE_VNO to get the first match,
      * and enctype is currently ignored anyhow.)
      */
-    if (error = krb5_kt_read_service_key(sudo_context, NULL, princ, 0,
-                                        ENCTYPE_DES_CBC_MD5, &keyblock)) {
+    if ((error = krb5_kt_read_service_key(sudo_context, NULL, princ, 0,
+                                        ENCTYPE_DES_CBC_MD5, &keyblock))) {
        /* Keytab or service key does not exist. */
        log_error(NO_EXIT,
                  "%s: host service key not found: %s", auth_name,
@@ -311,7 +298,7 @@ cleanup:
     krb5_free_principal(sudo_context, princ);
 
     if (error)
-       log_error(NO_EXIT|NO_MAIL, 
+       log_error(NO_EXIT|NO_MAIL,
                  "%s: Cannot verify TGT! Possible attack!: %s", auth_name,
                  error_message(error));
     return(error);