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
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 || pwd
== NULL
){
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 || fpwd
== NULL
){
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(krb5_cc_resolve(s
->context
, s
->ticket
, &ccache
) == 0) {
337 if(k_afs_cell_of_file(entity
->pwd
->pw_dir
, cell
, sizeof(cell
)) == 0)
338 krb5_afslog(s
->context
, ccache
, cell
, 0);
339 krb5_afslog_home(s
->context
, ccache
, 0, 0, entity
->pwd
->pw_dir
);
347 if(k_afs_cell_of_file(entity
->pwd
->pw_dir
, cell
, sizeof(cell
)) == 0)
349 krb_afslog_home(0, 0, entity
->pwd
->pw_dir
);
356 siad_ses_release(SIAENTITY
*entity
, int pkgind
)
358 SIA_DEBUG(("DEBUG", "siad_ses_release"));
359 if(entity
->mech
[pkgind
]){
361 struct state
*s
= (struct state
*)entity
->mech
[pkgind
];
362 krb5_free_context(s
->context
);
364 free(entity
->mech
[pkgind
]);
370 siad_ses_suauthent(sia_collect_func_t
*collect
,
375 SIA_DEBUG(("DEBUG", "siad_ses_suauth"));
378 if(entity
->name
== NULL
)
380 if(entity
->name
[0] == '\0') {
382 entity
->name
= strdup("root");
383 if (entity
->name
== NULL
)
386 return common_auth(collect
, entity
, siastat
, pkgind
);
390 siad_ses_reauthent (sia_collect_func_t
*collect
,
396 SIA_DEBUG(("DEBUG", "siad_ses_reauthent"));
397 if(entity
== NULL
|| entity
->name
== NULL
)
399 ret
= common_auth(collect
, entity
, siastat
, pkgind
);
400 if((ret
& SIADSUCCESS
)){
401 /* launch isn't (always?) called when doing reauth, so we must
402 duplicate some code here... */
403 struct state
*s
= (struct state
*)entity
->mech
[pkgind
];
404 chown(s
->ticket
, entity
->pwd
->pw_uid
, entity
->pwd
->pw_gid
);
409 if(krb5_cc_resolve(s
->context
, s
->ticket
, &ccache
) == 0) {
411 if(k_afs_cell_of_file(entity
->pwd
->pw_dir
,
412 cell
, sizeof(cell
)) == 0)
413 krb5_afslog(s
->context
, ccache
, cell
, 0);
414 krb5_afslog_home(s
->context
, ccache
, 0, 0, entity
->pwd
->pw_dir
);
421 if(k_afs_cell_of_file(entity
->pwd
->pw_dir
,
422 cell
, sizeof(cell
)) == 0)
424 krb_afslog_home(0, 0, entity
->pwd
->pw_dir
);
432 siad_chg_finger (sia_collect_func_t
*collect
,
433 const char *username
,
437 SIA_DEBUG(("DEBUG", "siad_chg_finger"));
443 siad_chg_password (sia_collect_func_t
*collect
,
444 const char *username
,
454 sia_message(sia_collect_func_t
*collect
, int rendition
,
455 const char *title
, const char *message
)
458 prompt
.prompt
= (unsigned char*)message
;
459 (*collect
)(0, rendition
, (unsigned char*)title
, 1, &prompt
);
463 init_change(sia_collect_func_t
*collect
, krb_principal
*princ
)
466 char old_pw
[MAX_KPW_LEN
+1];
471 SIA_DEBUG(("DEBUG", "init_change"));
472 prompt
.prompt
= (unsigned char*)"Old password: ";
473 prompt
.result
= (unsigned char*)old_pw
;
474 prompt
.min_result_length
= 0;
475 prompt
.max_result_length
= sizeof(old_pw
) - 1;
476 prompt
.control_flags
= SIARESINVIS
;
477 asprintf(&msg
, "Changing password for %s", krb_unparse_name(princ
));
479 SIA_DEBUG(("DEBUG", "out of memory"));
482 ret
= (*collect
)(60, SIAONELINER
, (unsigned char*)msg
, 1, &prompt
);
484 SIA_DEBUG(("DEBUG", "ret = %d", ret
));
485 if(ret
!= SIACOLSUCCESS
)
487 snprintf(tktstring
, sizeof(tktstring
),
488 "%s_cpw_%u", TKT_ROOT
, (unsigned)getpid());
489 krb_set_tkt_string(tktstring
);
491 ret
= krb_get_pw_in_tkt(princ
->name
, princ
->instance
, princ
->realm
,
492 PWSERV_NAME
, KADM_SINST
, 1, old_pw
);
493 if (ret
!= KSUCCESS
) {
494 SIA_DEBUG(("DEBUG", "krb_get_pw_in_tkt: %s", krb_get_err_text(ret
)));
495 if (ret
== INTK_BADPW
)
496 sia_message(collect
, SIAWARNING
, "", "Incorrect old password.");
498 sia_message(collect
, SIAWARNING
, "", "Kerberos error.");
499 memset(old_pw
, 0, sizeof(old_pw
));
502 if(chown(tktstring
, getuid(), -1) < 0){
506 memset(old_pw
, 0, sizeof(old_pw
));
511 siad_chg_password (sia_collect_func_t
*collect
,
512 const char *username
,
519 char new_pw1
[MAX_KPW_LEN
+1];
520 char new_pw2
[MAX_KPW_LEN
+1];
521 static struct et_list
*et_list
;
523 setprogname(argv
[0]);
525 SIA_DEBUG(("DEBUG", "siad_chg_password"));
530 username
= getlogin();
532 ret
= krb_parse_name(username
, &princ
);
535 if(princ
.realm
[0] == '\0')
536 krb_get_lrealm(princ
.realm
, 1);
538 if(et_list
== NULL
) {
539 initialize_kadm_error_table_r(&et_list
);
540 initialize_krb_error_table_r(&et_list
);
543 ret
= init_change(collect
, &princ
);
544 if(ret
!= SIADSUCCESS
)
548 prompts
[0].prompt
= (unsigned char*)"New password: ";
549 prompts
[0].result
= (unsigned char*)new_pw1
;
550 prompts
[0].min_result_length
= MIN_KPW_LEN
;
551 prompts
[0].max_result_length
= sizeof(new_pw1
) - 1;
552 prompts
[0].control_flags
= SIARESINVIS
;
553 prompts
[1].prompt
= (unsigned char*)"Verify new password: ";
554 prompts
[1].result
= (unsigned char*)new_pw2
;
555 prompts
[1].min_result_length
= MIN_KPW_LEN
;
556 prompts
[1].max_result_length
= sizeof(new_pw2
) - 1;
557 prompts
[1].control_flags
= SIARESINVIS
;
558 if((*collect
)(120, SIAFORM
, (unsigned char*)"", 2, prompts
) !=
563 if(strcmp(new_pw1
, new_pw2
) != 0){
564 sia_message(collect
, SIAWARNING
, "", "Password mismatch.");
567 ret
= kadm_check_pw(new_pw1
);
569 sia_message(collect
, SIAWARNING
, "", com_right(et_list
, ret
));
573 memset(new_pw2
, 0, sizeof(new_pw2
));
574 ret
= kadm_init_link (PWSERV_NAME
, KRB_MASTER
, princ
.realm
);
575 if (ret
!= KADM_SUCCESS
)
576 sia_message(collect
, SIAWARNING
, "Error initing kadmin connection",
577 com_right(et_list
, ret
));
580 char *pw_msg
; /* message from server */
582 des_string_to_key(new_pw1
, &newkey
);
583 ret
= kadm_change_pw_plain((unsigned char*)&newkey
, new_pw1
, &pw_msg
);
584 memset(newkey
, 0, sizeof(newkey
));
586 if (ret
== KADM_INSECURE_PW
)
587 sia_message(collect
, SIAWARNING
, "Insecure password", pw_msg
);
588 else if (ret
!= KADM_SUCCESS
)
589 sia_message(collect
, SIAWARNING
, "Error changing password",
590 com_right(et_list
, ret
));
592 memset(new_pw1
, 0, sizeof(new_pw1
));
594 if (ret
!= KADM_SUCCESS
)
595 sia_message(collect
, SIAWARNING
, "", "Password NOT changed.");
597 sia_message(collect
, SIAINFO
, "", "Password changed.");
607 siad_chg_shell (sia_collect_func_t
*collect
,
608 const char *username
,
616 siad_getpwent(struct passwd
*result
,
619 struct sia_context
*context
)
625 siad_getpwuid (uid_t uid
,
626 struct passwd
*result
,
629 struct sia_context
*context
)
635 siad_getpwnam (const char *name
,
636 struct passwd
*result
,
639 struct sia_context
*context
)
645 siad_setpwent (struct sia_context
*context
)
651 siad_endpwent (struct sia_context
*context
)
657 siad_getgrent(struct group
*result
,
660 struct sia_context
*context
)
666 siad_getgrgid (gid_t gid
,
667 struct group
*result
,
670 struct sia_context
*context
)
676 siad_getgrnam (const char *name
,
677 struct group
*result
,
680 struct sia_context
*context
)
686 siad_setgrent (struct sia_context
*context
)
692 siad_endgrent (struct sia_context
*context
)
698 siad_chk_user (const char *logname
, int checkflag
)
700 if(checkflag
!= CHGPASSWD
)