components/openssh/patches/016-pam_enhancement.patch
changeset 1979 bdbb0de8834e
child 4071 4b68c2b0134b
equal deleted inserted replaced
1978:e9a8064da9fd 1979:bdbb0de8834e
       
     1 #
       
     2 # This patch contains a couple of PAM enhancements:
       
     3 #   1) Each SSHv2 userauth method has its own PAM service name so that PAM can
       
     4 #      be used to control what userauth methods are allowed.
       
     5 #   2) The PAMServiceName and PAMServicePrefix options.
       
     6 # 
       
     7 # We have contributed back this feature to the OpenSSH upstream community. 
       
     8 # For more information, see https://bugzilla.mindrot.org/show_bug.cgi?id=2246
       
     9 # In the future, if these enhancements are accepted by the upsteam in a 
       
    10 # later release, we will remove this patch when we upgrade to that release.
       
    11 #
       
    12 --- orig/auth-pam.c	Fri Jun 20 15:39:05 2014
       
    13 +++ new/auth-pam.c	Fri Jun 20 16:47:09 2014
       
    14 @@ -617,6 +617,72 @@
       
    15  	sshpam_handle = NULL;
       
    16  }
       
    17  
       
    18 +#ifdef PAM_ENHANCEMENT
       
    19 +char *
       
    20 +derive_pam_service_name(Authctxt *authctxt)
       
    21 +{
       
    22 +	char *svcname = xmalloc(BUFSIZ);
       
    23 +
       
    24 +	/*
       
    25 +	 * If PamServiceName is set we use that for everything, including
       
    26 +	 * SSHv1
       
    27 +	 */
       
    28 +	if (options.pam_service_name != NULL) {
       
    29 +		(void) strlcpy(svcname, options.pam_service_name, BUFSIZ);
       
    30 +		return (svcname);
       
    31 +	}
       
    32 +
       
    33 +	if (compat20) {
       
    34 +		char *method_name = authctxt->authmethod_name;
       
    35 +
       
    36 +		if (!method_name)
       
    37 +			fatal("Userauth method unknown while starting PAM");
       
    38 +
       
    39 +		/*
       
    40 +		 * For SSHv2 we use "sshd-<userauth name>
       
    41 +		 * The "sshd" prefix can be changed via the PAMServicePrefix
       
    42 +		 * sshd_config option.
       
    43 +		 */
       
    44 +		if (strcmp(method_name, "none") == 0) {
       
    45 +			snprintf(svcname, BUFSIZ, "%s-none",
       
    46 +			    options.pam_service_prefix);
       
    47 +		}
       
    48 +		if (strcmp(method_name, "password") == 0) {
       
    49 +			snprintf(svcname, BUFSIZ, "%s-password",
       
    50 +			    options.pam_service_prefix);
       
    51 +		}
       
    52 +		if (strcmp(method_name, "keyboard-interactive") == 0) {
       
    53 +			/* "keyboard-interactive" is too long, shorten it */
       
    54 +			snprintf(svcname, BUFSIZ, "%s-kbdint",
       
    55 +			    options.pam_service_prefix);
       
    56 +		}
       
    57 +		if (strcmp(method_name, "publickey") == 0) {
       
    58 +			/* "publickey" is too long, shorten it */
       
    59 +			snprintf(svcname, BUFSIZ, "%s-pubkey",
       
    60 +			    options.pam_service_prefix);
       
    61 +		}
       
    62 +		if (strcmp(method_name, "hostbased") == 0) {
       
    63 +			snprintf(svcname, BUFSIZ, "%s-hostbased",
       
    64 +			    options.pam_service_prefix);
       
    65 +		}
       
    66 +		if (strncmp(method_name, "gssapi-", 7) == 0) {
       
    67 +		        /*
       
    68 +			 * Although OpenSSH only supports "gssapi-with-mic"
       
    69 +			 * for now. We will still map any userauth method
       
    70 +                         * prefixed with "gssapi-" to the gssapi PAM service.
       
    71 +			 */ 
       
    72 +			snprintf(svcname, BUFSIZ, "%s-gssapi",
       
    73 +			    options.pam_service_prefix);
       
    74 +		}
       
    75 +		return svcname;
       
    76 +	} else {
       
    77 +		/* SSHv1 doesn't get to be so cool */
       
    78 +	        snprintf(svcname, BUFSIZ, "sshd-v1");
       
    79 +	}
       
    80 +	return svcname;
       
    81 +}
       
    82 +#endif /* PAM_ENHANCEMENT */
       
    83 +
       
    84  static int
       
    85  sshpam_init(Authctxt *authctxt)
       
    86  {
       
    87 @@ -624,18 +690,61 @@
       
    88  	const char *pam_rhost, *pam_user, *user = authctxt->user;
       
    89  	const char **ptr_pam_user = &pam_user;
       
    90  
       
    91 +#ifdef PAM_ENHANCEMENT
       
    92 +	const char *pam_service;
       
    93 +        const char **ptr_pam_service = &pam_service;
       
    94 +	char *svc = NULL;
       
    95 +
       
    96 +	svc = derive_pam_service_name(authctxt);
       
    97 +        debug3("PAM service is %s", svc);
       
    98 +#endif
       
    99 +
       
   100  	if (sshpam_handle != NULL) {
       
   101 +#ifdef PAM_ENHANCEMENT
       
   102 +	        /* get the pam service name */
       
   103 +		sshpam_err = pam_get_item(sshpam_handle,
       
   104 +		    PAM_SERVICE, (sshpam_const void **)ptr_pam_service);
       
   105 +                if (sshpam_err != PAM_SUCCESS) 
       
   106 +		    fatal("Failed to get the PAM service name");
       
   107 +		debug3("Previous pam_service is %s", pam_service ?
       
   108 +                    pam_service : "NULL");
       
   109 +
       
   110 +		/* get the pam user name */
       
   111 +		sshpam_err = pam_get_item(sshpam_handle,
       
   112 +		    PAM_USER, (sshpam_const void **)ptr_pam_user);
       
   113 +
       
   114 +		/*
       
   115 +		 * only need to re-start if either user or service is 
       
   116 +                 * different.
       
   117 +                 */
       
   118 +		if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0
       
   119 +		    && strncmp(svc, pam_service, strlen(svc)) == 0) {
       
   120 +		        free(svc);
       
   121 +			return (0);
       
   122 +                }
       
   123 +
       
   124 +#else /* Original */
       
   125  		/* We already have a PAM context; check if the user matches */
       
   126  		sshpam_err = pam_get_item(sshpam_handle,
       
   127  		    PAM_USER, (sshpam_const void **)ptr_pam_user);
       
   128  		if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0)
       
   129  			return (0);
       
   130 +#endif /* PAM_ENHANCEMENT */
       
   131  		pam_end(sshpam_handle, sshpam_err);
       
   132  		sshpam_handle = NULL;
       
   133  	}
       
   134  	debug("PAM: initializing for \"%s\"", user);
       
   135 +
       
   136 +#ifdef PAM_ENHANCEMENT
       
   137 +        debug3("Starting PAM service %s for user %s method %s", svc, user,
       
   138 +            authctxt->authmethod_name);
       
   139  	sshpam_err =
       
   140 +	    pam_start(svc, user, &store_conv, &sshpam_handle);
       
   141 +	free(svc);
       
   142 +#else /* Original */
       
   143 +	sshpam_err =
       
   144  	    pam_start(SSHD_PAM_SERVICE, user, &store_conv, &sshpam_handle);
       
   145 +#endif
       
   146  	sshpam_authctxt = authctxt;
       
   147  
       
   148  	if (sshpam_err != PAM_SUCCESS) {
       
   149 --- orig/auth.h	Fri Jun 20 15:39:05 2014
       
   150 +++ new/auth.h	Fri Jun 20 15:39:05 2014
       
   151 @@ -76,6 +76,9 @@
       
   152  #endif
       
   153  	Buffer		*loginmsg;
       
   154  	void		*methoddata;
       
   155 +#ifdef PAM_ENHANCEMENT
       
   156 +        char            *authmethod_name;
       
   157 +#endif 
       
   158  };
       
   159  /*
       
   160   * Every authentication method has to handle authentication requests for
       
   161 --- orig/auth2.c	Fri Jun 20 15:39:05 2014
       
   162 +++ new/auth2.c	Fri Jun 20 15:39:05 2014
       
   163 @@ -249,10 +249,13 @@
       
   164  			PRIVSEP(audit_event(SSH_INVALID_USER));
       
   165  #endif
       
   166  		}
       
   167 +
       
   168 +#ifndef PAM_ENHANCEMENT
       
   169  #ifdef USE_PAM
       
   170  		if (options.use_pam)
       
   171  			PRIVSEP(start_pam(authctxt));
       
   172  #endif
       
   173 +#endif
       
   174  		setproctitle("%s%s", authctxt->valid ? user : "unknown",
       
   175  		    use_privsep ? " [net]" : "");
       
   176  		authctxt->service = xstrdup(service);
       
   177 @@ -286,6 +289,14 @@
       
   178  	/* try to authenticate user */
       
   179  	m = authmethod_lookup(authctxt, method);
       
   180  	if (m != NULL && authctxt->failures < options.max_authtries) {
       
   181 +
       
   182 +#ifdef PAM_ENHANCEMENT
       
   183 +                authctxt->authmethod_name = xstrdup(method);
       
   184 +                if (use_privsep)
       
   185 +                       mm_inform_authmethod(method);
       
   186 +		if (options.use_pam)
       
   187 +		       PRIVSEP(start_pam(authctxt));
       
   188 +#endif
       
   189  		debug2("input_userauth_request: try method %s", method);
       
   190  		authenticated =	m->userauth(authctxt);
       
   191  	}
       
   192 @@ -303,6 +314,10 @@
       
   193  	char *methods;
       
   194  	int partial = 0;
       
   195  
       
   196 +#ifdef  PAM_ENHANCEMENT
       
   197 +        debug3("%s: entering", __func__);
       
   198 +#endif
       
   199 +
       
   200  	if (!authctxt->valid && authenticated)
       
   201  		fatal("INTERNAL ERROR: authenticated invalid user %s",
       
   202  		    authctxt->user);
       
   203 @@ -623,5 +638,3 @@
       
   204  		fatal("%s: method not in AuthenticationMethods", __func__);
       
   205  	return 0;
       
   206  }
       
   207 -
       
   208 -
       
   209 --- orig/monitor_wrap.c	Fri Jun 20 15:39:05 2014
       
   210 +++ new/monitor_wrap.c	Fri Jun 20 15:39:05 2014
       
   211 @@ -338,6 +338,24 @@
       
   212  	buffer_free(&m);
       
   213  }
       
   214  
       
   215 +#ifdef PAM_ENHANCEMENT
       
   216 +/* Inform the privileged process about the authentication method */
       
   217 +void
       
   218 +mm_inform_authmethod(char *authmethod)
       
   219 +{
       
   220 +	Buffer m;
       
   221 +
       
   222 +	debug3("%s entering", __func__);
       
   223 +
       
   224 +	buffer_init(&m);
       
   225 +	buffer_put_cstring(&m, authmethod);
       
   226 +
       
   227 +	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHMETHOD, &m);
       
   228 +
       
   229 +	buffer_free(&m);
       
   230 +}
       
   231 +#endif
       
   232 +
       
   233  /* Do the password authentication */
       
   234  int
       
   235  mm_auth_password(Authctxt *authctxt, char *password)
       
   236 --- orig/monitor.c	Fri Jun 20 15:39:05 2014
       
   237 +++ new/monitor.c	Fri Jun 20 15:39:05 2014
       
   238 @@ -146,6 +146,9 @@
       
   239  int mm_answer_pwnamallow(int, Buffer *);
       
   240  int mm_answer_auth2_read_banner(int, Buffer *);
       
   241  int mm_answer_authserv(int, Buffer *);
       
   242 +#ifdef PAM_ENHANCEMENT
       
   243 +int mm_answer_authmethod(int, Buffer *);
       
   244 +#endif
       
   245  int mm_answer_authpassword(int, Buffer *);
       
   246  int mm_answer_bsdauthquery(int, Buffer *);
       
   247  int mm_answer_bsdauthrespond(int, Buffer *);
       
   248 @@ -225,10 +228,17 @@
       
   249      {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign},
       
   250      {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
       
   251      {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv},
       
   252 +#ifdef PAM_ENHANCEMENT
       
   253 +    {MONITOR_REQ_AUTHMETHOD, MON_ISAUTH, mm_answer_authmethod},
       
   254 +#endif
       
   255      {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner},
       
   256      {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword},
       
   257  #ifdef USE_PAM
       
   258 +#ifdef PAM_ENHANCEMENT
       
   259 +    {MONITOR_REQ_PAM_START, MON_ISAUTH, mm_answer_pam_start},
       
   260 +#else
       
   261      {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
       
   262 +#endif
       
   263      {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account},
       
   264      {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx},
       
   265      {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query},
       
   266 @@ -828,6 +838,10 @@
       
   267  		/* Allow service/style information on the auth context */
       
   268  		monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1);
       
   269  		monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1);
       
   270 +#ifdef PAM_ENHANCEMENT
       
   271 +                /* Allow authmethod information on the auth context */
       
   272 +		monitor_permit(mon_dispatch, MONITOR_REQ_AUTHMETHOD, 1);
       
   273 +#endif
       
   274  	}
       
   275  #ifdef USE_PAM
       
   276  	if (options.use_pam)
       
   277 @@ -868,7 +882,25 @@
       
   278  	return (0);
       
   279  }
       
   280  
       
   281 +#ifdef PAM_ENHANCEMENT
       
   282  int
       
   283 +mm_answer_authmethod(int sock, Buffer *m)
       
   284 +{
       
   285 +	monitor_permit_authentications(1);
       
   286 +
       
   287 +	authctxt->authmethod_name = buffer_get_string(m, NULL);
       
   288 +	debug3("%s: authmethod_name=%s", __func__, authctxt->authmethod_name);
       
   289 +
       
   290 +	if (strlen(authctxt->authmethod_name) == 0) {
       
   291 +		free(authctxt->authmethod_name);
       
   292 +		authctxt->authmethod_name = NULL;
       
   293 +	}
       
   294 +
       
   295 +	return (0);
       
   296 +}
       
   297 +#endif
       
   298 +
       
   299 +int
       
   300  mm_answer_authpassword(int sock, Buffer *m)
       
   301  {
       
   302  	static int call_count;
       
   303 --- orig/monitor.h	Fri Jun 20 15:39:05 2014
       
   304 +++ new/monitor.h	Fri Jun 20 15:39:05 2014
       
   305 @@ -70,6 +70,9 @@
       
   306  	MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111,
       
   307  	MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113,
       
   308  
       
   309 +#ifdef PAM_ENHANCEMENT
       
   310 +        MONITOR_REQ_AUTHMETHOD = 114,
       
   311 +#endif        
       
   312  };
       
   313  
       
   314  struct mm_master;
       
   315 --- orig/servconf.c	Fri Jun 20 15:39:05 2014
       
   316 +++ new/servconf.c	Fri Jun 20 15:39:05 2014
       
   317 @@ -154,6 +154,10 @@
       
   318  	options->ip_qos_interactive = -1;
       
   319  	options->ip_qos_bulk = -1;
       
   320  	options->version_addendum = NULL;
       
   321 +#ifdef PAM_ENHANCEMENT
       
   322 +	options->pam_service_name = NULL;
       
   323 +	options->pam_service_prefix = NULL;
       
   324 +#endif
       
   325  }
       
   326  
       
   327  void
       
   328 @@ -303,6 +307,12 @@
       
   329  		options->ip_qos_bulk = IPTOS_THROUGHPUT;
       
   330  	if (options->version_addendum == NULL)
       
   331  		options->version_addendum = xstrdup("");
       
   332 +
       
   333 +#ifdef PAM_ENHANCEMENT
       
   334 +        if (options->pam_service_prefix == NULL)
       
   335 +                options->pam_service_prefix = _SSH_PAM_SERVICE_PREFIX;
       
   336 +#endif
       
   337 +
       
   338  	/* Turn privilege separation on by default */
       
   339  	if (use_privsep == -1)
       
   340  		use_privsep = PRIVSEP_NOSANDBOX;
       
   341 @@ -351,6 +361,9 @@
       
   342  	sKexAlgorithms, sIPQoS, sVersionAddendum,
       
   343  	sAuthorizedKeysCommand, sAuthorizedKeysCommandUser,
       
   344  	sAuthenticationMethods, sHostKeyAgent,
       
   345 +#ifdef PAM_ENHANCEMENT
       
   346 +	sPAMServicePrefix, sPAMServiceName,
       
   347 +#endif
       
   348  	sDeprecated, sUnsupported
       
   349  } ServerOpCodes;
       
   350  
       
   351 @@ -482,6 +495,10 @@
       
   352  	{ "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL },
       
   353  	{ "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL },
       
   354  	{ "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL },
       
   355 +#ifdef PAM_ENHANCEMENT
       
   356 +        { "pamserviceprefix", sPAMServicePrefix, SSHCFG_GLOBAL },
       
   357 +        { "pamservicename", sPAMServiceName, SSHCFG_GLOBAL },
       
   358 +#endif
       
   359  	{ NULL, sBadOption, 0 }
       
   360  };
       
   361  
       
   362 @@ -1632,6 +1649,30 @@
       
   363  		}
       
   364  		return 0;
       
   365  
       
   366 +	case sPAMServicePrefix:
       
   367 +		arg = strdelim(&cp);
       
   368 +		if (!arg || *arg == '\0')
       
   369 +			fatal("%s line %d: Missing argument.",
       
   370 +			    filename, linenum);
       
   371 +		if (options->pam_service_name != NULL)
       
   372 +			fatal("%s line %d: PAMServiceName and PAMServicePrefix"
       
   373 +			    " are mutually exclusive.", filename, linenum);
       
   374 +		if (options->pam_service_prefix == NULL)
       
   375 +			options->pam_service_prefix = xstrdup(arg);
       
   376 +		break;
       
   377 +
       
   378 +	case sPAMServiceName:
       
   379 +		arg = strdelim(&cp);
       
   380 +		if (!arg || *arg == '\0')
       
   381 +			fatal("%s line %d: Missing argument.",
       
   382 +			    filename, linenum);
       
   383 +		if (options->pam_service_prefix != NULL)
       
   384 +			fatal("%s line %d: PAMServiceName and PAMServicePrefix"
       
   385 +			    " are mutually exclusive.", filename, linenum);
       
   386 +		if (options->pam_service_name == NULL)
       
   387 +			options->pam_service_name = xstrdup(arg);
       
   388 +		break;
       
   389 +
       
   390  	case sDeprecated:
       
   391  		logit("%s line %d: Deprecated option %s",
       
   392  		    filename, linenum, arg);
       
   393 --- orig/servconf.h	Fri Jun 20 15:39:05 2014
       
   394 +++ new/servconf.h	Fri Jun 20 15:39:05 2014
       
   395 @@ -54,6 +54,10 @@
       
   396  /* Magic name for internal sftp-server */
       
   397  #define INTERNAL_SFTP_NAME	"internal-sftp"
       
   398  
       
   399 +#ifdef PAM_ENHANCEMENT
       
   400 +#define _SSH_PAM_SERVICE_PREFIX "sshd"
       
   401 +#endif
       
   402 +
       
   403  typedef struct {
       
   404  	u_int	num_ports;
       
   405  	u_int	ports_from_cmdline;
       
   406 @@ -185,6 +189,12 @@
       
   407  
       
   408  	u_int	num_auth_methods;
       
   409  	char   *auth_methods[MAX_AUTH_METHODS];
       
   410 +
       
   411 +#ifdef PAM_ENHANCEMENT
       
   412 +	char   *pam_service_prefix;
       
   413 +	char   *pam_service_name;
       
   414 +#endif
       
   415 +        
       
   416  }       ServerOptions;
       
   417  
       
   418  /* Information about the incoming connection as used by Match */
       
   419 --- orig/sshd_config.5	Fri Jun 20 15:39:05 2014
       
   420 +++ new/sshd_config.5	Fri Jun 20 15:39:05 2014
       
   421 @@ -868,6 +868,21 @@
       
   422  are refused if the number of unauthenticated connections reaches
       
   423  .Dq full
       
   424  (60).
       
   425 +.It Cm PAMServiceName
       
   426 +Specifies the PAM service name for the PAM session. The PAMServiceName and 
       
   427 +PAMServicePrefix options are mutually exclusive and if both set, sshd does not
       
   428 +start. If this option is set the service name is the same for all user 
       
   429 +authentication methods. The option has no default value. See PAMServicePrefix 
       
   430 +for more information.
       
   431 +.It Cm PAMServicePrefix
       
   432 +Specifies the PAM service name prefix for service names used for individual 
       
   433 +user authentication methods. The default is sshd. The PAMServiceName and 
       
   434 +PAMServicePrefix options are mutually exclusive and if both set, sshd does not 
       
   435 +start.
       
   436 +.Pp
       
   437 +For example, if this option is set to admincli, the service name for the 
       
   438 +keyboard-interactive authentication method is admincli-kbdint instead of the 
       
   439 +default sshd-kbdint.
       
   440  .It Cm PasswordAuthentication
       
   441  Specifies whether password authentication is allowed.
       
   442  The default is
       
   443 --- orig/sshd.8	Fri Jun 20 15:39:05 2014
       
   444 +++ new/sshd.8	Fri Jun 20 15:39:05 2014
       
   445 @@ -951,6 +951,33 @@
       
   446  started last).
       
   447  The content of this file is not sensitive; it can be world-readable.
       
   448  .El
       
   449 +
       
   450 +.Sh SECURITY
       
   451 +sshd uses pam(3PAM) for password and keyboard-interactive methods as well as 
       
   452 +for account management, session management, and the password management for all
       
   453 +authentication methods.
       
   454 +.Pp
       
   455 +Each SSHv2 userauth type has its own PAM service name:
       
   456 +
       
   457 +.Bd -literal -offset 3n
       
   458 +
       
   459 +-----------------------------------------------
       
   460 +| SSHv2 Userauth       | PAM Service Name     |
       
   461 +-----------------------------------------------
       
   462 +| none                 | sshd-none            |
       
   463 +-----------------------------------------------
       
   464 +| password             | sshd-password        |
       
   465 +-----------------------------------------------
       
   466 +| keyboard-interactive | sshd-kbdint          |
       
   467 +-----------------------------------------------
       
   468 +| pubkey               | sshd-pubkey          |
       
   469 +-----------------------------------------------
       
   470 +| hostbased            | sshd-hostbased       |
       
   471 +-----------------------------------------------
       
   472 +| gssapi-with-mic      | sshd-gssapi          |
       
   473 +-----------------------------------------------
       
   474 +.Ed
       
   475 +
       
   476  .Sh SEE ALSO
       
   477  .Xr scp 1 ,
       
   478  .Xr sftp 1 ,