No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / lib / auth / sia / sia.c
bloba36bfc0c2a39409a1ab47572285c8f02767195ce
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("$Heimdal: sia.c 14838 2005-04-19 04:41:07Z lha $"
37 "$NetBSD$");
39 int
40 siad_init(void)
42 return SIADSUCCESS;
45 int
46 siad_chk_invoker(void)
48 SIA_DEBUG(("DEBUG", "siad_chk_invoker"));
49 return SIADFAIL;
52 int
53 siad_ses_init(SIAENTITY *entity, int pkgind)
55 struct state *s = malloc(sizeof(*s));
57 SIA_DEBUG(("DEBUG", "siad_ses_init"));
58 if(s == NULL)
59 return SIADFAIL;
60 memset(s, 0, sizeof(*s));
61 #ifdef SIA_KRB5
63 krb5_error_code ret;
64 ret = krb5_init_context(&s->context);
65 if (ret)
66 return SIADFAIL;
68 #endif
69 entity->mech[pkgind] = (int*)s;
70 return SIADSUCCESS;
73 static int
74 setup_name(SIAENTITY *e, prompt_t *p)
76 SIA_DEBUG(("DEBUG", "setup_name"));
77 e->name = malloc(SIANAMEMIN + 1);
78 if(e->name == NULL){
79 SIA_DEBUG(("DEBUG", "failed to malloc %u bytes", SIANAMEMIN+1));
80 return SIADFAIL;
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;
86 p->control_flags = 0;
87 return SIADSUCCESS;
90 static int
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));
97 return SIADFAIL;
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;
104 return SIADSUCCESS;
108 static int
109 doauth(SIAENTITY *entity, int pkgind, char *name)
111 struct passwd pw, *pwd;
112 char pwbuf[1024];
113 struct state *s = (struct state*)entity->mech[pkgind];
114 #ifdef SIA_KRB5
115 krb5_realm *realms, *r;
116 krb5_principal principal;
117 krb5_ccache ccache;
118 krb5_error_code ret;
119 #endif
120 #ifdef SIA_KRB4
121 char realm[REALM_SZ];
122 char *toname, *toinst;
123 int ret;
124 struct passwd fpw, *fpwd;
125 char fpwbuf[1024];
126 int secure;
127 #endif
129 if(getpwnam_r(name, &pw, pwbuf, sizeof(pwbuf), &pwd) != 0 || pwd == NULL){
130 SIA_DEBUG(("DEBUG", "failed to getpwnam(%s)", name));
131 return SIADFAIL;
134 #ifdef SIA_KRB5
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))
141 break;
143 krb5_free_host_realm (s->context, realms);
144 if (*r == NULL)
145 return SIADFAIL;
147 sprintf(s->ticket, "FILE:/tmp/krb5_cc%d_%d", pwd->pw_uid, getpid());
148 ret = krb5_cc_resolve(s->context, s->ticket, &ccache);
149 if(ret)
150 return SIADFAIL;
151 #endif
153 #ifdef SIA_KRB4
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);
157 toname = name;
158 toinst = "";
159 if(entity->authtype == SIA_A_SUAUTH){
160 uid_t ouid;
161 #ifdef HAVE_SIAENTITY_OUID
162 ouid = entity->ouid;
163 #else
164 ouid = getuid();
165 #endif
166 if(getpwuid_r(ouid, &fpw, fpwbuf, sizeof(fpwbuf), &fpwd) != 0 || fpwd == NULL){
167 SIA_DEBUG(("DEBUG", "failed to getpwuid(%u)", ouid));
168 return SIADFAIL;
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));
186 return SIADFAIL;
188 #endif
189 #ifdef SIA_KRB5
190 ret = krb5_verify_user_lrealm(s->context, principal, ccache,
191 entity->password, 1, NULL);
192 if(ret){
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));
200 return SIADFAIL;
202 #endif
203 #ifdef SIA_KRB4
204 if (getuid () == 0)
205 secure = KRB_VERIFY_SECURE;
206 else
207 secure = KRB_VERIFY_NOT_SECURE;
209 ret = krb_verify_user(toname, toinst, realm,
210 entity->password, secure, NULL);
211 if(ret){
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));
219 return SIADFAIL;
221 #endif
222 if(sia_make_entity_pwd(pwd, entity) == SIAFAIL)
223 return SIADFAIL;
224 s->valid = 1;
225 return SIADSUCCESS;
229 static int
230 common_auth(sia_collect_func_t *collect,
231 SIAENTITY *entity,
232 int siastat,
233 int pkgind)
235 prompt_t prompts[2], *pr;
236 char *name;
238 SIA_DEBUG(("DEBUG", "common_auth"));
239 if((siastat == SIADSUCCESS) && (geteuid() == 0))
240 return SIADSUCCESS;
241 if(entity == NULL) {
242 SIA_DEBUG(("DEBUG", "entity == NULL"));
243 return SIADFAIL | SIADSTOP;
245 name = entity->name;
246 if(entity->acctname)
247 name = entity->acctname;
249 if((collect != NULL) && entity->colinput) {
250 int num;
251 pr = prompts;
252 if(name == NULL){
253 if(setup_name(entity, pr) != SIADSUCCESS)
254 return SIADFAIL;
255 pr++;
257 if(entity->password == NULL){
258 if(setup_password(entity, pr) != SIADSUCCESS)
259 return SIADFAIL;
260 pr++;
262 num = pr - prompts;
263 if(num == 1){
264 if((*collect)(240, SIAONELINER, (unsigned char*)"", num,
265 prompts) != SIACOLSUCCESS){
266 SIA_DEBUG(("DEBUG", "collect failed"));
267 return SIADFAIL | SIADSTOP;
269 } else if(num > 0){
270 if((*collect)(0, SIAFORM, (unsigned char*)"", num,
271 prompts) != SIACOLSUCCESS){
272 SIA_DEBUG(("DEBUG", "collect failed"));
273 return SIADFAIL | SIADSTOP;
277 if(name == NULL)
278 name = entity->name;
279 if(name == NULL || name[0] == '\0'){
280 SIA_DEBUG(("DEBUG", "name is null"));
281 return SIADFAIL;
284 if(entity->password == NULL || strlen(entity->password) > SIAMXPASSWORD){
285 SIA_DEBUG(("DEBUG", "entity->password is null"));
286 return SIADFAIL;
289 return doauth(entity, pkgind, name);
293 int
294 siad_ses_authent(sia_collect_func_t *collect,
295 SIAENTITY *entity,
296 int siastat,
297 int pkgind)
299 SIA_DEBUG(("DEBUG", "siad_ses_authent"));
300 return common_auth(collect, entity, siastat, pkgind);
303 int
304 siad_ses_estab(sia_collect_func_t *collect,
305 SIAENTITY *entity, int pkgind)
307 SIA_DEBUG(("DEBUG", "siad_ses_estab"));
308 return SIADFAIL;
311 int
312 siad_ses_launch(sia_collect_func_t *collect,
313 SIAENTITY *entity,
314 int pkgind)
316 static char env[MaxPathLen];
317 struct state *s = (struct state*)entity->mech[pkgind];
318 SIA_DEBUG(("DEBUG", "siad_ses_launch"));
319 if(s->valid){
320 #ifdef SIA_KRB5
321 chown(s->ticket + sizeof("FILE:") - 1,
322 entity->pwd->pw_uid,
323 entity->pwd->pw_gid);
324 snprintf(env, sizeof(env), "KRB5CCNAME=%s", s->ticket);
325 #endif
326 #ifdef SIA_KRB4
327 chown(s->ticket, entity->pwd->pw_uid, entity->pwd->pw_gid);
328 snprintf(env, sizeof(env), "KRBTKFILE=%s", s->ticket);
329 #endif
330 putenv(env);
332 #ifdef SIA_KRB5
333 if (k_hasafs()) {
334 char cell[64];
335 krb5_ccache ccache;
336 if(krb5_cc_resolve(s->context, s->ticket, &ccache) == 0) {
337 k_setpag();
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);
343 #endif
344 #ifdef SIA_KRB4
345 if (k_hasafs()) {
346 char cell[64];
347 k_setpag();
348 if(k_afs_cell_of_file(entity->pwd->pw_dir, cell, sizeof(cell)) == 0)
349 krb_afslog(cell, 0);
350 krb_afslog_home(0, 0, entity->pwd->pw_dir);
352 #endif
353 return SIADSUCCESS;
356 int
357 siad_ses_release(SIAENTITY *entity, int pkgind)
359 SIA_DEBUG(("DEBUG", "siad_ses_release"));
360 if(entity->mech[pkgind]){
361 #ifdef SIA_KRB5
362 struct state *s = (struct state*)entity->mech[pkgind];
363 krb5_free_context(s->context);
364 #endif
365 free(entity->mech[pkgind]);
367 return SIADSUCCESS;
370 int
371 siad_ses_suauthent(sia_collect_func_t *collect,
372 SIAENTITY *entity,
373 int siastat,
374 int pkgind)
376 SIA_DEBUG(("DEBUG", "siad_ses_suauth"));
377 if(geteuid() != 0)
378 return SIADFAIL;
379 if(entity->name == NULL)
380 return SIADFAIL;
381 if(entity->name[0] == '\0') {
382 free(entity->name);
383 entity->name = strdup("root");
384 if (entity->name == NULL)
385 return SIADFAIL;
387 return common_auth(collect, entity, siastat, pkgind);
391 siad_ses_reauthent (sia_collect_func_t *collect,
392 SIAENTITY *entity,
393 int siastat,
394 int pkgind)
396 int ret;
397 SIA_DEBUG(("DEBUG", "siad_ses_reauthent"));
398 if(entity == NULL || entity->name == NULL)
399 return SIADFAIL;
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);
406 #ifdef SIA_KRB5
407 if (k_hasafs()) {
408 char cell[64];
409 krb5_ccache ccache;
410 if(krb5_cc_resolve(s->context, s->ticket, &ccache) == 0) {
411 k_setpag();
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);
418 #endif
419 #ifdef SIA_KRB4
420 if(k_hasafs()) {
421 char cell[64];
422 if(k_afs_cell_of_file(entity->pwd->pw_dir,
423 cell, sizeof(cell)) == 0)
424 krb_afslog(cell, 0);
425 krb_afslog_home(0, 0, entity->pwd->pw_dir);
427 #endif
429 return ret;
433 siad_chg_finger (sia_collect_func_t *collect,
434 const char *username,
435 int argc,
436 char *argv[])
438 SIA_DEBUG(("DEBUG", "siad_chg_finger"));
439 return SIADFAIL;
442 #ifdef SIA_KRB5
444 siad_chg_password (sia_collect_func_t *collect,
445 const char *username,
446 int argc,
447 char *argv[])
449 return SIADFAIL;
451 #endif
453 #ifdef SIA_KRB4
454 static void
455 sia_message(sia_collect_func_t *collect, int rendition,
456 const char *title, const char *message)
458 prompt_t prompt;
459 prompt.prompt = (unsigned char*)message;
460 (*collect)(0, rendition, (unsigned char*)title, 1, &prompt);
463 static int
464 init_change(sia_collect_func_t *collect, krb_principal *princ)
466 prompt_t prompt;
467 char old_pw[MAX_KPW_LEN+1];
468 char *msg;
469 char tktstring[128];
470 int ret;
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));
479 if(msg == NULL){
480 SIA_DEBUG(("DEBUG", "out of memory"));
481 return SIADFAIL;
483 ret = (*collect)(60, SIAONELINER, (unsigned char*)msg, 1, &prompt);
484 free(msg);
485 SIA_DEBUG(("DEBUG", "ret = %d", ret));
486 if(ret != SIACOLSUCCESS)
487 return SIADFAIL;
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.");
498 else
499 sia_message(collect, SIAWARNING, "", "Kerberos error.");
500 memset(old_pw, 0, sizeof(old_pw));
501 return SIADFAIL;
503 if(chown(tktstring, getuid(), -1) < 0){
504 dest_tkt();
505 return SIADFAIL;
507 memset(old_pw, 0, sizeof(old_pw));
508 return SIADSUCCESS;
512 siad_chg_password (sia_collect_func_t *collect,
513 const char *username,
514 int argc,
515 char *argv[])
517 prompt_t prompts[2];
518 krb_principal princ;
519 int ret;
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"));
527 if(collect == NULL)
528 return SIADFAIL;
530 if(username == NULL)
531 username = getlogin();
533 ret = krb_parse_name(username, &princ);
534 if(ret)
535 return SIADFAIL;
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)
546 return ret;
548 again:
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) !=
560 SIACOLSUCCESS) {
561 dest_tkt();
562 return SIADFAIL;
564 if(strcmp(new_pw1, new_pw2) != 0){
565 sia_message(collect, SIAWARNING, "", "Password mismatch.");
566 goto again;
568 ret = kadm_check_pw(new_pw1);
569 if(ret) {
570 sia_message(collect, SIAWARNING, "", com_right(et_list, ret));
571 goto again;
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));
579 else {
580 des_cblock newkey;
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.");
597 else
598 sia_message(collect, SIAINFO, "", "Password changed.");
600 dest_tkt();
601 if(ret)
602 return SIADFAIL;
603 return SIADSUCCESS;
605 #endif
608 siad_chg_shell (sia_collect_func_t *collect,
609 const char *username,
610 int argc,
611 char *argv[])
613 return SIADFAIL;
617 siad_getpwent(struct passwd *result,
618 char *buf,
619 int bufsize,
620 struct sia_context *context)
622 return SIADFAIL;
626 siad_getpwuid (uid_t uid,
627 struct passwd *result,
628 char *buf,
629 int bufsize,
630 struct sia_context *context)
632 return SIADFAIL;
636 siad_getpwnam (const char *name,
637 struct passwd *result,
638 char *buf,
639 int bufsize,
640 struct sia_context *context)
642 return SIADFAIL;
646 siad_setpwent (struct sia_context *context)
648 return SIADFAIL;
652 siad_endpwent (struct sia_context *context)
654 return SIADFAIL;
658 siad_getgrent(struct group *result,
659 char *buf,
660 int bufsize,
661 struct sia_context *context)
663 return SIADFAIL;
667 siad_getgrgid (gid_t gid,
668 struct group *result,
669 char *buf,
670 int bufsize,
671 struct sia_context *context)
673 return SIADFAIL;
677 siad_getgrnam (const char *name,
678 struct group *result,
679 char *buf,
680 int bufsize,
681 struct sia_context *context)
683 return SIADFAIL;
687 siad_setgrent (struct sia_context *context)
689 return SIADFAIL;
693 siad_endgrent (struct sia_context *context)
695 return SIADFAIL;
699 siad_chk_user (const char *logname, int checkflag)
701 if(checkflag != CHGPASSWD)
702 return SIADFAIL;
703 return SIADSUCCESS;