]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - crypto/heimdal/lib/auth/sia/sia.c
import of heimdal 0.3f
[FreeBSD/FreeBSD.git] / crypto / heimdal / lib / auth / sia / sia.c
1 /*
2  * Copyright (c) 1995-2000 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  * 
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include "sia_locl.h"
35
36 RCSID("$Id: sia.c,v 1.35 2001/02/20 01:44:53 assar Exp $");
37
38 int 
39 siad_init(void)
40 {
41     return SIADSUCCESS;
42 }
43
44 int 
45 siad_chk_invoker(void)
46 {
47     SIA_DEBUG(("DEBUG", "siad_chk_invoker"));
48     return SIADFAIL;
49 }
50
51 int 
52 siad_ses_init(SIAENTITY *entity, int pkgind)
53 {
54     krb5_error_code ret;
55     struct state *s = malloc(sizeof(*s));
56
57     SIA_DEBUG(("DEBUG", "siad_ses_init"));
58     if(s == NULL)
59         return SIADFAIL;
60     memset(s, 0, sizeof(*s));
61 #ifdef SIA_KRB5
62     ret = krb5_init_context(&s->context);
63     if (ret)
64         return SIADFAIL;
65 #endif
66     entity->mech[pkgind] = (int*)s;
67     return SIADSUCCESS;
68 }
69
70 static int
71 setup_name(SIAENTITY *e, prompt_t *p)
72 {
73     SIA_DEBUG(("DEBUG", "setup_name"));
74     e->name = malloc(SIANAMEMIN + 1);
75     if(e->name == NULL){
76         SIA_DEBUG(("DEBUG", "failed to malloc %u bytes", SIANAMEMIN+1));
77         return SIADFAIL;
78     }
79     p->prompt = (unsigned char*)"login: ";
80     p->result = (unsigned char*)e->name;
81     p->min_result_length = 1;
82     p->max_result_length = SIANAMEMIN;
83     p->control_flags = 0;
84     return SIADSUCCESS;
85 }
86
87 static int
88 setup_password(SIAENTITY *e, prompt_t *p)
89 {
90     SIA_DEBUG(("DEBUG", "setup_password"));
91     e->password = malloc(SIAMXPASSWORD + 1);
92     if(e->password == NULL){
93         SIA_DEBUG(("DEBUG", "failed to malloc %u bytes", SIAMXPASSWORD+1));
94         return SIADFAIL;
95     }
96     p->prompt = (unsigned char*)"Password: ";
97     p->result = (unsigned char*)e->password;
98     p->min_result_length = 0;
99     p->max_result_length = SIAMXPASSWORD;
100     p->control_flags = SIARESINVIS;
101     return SIADSUCCESS;
102 }
103
104
105 static int
106 doauth(SIAENTITY *entity, int pkgind, char *name)
107 {
108     struct passwd pw, *pwd;
109     char pwbuf[1024];
110     struct state *s = (struct state*)entity->mech[pkgind];
111 #ifdef SIA_KRB5
112     krb5_realm *realms, *r;
113     krb5_principal principal;
114     krb5_ccache ccache;
115     krb5_error_code ret;
116 #endif
117 #ifdef SIA_KRB4
118     char realm[REALM_SZ];
119     char *toname, *toinst;
120     int ret;
121     struct passwd fpw, *fpwd;
122     char fpwbuf[1024];
123     int secure;
124 #endif
125         
126     if(getpwnam_r(name, &pw, pwbuf, sizeof(pwbuf), &pwd) != 0){
127         SIA_DEBUG(("DEBUG", "failed to getpwnam(%s)", name));
128         return SIADFAIL;
129     }
130
131 #ifdef SIA_KRB5
132     ret = krb5_get_default_realms(s->context, &realms);
133
134     for (r = realms; *r != NULL; ++r) {
135         krb5_make_principal (s->context, &principal, *r, entity->name, NULL);
136
137         if(krb5_kuserok(s->context, principal, entity->name))
138             break;
139     }
140     krb5_free_host_realm (s->context, realms);
141     if (*r == NULL)
142         return SIADFAIL;
143
144     sprintf(s->ticket, "FILE:/tmp/krb5_cc%d_%d", pwd->pw_uid, getpid());
145     ret = krb5_cc_resolve(s->context, s->ticket, &ccache);
146     if(ret)
147         return SIADFAIL;
148 #endif
149         
150 #ifdef SIA_KRB4
151     snprintf(s->ticket, sizeof(s->ticket),
152              "%s%u_%u", TKT_ROOT, (unsigned)pwd->pw_uid, (unsigned)getpid());
153     krb_get_lrealm(realm, 1);
154     toname = name;
155     toinst = "";
156     if(entity->authtype == SIA_A_SUAUTH){
157         uid_t ouid;
158 #ifdef HAVE_SIAENTITY_OUID
159         ouid = entity->ouid;
160 #else
161         ouid = getuid();
162 #endif
163         if(getpwuid_r(ouid, &fpw, fpwbuf, sizeof(fpwbuf), &fpwd) != 0){
164             SIA_DEBUG(("DEBUG", "failed to getpwuid(%u)", ouid));
165             return SIADFAIL;
166         }
167         snprintf(s->ticket, sizeof(s->ticket), "%s_%s_to_%s_%d", 
168                  TKT_ROOT, fpwd->pw_name, pwd->pw_name, getpid());
169         if(strcmp(pwd->pw_name, "root") == 0){
170             toname = fpwd->pw_name;
171             toinst = pwd->pw_name;
172         }
173     }
174     if(entity->authtype == SIA_A_REAUTH) 
175         snprintf(s->ticket, sizeof(s->ticket), "%s", tkt_string());
176     
177     krb_set_tkt_string(s->ticket);
178         
179     setuid(0); /* XXX fix for fix in tf_util.c */
180     if(krb_kuserok(toname, toinst, realm, name)){
181         SIA_DEBUG(("DEBUG", "%s.%s@%s is not allowed to login as %s", 
182                    toname, toinst, realm, name));
183         return SIADFAIL;
184     }
185 #endif
186 #ifdef SIA_KRB5
187     ret = krb5_verify_user_lrealm(s->context, principal, ccache,
188                                   entity->password, 1, NULL);
189     if(ret){
190         /* if this is most likely a local user (such as
191            root), just silently return failure when the
192            principal doesn't exist */
193         if(ret != KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN && 
194            ret != KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN)
195             SIALOG("WARNING", "krb5_verify_user(%s): %s", 
196                    entity->name, error_message(ret));
197         return SIADFAIL;
198     }
199 #endif
200 #ifdef SIA_KRB4
201     if (getuid () == 0)
202         secure = KRB_VERIFY_SECURE;
203     else
204         secure = KRB_VERIFY_NOT_SECURE;
205         
206     ret = krb_verify_user(toname, toinst, realm,
207                           entity->password, secure, NULL);
208     if(ret){
209         SIA_DEBUG(("DEBUG", "krb_verify_user: %s", krb_get_err_text(ret)));
210         if(ret != KDC_PR_UNKNOWN)
211             /* since this is most likely a local user (such as
212                root), just silently return failure when the
213                principal doesn't exist */
214             SIALOG("WARNING", "krb_verify_user(%s.%s): %s", 
215                    toname, toinst, krb_get_err_text(ret));
216         return SIADFAIL;
217     }
218 #endif
219     if(sia_make_entity_pwd(pwd, entity) == SIAFAIL)
220         return SIADFAIL;
221     s->valid = 1;
222     return SIADSUCCESS;
223 }
224
225
226 static int 
227 common_auth(sia_collect_func_t *collect, 
228             SIAENTITY *entity, 
229             int siastat,
230             int pkgind)
231 {
232     prompt_t prompts[2], *pr;
233     char *name;
234
235     SIA_DEBUG(("DEBUG", "common_auth"));
236     if((siastat == SIADSUCCESS) && (geteuid() == 0))
237         return SIADSUCCESS;
238     if(entity == NULL) {
239         SIA_DEBUG(("DEBUG", "entity == NULL"));
240         return SIADFAIL | SIADSTOP;
241     }
242     name = entity->name;
243     if(entity->acctname)
244         name = entity->acctname;
245     
246     if((collect != NULL) && entity->colinput) {
247         int num;
248         pr = prompts;
249         if(name == NULL){
250             if(setup_name(entity, pr) != SIADSUCCESS)
251                 return SIADFAIL;
252             pr++;
253         }
254         if(entity->password == NULL){
255             if(setup_password(entity, pr) != SIADSUCCESS)
256                 return SIADFAIL;
257             pr++;
258         }
259         num = pr - prompts;
260         if(num == 1){
261             if((*collect)(240, SIAONELINER, (unsigned char*)"", num, 
262                           prompts) != SIACOLSUCCESS){
263                 SIA_DEBUG(("DEBUG", "collect failed"));
264                 return SIADFAIL | SIADSTOP;
265             }
266         } else if(num > 0){
267             if((*collect)(0, SIAFORM, (unsigned char*)"", num, 
268                           prompts) != SIACOLSUCCESS){
269                 SIA_DEBUG(("DEBUG", "collect failed"));
270                 return SIADFAIL | SIADSTOP;
271             }
272         }
273     }
274     if(name == NULL)
275         name = entity->name;
276     if(name == NULL || name[0] == '\0'){
277         SIA_DEBUG(("DEBUG", "name is null"));
278         return SIADFAIL;
279     }
280
281     if(entity->password == NULL || strlen(entity->password) > SIAMXPASSWORD){
282         SIA_DEBUG(("DEBUG", "entity->password is null"));
283         return SIADFAIL;
284     }
285     
286     return doauth(entity, pkgind, name);
287 }
288
289
290 int 
291 siad_ses_authent(sia_collect_func_t *collect, 
292                  SIAENTITY *entity, 
293                  int siastat,
294                  int pkgind)
295 {
296     SIA_DEBUG(("DEBUG", "siad_ses_authent"));
297     return common_auth(collect, entity, siastat, pkgind);
298 }
299
300 int 
301 siad_ses_estab(sia_collect_func_t *collect, 
302                SIAENTITY *entity, int pkgind)
303 {
304     SIA_DEBUG(("DEBUG", "siad_ses_estab"));
305     return SIADFAIL;
306 }
307
308 int 
309 siad_ses_launch(sia_collect_func_t *collect,
310                 SIAENTITY *entity,
311                 int pkgind)
312 {
313     static char env[MaxPathLen];
314     struct state *s = (struct state*)entity->mech[pkgind];
315     SIA_DEBUG(("DEBUG", "siad_ses_launch"));
316     if(s->valid){
317 #ifdef SIA_KRB5
318         chown(s->ticket + sizeof("FILE:") - 1, 
319               entity->pwd->pw_uid, 
320               entity->pwd->pw_gid);
321         snprintf(env, sizeof(env), "KRB5CCNAME=%s", s->ticket);
322 #endif
323 #ifdef SIA_KRB4
324         chown(s->ticket, entity->pwd->pw_uid, entity->pwd->pw_gid);
325         snprintf(env, sizeof(env), "KRBTKFILE=%s", s->ticket);
326 #endif
327         putenv(env);
328     }
329 #ifdef KRB4
330     if (k_hasafs()) {
331         char cell[64];
332         k_setpag();
333         if(k_afs_cell_of_file(entity->pwd->pw_dir, cell, sizeof(cell)) == 0)
334             krb_afslog(cell, 0);
335         krb_afslog_home(0, 0, entity->pwd->pw_dir);
336     }
337 #endif
338     return SIADSUCCESS;
339 }
340
341 int 
342 siad_ses_release(SIAENTITY *entity, int pkgind)
343 {
344     SIA_DEBUG(("DEBUG", "siad_ses_release"));
345     if(entity->mech[pkgind]){
346 #ifdef SIA_KRB5
347         struct state *s = (struct state*)entity->mech[pkgind];
348         krb5_free_context(s->context);
349 #endif
350         free(entity->mech[pkgind]);
351     }
352     return SIADSUCCESS;
353 }
354
355 int 
356 siad_ses_suauthent(sia_collect_func_t *collect,
357                    SIAENTITY *entity,
358                    int siastat,
359                    int pkgind)
360 {
361     SIA_DEBUG(("DEBUG", "siad_ses_suauth"));
362     if(geteuid() != 0)
363         return SIADFAIL;
364     if(entity->name == NULL)
365         return SIADFAIL;
366     if(entity->name[0] == '\0') {
367         free(entity->name);
368         entity->name = strdup("root");
369         if (entity->name == NULL)
370             return SIADFAIL;
371     }
372     return common_auth(collect, entity, siastat, pkgind);
373 }
374
375 int
376 siad_ses_reauthent (sia_collect_func_t *collect,
377                     SIAENTITY *entity,
378                     int siastat,
379                     int pkgind)
380 {
381     int ret;
382     SIA_DEBUG(("DEBUG", "siad_ses_reauthent"));
383     if(entity == NULL || entity->name == NULL)
384         return SIADFAIL;
385     ret = common_auth(collect, entity, siastat, pkgind);
386     if((ret & SIADSUCCESS)){
387         /* launch isn't (always?) called when doing reauth, so we must
388            duplicate some code here... */
389         struct state *s = (struct state*)entity->mech[pkgind];
390         chown(s->ticket, entity->pwd->pw_uid, entity->pwd->pw_gid);
391 #ifdef KRB4
392         if(k_hasafs()) {
393             char cell[64];
394             if(k_afs_cell_of_file(entity->pwd->pw_dir, 
395                                   cell, sizeof(cell)) == 0)
396                 krb_afslog(cell, 0);
397             krb_afslog_home(0, 0, entity->pwd->pw_dir);
398         }
399 #endif
400     }
401     return ret;
402 }
403
404 int
405 siad_chg_finger (sia_collect_func_t *collect,
406                      const char *username, 
407                      int argc, 
408                      char *argv[])
409 {
410     SIA_DEBUG(("DEBUG", "siad_chg_finger"));
411     return SIADFAIL;
412 }
413
414 #ifdef SIA_KRB5
415 int
416 siad_chg_password (sia_collect_func_t *collect,
417                      const char *username, 
418                      int argc, 
419                      char *argv[])
420 {
421     return SIADFAIL;
422 }
423 #endif
424
425 #ifdef SIA_KRB4
426 static void
427 sia_message(sia_collect_func_t *collect, int rendition, 
428             const char *title, const char *message)
429 {
430     prompt_t prompt;
431     prompt.prompt = (unsigned char*)message;
432     (*collect)(0, rendition, (unsigned char*)title, 1, &prompt);
433 }
434
435 static int
436 init_change(sia_collect_func_t *collect, krb_principal *princ)
437 {
438     prompt_t prompt;
439     char old_pw[MAX_KPW_LEN+1];
440     char *msg;
441     char tktstring[128];
442     int ret;
443     
444     SIA_DEBUG(("DEBUG", "init_change"));
445     prompt.prompt = (unsigned char*)"Old password: ";
446     prompt.result = (unsigned char*)old_pw;
447     prompt.min_result_length = 0;
448     prompt.max_result_length = sizeof(old_pw) - 1;
449     prompt.control_flags = SIARESINVIS;
450     asprintf(&msg, "Changing password for %s", krb_unparse_name(princ));
451     if(msg == NULL){
452         SIA_DEBUG(("DEBUG", "out of memory"));
453         return SIADFAIL;
454     }
455     ret = (*collect)(60, SIAONELINER, (unsigned char*)msg, 1, &prompt);
456     free(msg);
457     SIA_DEBUG(("DEBUG", "ret = %d", ret));
458     if(ret != SIACOLSUCCESS)
459         return SIADFAIL;
460     snprintf(tktstring, sizeof(tktstring), 
461              "%s_cpw_%u", TKT_ROOT, (unsigned)getpid());
462     krb_set_tkt_string(tktstring);
463     
464     ret = krb_get_pw_in_tkt(princ->name, princ->instance, princ->realm, 
465                             PWSERV_NAME, KADM_SINST, 1, old_pw);
466     if (ret != KSUCCESS) {
467         SIA_DEBUG(("DEBUG", "krb_get_pw_in_tkt: %s", krb_get_err_text(ret)));
468         if (ret == INTK_BADPW)
469             sia_message(collect, SIAWARNING, "", "Incorrect old password.");
470         else
471             sia_message(collect, SIAWARNING, "", "Kerberos error.");
472         memset(old_pw, 0, sizeof(old_pw));
473         return SIADFAIL;
474     }
475     if(chown(tktstring, getuid(), -1) < 0){
476         dest_tkt();
477         return SIADFAIL;
478     }
479     memset(old_pw, 0, sizeof(old_pw));
480     return SIADSUCCESS;
481 }
482
483 int
484 siad_chg_password (sia_collect_func_t *collect,
485                    const char *username, 
486                    int argc, 
487                    char *argv[])
488 {
489     prompt_t prompts[2];
490     krb_principal princ;
491     int ret;
492     char new_pw1[MAX_KPW_LEN+1];
493     char new_pw2[MAX_KPW_LEN+1];
494     static struct et_list *et_list;
495
496     setprogname(argv[0]);
497
498     SIA_DEBUG(("DEBUG", "siad_chg_password"));
499     if(collect == NULL)
500         return SIADFAIL;
501
502     if(username == NULL)
503         username = getlogin();
504
505     ret = krb_parse_name(username, &princ);
506     if(ret)
507         return SIADFAIL;
508     if(princ.realm[0] == '\0')
509         krb_get_lrealm(princ.realm, 1);
510
511     if(et_list == NULL) {
512         initialize_kadm_error_table_r(&et_list);
513         initialize_krb_error_table_r(&et_list);
514     }
515
516     ret = init_change(collect, &princ);
517     if(ret != SIADSUCCESS)
518         return ret;
519
520 again:
521     prompts[0].prompt = (unsigned char*)"New password: ";
522     prompts[0].result = (unsigned char*)new_pw1;
523     prompts[0].min_result_length = MIN_KPW_LEN;
524     prompts[0].max_result_length = sizeof(new_pw1) - 1;
525     prompts[0].control_flags = SIARESINVIS;
526     prompts[1].prompt = (unsigned char*)"Verify new password: ";
527     prompts[1].result = (unsigned char*)new_pw2;
528     prompts[1].min_result_length = MIN_KPW_LEN;
529     prompts[1].max_result_length = sizeof(new_pw2) - 1;
530     prompts[1].control_flags = SIARESINVIS;
531     if((*collect)(120, SIAFORM, (unsigned char*)"", 2, prompts) != 
532        SIACOLSUCCESS) {
533         dest_tkt();
534         return SIADFAIL;
535     }
536     if(strcmp(new_pw1, new_pw2) != 0){
537         sia_message(collect, SIAWARNING, "", "Password mismatch.");
538         goto again;
539     }
540     ret = kadm_check_pw(new_pw1);
541     if(ret) {
542         sia_message(collect, SIAWARNING, "", com_right(et_list, ret));
543         goto again;
544     }
545     
546     memset(new_pw2, 0, sizeof(new_pw2));
547     ret = kadm_init_link (PWSERV_NAME, KRB_MASTER, princ.realm);
548     if (ret != KADM_SUCCESS)
549         sia_message(collect, SIAWARNING, "Error initing kadmin connection", 
550                     com_right(et_list, ret));
551     else {
552         des_cblock newkey;
553         char *pw_msg; /* message from server */
554
555         des_string_to_key(new_pw1, &newkey);
556         ret = kadm_change_pw_plain((unsigned char*)&newkey, new_pw1, &pw_msg);
557         memset(newkey, 0, sizeof(newkey));
558       
559         if (ret == KADM_INSECURE_PW)
560             sia_message(collect, SIAWARNING, "Insecure password", pw_msg);
561         else if (ret != KADM_SUCCESS)
562             sia_message(collect, SIAWARNING, "Error changing password", 
563                         com_right(et_list, ret));
564     }
565     memset(new_pw1, 0, sizeof(new_pw1));
566
567     if (ret != KADM_SUCCESS)
568         sia_message(collect, SIAWARNING, "", "Password NOT changed.");
569     else
570         sia_message(collect, SIAINFO, "", "Password changed.");
571     
572     dest_tkt();
573     if(ret)
574         return SIADFAIL;
575     return SIADSUCCESS;
576 }
577 #endif
578
579 int
580 siad_chg_shell (sia_collect_func_t *collect,
581                      const char *username, 
582                      int argc, 
583                      char *argv[])
584 {
585     return SIADFAIL;
586 }
587
588 int
589 siad_getpwent(struct passwd *result, 
590               char *buf, 
591               int bufsize, 
592               struct sia_context *context)
593 {
594     return SIADFAIL;
595 }
596
597 int
598 siad_getpwuid (uid_t uid, 
599                struct passwd *result, 
600                char *buf, 
601                int bufsize, 
602                struct sia_context *context)
603 {
604     return SIADFAIL;
605 }
606
607 int
608 siad_getpwnam (const char *name, 
609                struct passwd *result, 
610                char *buf, 
611                int bufsize, 
612                struct sia_context *context)
613 {
614     return SIADFAIL;
615 }
616
617 int
618 siad_setpwent (struct sia_context *context)
619 {
620     return SIADFAIL;
621 }
622
623 int
624 siad_endpwent (struct sia_context *context)
625 {
626     return SIADFAIL;
627 }
628
629 int
630 siad_getgrent(struct group *result, 
631               char *buf, 
632               int bufsize, 
633               struct sia_context *context)
634 {
635     return SIADFAIL;
636 }
637
638 int
639 siad_getgrgid (gid_t gid, 
640                struct group *result, 
641                char *buf, 
642                int bufsize, 
643                struct sia_context *context)
644 {
645     return SIADFAIL;
646 }
647
648 int
649 siad_getgrnam (const char *name, 
650                struct group *result, 
651                char *buf, 
652                int bufsize, 
653                struct sia_context *context)
654 {
655     return SIADFAIL;
656 }
657
658 int
659 siad_setgrent (struct sia_context *context)
660 {
661     return SIADFAIL;
662 }
663
664 int
665 siad_endgrent (struct sia_context *context)
666 {
667     return SIADFAIL;
668 }
669
670 int
671 siad_chk_user (const char *logname, int checkflag)
672 {
673     if(checkflag != CHGPASSWD)
674         return SIADFAIL;
675     return SIADSUCCESS;
676 }