2 * Copyright (c) 1995-1999 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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
36 RCSID("$Id: sia.c,v 1.32.2.1 1999/12/20 09:49:30 joda Exp $");
45 siad_chk_invoker(void)
47 SIA_DEBUG(("DEBUG", "siad_chk_invoker"));
52 siad_ses_init(SIAENTITY *entity, int pkgind)
54 struct state *s = malloc(sizeof(*s));
55 SIA_DEBUG(("DEBUG", "siad_ses_init"));
58 memset(s, 0, sizeof(*s));
60 krb5_init_context(&s->context);
62 entity->mech[pkgind] = (int*)s;
67 setup_name(SIAENTITY *e, prompt_t *p)
69 SIA_DEBUG(("DEBUG", "setup_name"));
70 e->name = malloc(SIANAMEMIN + 1);
72 SIA_DEBUG(("DEBUG", "failed to malloc %u bytes", SIANAMEMIN+1));
75 p->prompt = (unsigned char*)"login: ";
76 p->result = (unsigned char*)e->name;
77 p->min_result_length = 1;
78 p->max_result_length = SIANAMEMIN;
84 setup_password(SIAENTITY *e, prompt_t *p)
86 SIA_DEBUG(("DEBUG", "setup_password"));
87 e->password = malloc(SIAMXPASSWORD + 1);
88 if(e->password == NULL){
89 SIA_DEBUG(("DEBUG", "failed to malloc %u bytes", SIAMXPASSWORD+1));
92 p->prompt = (unsigned char*)"Password: ";
93 p->result = (unsigned char*)e->password;
94 p->min_result_length = 0;
95 p->max_result_length = SIAMXPASSWORD;
96 p->control_flags = SIARESINVIS;
102 doauth(SIAENTITY *entity, int pkgind, char *name)
104 struct passwd pw, *pwd;
106 struct state *s = (struct state*)entity->mech[pkgind];
108 krb5_realm *realms, *r;
109 krb5_principal principal;
114 char realm[REALM_SZ];
115 char *toname, *toinst;
117 struct passwd fpw, *fpwd;
122 if(getpwnam_r(name, &pw, pwbuf, sizeof(pwbuf), &pwd) != 0){
123 SIA_DEBUG(("DEBUG", "failed to getpwnam(%s)", name));
128 ret = krb5_get_default_realms(s->context, &realms);
130 for (r = realms; *r != NULL; ++r) {
131 krb5_make_principal (s->context, &principal, *r, entity->name, NULL);
133 if(krb5_kuserok(s->context, principal, entity->name))
136 krb5_free_host_realm (s->context, realms);
140 sprintf(s->ticket, "FILE:/tmp/krb5_cc%d_%d", pwd->pw_uid, getpid());
141 ret = krb5_cc_resolve(s->context, s->ticket, &ccache);
147 snprintf(s->ticket, sizeof(s->ticket),
148 "%s%u_%u", TKT_ROOT, (unsigned)pwd->pw_uid, (unsigned)getpid());
149 krb_get_lrealm(realm, 1);
152 if(entity->authtype == SIA_A_SUAUTH){
154 #ifdef HAVE_SIAENTITY_OUID
159 if(getpwuid_r(ouid, &fpw, fpwbuf, sizeof(fpwbuf), &fpwd) != 0){
160 SIA_DEBUG(("DEBUG", "failed to getpwuid(%u)", ouid));
163 snprintf(s->ticket, sizeof(s->ticket), "%s_%s_to_%s_%d",
164 TKT_ROOT, fpwd->pw_name, pwd->pw_name, getpid());
165 if(strcmp(pwd->pw_name, "root") == 0){
166 toname = fpwd->pw_name;
167 toinst = pwd->pw_name;
170 if(entity->authtype == SIA_A_REAUTH)
171 snprintf(s->ticket, sizeof(s->ticket), "%s", tkt_string());
173 krb_set_tkt_string(s->ticket);
175 setuid(0); /* XXX fix for fix in tf_util.c */
176 if(krb_kuserok(toname, toinst, realm, name)){
177 SIA_DEBUG(("DEBUG", "%s.%s@%s is not allowed to login as %s",
178 toname, toinst, realm, name));
183 ret = krb5_verify_user_lrealm(s->context, principal, ccache,
184 entity->password, 1, NULL);
186 /* if this is most likely a local user (such as
187 root), just silently return failure when the
188 principal doesn't exist */
189 if(ret != KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN &&
190 ret != KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN)
191 SIALOG("WARNING", "krb5_verify_user(%s): %s",
192 entity->name, error_message(ret));
198 secure = KRB_VERIFY_SECURE;
200 secure = KRB_VERIFY_NOT_SECURE;
202 ret = krb_verify_user(toname, toinst, realm,
203 entity->password, secure, NULL);
205 SIA_DEBUG(("DEBUG", "krb_verify_user: %s", krb_get_err_text(ret)));
206 if(ret != KDC_PR_UNKNOWN)
207 /* since this is most likely a local user (such as
208 root), just silently return failure when the
209 principal doesn't exist */
210 SIALOG("WARNING", "krb_verify_user(%s.%s): %s",
211 toname, toinst, krb_get_err_text(ret));
215 if(sia_make_entity_pwd(pwd, entity) == SIAFAIL)
223 common_auth(sia_collect_func_t *collect,
228 prompt_t prompts[2], *pr;
231 SIA_DEBUG(("DEBUG", "common_auth"));
232 if((siastat == SIADSUCCESS) && (geteuid() == 0))
235 SIA_DEBUG(("DEBUG", "entity == NULL"));
236 return SIADFAIL | SIADSTOP;
240 name = entity->acctname;
242 if((collect != NULL) && entity->colinput) {
246 if(setup_name(entity, pr) != SIADSUCCESS)
250 if(entity->password == NULL){
251 if(setup_password(entity, pr) != SIADSUCCESS)
257 if((*collect)(240, SIAONELINER, (unsigned char*)"", num,
258 prompts) != SIACOLSUCCESS){
259 SIA_DEBUG(("DEBUG", "collect failed"));
260 return SIADFAIL | SIADSTOP;
263 if((*collect)(0, SIAFORM, (unsigned char*)"", num,
264 prompts) != SIACOLSUCCESS){
265 SIA_DEBUG(("DEBUG", "collect failed"));
266 return SIADFAIL | SIADSTOP;
272 if(name == NULL || name[0] == '\0'){
273 SIA_DEBUG(("DEBUG", "name is null"));
277 if(entity->password == NULL || strlen(entity->password) > SIAMXPASSWORD){
278 SIA_DEBUG(("DEBUG", "entity->password is null"));
282 return doauth(entity, pkgind, name);
287 siad_ses_authent(sia_collect_func_t *collect,
292 SIA_DEBUG(("DEBUG", "siad_ses_authent"));
293 return common_auth(collect, entity, siastat, pkgind);
297 siad_ses_estab(sia_collect_func_t *collect,
298 SIAENTITY *entity, int pkgind)
300 SIA_DEBUG(("DEBUG", "siad_ses_estab"));
305 siad_ses_launch(sia_collect_func_t *collect,
309 static char env[MaxPathLen];
310 struct state *s = (struct state*)entity->mech[pkgind];
311 SIA_DEBUG(("DEBUG", "siad_ses_launch"));
314 chown(s->ticket + sizeof("FILE:") - 1,
316 entity->pwd->pw_gid);
317 snprintf(env, sizeof(env), "KRB5CCNAME=%s", s->ticket);
320 chown(s->ticket, entity->pwd->pw_uid, entity->pwd->pw_gid);
321 snprintf(env, sizeof(env), "KRBTKFILE=%s", s->ticket);
329 if(k_afs_cell_of_file(entity->pwd->pw_dir, cell, sizeof(cell)) == 0)
331 krb_afslog_home(0, 0, entity->pwd->pw_dir);
338 siad_ses_release(SIAENTITY *entity, int pkgind)
340 SIA_DEBUG(("DEBUG", "siad_ses_release"));
341 if(entity->mech[pkgind]){
343 struct state *s = (struct state*)entity->mech[pkgind];
344 krb5_free_context(s->context);
346 free(entity->mech[pkgind]);
352 siad_ses_suauthent(sia_collect_func_t *collect,
357 SIA_DEBUG(("DEBUG", "siad_ses_suauth"));
360 if(entity->name == NULL)
362 if(entity->name[0] == '\0') {
364 entity->name = strdup("root");
365 if (entity->name == NULL)
368 return common_auth(collect, entity, siastat, pkgind);
372 siad_ses_reauthent (sia_collect_func_t *collect,
378 SIA_DEBUG(("DEBUG", "siad_ses_reauthent"));
379 if(entity == NULL || entity->name == NULL)
381 ret = common_auth(collect, entity, siastat, pkgind);
382 if((ret & SIADSUCCESS)){
383 /* launch isn't (always?) called when doing reauth, so we must
384 duplicate some code here... */
385 struct state *s = (struct state*)entity->mech[pkgind];
386 chown(s->ticket, entity->pwd->pw_uid, entity->pwd->pw_gid);
390 if(k_afs_cell_of_file(entity->pwd->pw_dir,
391 cell, sizeof(cell)) == 0)
393 krb_afslog_home(0, 0, entity->pwd->pw_dir);
401 siad_chg_finger (sia_collect_func_t *collect,
402 const char *username,
406 SIA_DEBUG(("DEBUG", "siad_chg_finger"));
412 siad_chg_password (sia_collect_func_t *collect,
413 const char *username,
423 sia_message(sia_collect_func_t *collect, int rendition,
424 const char *title, const char *message)
427 prompt.prompt = (unsigned char*)message;
428 (*collect)(0, rendition, (unsigned char*)title, 1, &prompt);
432 init_change(sia_collect_func_t *collect, krb_principal *princ)
435 char old_pw[MAX_KPW_LEN+1];
440 SIA_DEBUG(("DEBUG", "init_change"));
441 prompt.prompt = (unsigned char*)"Old password: ";
442 prompt.result = (unsigned char*)old_pw;
443 prompt.min_result_length = 0;
444 prompt.max_result_length = sizeof(old_pw) - 1;
445 prompt.control_flags = SIARESINVIS;
446 asprintf(&msg, "Changing password for %s", krb_unparse_name(princ));
448 SIA_DEBUG(("DEBUG", "out of memory"));
451 ret = (*collect)(60, SIAONELINER, (unsigned char*)msg, 1, &prompt);
453 SIA_DEBUG(("DEBUG", "ret = %d", ret));
454 if(ret != SIACOLSUCCESS)
456 snprintf(tktstring, sizeof(tktstring),
457 "%s_cpw_%u", TKT_ROOT, (unsigned)getpid());
458 krb_set_tkt_string(tktstring);
460 ret = krb_get_pw_in_tkt(princ->name, princ->instance, princ->realm,
461 PWSERV_NAME, KADM_SINST, 1, old_pw);
462 if (ret != KSUCCESS) {
463 SIA_DEBUG(("DEBUG", "krb_get_pw_in_tkt: %s", krb_get_err_text(ret)));
464 if (ret == INTK_BADPW)
465 sia_message(collect, SIAWARNING, "", "Incorrect old password.");
467 sia_message(collect, SIAWARNING, "", "Kerberos error.");
468 memset(old_pw, 0, sizeof(old_pw));
471 if(chown(tktstring, getuid(), -1) < 0){
475 memset(old_pw, 0, sizeof(old_pw));
480 siad_chg_password (sia_collect_func_t *collect,
481 const char *username,
488 char new_pw1[MAX_KPW_LEN+1];
489 char new_pw2[MAX_KPW_LEN+1];
490 static struct et_list *et_list;
492 set_progname(argv[0]);
494 SIA_DEBUG(("DEBUG", "siad_chg_password"));
499 username = getlogin();
501 ret = krb_parse_name(username, &princ);
504 if(princ.realm[0] == '\0')
505 krb_get_lrealm(princ.realm, 1);
507 if(et_list == NULL) {
508 initialize_kadm_error_table_r(&et_list);
509 initialize_krb_error_table_r(&et_list);
512 ret = init_change(collect, &princ);
513 if(ret != SIADSUCCESS)
517 prompts[0].prompt = (unsigned char*)"New password: ";
518 prompts[0].result = (unsigned char*)new_pw1;
519 prompts[0].min_result_length = MIN_KPW_LEN;
520 prompts[0].max_result_length = sizeof(new_pw1) - 1;
521 prompts[0].control_flags = SIARESINVIS;
522 prompts[1].prompt = (unsigned char*)"Verify new password: ";
523 prompts[1].result = (unsigned char*)new_pw2;
524 prompts[1].min_result_length = MIN_KPW_LEN;
525 prompts[1].max_result_length = sizeof(new_pw2) - 1;
526 prompts[1].control_flags = SIARESINVIS;
527 if((*collect)(120, SIAFORM, (unsigned char*)"", 2, prompts) !=
532 if(strcmp(new_pw1, new_pw2) != 0){
533 sia_message(collect, SIAWARNING, "", "Password mismatch.");
536 ret = kadm_check_pw(new_pw1);
538 sia_message(collect, SIAWARNING, "", com_right(et_list, ret));
542 memset(new_pw2, 0, sizeof(new_pw2));
543 ret = kadm_init_link (PWSERV_NAME, KRB_MASTER, princ.realm);
544 if (ret != KADM_SUCCESS)
545 sia_message(collect, SIAWARNING, "Error initing kadmin connection",
546 com_right(et_list, ret));
549 char *pw_msg; /* message from server */
551 des_string_to_key(new_pw1, &newkey);
552 ret = kadm_change_pw_plain((unsigned char*)&newkey, new_pw1, &pw_msg);
553 memset(newkey, 0, sizeof(newkey));
555 if (ret == KADM_INSECURE_PW)
556 sia_message(collect, SIAWARNING, "Insecure password", pw_msg);
557 else if (ret != KADM_SUCCESS)
558 sia_message(collect, SIAWARNING, "Error changing password",
559 com_right(et_list, ret));
561 memset(new_pw1, 0, sizeof(new_pw1));
563 if (ret != KADM_SUCCESS)
564 sia_message(collect, SIAWARNING, "", "Password NOT changed.");
566 sia_message(collect, SIAINFO, "", "Password changed.");
576 siad_chg_shell (sia_collect_func_t *collect,
577 const char *username,
585 siad_getpwent(struct passwd *result,
588 struct sia_context *context)
594 siad_getpwuid (uid_t uid,
595 struct passwd *result,
598 struct sia_context *context)
604 siad_getpwnam (const char *name,
605 struct passwd *result,
608 struct sia_context *context)
614 siad_setpwent (struct sia_context *context)
620 siad_endpwent (struct sia_context *context)
626 siad_getgrent(struct group *result,
629 struct sia_context *context)
635 siad_getgrgid (gid_t gid,
636 struct group *result,
639 struct sia_context *context)
645 siad_getgrnam (const char *name,
646 struct group *result,
649 struct sia_context *context)
655 siad_setgrent (struct sia_context *context)
661 siad_endgrent (struct sia_context *context)
667 siad_chk_user (const char *logname, int checkflag)
669 if(checkflag != CHGPASSWD)