This commit was manufactured by cvs2svn to create tag
[heimdal.git] / lib / auth / sia / sia.c
blob91fbef945a40912eba06bc5ca2ec1f64d689d38a
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){
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){
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 KRB4
332 if (k_hasafs()) {
333 char cell[64];
334 k_setpag();
335 if(k_afs_cell_of_file(entity->pwd->pw_dir, cell, sizeof(cell)) == 0)
336 krb_afslog(cell, 0);
337 krb_afslog_home(0, 0, entity->pwd->pw_dir);
339 #endif
340 return SIADSUCCESS;
343 int
344 siad_ses_release(SIAENTITY *entity, int pkgind)
346 SIA_DEBUG(("DEBUG", "siad_ses_release"));
347 if(entity->mech[pkgind]){
348 #ifdef SIA_KRB5
349 struct state *s = (struct state*)entity->mech[pkgind];
350 krb5_free_context(s->context);
351 #endif
352 free(entity->mech[pkgind]);
354 return SIADSUCCESS;
357 int
358 siad_ses_suauthent(sia_collect_func_t *collect,
359 SIAENTITY *entity,
360 int siastat,
361 int pkgind)
363 SIA_DEBUG(("DEBUG", "siad_ses_suauth"));
364 if(geteuid() != 0)
365 return SIADFAIL;
366 if(entity->name == NULL)
367 return SIADFAIL;
368 if(entity->name[0] == '\0') {
369 free(entity->name);
370 entity->name = strdup("root");
371 if (entity->name == NULL)
372 return SIADFAIL;
374 return common_auth(collect, entity, siastat, pkgind);
378 siad_ses_reauthent (sia_collect_func_t *collect,
379 SIAENTITY *entity,
380 int siastat,
381 int pkgind)
383 int ret;
384 SIA_DEBUG(("DEBUG", "siad_ses_reauthent"));
385 if(entity == NULL || entity->name == NULL)
386 return SIADFAIL;
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);
393 #ifdef KRB4
394 if(k_hasafs()) {
395 char cell[64];
396 if(k_afs_cell_of_file(entity->pwd->pw_dir,
397 cell, sizeof(cell)) == 0)
398 krb_afslog(cell, 0);
399 krb_afslog_home(0, 0, entity->pwd->pw_dir);
401 #endif
403 return ret;
407 siad_chg_finger (sia_collect_func_t *collect,
408 const char *username,
409 int argc,
410 char *argv[])
412 SIA_DEBUG(("DEBUG", "siad_chg_finger"));
413 return SIADFAIL;
416 #ifdef SIA_KRB5
418 siad_chg_password (sia_collect_func_t *collect,
419 const char *username,
420 int argc,
421 char *argv[])
423 return SIADFAIL;
425 #endif
427 #ifdef SIA_KRB4
428 static void
429 sia_message(sia_collect_func_t *collect, int rendition,
430 const char *title, const char *message)
432 prompt_t prompt;
433 prompt.prompt = (unsigned char*)message;
434 (*collect)(0, rendition, (unsigned char*)title, 1, &prompt);
437 static int
438 init_change(sia_collect_func_t *collect, krb_principal *princ)
440 prompt_t prompt;
441 char old_pw[MAX_KPW_LEN+1];
442 char *msg;
443 char tktstring[128];
444 int ret;
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));
453 if(msg == NULL){
454 SIA_DEBUG(("DEBUG", "out of memory"));
455 return SIADFAIL;
457 ret = (*collect)(60, SIAONELINER, (unsigned char*)msg, 1, &prompt);
458 free(msg);
459 SIA_DEBUG(("DEBUG", "ret = %d", ret));
460 if(ret != SIACOLSUCCESS)
461 return SIADFAIL;
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.");
472 else
473 sia_message(collect, SIAWARNING, "", "Kerberos error.");
474 memset(old_pw, 0, sizeof(old_pw));
475 return SIADFAIL;
477 if(chown(tktstring, getuid(), -1) < 0){
478 dest_tkt();
479 return SIADFAIL;
481 memset(old_pw, 0, sizeof(old_pw));
482 return SIADSUCCESS;
486 siad_chg_password (sia_collect_func_t *collect,
487 const char *username,
488 int argc,
489 char *argv[])
491 prompt_t prompts[2];
492 krb_principal princ;
493 int ret;
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"));
501 if(collect == NULL)
502 return SIADFAIL;
504 if(username == NULL)
505 username = getlogin();
507 ret = krb_parse_name(username, &princ);
508 if(ret)
509 return SIADFAIL;
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)
520 return ret;
522 again:
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) !=
534 SIACOLSUCCESS) {
535 dest_tkt();
536 return SIADFAIL;
538 if(strcmp(new_pw1, new_pw2) != 0){
539 sia_message(collect, SIAWARNING, "", "Password mismatch.");
540 goto again;
542 ret = kadm_check_pw(new_pw1);
543 if(ret) {
544 sia_message(collect, SIAWARNING, "", com_right(et_list, ret));
545 goto again;
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));
553 else {
554 des_cblock newkey;
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.");
571 else
572 sia_message(collect, SIAINFO, "", "Password changed.");
574 dest_tkt();
575 if(ret)
576 return SIADFAIL;
577 return SIADSUCCESS;
579 #endif
582 siad_chg_shell (sia_collect_func_t *collect,
583 const char *username,
584 int argc,
585 char *argv[])
587 return SIADFAIL;
591 siad_getpwent(struct passwd *result,
592 char *buf,
593 int bufsize,
594 struct sia_context *context)
596 return SIADFAIL;
600 siad_getpwuid (uid_t uid,
601 struct passwd *result,
602 char *buf,
603 int bufsize,
604 struct sia_context *context)
606 return SIADFAIL;
610 siad_getpwnam (const char *name,
611 struct passwd *result,
612 char *buf,
613 int bufsize,
614 struct sia_context *context)
616 return SIADFAIL;
620 siad_setpwent (struct sia_context *context)
622 return SIADFAIL;
626 siad_endpwent (struct sia_context *context)
628 return SIADFAIL;
632 siad_getgrent(struct group *result,
633 char *buf,
634 int bufsize,
635 struct sia_context *context)
637 return SIADFAIL;
641 siad_getgrgid (gid_t gid,
642 struct group *result,
643 char *buf,
644 int bufsize,
645 struct sia_context *context)
647 return SIADFAIL;
651 siad_getgrnam (const char *name,
652 struct group *result,
653 char *buf,
654 int bufsize,
655 struct sia_context *context)
657 return SIADFAIL;
661 siad_setgrent (struct sia_context *context)
663 return SIADFAIL;
667 siad_endgrent (struct sia_context *context)
669 return SIADFAIL;
673 siad_chk_user (const char *logname, int checkflag)
675 if(checkflag != CHGPASSWD)
676 return SIADFAIL;
677 return SIADSUCCESS;