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("$Heimdal: sia.c 14838 2005-04-19 04:41:07Z lha $"
46 siad_chk_invoker(void)
48 SIA_DEBUG(("DEBUG", "siad_chk_invoker"));
53 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
));
64 ret
= krb5_init_context(&s
->context
);
69 entity
->mech
[pkgind
] = (int*)s
;
74 setup_name(SIAENTITY
*e
, prompt_t
*p
)
76 SIA_DEBUG(("DEBUG", "setup_name"));
77 e
->name
= malloc(SIANAMEMIN
+ 1);
79 SIA_DEBUG(("DEBUG", "failed to malloc %u bytes", SIANAMEMIN
+1));
82 p
->prompt
= (unsigned char*)"login: ";
83 p
->result
= (unsigned char*)e
->name
;
84 p
->min_result_length
= 1;
85 p
->max_result_length
= SIANAMEMIN
;
91 setup_password(SIAENTITY
*e
, prompt_t
*p
)
93 SIA_DEBUG(("DEBUG", "setup_password"));
94 e
->password
= malloc(SIAMXPASSWORD
+ 1);
95 if(e
->password
== NULL
){
96 SIA_DEBUG(("DEBUG", "failed to malloc %u bytes", SIAMXPASSWORD
+1));
99 p
->prompt
= (unsigned char*)"Password: ";
100 p
->result
= (unsigned char*)e
->password
;
101 p
->min_result_length
= 0;
102 p
->max_result_length
= SIAMXPASSWORD
;
103 p
->control_flags
= SIARESINVIS
;
109 doauth(SIAENTITY
*entity
, int pkgind
, char *name
)
111 struct passwd pw
, *pwd
;
113 struct state
*s
= (struct state
*)entity
->mech
[pkgind
];
115 krb5_realm
*realms
, *r
;
116 krb5_principal principal
;
121 char realm
[REALM_SZ
];
122 char *toname
, *toinst
;
124 struct passwd fpw
, *fpwd
;
129 if(getpwnam_r(name
, &pw
, pwbuf
, sizeof(pwbuf
), &pwd
) != 0 || pwd
== NULL
){
130 SIA_DEBUG(("DEBUG", "failed to getpwnam(%s)", name
));
135 ret
= krb5_get_default_realms(s
->context
, &realms
);
137 for (r
= realms
; *r
!= NULL
; ++r
) {
138 krb5_make_principal (s
->context
, &principal
, *r
, entity
->name
, NULL
);
140 if(krb5_kuserok(s
->context
, principal
, entity
->name
))
143 krb5_free_host_realm (s
->context
, realms
);
147 sprintf(s
->ticket
, "FILE:/tmp/krb5_cc%d_%d", pwd
->pw_uid
, getpid());
148 ret
= krb5_cc_resolve(s
->context
, s
->ticket
, &ccache
);
154 snprintf(s
->ticket
, sizeof(s
->ticket
),
155 "%s%u_%u", TKT_ROOT
, (unsigned)pwd
->pw_uid
, (unsigned)getpid());
156 krb_get_lrealm(realm
, 1);
159 if(entity
->authtype
== SIA_A_SUAUTH
){
161 #ifdef HAVE_SIAENTITY_OUID
166 if(getpwuid_r(ouid
, &fpw
, fpwbuf
, sizeof(fpwbuf
), &fpwd
) != 0 || fpwd
== NULL
){
167 SIA_DEBUG(("DEBUG", "failed to getpwuid(%u)", ouid
));
170 snprintf(s
->ticket
, sizeof(s
->ticket
), "%s_%s_to_%s_%d",
171 TKT_ROOT
, fpwd
->pw_name
, pwd
->pw_name
, getpid());
172 if(strcmp(pwd
->pw_name
, "root") == 0){
173 toname
= fpwd
->pw_name
;
174 toinst
= pwd
->pw_name
;
177 if(entity
->authtype
== SIA_A_REAUTH
)
178 snprintf(s
->ticket
, sizeof(s
->ticket
), "%s", tkt_string());
180 krb_set_tkt_string(s
->ticket
);
182 setuid(0); /* XXX fix for fix in tf_util.c */
183 if(krb_kuserok(toname
, toinst
, realm
, name
)){
184 SIA_DEBUG(("DEBUG", "%s.%s@%s is not allowed to login as %s",
185 toname
, toinst
, realm
, name
));
190 ret
= krb5_verify_user_lrealm(s
->context
, principal
, ccache
,
191 entity
->password
, 1, NULL
);
193 /* if this is most likely a local user (such as
194 root), just silently return failure when the
195 principal doesn't exist */
196 if(ret
!= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
&&
197 ret
!= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
)
198 SIALOG("WARNING", "krb5_verify_user(%s): %s",
199 entity
->name
, error_message(ret
));
205 secure
= KRB_VERIFY_SECURE
;
207 secure
= KRB_VERIFY_NOT_SECURE
;
209 ret
= krb_verify_user(toname
, toinst
, realm
,
210 entity
->password
, secure
, NULL
);
212 SIA_DEBUG(("DEBUG", "krb_verify_user: %s", krb_get_err_text(ret
)));
213 if(ret
!= KDC_PR_UNKNOWN
)
214 /* since this is most likely a local user (such as
215 root), just silently return failure when the
216 principal doesn't exist */
217 SIALOG("WARNING", "krb_verify_user(%s.%s): %s",
218 toname
, toinst
, krb_get_err_text(ret
));
222 if(sia_make_entity_pwd(pwd
, entity
) == SIAFAIL
)
230 common_auth(sia_collect_func_t
*collect
,
235 prompt_t prompts
[2], *pr
;
238 SIA_DEBUG(("DEBUG", "common_auth"));
239 if((siastat
== SIADSUCCESS
) && (geteuid() == 0))
242 SIA_DEBUG(("DEBUG", "entity == NULL"));
243 return SIADFAIL
| SIADSTOP
;
247 name
= entity
->acctname
;
249 if((collect
!= NULL
) && entity
->colinput
) {
253 if(setup_name(entity
, pr
) != SIADSUCCESS
)
257 if(entity
->password
== NULL
){
258 if(setup_password(entity
, pr
) != SIADSUCCESS
)
264 if((*collect
)(240, SIAONELINER
, (unsigned char*)"", num
,
265 prompts
) != SIACOLSUCCESS
){
266 SIA_DEBUG(("DEBUG", "collect failed"));
267 return SIADFAIL
| SIADSTOP
;
270 if((*collect
)(0, SIAFORM
, (unsigned char*)"", num
,
271 prompts
) != SIACOLSUCCESS
){
272 SIA_DEBUG(("DEBUG", "collect failed"));
273 return SIADFAIL
| SIADSTOP
;
279 if(name
== NULL
|| name
[0] == '\0'){
280 SIA_DEBUG(("DEBUG", "name is null"));
284 if(entity
->password
== NULL
|| strlen(entity
->password
) > SIAMXPASSWORD
){
285 SIA_DEBUG(("DEBUG", "entity->password is null"));
289 return doauth(entity
, pkgind
, name
);
294 siad_ses_authent(sia_collect_func_t
*collect
,
299 SIA_DEBUG(("DEBUG", "siad_ses_authent"));
300 return common_auth(collect
, entity
, siastat
, pkgind
);
304 siad_ses_estab(sia_collect_func_t
*collect
,
305 SIAENTITY
*entity
, int pkgind
)
307 SIA_DEBUG(("DEBUG", "siad_ses_estab"));
312 siad_ses_launch(sia_collect_func_t
*collect
,
316 static char env
[MaxPathLen
];
317 struct state
*s
= (struct state
*)entity
->mech
[pkgind
];
318 SIA_DEBUG(("DEBUG", "siad_ses_launch"));
321 chown(s
->ticket
+ sizeof("FILE:") - 1,
323 entity
->pwd
->pw_gid
);
324 snprintf(env
, sizeof(env
), "KRB5CCNAME=%s", s
->ticket
);
327 chown(s
->ticket
, entity
->pwd
->pw_uid
, entity
->pwd
->pw_gid
);
328 snprintf(env
, sizeof(env
), "KRBTKFILE=%s", s
->ticket
);
336 if(krb5_cc_resolve(s
->context
, s
->ticket
, &ccache
) == 0) {
338 if(k_afs_cell_of_file(entity
->pwd
->pw_dir
, cell
, sizeof(cell
)) == 0)
339 krb5_afslog(s
->context
, ccache
, cell
, 0);
340 krb5_afslog_home(s
->context
, ccache
, 0, 0, entity
->pwd
->pw_dir
);
348 if(k_afs_cell_of_file(entity
->pwd
->pw_dir
, cell
, sizeof(cell
)) == 0)
350 krb_afslog_home(0, 0, entity
->pwd
->pw_dir
);
357 siad_ses_release(SIAENTITY
*entity
, int pkgind
)
359 SIA_DEBUG(("DEBUG", "siad_ses_release"));
360 if(entity
->mech
[pkgind
]){
362 struct state
*s
= (struct state
*)entity
->mech
[pkgind
];
363 krb5_free_context(s
->context
);
365 free(entity
->mech
[pkgind
]);
371 siad_ses_suauthent(sia_collect_func_t
*collect
,
376 SIA_DEBUG(("DEBUG", "siad_ses_suauth"));
379 if(entity
->name
== NULL
)
381 if(entity
->name
[0] == '\0') {
383 entity
->name
= strdup("root");
384 if (entity
->name
== NULL
)
387 return common_auth(collect
, entity
, siastat
, pkgind
);
391 siad_ses_reauthent (sia_collect_func_t
*collect
,
397 SIA_DEBUG(("DEBUG", "siad_ses_reauthent"));
398 if(entity
== NULL
|| entity
->name
== NULL
)
400 ret
= common_auth(collect
, entity
, siastat
, pkgind
);
401 if((ret
& SIADSUCCESS
)){
402 /* launch isn't (always?) called when doing reauth, so we must
403 duplicate some code here... */
404 struct state
*s
= (struct state
*)entity
->mech
[pkgind
];
405 chown(s
->ticket
, entity
->pwd
->pw_uid
, entity
->pwd
->pw_gid
);
410 if(krb5_cc_resolve(s
->context
, s
->ticket
, &ccache
) == 0) {
412 if(k_afs_cell_of_file(entity
->pwd
->pw_dir
,
413 cell
, sizeof(cell
)) == 0)
414 krb5_afslog(s
->context
, ccache
, cell
, 0);
415 krb5_afslog_home(s
->context
, ccache
, 0, 0, entity
->pwd
->pw_dir
);
422 if(k_afs_cell_of_file(entity
->pwd
->pw_dir
,
423 cell
, sizeof(cell
)) == 0)
425 krb_afslog_home(0, 0, entity
->pwd
->pw_dir
);
433 siad_chg_finger (sia_collect_func_t
*collect
,
434 const char *username
,
438 SIA_DEBUG(("DEBUG", "siad_chg_finger"));
444 siad_chg_password (sia_collect_func_t
*collect
,
445 const char *username
,
455 sia_message(sia_collect_func_t
*collect
, int rendition
,
456 const char *title
, const char *message
)
459 prompt
.prompt
= (unsigned char*)message
;
460 (*collect
)(0, rendition
, (unsigned char*)title
, 1, &prompt
);
464 init_change(sia_collect_func_t
*collect
, krb_principal
*princ
)
467 char old_pw
[MAX_KPW_LEN
+1];
472 SIA_DEBUG(("DEBUG", "init_change"));
473 prompt
.prompt
= (unsigned char*)"Old password: ";
474 prompt
.result
= (unsigned char*)old_pw
;
475 prompt
.min_result_length
= 0;
476 prompt
.max_result_length
= sizeof(old_pw
) - 1;
477 prompt
.control_flags
= SIARESINVIS
;
478 asprintf(&msg
, "Changing password for %s", krb_unparse_name(princ
));
480 SIA_DEBUG(("DEBUG", "out of memory"));
483 ret
= (*collect
)(60, SIAONELINER
, (unsigned char*)msg
, 1, &prompt
);
485 SIA_DEBUG(("DEBUG", "ret = %d", ret
));
486 if(ret
!= SIACOLSUCCESS
)
488 snprintf(tktstring
, sizeof(tktstring
),
489 "%s_cpw_%u", TKT_ROOT
, (unsigned)getpid());
490 krb_set_tkt_string(tktstring
);
492 ret
= krb_get_pw_in_tkt(princ
->name
, princ
->instance
, princ
->realm
,
493 PWSERV_NAME
, KADM_SINST
, 1, old_pw
);
494 if (ret
!= KSUCCESS
) {
495 SIA_DEBUG(("DEBUG", "krb_get_pw_in_tkt: %s", krb_get_err_text(ret
)));
496 if (ret
== INTK_BADPW
)
497 sia_message(collect
, SIAWARNING
, "", "Incorrect old password.");
499 sia_message(collect
, SIAWARNING
, "", "Kerberos error.");
500 memset(old_pw
, 0, sizeof(old_pw
));
503 if(chown(tktstring
, getuid(), -1) < 0){
507 memset(old_pw
, 0, sizeof(old_pw
));
512 siad_chg_password (sia_collect_func_t
*collect
,
513 const char *username
,
520 char new_pw1
[MAX_KPW_LEN
+1];
521 char new_pw2
[MAX_KPW_LEN
+1];
522 static struct et_list
*et_list
;
524 setprogname(argv
[0]);
526 SIA_DEBUG(("DEBUG", "siad_chg_password"));
531 username
= getlogin();
533 ret
= krb_parse_name(username
, &princ
);
536 if(princ
.realm
[0] == '\0')
537 krb_get_lrealm(princ
.realm
, 1);
539 if(et_list
== NULL
) {
540 initialize_kadm_error_table_r(&et_list
);
541 initialize_krb_error_table_r(&et_list
);
544 ret
= init_change(collect
, &princ
);
545 if(ret
!= SIADSUCCESS
)
549 prompts
[0].prompt
= (unsigned char*)"New password: ";
550 prompts
[0].result
= (unsigned char*)new_pw1
;
551 prompts
[0].min_result_length
= MIN_KPW_LEN
;
552 prompts
[0].max_result_length
= sizeof(new_pw1
) - 1;
553 prompts
[0].control_flags
= SIARESINVIS
;
554 prompts
[1].prompt
= (unsigned char*)"Verify new password: ";
555 prompts
[1].result
= (unsigned char*)new_pw2
;
556 prompts
[1].min_result_length
= MIN_KPW_LEN
;
557 prompts
[1].max_result_length
= sizeof(new_pw2
) - 1;
558 prompts
[1].control_flags
= SIARESINVIS
;
559 if((*collect
)(120, SIAFORM
, (unsigned char*)"", 2, prompts
) !=
564 if(strcmp(new_pw1
, new_pw2
) != 0){
565 sia_message(collect
, SIAWARNING
, "", "Password mismatch.");
568 ret
= kadm_check_pw(new_pw1
);
570 sia_message(collect
, SIAWARNING
, "", com_right(et_list
, ret
));
574 memset(new_pw2
, 0, sizeof(new_pw2
));
575 ret
= kadm_init_link (PWSERV_NAME
, KRB_MASTER
, princ
.realm
);
576 if (ret
!= KADM_SUCCESS
)
577 sia_message(collect
, SIAWARNING
, "Error initing kadmin connection",
578 com_right(et_list
, ret
));
581 char *pw_msg
; /* message from server */
583 des_string_to_key(new_pw1
, &newkey
);
584 ret
= kadm_change_pw_plain((unsigned char*)&newkey
, new_pw1
, &pw_msg
);
585 memset(newkey
, 0, sizeof(newkey
));
587 if (ret
== KADM_INSECURE_PW
)
588 sia_message(collect
, SIAWARNING
, "Insecure password", pw_msg
);
589 else if (ret
!= KADM_SUCCESS
)
590 sia_message(collect
, SIAWARNING
, "Error changing password",
591 com_right(et_list
, ret
));
593 memset(new_pw1
, 0, sizeof(new_pw1
));
595 if (ret
!= KADM_SUCCESS
)
596 sia_message(collect
, SIAWARNING
, "", "Password NOT changed.");
598 sia_message(collect
, SIAINFO
, "", "Password changed.");
608 siad_chg_shell (sia_collect_func_t
*collect
,
609 const char *username
,
617 siad_getpwent(struct passwd
*result
,
620 struct sia_context
*context
)
626 siad_getpwuid (uid_t uid
,
627 struct passwd
*result
,
630 struct sia_context
*context
)
636 siad_getpwnam (const char *name
,
637 struct passwd
*result
,
640 struct sia_context
*context
)
646 siad_setpwent (struct sia_context
*context
)
652 siad_endpwent (struct sia_context
*context
)
658 siad_getgrent(struct group
*result
,
661 struct sia_context
*context
)
667 siad_getgrgid (gid_t gid
,
668 struct group
*result
,
671 struct sia_context
*context
)
677 siad_getgrnam (const char *name
,
678 struct group
*result
,
681 struct sia_context
*context
)
687 siad_setgrent (struct sia_context
*context
)
693 siad_endgrent (struct sia_context
*context
)
699 siad_chk_user (const char *logname
, int checkflag
)
701 if(checkflag
!= CHGPASSWD
)