1.2.2rc2
[heimdal.git] / lib / auth / sia / sia.c
blobeb0e8303ceedbc0fae799b589d013ed4ac50396b
1 /*
2 * Copyright (c) 1995-2001 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
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
31 * SUCH DAMAGE.
34 #include "sia_locl.h"
36 RCSID("$Id$");
38 int
39 siad_init(void)
41 return SIADSUCCESS;
44 int
45 siad_chk_invoker(void)
47 SIA_DEBUG(("DEBUG", "siad_chk_invoker"));
48 return SIADFAIL;
51 int
52 siad_ses_init(SIAENTITY *entity, int pkgind)
54 struct state *s = malloc(sizeof(*s));
56 SIA_DEBUG(("DEBUG", "siad_ses_init"));
57 if(s == NULL)
58 return SIADFAIL;
59 memset(s, 0, sizeof(*s));
60 #ifdef SIA_KRB5
62 krb5_error_code ret;
63 ret = krb5_init_context(&s->context);
64 if (ret)
65 return SIADFAIL;
67 #endif
68 entity->mech[pkgind] = (int*)s;
69 return SIADSUCCESS;
72 static int
73 setup_name(SIAENTITY *e, prompt_t *p)
75 SIA_DEBUG(("DEBUG", "setup_name"));
76 e->name = malloc(SIANAMEMIN + 1);
77 if(e->name == NULL){
78 SIA_DEBUG(("DEBUG", "failed to malloc %u bytes", SIANAMEMIN+1));
79 return SIADFAIL;
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;
85 p->control_flags = 0;
86 return SIADSUCCESS;
89 static int
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));
96 return SIADFAIL;
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;
103 return SIADSUCCESS;
107 static int
108 doauth(SIAENTITY *entity, int pkgind, char *name)
110 struct passwd pw, *pwd;
111 char pwbuf[1024];
112 struct state *s = (struct state*)entity->mech[pkgind];
113 #ifdef SIA_KRB5
114 krb5_realm *realms, *r;
115 krb5_principal principal;
116 krb5_ccache ccache;
117 krb5_error_code ret;
118 #endif
119 #ifdef SIA_KRB4
120 char realm[REALM_SZ];
121 char *toname, *toinst;
122 int ret;
123 struct passwd fpw, *fpwd;
124 char fpwbuf[1024];
125 int secure;
126 #endif
128 if(getpwnam_r(name, &pw, pwbuf, sizeof(pwbuf), &pwd) != 0 || pwd == NULL){
129 SIA_DEBUG(("DEBUG", "failed to getpwnam(%s)", name));
130 return SIADFAIL;
133 #ifdef SIA_KRB5
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))
140 break;
142 krb5_free_host_realm (s->context, realms);
143 if (*r == NULL)
144 return SIADFAIL;
146 sprintf(s->ticket, "FILE:/tmp/krb5_cc%d_%d", pwd->pw_uid, getpid());
147 ret = krb5_cc_resolve(s->context, s->ticket, &ccache);
148 if(ret)
149 return SIADFAIL;
150 #endif
152 #ifdef SIA_KRB4
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);
156 toname = name;
157 toinst = "";
158 if(entity->authtype == SIA_A_SUAUTH){
159 uid_t ouid;
160 #ifdef HAVE_SIAENTITY_OUID
161 ouid = entity->ouid;
162 #else
163 ouid = getuid();
164 #endif
165 if(getpwuid_r(ouid, &fpw, fpwbuf, sizeof(fpwbuf), &fpwd) != 0 || fpwd == NULL){
166 SIA_DEBUG(("DEBUG", "failed to getpwuid(%u)", ouid));
167 return SIADFAIL;
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));
185 return SIADFAIL;
187 #endif
188 #ifdef SIA_KRB5
189 ret = krb5_verify_user_lrealm(s->context, principal, ccache,
190 entity->password, 1, NULL);
191 if(ret){
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));
199 return SIADFAIL;
201 #endif
202 #ifdef SIA_KRB4
203 if (getuid () == 0)
204 secure = KRB_VERIFY_SECURE;
205 else
206 secure = KRB_VERIFY_NOT_SECURE;
208 ret = krb_verify_user(toname, toinst, realm,
209 entity->password, secure, NULL);
210 if(ret){
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));
218 return SIADFAIL;
220 #endif
221 if(sia_make_entity_pwd(pwd, entity) == SIAFAIL)
222 return SIADFAIL;
223 s->valid = 1;
224 return SIADSUCCESS;
228 static int
229 common_auth(sia_collect_func_t *collect,
230 SIAENTITY *entity,
231 int siastat,
232 int pkgind)
234 prompt_t prompts[2], *pr;
235 char *name;
237 SIA_DEBUG(("DEBUG", "common_auth"));
238 if((siastat == SIADSUCCESS) && (geteuid() == 0))
239 return SIADSUCCESS;
240 if(entity == NULL) {
241 SIA_DEBUG(("DEBUG", "entity == NULL"));
242 return SIADFAIL | SIADSTOP;
244 name = entity->name;
245 if(entity->acctname)
246 name = entity->acctname;
248 if((collect != NULL) && entity->colinput) {
249 int num;
250 pr = prompts;
251 if(name == NULL){
252 if(setup_name(entity, pr) != SIADSUCCESS)
253 return SIADFAIL;
254 pr++;
256 if(entity->password == NULL){
257 if(setup_password(entity, pr) != SIADSUCCESS)
258 return SIADFAIL;
259 pr++;
261 num = pr - prompts;
262 if(num == 1){
263 if((*collect)(240, SIAONELINER, (unsigned char*)"", num,
264 prompts) != SIACOLSUCCESS){
265 SIA_DEBUG(("DEBUG", "collect failed"));
266 return SIADFAIL | SIADSTOP;
268 } else if(num > 0){
269 if((*collect)(0, SIAFORM, (unsigned char*)"", num,
270 prompts) != SIACOLSUCCESS){
271 SIA_DEBUG(("DEBUG", "collect failed"));
272 return SIADFAIL | SIADSTOP;
276 if(name == NULL)
277 name = entity->name;
278 if(name == NULL || name[0] == '\0'){
279 SIA_DEBUG(("DEBUG", "name is null"));
280 return SIADFAIL;
283 if(entity->password == NULL || strlen(entity->password) > SIAMXPASSWORD){
284 SIA_DEBUG(("DEBUG", "entity->password is null"));
285 return SIADFAIL;
288 return doauth(entity, pkgind, name);
292 int
293 siad_ses_authent(sia_collect_func_t *collect,
294 SIAENTITY *entity,
295 int siastat,
296 int pkgind)
298 SIA_DEBUG(("DEBUG", "siad_ses_authent"));
299 return common_auth(collect, entity, siastat, pkgind);
302 int
303 siad_ses_estab(sia_collect_func_t *collect,
304 SIAENTITY *entity, int pkgind)
306 SIA_DEBUG(("DEBUG", "siad_ses_estab"));
307 return SIADFAIL;
310 int
311 siad_ses_launch(sia_collect_func_t *collect,
312 SIAENTITY *entity,
313 int pkgind)
315 static char env[MaxPathLen];
316 struct state *s = (struct state*)entity->mech[pkgind];
317 SIA_DEBUG(("DEBUG", "siad_ses_launch"));
318 if(s->valid){
319 #ifdef SIA_KRB5
320 chown(s->ticket + sizeof("FILE:") - 1,
321 entity->pwd->pw_uid,
322 entity->pwd->pw_gid);
323 snprintf(env, sizeof(env), "KRB5CCNAME=%s", s->ticket);
324 #endif
325 #ifdef SIA_KRB4
326 chown(s->ticket, entity->pwd->pw_uid, entity->pwd->pw_gid);
327 snprintf(env, sizeof(env), "KRBTKFILE=%s", s->ticket);
328 #endif
329 putenv(env);
331 #ifdef SIA_KRB5
332 if (k_hasafs()) {
333 char cell[64];
334 krb5_ccache ccache;
335 if(krb5_cc_resolve(s->context, s->ticket, &ccache) == 0) {
336 k_setpag();
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);
342 #endif
343 #ifdef SIA_KRB4
344 if (k_hasafs()) {
345 char cell[64];
346 k_setpag();
347 if(k_afs_cell_of_file(entity->pwd->pw_dir, cell, sizeof(cell)) == 0)
348 krb_afslog(cell, 0);
349 krb_afslog_home(0, 0, entity->pwd->pw_dir);
351 #endif
352 return SIADSUCCESS;
355 int
356 siad_ses_release(SIAENTITY *entity, int pkgind)
358 SIA_DEBUG(("DEBUG", "siad_ses_release"));
359 if(entity->mech[pkgind]){
360 #ifdef SIA_KRB5
361 struct state *s = (struct state*)entity->mech[pkgind];
362 krb5_free_context(s->context);
363 #endif
364 free(entity->mech[pkgind]);
366 return SIADSUCCESS;
369 int
370 siad_ses_suauthent(sia_collect_func_t *collect,
371 SIAENTITY *entity,
372 int siastat,
373 int pkgind)
375 SIA_DEBUG(("DEBUG", "siad_ses_suauth"));
376 if(geteuid() != 0)
377 return SIADFAIL;
378 if(entity->name == NULL)
379 return SIADFAIL;
380 if(entity->name[0] == '\0') {
381 free(entity->name);
382 entity->name = strdup("root");
383 if (entity->name == NULL)
384 return SIADFAIL;
386 return common_auth(collect, entity, siastat, pkgind);
390 siad_ses_reauthent (sia_collect_func_t *collect,
391 SIAENTITY *entity,
392 int siastat,
393 int pkgind)
395 int ret;
396 SIA_DEBUG(("DEBUG", "siad_ses_reauthent"));
397 if(entity == NULL || entity->name == NULL)
398 return SIADFAIL;
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);
405 #ifdef SIA_KRB5
406 if (k_hasafs()) {
407 char cell[64];
408 krb5_ccache ccache;
409 if(krb5_cc_resolve(s->context, s->ticket, &ccache) == 0) {
410 k_setpag();
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);
417 #endif
418 #ifdef SIA_KRB4
419 if(k_hasafs()) {
420 char cell[64];
421 if(k_afs_cell_of_file(entity->pwd->pw_dir,
422 cell, sizeof(cell)) == 0)
423 krb_afslog(cell, 0);
424 krb_afslog_home(0, 0, entity->pwd->pw_dir);
426 #endif
428 return ret;
432 siad_chg_finger (sia_collect_func_t *collect,
433 const char *username,
434 int argc,
435 char *argv[])
437 SIA_DEBUG(("DEBUG", "siad_chg_finger"));
438 return SIADFAIL;
441 #ifdef SIA_KRB5
443 siad_chg_password (sia_collect_func_t *collect,
444 const char *username,
445 int argc,
446 char *argv[])
448 return SIADFAIL;
450 #endif
452 #ifdef SIA_KRB4
453 static void
454 sia_message(sia_collect_func_t *collect, int rendition,
455 const char *title, const char *message)
457 prompt_t prompt;
458 prompt.prompt = (unsigned char*)message;
459 (*collect)(0, rendition, (unsigned char*)title, 1, &prompt);
462 static int
463 init_change(sia_collect_func_t *collect, krb_principal *princ)
465 prompt_t prompt;
466 char old_pw[MAX_KPW_LEN+1];
467 char *msg;
468 char tktstring[128];
469 int ret;
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));
478 if(msg == NULL){
479 SIA_DEBUG(("DEBUG", "out of memory"));
480 return SIADFAIL;
482 ret = (*collect)(60, SIAONELINER, (unsigned char*)msg, 1, &prompt);
483 free(msg);
484 SIA_DEBUG(("DEBUG", "ret = %d", ret));
485 if(ret != SIACOLSUCCESS)
486 return SIADFAIL;
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.");
497 else
498 sia_message(collect, SIAWARNING, "", "Kerberos error.");
499 memset(old_pw, 0, sizeof(old_pw));
500 return SIADFAIL;
502 if(chown(tktstring, getuid(), -1) < 0){
503 dest_tkt();
504 return SIADFAIL;
506 memset(old_pw, 0, sizeof(old_pw));
507 return SIADSUCCESS;
511 siad_chg_password (sia_collect_func_t *collect,
512 const char *username,
513 int argc,
514 char *argv[])
516 prompt_t prompts[2];
517 krb_principal princ;
518 int ret;
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"));
526 if(collect == NULL)
527 return SIADFAIL;
529 if(username == NULL)
530 username = getlogin();
532 ret = krb_parse_name(username, &princ);
533 if(ret)
534 return SIADFAIL;
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)
545 return ret;
547 again:
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) !=
559 SIACOLSUCCESS) {
560 dest_tkt();
561 return SIADFAIL;
563 if(strcmp(new_pw1, new_pw2) != 0){
564 sia_message(collect, SIAWARNING, "", "Password mismatch.");
565 goto again;
567 ret = kadm_check_pw(new_pw1);
568 if(ret) {
569 sia_message(collect, SIAWARNING, "", com_right(et_list, ret));
570 goto again;
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));
578 else {
579 des_cblock newkey;
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.");
596 else
597 sia_message(collect, SIAINFO, "", "Password changed.");
599 dest_tkt();
600 if(ret)
601 return SIADFAIL;
602 return SIADSUCCESS;
604 #endif
607 siad_chg_shell (sia_collect_func_t *collect,
608 const char *username,
609 int argc,
610 char *argv[])
612 return SIADFAIL;
616 siad_getpwent(struct passwd *result,
617 char *buf,
618 int bufsize,
619 struct sia_context *context)
621 return SIADFAIL;
625 siad_getpwuid (uid_t uid,
626 struct passwd *result,
627 char *buf,
628 int bufsize,
629 struct sia_context *context)
631 return SIADFAIL;
635 siad_getpwnam (const char *name,
636 struct passwd *result,
637 char *buf,
638 int bufsize,
639 struct sia_context *context)
641 return SIADFAIL;
645 siad_setpwent (struct sia_context *context)
647 return SIADFAIL;
651 siad_endpwent (struct sia_context *context)
653 return SIADFAIL;
657 siad_getgrent(struct group *result,
658 char *buf,
659 int bufsize,
660 struct sia_context *context)
662 return SIADFAIL;
666 siad_getgrgid (gid_t gid,
667 struct group *result,
668 char *buf,
669 int bufsize,
670 struct sia_context *context)
672 return SIADFAIL;
676 siad_getgrnam (const char *name,
677 struct group *result,
678 char *buf,
679 int bufsize,
680 struct sia_context *context)
682 return SIADFAIL;
686 siad_setgrent (struct sia_context *context)
688 return SIADFAIL;
692 siad_endgrent (struct sia_context *context)
694 return SIADFAIL;
698 siad_chk_user (const char *logname, int checkflag)
700 if(checkflag != CHGPASSWD)
701 return SIADFAIL;
702 return SIADSUCCESS;