int main (int argc, char **argv) { krb5_error_code ret; krb5_context context; krb5_ccache ccache; krb5_principal principal; int optidx = 0; krb5_deltat ticket_life = 0; int parseflags = 0; setprogname (argv[0]); setlocale (LC_ALL, ""); bindtextdomain ("heimdal_kuser", HEIMDAL_LOCALEDIR); textdomain("heimdal_kuser"); ret = krb5_init_context (&context); if (ret == KRB5_CONFIG_BADFORMAT) errx (1, "krb5_init_context failed to parse configuration file"); else if (ret) errx(1, "krb5_init_context failed: %d", ret); if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) usage(1); if (help_flag) usage (0); if(version_flag) { print_version(NULL); exit(0); } argc -= optidx; argv += optidx; if (!home_directory_flag) krb5_set_home_dir_access(NULL, FALSE); if (enterprise_flag) parseflags |= KRB5_PRINCIPAL_PARSE_ENTERPRISE; if (pk_enterprise_flag) { #ifdef PKINIT ret = krb5_pk_enterprise_cert(context, pk_user_id, argv[0], &principal, &ent_user_id); if (ret) krb5_err(context, 1, ret, "krb5_pk_enterprise_certs"); pk_user_id = NULL; #endif } else if (anonymous_flag) { ret = krb5_make_principal(context, &principal, argv[0], KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME, NULL); if (ret) krb5_err(context, 1, ret, "krb5_make_principal"); krb5_principal_set_type(context, principal, KRB5_NT_WELLKNOWN); } else { if (argv[0]) { ret = krb5_parse_name_flags (context, argv[0], parseflags, &principal); if (ret) krb5_err (context, 1, ret, "krb5_parse_name"); } else { ret = krb5_get_default_principal (context, &principal); if (ret) krb5_err (context, 1, ret, "krb5_get_default_principal"); } } if(fcache_version) krb5_set_fcache_version(context, fcache_version); if(renewable_flag == -1) /* this seems somewhat pointless, but whatever */ krb5_appdefault_boolean(context, "kinit", krb5_principal_get_realm(context, principal), "renewable", FALSE, &renewable_flag); if(do_afslog == -1) krb5_appdefault_boolean(context, "kinit", krb5_principal_get_realm(context, principal), "afslog", TRUE, &do_afslog); if(cred_cache) ret = krb5_cc_resolve(context, cred_cache, &ccache); else { if(argc > 1) { char s[1024]; ret = krb5_cc_new_unique(context, NULL, NULL, &ccache); if(ret) krb5_err(context, 1, ret, "creating cred cache"); snprintf(s, sizeof(s), "%s:%s", krb5_cc_get_type(context, ccache), krb5_cc_get_name(context, ccache)); setenv("KRB5CCNAME", s, 1); } else { ret = krb5_cc_cache_match(context, principal, &ccache); if (ret) { const char *type; ret = krb5_cc_default (context, &ccache); if (ret) krb5_err (context, 1, ret, N_("resolving credentials cache", "")); /* * Check if the type support switching, and we do, * then do that instead over overwriting the current * default credential */ type = krb5_cc_get_type(context, ccache); if (krb5_cc_support_switch(context, type)) { krb5_cc_close(context, ccache); ret = krb5_cc_new_unique(context, type, NULL, &ccache); } } } } if (ret) krb5_err (context, 1, ret, N_("resolving credentials cache", "")); #ifndef NO_AFS if(argc > 1 && k_hasafs ()) k_setpag(); #endif if (lifetime) { int tmp = parse_time (lifetime, "s"); if (tmp < 0) errx (1, N_("unparsable time: %s", ""), lifetime); ticket_life = tmp; } if(addrs_flag == 0 && extra_addresses.num_strings > 0) krb5_errx(context, 1, N_("specifying both extra addresses and " "no addresses makes no sense", "")); { int i; krb5_addresses addresses; memset(&addresses, 0, sizeof(addresses)); for(i = 0; i < extra_addresses.num_strings; i++) { ret = krb5_parse_address(context, extra_addresses.strings[i], &addresses); if (ret == 0) { krb5_add_extra_addresses(context, &addresses); krb5_free_addresses(context, &addresses); } } free_getarg_strings(&extra_addresses); } if(renew_flag || validate_flag) { ret = renew_validate(context, renew_flag, validate_flag, ccache, server_str, ticket_life); exit(ret != 0); } get_new_tickets(context, principal, ccache, ticket_life, 1); #ifndef NO_AFS if(do_afslog && k_hasafs()) krb5_afslog(context, ccache, NULL, NULL); #endif if (verbose_flag) { char *p; ret = krb5_unparse_name(context, principal, &p); if (ret) krb5_err(context, 1, ret, "krb5_unparse_name"); printf("Placing tickets for '%s' in cache '%s:%s'\n", p, krb5_cc_get_type(context, ccache), krb5_cc_get_name(context, ccache)); free(p); } if(argc > 1) { struct renew_ctx ctx; time_t timeout; timeout = ticket_lifetime(context, ccache, principal, server_str) / 2; ctx.context = context; ctx.ccache = ccache; ctx.principal = principal; ctx.ticket_life = ticket_life; ret = simple_execvp_timed(argv[1], argv+1, renew_func, &ctx, timeout); #define EX_NOEXEC 126 #define EX_NOTFOUND 127 if(ret == EX_NOEXEC) krb5_warnx(context, N_("permission denied: %s", ""), argv[1]); else if(ret == EX_NOTFOUND) krb5_warnx(context, N_("command not found: %s", ""), argv[1]); krb5_cc_destroy(context, ccache); #ifndef NO_AFS if(k_hasafs()) k_unlog(); #endif } else { krb5_cc_close (context, ccache); ret = 0; } krb5_free_principal(context, principal); krb5_free_context (context); return ret; }
static void doit (void) { u_char buf[BUFSIZ]; u_char *p; struct sockaddr_storage thisaddr_ss; struct sockaddr *thisaddr = (struct sockaddr *)&thisaddr_ss; struct sockaddr_storage thataddr_ss; struct sockaddr *thataddr = (struct sockaddr *)&thataddr_ss; struct sockaddr_storage erraddr_ss; struct sockaddr *erraddr = (struct sockaddr *)&erraddr_ss; socklen_t thisaddr_len, thataddr_len; int port; int errsock = -1; char *client_user = NULL, *server_user = NULL, *cmd = NULL; struct passwd *pwd; int s = STDIN_FILENO; char **env; int ret; char that_host[NI_MAXHOST]; thisaddr_len = sizeof(thisaddr_ss); if (getsockname (s, thisaddr, &thisaddr_len) < 0) syslog_and_die("getsockname: %s", strerror(errno)); thataddr_len = sizeof(thataddr_ss); if (getpeername (s, thataddr, &thataddr_len) < 0) syslog_and_die ("getpeername: %s", strerror(errno)); /* check for V4MAPPED addresses? */ if (do_kerberos == 0 && !is_reserved(socket_get_port(thataddr))) fatal(s, NULL, "Permission denied."); p = buf; port = 0; for(;;) { if (net_read (s, p, 1) != 1) syslog_and_die ("reading port number: %s", strerror(errno)); if (*p == '\0') break; else if (isdigit(*p)) port = port * 10 + *p - '0'; else syslog_and_die ("non-digit in port number: %c", *p); } if (do_kerberos == 0 && !is_reserved(htons(port))) fatal(s, NULL, "Permission denied."); if (port) { int priv_port = IPPORT_RESERVED - 1; /* * There's no reason to require a ``privileged'' port number * here, but for some reason the brain dead rsh clients * do... :-( */ erraddr->sa_family = thataddr->sa_family; socket_set_address_and_port (erraddr, socket_get_address (thataddr), htons(port)); /* * we only do reserved port for IPv4 */ if (erraddr->sa_family == AF_INET) errsock = rresvport (&priv_port); else errsock = socket (erraddr->sa_family, SOCK_STREAM, 0); if (errsock < 0) syslog_and_die ("socket: %s", strerror(errno)); if (connect (errsock, erraddr, socket_sockaddr_size (erraddr)) < 0) { syslog (LOG_WARNING, "connect: %s", strerror(errno)); close (errsock); } } if(do_kerberos) { if (net_read (s, buf, 4) != 4) syslog_and_die ("reading auth info: %s", strerror(errno)); #ifdef KRB5 if((do_kerberos & DO_KRB5) && recv_krb5_auth (s, buf, thisaddr, thataddr, &client_user, &server_user, &cmd) == 0) auth_method = AUTH_KRB5; else #endif /* KRB5 */ syslog_and_die ("unrecognized auth protocol: %x %x %x %x", buf[0], buf[1], buf[2], buf[3]); } else { if(recv_bsd_auth (s, buf, (struct sockaddr_in *)thisaddr, (struct sockaddr_in *)thataddr, &client_user, &server_user, &cmd) == 0) { auth_method = AUTH_BROKEN; if(do_vacuous) { printf("Remote host requires Kerberos authentication\n"); exit(0); } } else syslog_and_die("recv_bsd_auth failed"); } if (client_user == NULL || server_user == NULL || cmd == NULL) syslog_and_die("mising client/server/cmd"); pwd = getpwnam (server_user); if (pwd == NULL) fatal (s, NULL, "Login incorrect."); if (*pwd->pw_shell == '\0') pwd->pw_shell = _PATH_BSHELL; if (pwd->pw_uid != 0 && access (_PATH_NOLOGIN, F_OK) == 0) fatal (s, NULL, "Login disabled."); ret = getnameinfo_verified (thataddr, thataddr_len, that_host, sizeof(that_host), NULL, 0, 0); if (ret) fatal (s, NULL, "getnameinfo: %s", gai_strerror(ret)); if (login_access(pwd, that_host) == 0) { syslog(LOG_NOTICE, "Kerberos rsh denied to %s from %s", server_user, that_host); fatal(s, NULL, "Permission denied."); } #ifdef HAVE_GETSPNAM { struct spwd *sp; long today; sp = getspnam(server_user); if (sp != NULL) { today = time(0)/(24L * 60 * 60); if (sp->sp_expire > 0) if (today > sp->sp_expire) fatal(s, NULL, "Account has expired."); } } #endif #ifdef HAVE_SETLOGIN if (setlogin(pwd->pw_name) < 0) syslog(LOG_ERR, "setlogin() failed: %s", strerror(errno)); #endif #ifdef HAVE_SETPCRED if (setpcred (pwd->pw_name, NULL) == -1) syslog(LOG_ERR, "setpcred() failure: %s", strerror(errno)); #endif /* HAVE_SETPCRED */ /* Apply limits if not root */ if(pwd->pw_uid != 0) { const char *file = _PATH_LIMITS_CONF; read_limits_conf(file, pwd); } if (initgroups (pwd->pw_name, pwd->pw_gid) < 0) fatal (s, "initgroups", "Login incorrect."); if (setgid(pwd->pw_gid) < 0) fatal (s, "setgid", "Login incorrect."); if (setuid (pwd->pw_uid) < 0) fatal (s, "setuid", "Login incorrect."); if (chdir (pwd->pw_dir) < 0) fatal (s, "chdir", "Remote directory."); if (errsock >= 0) { if (dup2 (errsock, STDERR_FILENO) < 0) fatal (s, "dup2", "Cannot dup stderr."); close (errsock); } else { if (dup2 (STDOUT_FILENO, STDERR_FILENO) < 0) fatal (s, "dup2", "Cannot dup stderr."); } #ifdef KRB5 { int fd; if (!do_unique_tkfile) snprintf(tkfile,sizeof(tkfile),"FILE:/tmp/krb5cc_%lu", (unsigned long)pwd->pw_uid); else if (*tkfile=='\0') { snprintf(tkfile,sizeof(tkfile),"FILE:/tmp/krb5cc_XXXXXX"); fd = mkstemp(tkfile+5); close(fd); unlink(tkfile+5); } if (kerberos_status) krb5_start_session(); } #endif setup_environment (&env, pwd); if (do_encrypt) { setup_copier (errsock >= 0); } else { if (net_write (s, "", 1) != 1) fatal (s, "net_write", "write failed"); } #if defined(KRB5) if(k_hasafs()) { char cell[64]; if(do_newpag) k_setpag(); /* XXX */ if (kerberos_status) { krb5_ccache ccache; krb5_error_code status; status = krb5_cc_resolve (context, tkfile, &ccache); if (!status) { if (k_afs_cell_of_file (pwd->pw_dir, cell, sizeof(cell)) == 0) krb5_afslog_uid_home(context, ccache, cell, NULL, pwd->pw_uid, pwd->pw_dir); krb5_afslog_uid_home(context, ccache, NULL, NULL, pwd->pw_uid, pwd->pw_dir); krb5_cc_close (context, ccache); } } } #endif /* KRB5 */ execle (pwd->pw_shell, pwd->pw_shell, "-c", cmd, NULL, env); err(1, "exec %s", pwd->pw_shell); }
int Verify (struct display *d, struct greet_info *greet, struct verify_info *verify) { struct passwd *p; login_cap_t *lc; auth_session_t *as; char *style, *shell, *home, *s, **argv; char path[MAXPATHLEN]; int authok; /* User may have specified an authentication style. */ if ((style = strchr(greet->name, ':')) != NULL) *style++ = '\0'; Debug ("Verify %s, style %s ...\n", greet->name, style ? style : "default"); p = getpwnam (greet->name); endpwent(); if (!p || strlen (greet->name) == 0) { Debug("getpwnam() failed.\n"); bzero(greet->password, strlen(greet->password)); return 0; } if ((lc = login_getclass(p->pw_class)) == NULL) { Debug("login_getclass() failed.\n"); bzero(greet->password, strlen(greet->password)); return 0; } if ((style = login_getstyle(lc, style, "xdm")) == NULL) { Debug("login_getstyle() failed.\n"); bzero(greet->password, strlen(greet->password)); return 0; } if ((as = auth_open()) == NULL) { Debug("auth_open() failed.\n"); login_close(lc); bzero(greet->password, strlen(greet->password)); return 0; } if (auth_setoption(as, "login", "yes") == -1) { Debug("auth_setoption() failed.\n"); login_close(lc); bzero(greet->password, strlen(greet->password)); return 0; } /* Set up state for no challenge, just check a response. */ auth_setstate(as, 0); auth_setdata(as, "", 1); auth_setdata(as, greet->password, strlen(greet->password) + 1); /* Build path of the auth script and call it */ snprintf(path, sizeof(path), _PATH_AUTHPROG "%s", style); auth_call(as, path, style, "-s", "response", greet->name, lc->lc_class, (void *)NULL); authok = auth_getstate(as); if ((authok & AUTH_ALLOW) == 0) { Debug("password verify failed\n"); bzero(greet->password, strlen(greet->password)); auth_close(as); login_close(lc); return 0; } /* Run the approval script */ if (!auth_approval(as, lc, greet->name, "auth-xdm")) { Debug("login not approved\n"); bzero(greet->password, strlen(greet->password)); auth_close(as); login_close(lc); return 0; } auth_close(as); login_close(lc); /* Check empty passwords against allowNullPasswd */ if (!greet->allow_null_passwd && strlen(greet->password) == 0) { Debug("empty password not allowed\n"); return 0; } /* Only accept root logins if allowRootLogin resource is set */ if (p->pw_uid == 0 && !greet->allow_root_login) { Debug("root logins not allowed\n"); bzero(greet->password, strlen(greet->password)); return 0; } /* * Shell must be in /etc/shells */ for (;;) { s = getusershell(); if (s == NULL) { /* did not found the shell in /etc/shells -> failure */ Debug("shell not in /etc/shells\n"); bzero(greet->password, strlen(greet->password)); endusershell(); return 0; } if (strcmp(s, p->pw_shell) == 0) { /* found the shell in /etc/shells */ endusershell(); break; } } #else /* !USE_BSDAUTH */ int Verify (struct display *d, struct greet_info *greet, struct verify_info *verify) { struct passwd *p; #ifdef USE_PAM pam_handle_t **pamhp = thepamhp(); #else #ifdef USESHADOW struct spwd *sp; #endif char *user_pass = NULL; #endif #ifdef __OpenBSD__ char *s; struct timeval tp; #endif char *shell, *home; char **argv; Debug ("Verify %s ...\n", greet->name); #if defined(sun) && defined(SVR4) /* Solaris: If CONSOLE is set to /dev/console in /etc/default/login, then root can only login on system console */ # define SOLARIS_LOGIN_DEFAULTS "/etc/default/login" if (strcmp(greet->name, "root") == 0) { char *console = NULL, *tmp = NULL; FILE *fs; if ((fs= fopen(SOLARIS_LOGIN_DEFAULTS, "r")) != NULL) { char str[120]; while (!feof(fs)) { fgets(str, 120, fs); if(str[0] == '#' || strlen(str) < 8) continue; if((tmp = strstr(str, "CONSOLE=")) != NULL) console = strdup((tmp+8)); } fclose(fs); if ( console != NULL && (strncmp(console, "/dev/console", 12) == 0) && (strncmp(d->name,":0",2) != 0) ) { Debug("Not on system console\n"); bzero(greet->password, strlen(greet->password)); XFree(console); return 0; } XFree(console); } else { Debug("Could not open %s\n", SOLARIS_LOGIN_DEFAULTS); } } #endif #ifndef USE_PAM p = getpwnam (greet->name); endpwent(); if (!p || strlen (greet->name) == 0) { Debug ("getpwnam() failed.\n"); bzero(greet->password, strlen(greet->password)); return 0; } else { #ifdef linux if (!strcmp(p->pw_passwd, "!") || !strcmp(p->pw_passwd, "*")) { Debug ("The account is locked, no login allowed.\n"); bzero(greet->password, strlen(greet->password)); return 0; } #endif user_pass = p->pw_passwd; } #endif #ifdef KERBEROS if(strcmp(greet->name, "root") != 0){ char name[ANAME_SZ]; char realm[REALM_SZ]; char *q; int ret; if(krb_get_lrealm(realm, 1)){ Debug ("Can't get Kerberos realm.\n"); } else { sprintf(krbtkfile, "%s.%s", TKT_ROOT, d->name); krb_set_tkt_string(krbtkfile); unlink(krbtkfile); ret = krb_verify_user(greet->name, "", realm, greet->password, 1, "rcmd"); if(ret == KSUCCESS){ chown(krbtkfile, p->pw_uid, p->pw_gid); Debug("kerberos verify succeeded\n"); if (k_hasafs()) { if (k_setpag() == -1) LogError ("setpag() failed for %s\n", greet->name); if((ret = k_afsklog(NULL, NULL)) != KSUCCESS) LogError("Warning %s\n", krb_get_err_text(ret)); } goto done; } else if(ret != KDC_PR_UNKNOWN && ret != SKDC_CANT){ /* failure */ Debug("kerberos verify failure %d\n", ret); krbtkfile[0] = '\0'; } } } #endif #ifndef USE_PAM #ifdef USESHADOW errno = 0; sp = getspnam(greet->name); if (sp == NULL) { Debug ("getspnam() failed, errno=%d. Are you root?\n", errno); } else { user_pass = sp->sp_pwdp; } #ifndef QNX4 endspent(); #endif /* QNX4 doesn't need endspent() to end shadow passwd ops */ #endif #if defined(ultrix) || defined(__ultrix__) if (authenticate_user(p, greet->password, NULL) < 0) #else if (strcmp (crypt (greet->password, user_pass), user_pass)) #endif { if(!greet->allow_null_passwd || strlen(p->pw_passwd) > 0) { Debug ("password verify failed\n"); bzero(greet->password, strlen(greet->password)); return 0; } /* else: null passwd okay */ } #ifdef KERBEROS done: #endif #ifdef __OpenBSD__ /* * Only accept root logins if allowRootLogin resource is set */ if ((p->pw_uid == 0) && !greet->allow_root_login) { Debug("root logins not allowed\n"); bzero(greet->password, strlen(greet->password)); return 0; } /* * Shell must be in /etc/shells */ for (;;) { s = getusershell(); if (s == NULL) { /* did not found the shell in /etc/shells -> failure */ Debug("shell not in /etc/shells\n"); bzero(greet->password, strlen(greet->password)); endusershell(); return 0; } if (strcmp(s, p->pw_shell) == 0) { /* found the shell in /etc/shells */ endusershell(); break; } } /* * Test for expired password */ if (p->pw_change || p->pw_expire) (void)gettimeofday(&tp, (struct timezone *)NULL); if (p->pw_change) { if (tp.tv_sec >= p->pw_change) { Debug("Password has expired.\n"); bzero(greet->password, strlen(greet->password)); return 0; } } if (p->pw_expire) { if (tp.tv_sec >= p->pw_expire) { Debug("account has expired.\n"); bzero(greet->password, strlen(greet->password)); return 0; } } #endif /* __OpenBSD__ */ bzero(user_pass, strlen(user_pass)); /* in case shadow password */ #else /* USE_PAM */ #define PAM_BAIL \ if (pam_error != PAM_SUCCESS) goto pam_failed; PAM_password = greet->password; pam_error = pam_start("xdm", greet->name, &PAM_conversation, pamhp); PAM_BAIL; pam_error = pam_set_item(*pamhp, PAM_TTY, d->name); PAM_BAIL; pam_error = pam_set_item(*pamhp, PAM_RHOST, ""); PAM_BAIL; pam_error = pam_authenticate(*pamhp, 0); PAM_BAIL; pam_error = pam_acct_mgmt(*pamhp, 0); /* really should do password changing, but it doesn't fit well */ PAM_BAIL; pam_error = pam_setcred(*pamhp, 0); PAM_BAIL; p = getpwnam (greet->name); endpwent(); if (!p || strlen (greet->name) == 0) { Debug ("getpwnam() failed.\n"); bzero(greet->password, strlen(greet->password)); return 0; } if (pam_error != PAM_SUCCESS) { pam_failed: pam_end(*pamhp, PAM_SUCCESS); *pamhp = NULL; return 0; } #undef PAM_BAIL #endif /* USE_PAM */ #endif /* USE_BSDAUTH */ Debug ("verify succeeded\n"); /* The password is passed to StartClient() for use by user-based authorization schemes. It is zeroed there. */ verify->uid = p->pw_uid; verify->gid = p->pw_gid; home = p->pw_dir; shell = p->pw_shell; argv = 0; if (d->session) argv = parseArgs (argv, d->session); if (greet->string) argv = parseArgs (argv, greet->string); if (!argv) argv = parseArgs (argv, "xsession"); verify->argv = argv; verify->userEnviron = userEnv (d, p->pw_uid == 0, greet->name, home, shell); Debug ("user environment:\n"); printEnv (verify->userEnviron); verify->systemEnviron = systemEnv (d, greet->name, home); Debug ("system environment:\n"); printEnv (verify->systemEnviron); Debug ("end of environments\n"); return 1; }