2 * Copyright (c) 1995-2001 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.36 2001/09/13 01:19:14 assar 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));
56 SIA_DEBUG(("DEBUG", "siad_ses_init"));
59 memset(s, 0, sizeof(*s));
63 ret = krb5_init_context(&s->context);
68 entity->mech[pkgind] = (int*)s;
73 setup_name(SIAENTITY *e, prompt_t *p)
75 SIA_DEBUG(("DEBUG", "setup_name"));
76 e->name = malloc(SIANAMEMIN + 1);
78 SIA_DEBUG(("DEBUG", "failed to malloc %u bytes", SIANAMEMIN+1));
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;
90 setup_password(SIAENTITY *e, prompt_t *p)
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));
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;
108 doauth(SIAENTITY *entity, int pkgind, char *name)
110 struct passwd pw, *pwd;
112 struct state *s = (struct state*)entity->mech[pkgind];
114 krb5_realm *realms, *r;
115 krb5_principal principal;
120 char realm[REALM_SZ];
121 char *toname, *toinst;
123 struct passwd fpw, *fpwd;
128 if(getpwnam_r(name, &pw, pwbuf, sizeof(pwbuf), &pwd) != 0){
129 SIA_DEBUG(("DEBUG", "failed to getpwnam(%s)", name));
134 ret = krb5_get_default_realms(s->context, &realms);
136 for (r = realms; *r != NULL; ++r) {
137 krb5_make_principal (s->context, &principal, *r, entity->name, NULL);
139 if(krb5_kuserok(s->context, principal, entity->name))
142 krb5_free_host_realm (s->context, realms);
146 sprintf(s->ticket, "FILE:/tmp/krb5_cc%d_%d", pwd->pw_uid, getpid());
147 ret = krb5_cc_resolve(s->context, s->ticket, &ccache);
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);
158 if(entity->authtype == SIA_A_SUAUTH){
160 #ifdef HAVE_SIAENTITY_OUID
165 if(getpwuid_r(ouid, &fpw, fpwbuf, sizeof(fpwbuf), &fpwd) != 0){
166 SIA_DEBUG(("DEBUG", "failed to getpwuid(%u)", ouid));
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;
176 if(entity->authtype == SIA_A_REAUTH)
177 snprintf(s->ticket, sizeof(s->ticket), "%s", tkt_string());
179 krb_set_tkt_string(s->ticket);
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));
189 ret = krb5_verify_user_lrealm(s->context, principal, ccache,
190 entity->password, 1, NULL);
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));
204 secure = KRB_VERIFY_SECURE;
206 secure = KRB_VERIFY_NOT_SECURE;
208 ret = krb_verify_user(toname, toinst, realm,
209 entity->password, secure, NULL);
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));
221 if(sia_make_entity_pwd(pwd, entity) == SIAFAIL)
229 common_auth(sia_collect_func_t *collect,
234 prompt_t prompts[2], *pr;
237 SIA_DEBUG(("DEBUG", "common_auth"));
238 if((siastat == SIADSUCCESS) && (geteuid() == 0))
241 SIA_DEBUG(("DEBUG", "entity == NULL"));
242 return SIADFAIL | SIADSTOP;
246 name = entity->acctname;
248 if((collect != NULL) && entity->colinput) {
252 if(setup_name(entity, pr) != SIADSUCCESS)
256 if(entity->password == NULL){
257 if(setup_password(entity, pr) != SIADSUCCESS)
263 if((*collect)(240, SIAONELINER, (unsigned char*)"", num,
264 prompts) != SIACOLSUCCESS){
265 SIA_DEBUG(("DEBUG", "collect failed"));
266 return SIADFAIL | SIADSTOP;
269 if((*collect)(0, SIAFORM, (unsigned char*)"", num,
270 prompts) != SIACOLSUCCESS){
271 SIA_DEBUG(("DEBUG", "collect failed"));
272 return SIADFAIL | SIADSTOP;
278 if(name == NULL || name[0] == '\0'){
279 SIA_DEBUG(("DEBUG", "name is null"));
283 if(entity->password == NULL || strlen(entity->password) > SIAMXPASSWORD){
284 SIA_DEBUG(("DEBUG", "entity->password is null"));
288 return doauth(entity, pkgind, name);
293 siad_ses_authent(sia_collect_func_t *collect,
298 SIA_DEBUG(("DEBUG", "siad_ses_authent"));
299 return common_auth(collect, entity, siastat, pkgind);
303 siad_ses_estab(sia_collect_func_t *collect,
304 SIAENTITY *entity, int pkgind)
306 SIA_DEBUG(("DEBUG", "siad_ses_estab"));
311 siad_ses_launch(sia_collect_func_t *collect,
315 static char env[MaxPathLen];
316 struct state *s = (struct state*)entity->mech[pkgind];
317 SIA_DEBUG(("DEBUG", "siad_ses_launch"));
320 chown(s->ticket + sizeof("FILE:") - 1,
322 entity->pwd->pw_gid);
323 snprintf(env, sizeof(env), "KRB5CCNAME=%s", s->ticket);
326 chown(s->ticket, entity->pwd->pw_uid, entity->pwd->pw_gid);
327 snprintf(env, sizeof(env), "KRBTKFILE=%s", s->ticket);
335 if(k_afs_cell_of_file(entity->pwd->pw_dir, cell, sizeof(cell)) == 0)
337 krb_afslog_home(0, 0, entity->pwd->pw_dir);
344 siad_ses_release(SIAENTITY *entity, int pkgind)
346 SIA_DEBUG(("DEBUG", "siad_ses_release"));
347 if(entity->mech[pkgind]){
349 struct state *s = (struct state*)entity->mech[pkgind];
350 krb5_free_context(s->context);
352 free(entity->mech[pkgind]);
358 siad_ses_suauthent(sia_collect_func_t *collect,
363 SIA_DEBUG(("DEBUG", "siad_ses_suauth"));
366 if(entity->name == NULL)
368 if(entity->name[0] == '\0') {
370 entity->name = strdup("root");
371 if (entity->name == NULL)
374 return common_auth(collect, entity, siastat, pkgind);
378 siad_ses_reauthent (sia_collect_func_t *collect,
384 SIA_DEBUG(("DEBUG", "siad_ses_reauthent"));
385 if(entity == NULL || entity->name == NULL)
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);
396 if(k_afs_cell_of_file(entity->pwd->pw_dir,
397 cell, sizeof(cell)) == 0)
399 krb_afslog_home(0, 0, entity->pwd->pw_dir);
407 siad_chg_finger (sia_collect_func_t *collect,
408 const char *username,
412 SIA_DEBUG(("DEBUG", "siad_chg_finger"));
418 siad_chg_password (sia_collect_func_t *collect,
419 const char *username,
429 sia_message(sia_collect_func_t *collect, int rendition,
430 const char *title, const char *message)
433 prompt.prompt = (unsigned char*)message;
434 (*collect)(0, rendition, (unsigned char*)title, 1, &prompt);
438 init_change(sia_collect_func_t *collect, krb_principal *princ)
441 char old_pw[MAX_KPW_LEN+1];
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));
454 SIA_DEBUG(("DEBUG", "out of memory"));
457 ret = (*collect)(60, SIAONELINER, (unsigned char*)msg, 1, &prompt);
459 SIA_DEBUG(("DEBUG", "ret = %d", ret));
460 if(ret != SIACOLSUCCESS)
462 snprintf(tktstring, sizeof(tktstring),
463 "%s_cpw_%u", TKT_ROOT, (unsigned)getpid());
464 krb_set_tkt_string(tktstring);
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.");
473 sia_message(collect, SIAWARNING, "", "Kerberos error.");
474 memset(old_pw, 0, sizeof(old_pw));
477 if(chown(tktstring, getuid(), -1) < 0){
481 memset(old_pw, 0, sizeof(old_pw));
486 siad_chg_password (sia_collect_func_t *collect,
487 const char *username,
494 char new_pw1[MAX_KPW_LEN+1];
495 char new_pw2[MAX_KPW_LEN+1];
496 static struct et_list *et_list;
498 setprogname(argv[0]);
500 SIA_DEBUG(("DEBUG", "siad_chg_password"));
505 username = getlogin();
507 ret = krb_parse_name(username, &princ);
510 if(princ.realm[0] == '\0')
511 krb_get_lrealm(princ.realm, 1);
513 if(et_list == NULL) {
514 initialize_kadm_error_table_r(&et_list);
515 initialize_krb_error_table_r(&et_list);
518 ret = init_change(collect, &princ);
519 if(ret != SIADSUCCESS)
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) !=
538 if(strcmp(new_pw1, new_pw2) != 0){
539 sia_message(collect, SIAWARNING, "", "Password mismatch.");
542 ret = kadm_check_pw(new_pw1);
544 sia_message(collect, SIAWARNING, "", com_right(et_list, ret));
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));
555 char *pw_msg; /* message from server */
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));
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));
567 memset(new_pw1, 0, sizeof(new_pw1));
569 if (ret != KADM_SUCCESS)
570 sia_message(collect, SIAWARNING, "", "Password NOT changed.");
572 sia_message(collect, SIAINFO, "", "Password changed.");
582 siad_chg_shell (sia_collect_func_t *collect,
583 const char *username,
591 siad_getpwent(struct passwd *result,
594 struct sia_context *context)
600 siad_getpwuid (uid_t uid,
601 struct passwd *result,
604 struct sia_context *context)
610 siad_getpwnam (const char *name,
611 struct passwd *result,
614 struct sia_context *context)
620 siad_setpwent (struct sia_context *context)
626 siad_endpwent (struct sia_context *context)
632 siad_getgrent(struct group *result,
635 struct sia_context *context)
641 siad_getgrgid (gid_t gid,
642 struct group *result,
645 struct sia_context *context)
651 siad_getgrnam (const char *name,
652 struct group *result,
655 struct sia_context *context)
661 siad_setgrent (struct sia_context *context)
667 siad_endgrent (struct sia_context *context)
673 siad_chk_user (const char *logname, int checkflag)
675 if(checkflag != CHGPASSWD)