xref: /freebsd/crypto/krb5/src/clients/ksu/krb_auth_su.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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 ();
33 
krb5_auth_check(context,client_pname,hostname,options,target_user,cc,path_passwd,target_uid)34 krb5_boolean krb5_auth_check(context, client_pname, hostname, options,
35                              target_user, cc, path_passwd, target_uid)
36     krb5_context context;
37     krb5_principal client_pname;
38     char *hostname;
39     krb5_get_init_creds_opt *options;
40     char *target_user;
41     uid_t target_uid;
42     krb5_ccache cc;
43     int *path_passwd;
44 {
45     krb5_principal client;
46     krb5_verify_init_creds_opt vfy_opts;
47     krb5_creds tgt, tgtq;
48     krb5_error_code retval =0;
49     int got_it = 0;
50     krb5_boolean zero_password;
51 
52     *path_passwd = 0;
53     memset(&tgtq, 0, sizeof(tgtq));
54     memset(&tgt, 0, sizeof(tgt));
55 
56     if ((retval= krb5_copy_principal(context,  client_pname, &client))){
57         com_err(prog_name, retval, _("while copying client principal"));
58         return (FALSE) ;
59     }
60 
61     if ((retval= krb5_copy_principal(context,  client, &tgtq.client))){
62         com_err(prog_name, retval, _("while copying client principal"));
63         return (FALSE) ;
64     }
65 
66     if ((retval = ksu_tgtname(context,  krb5_princ_realm(context, client),
67                               krb5_princ_realm(context, client),
68                               &tgtq.server))){
69         com_err(prog_name, retval, _("while creating tgt for local realm"));
70         krb5_free_principal(context, client);
71         return (FALSE) ;
72     }
73 
74     if (auth_debug){ dump_principal(context, "local tgt principal name", tgtq.server ); }
75     retval = krb5_cc_retrieve_cred(context, cc,
76                                    KRB5_TC_MATCH_SRV_NAMEONLY | KRB5_TC_SUPPORTED_KTYPES,
77                                    &tgtq, &tgt);
78 
79     if (! retval) retval = krb5_check_exp(context, tgt.times);
80 
81     if (retval){
82         if ((retval != KRB5_CC_NOTFOUND) &&
83             (retval != KRB5KRB_AP_ERR_TKT_EXPIRED)){
84             com_err(prog_name, retval, _("while retrieving creds from cache"));
85             return (FALSE) ;
86         }
87     } else{
88         got_it = 1;
89     }
90 
91     if (! got_it){
92 
93 #ifdef GET_TGT_VIA_PASSWD
94         if (krb5_seteuid(0)||krb5_seteuid(target_uid)) {
95             com_err("ksu", errno, _("while switching to target uid"));
96             return FALSE;
97         }
98 
99 
100         fprintf(stderr, _("WARNING: Your password may be exposed if you enter "
101                           "it here and are logged \n"));
102         fprintf(stderr, _("         in remotely using an unsecure "
103                           "(non-encrypted) channel. \n"));
104 
105         /*get the ticket granting ticket, via passwd(prompt for passwd)*/
106         if (ksu_get_tgt_via_passwd(context, client, options, &zero_password,
107                                    &tgt) == FALSE) {
108             krb5_seteuid(0);
109 
110             return FALSE;
111         }
112         *path_passwd = 1;
113         if (krb5_seteuid(0)) {
114             com_err("ksu", errno, _("while reclaiming root uid"));
115             return FALSE;
116         }
117 
118 #else
119         plain_dump_principal (context, client);
120         fprintf(stderr,
121                 _("does not have any appropriate tickets in the cache.\n"));
122         return FALSE;
123 
124 #endif /* GET_TGT_VIA_PASSWD */
125 
126     }
127 
128     krb5_verify_init_creds_opt_init(&vfy_opts);
129     krb5_verify_init_creds_opt_set_ap_req_nofail( &vfy_opts, 1);
130     retval = krb5_verify_init_creds(context, &tgt, NULL, NULL, NULL,
131                                     &vfy_opts);
132     if (retval) {
133         com_err(prog_name, retval, _("while verifying ticket for server"));
134         return (FALSE);
135     }
136 
137     return (TRUE);
138 }
139 
ksu_get_tgt_via_passwd(context,client,options,zero_password,creds_out)140 krb5_boolean ksu_get_tgt_via_passwd(context, client, options, zero_password,
141                                     creds_out)
142     krb5_context context;
143     krb5_principal client;
144     krb5_get_init_creds_opt *options;
145     krb5_boolean *zero_password;
146     krb5_creds *creds_out;
147 {
148     krb5_error_code code;
149     krb5_creds creds;
150     krb5_timestamp now;
151     unsigned int pwsize;
152     char password[255], *client_name, prompt[255];
153     int result;
154 
155     *zero_password = FALSE;
156     if (creds_out != NULL)
157         memset(creds_out, 0, sizeof(*creds_out));
158 
159     if ((code = krb5_unparse_name(context, client, &client_name))) {
160         com_err (prog_name, code, _("when unparsing name"));
161         return (FALSE);
162     }
163 
164     memset(&creds, 0, sizeof(creds));
165 
166     if ((code = krb5_timeofday(context, &now))) {
167         com_err(prog_name, code, _("while getting time of day"));
168         return (FALSE);
169     }
170 
171     result = snprintf(prompt, sizeof(prompt), _("Kerberos password for %s: "),
172                       client_name);
173     if (SNPRINTF_OVERFLOW(result, sizeof(prompt))) {
174         fprintf(stderr,
175                 _("principal name %s too long for internal buffer space\n"),
176                 client_name);
177         return FALSE;
178     }
179 
180     pwsize = sizeof(password);
181 
182     code = krb5_read_password(context, prompt, 0, password, &pwsize);
183     if (code ) {
184         com_err(prog_name, code, _("while reading password for '%s'\n"),
185                 client_name);
186         return (FALSE);
187     }
188 
189     if ( pwsize == 0) {
190         fprintf(stderr, _("No password given\n"));
191         *zero_password = TRUE;
192         return (FALSE);
193     }
194 
195     code = krb5_get_init_creds_password(context, &creds, client, password,
196                                         krb5_prompter_posix, NULL, 0, NULL,
197                                         options);
198     zap(password, sizeof(password));
199 
200 
201     if (code) {
202         if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY)
203             fprintf(stderr, _("%s: Password incorrect\n"), prog_name);
204         else
205             com_err(prog_name, code, _("while getting initial credentials"));
206         return (FALSE);
207     }
208     if (creds_out != NULL)
209         *creds_out = creds;
210     else
211         krb5_free_cred_contents(context, &creds);
212     return (TRUE);
213 }
214 
215 
dump_principal(context,str,p)216 void dump_principal (context, str, p)
217     krb5_context context;
218     char *str;
219     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     }
228     fprintf(stderr, " %s: %s\n", str, stname);
229 }
230 
plain_dump_principal(context,p)231 void plain_dump_principal (context, p)
232     krb5_context context;
233     krb5_principal p;
234 {
235     char * stname;
236     krb5_error_code retval;
237 
238     if ((retval = krb5_unparse_name(context, p, &stname))) {
239         fprintf(stderr, _(" %s while unparsing name\n"),
240                 error_message(retval));
241     }
242     fprintf(stderr, "%s ", stname);
243 }
244 
245 
246 /**********************************************************************
247 returns the principal that is closest to client. plist contains
248 a principal list obtained from .k5login and parhaps .k5users file.
249 This routine gets called before getting the password for a tgt.
250 A principal is picked that has the best chance of getting in.
251 
252 **********************************************************************/
253 
254 
get_best_principal(context,plist,client)255 krb5_error_code get_best_principal(context, plist, client)
256     krb5_context context;
257     char **plist;
258     krb5_principal *client;
259 {
260     krb5_error_code retval =0;
261     krb5_principal temp_client, best_client = NULL;
262 
263     int i = 0, nelem;
264 
265     if (! plist ) return 0;
266 
267     nelem = krb5_princ_size(context, *client);
268 
269     while(plist[i]){
270 
271         if ((retval = krb5_parse_name(context, plist[i], &temp_client))){
272             return retval;
273         }
274 
275         if (data_eq(*krb5_princ_realm(context, *client),
276                     *krb5_princ_realm(context, temp_client))) {
277 
278             if (nelem &&
279                 krb5_princ_size(context, *client) > 0 &&
280                 krb5_princ_size(context, temp_client) > 0) {
281                 krb5_data *p1 =
282                     krb5_princ_component(context, *client, 0);
283                 krb5_data *p2 =
284                     krb5_princ_component(context, temp_client, 0);
285 
286                 if (data_eq(*p1, *p2)) {
287 
288                     if (auth_debug){
289                         fprintf(stderr,
290                                 "get_best_principal: compare with %s\n",
291                                 plist[i]);
292                     }
293 
294                     if(best_client){
295                         if(krb5_princ_size(context, best_client) >
296                            krb5_princ_size(context, temp_client)){
297                             best_client = temp_client;
298                         }
299                     }else{
300                         best_client = temp_client;
301                     }
302                 }
303             }
304 
305         }
306         i++;
307     }
308 
309     if (best_client) *client = best_client;
310     return 0;
311 }
312