1 /*
   2  * Author: Tatu Ylonen <ylo@cs.hut.fi>
   3  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
   4  *                    All rights reserved
   5  * As far as I am concerned, the code I have written for this software
   6  * can be used freely for any purpose.  Any derived versions of this
   7  * software must be clearly marked as such, and if the derived work is
   8  * incompatible with the protocol description in the RFC file, it must be
   9  * called by a name other than "ssh" or "Secure Shell".
  10  */
  11 
  12 #include "includes.h"
  13 RCSID("$OpenBSD: auth-options.c,v 1.26 2002/07/30 17:03:55 markus Exp $");
  14 
  15 #pragma ident   "%Z%%M% %I%     %E% SMI"
  16 
  17 #include "xmalloc.h"
  18 #include "match.h"
  19 #include "log.h"
  20 #include "canohost.h"
  21 #include "channels.h"
  22 #include "auth-options.h"
  23 #include "servconf.h"
  24 #include "misc.h"
  25 #include "auth.h"
  26 
  27 /* Flags set authorized_keys flags */
  28 int no_port_forwarding_flag = 0;
  29 int no_agent_forwarding_flag = 0;
  30 int no_x11_forwarding_flag = 0;
  31 int no_pty_flag = 0;
  32 
  33 /* "command=" option. */
  34 char *forced_command = NULL;
  35 
  36 /* "environment=" options. */
  37 struct envstring *custom_environment = NULL;
  38 
  39 extern ServerOptions options;
  40 
  41 void
  42 auth_clear_options(void)
  43 {
  44         no_agent_forwarding_flag = 0;
  45         no_port_forwarding_flag = 0;
  46         no_pty_flag = 0;
  47         no_x11_forwarding_flag = 0;
  48         while (custom_environment) {
  49                 struct envstring *ce = custom_environment;
  50                 custom_environment = ce->next;
  51                 xfree(ce->s);
  52                 xfree(ce);
  53         }
  54         if (forced_command) {
  55                 xfree(forced_command);
  56                 forced_command = NULL;
  57         }
  58         channel_clear_permitted_opens();
  59         auth_debug_reset();
  60 }
  61 
  62 /*
  63  * return 1 if access is granted, 0 if not.
  64  * side effect: sets key option flags
  65  */
  66 int
  67 auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
  68 {
  69         const char *cp;
  70         int i;
  71 
  72         /* reset options */
  73         auth_clear_options();
  74 
  75         if (!opts)
  76                 return 1;
  77 
  78         while (*opts && *opts != ' ' && *opts != '\t') {
  79                 cp = "no-port-forwarding";
  80                 if (strncasecmp(opts, cp, strlen(cp)) == 0) {
  81                         auth_debug_add("Port forwarding disabled.");
  82                         no_port_forwarding_flag = 1;
  83                         opts += strlen(cp);
  84                         goto next_option;
  85                 }
  86                 cp = "no-agent-forwarding";
  87                 if (strncasecmp(opts, cp, strlen(cp)) == 0) {
  88                         auth_debug_add("Agent forwarding disabled.");
  89                         no_agent_forwarding_flag = 1;
  90                         opts += strlen(cp);
  91                         goto next_option;
  92                 }
  93                 cp = "no-X11-forwarding";
  94                 if (strncasecmp(opts, cp, strlen(cp)) == 0) {
  95                         auth_debug_add("X11 forwarding disabled.");
  96                         no_x11_forwarding_flag = 1;
  97                         opts += strlen(cp);
  98                         goto next_option;
  99                 }
 100                 cp = "no-pty";
 101                 if (strncasecmp(opts, cp, strlen(cp)) == 0) {
 102                         auth_debug_add("Pty allocation disabled.");
 103                         no_pty_flag = 1;
 104                         opts += strlen(cp);
 105                         goto next_option;
 106                 }
 107                 cp = "command=\"";
 108                 if (strncasecmp(opts, cp, strlen(cp)) == 0) {
 109                         opts += strlen(cp);
 110                         forced_command = xmalloc(strlen(opts) + 1);
 111                         i = 0;
 112                         while (*opts) {
 113                                 if (*opts == '"')
 114                                         break;
 115                                 if (*opts == '\\' && opts[1] == '"') {
 116                                         opts += 2;
 117                                         forced_command[i++] = '"';
 118                                         continue;
 119                                 }
 120                                 forced_command[i++] = *opts++;
 121                         }
 122                         if (!*opts) {
 123                                 debug("%.100s, line %lu: missing end quote",
 124                                     file, linenum);
 125                                 auth_debug_add("%.100s, line %lu: missing end quote",
 126                                     file, linenum);
 127                                 xfree(forced_command);
 128                                 forced_command = NULL;
 129                                 goto bad_option;
 130                         }
 131                         forced_command[i] = 0;
 132                         auth_debug_add("Forced command: %.900s", forced_command);
 133                         opts++;
 134                         goto next_option;
 135                 }
 136                 cp = "environment=\"";
 137                 if (options.permit_user_env &&
 138                     strncasecmp(opts, cp, strlen(cp)) == 0) {
 139                         char *s;
 140                         struct envstring *new_envstring;
 141 
 142                         opts += strlen(cp);
 143                         s = xmalloc(strlen(opts) + 1);
 144                         i = 0;
 145                         while (*opts) {
 146                                 if (*opts == '"')
 147                                         break;
 148                                 if (*opts == '\\' && opts[1] == '"') {
 149                                         opts += 2;
 150                                         s[i++] = '"';
 151                                         continue;
 152                                 }
 153                                 s[i++] = *opts++;
 154                         }
 155                         if (!*opts) {
 156                                 debug("%.100s, line %lu: missing end quote",
 157                                     file, linenum);
 158                                 auth_debug_add("%.100s, line %lu: missing end quote",
 159                                     file, linenum);
 160                                 xfree(s);
 161                                 goto bad_option;
 162                         }
 163                         s[i] = 0;
 164                         auth_debug_add("Adding to environment: %.900s", s);
 165                         debug("Adding to environment: %.900s", s);
 166                         opts++;
 167                         new_envstring = xmalloc(sizeof(struct envstring));
 168                         new_envstring->s = s;
 169                         new_envstring->next = custom_environment;
 170                         custom_environment = new_envstring;
 171                         goto next_option;
 172                 }
 173                 cp = "from=\"";
 174                 if (strncasecmp(opts, cp, strlen(cp)) == 0) {
 175                         const char *remote_ip = get_remote_ipaddr();
 176                         const char *remote_host = get_canonical_hostname(
 177                             options.verify_reverse_mapping);
 178                         char *patterns = xmalloc(strlen(opts) + 1);
 179 
 180                         opts += strlen(cp);
 181                         i = 0;
 182                         while (*opts) {
 183                                 if (*opts == '"')
 184                                         break;
 185                                 if (*opts == '\\' && opts[1] == '"') {
 186                                         opts += 2;
 187                                         patterns[i++] = '"';
 188                                         continue;
 189                                 }
 190                                 patterns[i++] = *opts++;
 191                         }
 192                         if (!*opts) {
 193                                 debug("%.100s, line %lu: missing end quote",
 194                                     file, linenum);
 195                                 auth_debug_add("%.100s, line %lu: missing end quote",
 196                                     file, linenum);
 197                                 xfree(patterns);
 198                                 goto bad_option;
 199                         }
 200                         patterns[i] = 0;
 201                         opts++;
 202                         if (match_host_and_ip(remote_host, remote_ip,
 203                             patterns) != 1) {
 204                                 xfree(patterns);
 205                                 log("Authentication tried for %.100s with "
 206                                     "correct key but not from a permitted "
 207                                     "host (host=%.200s, ip=%.200s).",
 208                                     pw->pw_name, remote_host, remote_ip);
 209                                 auth_debug_add("Your host '%.200s' is not "
 210                                     "permitted to use this key for login.",
 211                                     remote_host);
 212                                 /* deny access */
 213                                 return 0;
 214                         }
 215                         xfree(patterns);
 216                         /* Host name matches. */
 217                         goto next_option;
 218                 }
 219                 cp = "permitopen=\"";
 220                 if (strncasecmp(opts, cp, strlen(cp)) == 0) {
 221                         char host[256], sport[6];
 222                         u_short port;
 223                         char *patterns = xmalloc(strlen(opts) + 1);
 224 
 225                         opts += strlen(cp);
 226                         i = 0;
 227                         while (*opts) {
 228                                 if (*opts == '"')
 229                                         break;
 230                                 if (*opts == '\\' && opts[1] == '"') {
 231                                         opts += 2;
 232                                         patterns[i++] = '"';
 233                                         continue;
 234                                 }
 235                                 patterns[i++] = *opts++;
 236                         }
 237                         if (!*opts) {
 238                                 debug("%.100s, line %lu: missing end quote",
 239                                     file, linenum);
 240                                 auth_debug_add("%.100s, line %lu: missing end quote",
 241                                     file, linenum);
 242                                 xfree(patterns);
 243                                 goto bad_option;
 244                         }
 245                         patterns[i] = 0;
 246                         opts++;
 247                         if (sscanf(patterns, "%255[^:]:%5[0-9]", host, sport) != 2 &&
 248                             sscanf(patterns, "%255[^/]/%5[0-9]", host, sport) != 2) {
 249                                 debug("%.100s, line %lu: Bad permitopen specification "
 250                                     "<%.100s>", file, linenum, patterns);
 251                                 auth_debug_add("%.100s, line %lu: "
 252                                     "Bad permitopen specification", file, linenum);
 253                                 xfree(patterns);
 254                                 goto bad_option;
 255                         }
 256                         if ((port = a2port(sport)) == 0) {
 257                                 debug("%.100s, line %lu: Bad permitopen port <%.100s>",
 258                                     file, linenum, sport);
 259                                 auth_debug_add("%.100s, line %lu: "
 260                                     "Bad permitopen port", file, linenum);
 261                                 xfree(patterns);
 262                                 goto bad_option;
 263                         }
 264                         if (options.allow_tcp_forwarding)
 265                                 channel_add_permitted_opens(host, port);
 266                         xfree(patterns);
 267                         goto next_option;
 268                 }
 269 next_option:
 270                 /*
 271                  * Skip the comma, and move to the next option
 272                  * (or break out if there are no more).
 273                  */
 274                 if (!*opts)
 275                         fatal("Bugs in auth-options.c option processing.");
 276                 if (*opts == ' ' || *opts == '\t')
 277                         break;          /* End of options. */
 278                 if (*opts != ',')
 279                         goto bad_option;
 280                 opts++;
 281                 /* Process the next option. */
 282         }
 283 
 284         auth_debug_send();
 285 
 286         /* grant access */
 287         return 1;
 288 
 289 bad_option:
 290         log("Bad options in %.100s file, line %lu: %.50s",
 291             file, linenum, opts);
 292         auth_debug_add("Bad options in %.100s file, line %lu: %.50s",
 293             file, linenum, opts);
 294 
 295         auth_debug_send();
 296 
 297         /* deny access */
 298         return 0;
 299 }