xref: /freebsd/crypto/krb5/src/clients/ksu/krb_auth_su.c (revision f1c4c3daccbaf3820f0e2224de53df12fc952fcc)
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  * Copyright (c) 1994 by the University of Southern California
4  *
5  * EXPORT OF THIS SOFTWARE from the United States of America may
6  *     require a specific license from the United States Government.
7  *     It is the responsibility of any person or organization contemplating
8  *     export to obtain such a license before exporting.
9  *
10  * WITHIN THAT CONSTRAINT, permission to copy, modify, and distribute
11  *     this software and its documentation in source and binary forms is
12  *     hereby granted, provided that any documentation or other materials
13  *     related to such distribution or use acknowledge that the software
14  *     was developed by the University of Southern California.
15  *
16  * DISCLAIMER OF WARRANTY.  THIS SOFTWARE IS PROVIDED "AS IS".  The
17  *     University of Southern California MAKES NO REPRESENTATIONS OR
18  *     WARRANTIES, EXPRESS OR IMPLIED.  By way of example, but not
19  *     limitation, the University of Southern California MAKES NO
20  *     REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
21  *     PARTICULAR PURPOSE. The University of Southern
22  *     California shall not be held liable for any liability nor for any
23  *     direct, indirect, or consequential damages with respect to any
24  *     claim by the user or distributor of the ksu software.
25  *
26  * KSU was written by:  Ari Medvinsky, ari@isi.edu
27  */
28 
29 #include "ksu.h"
30 
31 
32 void plain_dump_principal(krb5_context, krb5_principal);
33 
34 krb5_boolean
krb5_auth_check(krb5_context context,krb5_principal client_pname,char * hostname,krb5_get_init_creds_opt * options,char * target_user,krb5_ccache cc,int * path_passwd,uid_t target_uid)35 krb5_auth_check(krb5_context context, krb5_principal client_pname,
36                 char *hostname, krb5_get_init_creds_opt *options,
37                 char *target_user, krb5_ccache cc, int *path_passwd,
38                 uid_t target_uid)
39 {
40     krb5_principal client = NULL;
41     krb5_verify_init_creds_opt vfy_opts;
42     krb5_creds tgt = { 0 }, tgtq = { 0 };
43     krb5_error_code retval =0;
44     int got_it = 0;
45     krb5_boolean zero_password;
46     krb5_boolean ok = FALSE;
47 
48     *path_passwd = 0;
49 
50     if ((retval= krb5_copy_principal(context,  client_pname, &client))){
51         com_err(prog_name, retval, _("while copying client principal"));
52         goto cleanup;
53     }
54 
55     if ((retval= krb5_copy_principal(context,  client, &tgtq.client))){
56         com_err(prog_name, retval, _("while copying client principal"));
57         goto cleanup;
58     }
59 
60     if ((retval = ksu_tgtname(context,  krb5_princ_realm(context, client),
61                               krb5_princ_realm(context, client),
62                               &tgtq.server))){
63         com_err(prog_name, retval, _("while creating tgt for local realm"));
64         goto cleanup;
65     }
66 
67     if (auth_debug){ dump_principal(context, "local tgt principal name", tgtq.server ); }
68     retval = krb5_cc_retrieve_cred(context, cc,
69                                    KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_SUPPORTED_KTYPES,
70                                    &tgtq, &tgt);
71 
72     if (! retval) retval = krb5_check_exp(context, tgt.times);
73 
74     if (retval){
75         if ((retval != KRB5_CC_NOTFOUND) &&
76             (retval != KRB5KRB_AP_ERR_TKT_EXPIRED)){
77             com_err(prog_name, retval, _("while retrieving creds from cache"));
78             goto cleanup;
79         }
80     } else{
81         got_it = 1;
82     }
83 
84     if (! got_it){
85 
86 #ifdef GET_TGT_VIA_PASSWD
87         if (krb5_seteuid(0)||krb5_seteuid(target_uid)) {
88             com_err("ksu", errno, _("while switching to target uid"));
89             goto cleanup;
90         }
91 
92 
93         fprintf(stderr, _("WARNING: Your password may be exposed if you enter "
94                           "it here and are logged \n"));
95         fprintf(stderr, _("         in remotely using an unsecure "
96                           "(non-encrypted) channel. \n"));
97 
98         /*get the ticket granting ticket, via passwd(prompt for passwd)*/
99         if (ksu_get_tgt_via_passwd(context, client, options, &zero_password,
100                                    &tgt) == FALSE) {
101             krb5_seteuid(0);
102 
103             goto cleanup;
104         }
105         *path_passwd = 1;
106         if (krb5_seteuid(0)) {
107             com_err("ksu", errno, _("while reclaiming root uid"));
108             goto cleanup;
109         }
110 
111 #else
112         plain_dump_principal (context, client);
113         fprintf(stderr,
114                 _("does not have any appropriate tickets in the cache.\n"));
115         goto cleanup;
116 
117 #endif /* GET_TGT_VIA_PASSWD */
118 
119     }
120 
121     krb5_verify_init_creds_opt_init(&vfy_opts);
122     krb5_verify_init_creds_opt_set_ap_req_nofail( &vfy_opts, 1);
123     retval = krb5_verify_init_creds(context, &tgt, NULL, NULL, NULL,
124                                     &vfy_opts);
125     if (retval) {
126         com_err(prog_name, retval, _("while verifying ticket for server"));
127         goto cleanup;
128     }
129 
130     ok = TRUE;
131 
132 cleanup:
133     krb5_free_principal(context, client);
134     krb5_free_cred_contents(context, &tgt);
135     krb5_free_cred_contents(context, &tgtq);
136     return ok;
137 }
138 
139 krb5_boolean
ksu_get_tgt_via_passwd(krb5_context context,krb5_principal client,krb5_get_init_creds_opt * options,krb5_boolean * zero_password,krb5_creds * creds_out)140 ksu_get_tgt_via_passwd(krb5_context context, krb5_principal client,
141                        krb5_get_init_creds_opt *options,
142                        krb5_boolean *zero_password, krb5_creds *creds_out)
143 {
144     krb5_boolean ok = FALSE;
145     krb5_error_code code;
146     krb5_creds creds = { 0 };
147     krb5_timestamp now;
148     unsigned int pwsize;
149     char password[255], prompt[255], *client_name = NULL;
150     int result;
151 
152     *zero_password = FALSE;
153     if (creds_out != NULL)
154         memset(creds_out, 0, sizeof(*creds_out));
155 
156     if ((code = krb5_unparse_name(context, client, &client_name))) {
157         com_err (prog_name, code, _("when unparsing name"));
158         goto cleanup;
159     }
160 
161     memset(&creds, 0, sizeof(creds));
162 
163     if ((code = krb5_timeofday(context, &now))) {
164         com_err(prog_name, code, _("while getting time of day"));
165         goto cleanup;
166     }
167 
168     result = snprintf(prompt, sizeof(prompt), _("Kerberos password for %s: "),
169                       client_name);
170     if (SNPRINTF_OVERFLOW(result, sizeof(prompt))) {
171         fprintf(stderr,
172                 _("principal name %s too long for internal buffer space\n"),
173                 client_name);
174         goto cleanup;
175     }
176 
177     pwsize = sizeof(password);
178 
179     code = krb5_read_password(context, prompt, 0, password, &pwsize);
180     if (code ) {
181         com_err(prog_name, code, _("while reading password for '%s'\n"),
182                 client_name);
183         goto cleanup;
184     }
185 
186     if ( pwsize == 0) {
187         fprintf(stderr, _("No password given\n"));
188         *zero_password = TRUE;
189         goto cleanup;
190     }
191 
192     code = krb5_get_init_creds_password(context, &creds, client, password,
193                                         krb5_prompter_posix, NULL, 0, NULL,
194                                         options);
195     zap(password, sizeof(password));
196 
197 
198     if (code) {
199         if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY)
200             fprintf(stderr, _("%s: Password incorrect\n"), prog_name);
201         else
202             com_err(prog_name, code, _("while getting initial credentials"));
203         goto cleanup;
204     }
205     if (creds_out != NULL) {
206         *creds_out = creds;
207         memset(&creds, 0, sizeof(creds));
208     }
209 
210     ok = TRUE;
211 
212 cleanup:
213     krb5_free_cred_contents(context, &creds);
214     free(client_name);
215     return ok;
216 }
217 
218 void
dump_principal(krb5_context context,char * str,krb5_principal p)219 dump_principal(krb5_context context, char *str, krb5_principal p)
220 {
221     char * stname;
222     krb5_error_code retval;
223 
224     if ((retval = krb5_unparse_name(context, p, &stname))) {
225         fprintf(stderr, _(" %s while unparsing name\n"),
226                 error_message(retval));
227         return;
228     }
229     fprintf(stderr, " %s: %s\n", str, stname);
230     free(stname);
231 }
232 
233 void
plain_dump_principal(krb5_context context,krb5_principal p)234 plain_dump_principal (krb5_context context, krb5_principal p)
235 {
236     char * stname;
237     krb5_error_code retval;
238 
239     if ((retval = krb5_unparse_name(context, p, &stname))) {
240         fprintf(stderr, _(" %s while unparsing name\n"),
241                 error_message(retval));
242         return;
243     }
244     fprintf(stderr, "%s ", stname);
245     free(stname);
246 }
247