2 * Copyright (c) 1995-2000 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.35 2001/02/20 01:44:53 assar Exp $");
45 siad_chk_invoker(void)
47 SIA_DEBUG(("DEBUG", "siad_chk_invoker"));
52 siad_ses_init(SIAENTITY *entity, int pkgind)
55 struct state *s = malloc(sizeof(*s));
57 SIA_DEBUG(("DEBUG", "siad_ses_init"));
60 memset(s, 0, sizeof(*s));
62 ret = krb5_init_context(&s->context);
66 entity->mech[pkgind] = (int*)s;
71 setup_name(SIAENTITY *e, prompt_t *p)
73 SIA_DEBUG(("DEBUG", "setup_name"));
74 e->name = malloc(SIANAMEMIN + 1);
76 SIA_DEBUG(("DEBUG", "failed to malloc %u bytes", SIANAMEMIN+1));
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;
88 setup_password(SIAENTITY *e, prompt_t *p)
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));
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;
106 doauth(SIAENTITY *entity, int pkgind, char *name)
108 struct passwd pw, *pwd;
110 struct state *s = (struct state*)entity->mech[pkgind];
112 krb5_realm *realms, *r;
113 krb5_principal principal;
118 char realm[REALM_SZ];
119 char *toname, *toinst;
121 struct passwd fpw, *fpwd;
126 if(getpwnam_r(name, &pw, pwbuf, sizeof(pwbuf), &pwd) != 0){
127 SIA_DEBUG(("DEBUG", "failed to getpwnam(%s)", name));
132 ret = krb5_get_default_realms(s->context, &realms);
134 for (r = realms; *r != NULL; ++r) {
135 krb5_make_principal (s->context, &principal, *r, entity->name, NULL);
137 if(krb5_kuserok(s->context, principal, entity->name))
140 krb5_free_host_realm (s->context, realms);
144 sprintf(s->ticket, "FILE:/tmp/krb5_cc%d_%d", pwd->pw_uid, getpid());
145 ret = krb5_cc_resolve(s->context, s->ticket, &ccache);
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);
156 if(entity->authtype == SIA_A_SUAUTH){
158 #ifdef HAVE_SIAENTITY_OUID
163 if(getpwuid_r(ouid, &fpw, fpwbuf, sizeof(fpwbuf), &fpwd) != 0){
164 SIA_DEBUG(("DEBUG", "failed to getpwuid(%u)", ouid));
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;
174 if(entity->authtype == SIA_A_REAUTH)
175 snprintf(s->ticket, sizeof(s->ticket), "%s", tkt_string());
177 krb_set_tkt_string(s->ticket);
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));
187 ret = krb5_verify_user_lrealm(s->context, principal, ccache,
188 entity->password, 1, NULL);
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));
202 secure = KRB_VERIFY_SECURE;
204 secure = KRB_VERIFY_NOT_SECURE;
206 ret = krb_verify_user(toname, toinst, realm,
207 entity->password, secure, NULL);
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));
219 if(sia_make_entity_pwd(pwd, entity) == SIAFAIL)
227 common_auth(sia_collect_func_t *collect,
232 prompt_t prompts[2], *pr;
235 SIA_DEBUG(("DEBUG", "common_auth"));
236 if((siastat == SIADSUCCESS) && (geteuid() == 0))
239 SIA_DEBUG(("DEBUG", "entity == NULL"));
240 return SIADFAIL | SIADSTOP;
244 name = entity->acctname;
246 if((collect != NULL) && entity->colinput) {
250 if(setup_name(entity, pr) != SIADSUCCESS)
254 if(entity->password == NULL){
255 if(setup_password(entity, pr) != SIADSUCCESS)
261 if((*collect)(240, SIAONELINER, (unsigned char*)"", num,
262 prompts) != SIACOLSUCCESS){
263 SIA_DEBUG(("DEBUG", "collect failed"));
264 return SIADFAIL | SIADSTOP;
267 if((*collect)(0, SIAFORM, (unsigned char*)"", num,
268 prompts) != SIACOLSUCCESS){
269 SIA_DEBUG(("DEBUG", "collect failed"));
270 return SIADFAIL | SIADSTOP;
276 if(name == NULL || name[0] == '\0'){
277 SIA_DEBUG(("DEBUG", "name is null"));
281 if(entity->password == NULL || strlen(entity->password) > SIAMXPASSWORD){
282 SIA_DEBUG(("DEBUG", "entity->password is null"));
286 return doauth(entity, pkgind, name);
291 siad_ses_authent(sia_collect_func_t *collect,
296 SIA_DEBUG(("DEBUG", "siad_ses_authent"));
297 return common_auth(collect, entity, siastat, pkgind);
301 siad_ses_estab(sia_collect_func_t *collect,
302 SIAENTITY *entity, int pkgind)
304 SIA_DEBUG(("DEBUG", "siad_ses_estab"));
309 siad_ses_launch(sia_collect_func_t *collect,
313 static char env[MaxPathLen];
314 struct state *s = (struct state*)entity->mech[pkgind];
315 SIA_DEBUG(("DEBUG", "siad_ses_launch"));
318 chown(s->ticket + sizeof("FILE:") - 1,
320 entity->pwd->pw_gid);
321 snprintf(env, sizeof(env), "KRB5CCNAME=%s", s->ticket);
324 chown(s->ticket, entity->pwd->pw_uid, entity->pwd->pw_gid);
325 snprintf(env, sizeof(env), "KRBTKFILE=%s", s->ticket);
333 if(k_afs_cell_of_file(entity->pwd->pw_dir, cell, sizeof(cell)) == 0)
335 krb_afslog_home(0, 0, entity->pwd->pw_dir);
342 siad_ses_release(SIAENTITY *entity, int pkgind)
344 SIA_DEBUG(("DEBUG", "siad_ses_release"));
345 if(entity->mech[pkgind]){
347 struct state *s = (struct state*)entity->mech[pkgind];
348 krb5_free_context(s->context);
350 free(entity->mech[pkgind]);
356 siad_ses_suauthent(sia_collect_func_t *collect,
361 SIA_DEBUG(("DEBUG", "siad_ses_suauth"));
364 if(entity->name == NULL)
366 if(entity->name[0] == '\0') {
368 entity->name = strdup("root");
369 if (entity->name == NULL)
372 return common_auth(collect, entity, siastat, pkgind);
376 siad_ses_reauthent (sia_collect_func_t *collect,
382 SIA_DEBUG(("DEBUG", "siad_ses_reauthent"));
383 if(entity == NULL || entity->name == NULL)
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);
394 if(k_afs_cell_of_file(entity->pwd->pw_dir,
395 cell, sizeof(cell)) == 0)
397 krb_afslog_home(0, 0, entity->pwd->pw_dir);
405 siad_chg_finger (sia_collect_func_t *collect,
406 const char *username,
410 SIA_DEBUG(("DEBUG", "siad_chg_finger"));
416 siad_chg_password (sia_collect_func_t *collect,
417 const char *username,
427 sia_message(sia_collect_func_t *collect, int rendition,
428 const char *title, const char *message)
431 prompt.prompt = (unsigned char*)message;
432 (*collect)(0, rendition, (unsigned char*)title, 1, &prompt);
436 init_change(sia_collect_func_t *collect, krb_principal *princ)
439 char old_pw[MAX_KPW_LEN+1];
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));
452 SIA_DEBUG(("DEBUG", "out of memory"));
455 ret = (*collect)(60, SIAONELINER, (unsigned char*)msg, 1, &prompt);
457 SIA_DEBUG(("DEBUG", "ret = %d", ret));
458 if(ret != SIACOLSUCCESS)
460 snprintf(tktstring, sizeof(tktstring),
461 "%s_cpw_%u", TKT_ROOT, (unsigned)getpid());
462 krb_set_tkt_string(tktstring);
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.");
471 sia_message(collect, SIAWARNING, "", "Kerberos error.");
472 memset(old_pw, 0, sizeof(old_pw));
475 if(chown(tktstring, getuid(), -1) < 0){
479 memset(old_pw, 0, sizeof(old_pw));
484 siad_chg_password (sia_collect_func_t *collect,
485 const char *username,
492 char new_pw1[MAX_KPW_LEN+1];
493 char new_pw2[MAX_KPW_LEN+1];
494 static struct et_list *et_list;
496 setprogname(argv[0]);
498 SIA_DEBUG(("DEBUG", "siad_chg_password"));
503 username = getlogin();
505 ret = krb_parse_name(username, &princ);
508 if(princ.realm[0] == '\0')
509 krb_get_lrealm(princ.realm, 1);
511 if(et_list == NULL) {
512 initialize_kadm_error_table_r(&et_list);
513 initialize_krb_error_table_r(&et_list);
516 ret = init_change(collect, &princ);
517 if(ret != SIADSUCCESS)
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) !=
536 if(strcmp(new_pw1, new_pw2) != 0){
537 sia_message(collect, SIAWARNING, "", "Password mismatch.");
540 ret = kadm_check_pw(new_pw1);
542 sia_message(collect, SIAWARNING, "", com_right(et_list, ret));
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));
553 char *pw_msg; /* message from server */
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));
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));
565 memset(new_pw1, 0, sizeof(new_pw1));
567 if (ret != KADM_SUCCESS)
568 sia_message(collect, SIAWARNING, "", "Password NOT changed.");
570 sia_message(collect, SIAINFO, "", "Password changed.");
580 siad_chg_shell (sia_collect_func_t *collect,
581 const char *username,
589 siad_getpwent(struct passwd *result,
592 struct sia_context *context)
598 siad_getpwuid (uid_t uid,
599 struct passwd *result,
602 struct sia_context *context)
608 siad_getpwnam (const char *name,
609 struct passwd *result,
612 struct sia_context *context)
618 siad_setpwent (struct sia_context *context)
624 siad_endpwent (struct sia_context *context)
630 siad_getgrent(struct group *result,
633 struct sia_context *context)
639 siad_getgrgid (gid_t gid,
640 struct group *result,
643 struct sia_context *context)
649 siad_getgrnam (const char *name,
650 struct group *result,
653 struct sia_context *context)
659 siad_setgrent (struct sia_context *context)
665 siad_endgrent (struct sia_context *context)
671 siad_chk_user (const char *logname, int checkflag)
673 if(checkflag != CHGPASSWD)