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