extern int compat20;
extern u_int utmp_len;
+/* so we don't silently change behaviour */
#ifdef USE_POSIX_THREADS
+# error "USE_POSIX_THREADS replaced by UNSUPPORTED_POSIX_THREADS_HACK"
+#endif
+
+/*
+ * Formerly known as USE_POSIX_THREADS, using this is completely unsupported
+ * and generally a bad idea. Use at own risk and do not expect support if
+ * this breaks.
+ */
+#ifdef UNSUPPORTED_POSIX_THREADS_HACK
#include <pthread.h>
/*
* Avoid namespace clash when *not* using pthreads for systems *with*
static void sshpam_free_ctx(void *);
static struct pam_ctxt *cleanup_ctxt;
-#ifndef USE_POSIX_THREADS
+#ifndef UNSUPPORTED_POSIX_THREADS_HACK
/*
* Simulate threads with processes.
*/
static char **sshpam_env = NULL;
static Authctxt *sshpam_authctxt = NULL;
static const char *sshpam_password = NULL;
+static char badpw[] = "\b\n\r\177INCORRECT";
/* Some PAM implementations don't implement this */
#ifndef HAVE_PAM_GETENVLIST
debug3("PAM: %s entering", __func__);
-#ifndef USE_POSIX_THREADS
+#ifndef UNSUPPORTED_POSIX_THREADS_HACK
/* Import variables set by do_pam_account */
sshpam_account_status = buffer_get_int(b);
sshpam_password_change_required(buffer_get_int(b));
struct pam_conv sshpam_conv;
int flags = (options.permit_empty_passwd == 0 ?
PAM_DISALLOW_NULL_AUTHTOK : 0);
-#ifndef USE_POSIX_THREADS
+#ifndef UNSUPPORTED_POSIX_THREADS_HACK
extern char **environ;
char **env_from_pam;
u_int i;
buffer_put_cstring(&buffer, "OK");
-#ifndef USE_POSIX_THREADS
+#ifndef UNSUPPORTED_POSIX_THREADS_HACK
/* Export variables set by do_pam_account */
buffer_put_int(&buffer, sshpam_account_status);
buffer_put_int(&buffer, sshpam_authctxt->force_pwchange);
buffer_put_int(&buffer, i);
for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++)
buffer_put_cstring(&buffer, env_from_pam[i]);
-#endif /* USE_POSIX_THREADS */
+#endif /* UNSUPPORTED_POSIX_THREADS_HACK */
/* XXX - can't do much about an error here */
ssh_msg_send(ctxt->pam_csock, sshpam_err, &buffer);
size_t plen;
u_char type;
char *msg;
- size_t len;
+ size_t len, mlen;
debug3("PAM: %s entering", __func__);
buffer_init(&buffer);
while (ssh_msg_recv(ctxt->pam_psock, &buffer) == 0) {
type = buffer_get_char(&buffer);
msg = buffer_get_string(&buffer, NULL);
+ mlen = strlen(msg);
switch (type) {
case PAM_PROMPT_ECHO_ON:
case PAM_PROMPT_ECHO_OFF:
*num = 1;
- len = plen + strlen(msg) + 1;
+ len = plen + mlen + 1;
**prompts = xrealloc(**prompts, len);
- plen += snprintf(**prompts + plen, len, "%s", msg);
+ strlcpy(**prompts + plen, msg, len - plen);
+ plen += mlen;
**echo_on = (type == PAM_PROMPT_ECHO_ON);
xfree(msg);
return (0);
case PAM_ERROR_MSG:
case PAM_TEXT_INFO:
/* accumulate messages */
- len = plen + strlen(msg) + 2;
+ len = plen + mlen + 2;
**prompts = xrealloc(**prompts, len);
- plen += snprintf(**prompts + plen, len, "%s\n", msg);
+ strlcpy(**prompts + plen, msg, len - plen);
+ plen += mlen;
+ strlcat(**prompts + plen, "\n", len - plen);
+ plen++;
xfree(msg);
break;
case PAM_SUCCESS:
**prompts = NULL;
}
if (type == PAM_SUCCESS) {
+ if (!sshpam_authctxt->valid ||
+ (sshpam_authctxt->pw->pw_uid == 0 &&
+ options.permit_root_login != PERMIT_YES))
+ fatal("Internal error: PAM auth "
+ "succeeded when it should have "
+ "failed");
import_environments(&buffer);
*num = 0;
**echo_on = 0;
return (-1);
}
buffer_init(&buffer);
- buffer_put_cstring(&buffer, *resp);
+ if (sshpam_authctxt->valid &&
+ (sshpam_authctxt->pw->pw_uid != 0 ||
+ options.permit_root_login == PERMIT_YES))
+ buffer_put_cstring(&buffer, *resp);
+ else
+ buffer_put_cstring(&buffer, badpw);
if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer) == -1) {
buffer_free(&buffer);
return (-1);
{
int flags = (options.permit_empty_passwd == 0 ?
PAM_DISALLOW_NULL_AUTHTOK : 0);
- static char badpw[] = "\b\n\r\177INCORRECT";
if (!options.use_pam || sshpam_handle == NULL)
fatal("PAM: %s called when PAM disabled or failed to "