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  *
   6  * As far as I am concerned, the code I have written for this software
   7  * can be used freely for any purpose.  Any derived versions of this
   8  * software must be clearly marked as such, and if the derived work is
   9  * incompatible with the protocol description in the RFC file, it must be
  10  * called by a name other than "ssh" or "Secure Shell".
  11  */
  12 /*
  13  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  14  * Use is subject to license terms.
  15  */
  16 
  17 #include "includes.h"
  18 RCSID("$OpenBSD: tildexpand.c,v 1.13 2002/06/23 03:25:50 deraadt Exp $");
  19 
  20 #include <libgen.h>
  21 
  22 #include "xmalloc.h"
  23 #include "log.h"
  24 #include "tildexpand.h"
  25 
  26 /*
  27  * Expands tildes in the file name.  Returns data allocated by xmalloc.
  28  * Warning: this calls getpw*.
  29  */
  30 char *
  31 tilde_expand_filename(const char *filename, uid_t my_uid)
  32 {
  33         const char *cp;
  34         uint_t userlen;
  35         char *expanded;
  36         struct passwd *pw;
  37         char *pw_dir;
  38         char user[100];
  39         int len;
  40 
  41         /* Return immediately if no tilde. */
  42         if (filename[0] != '~')
  43                 return (xstrdup(filename));
  44 
  45         /* Skip the tilde. */
  46         filename++;
  47 
  48         /* Find where the username ends. */
  49         cp = strchr(filename, '/');
  50         if (cp)
  51                 userlen = cp - filename;        /* Something after username. */
  52         else
  53                 userlen = strlen(filename);     /* Nothing after username. */
  54 
  55         /* This is the ~/xyz case with no ~username specification. */
  56         if (userlen == 0)
  57                 pw = getpwuid(my_uid);
  58         else {
  59                 /* Tilde refers to someone elses home directory. */
  60                 if (userlen > sizeof (user) - 1)
  61                         fatal("User name after tilde too long.");
  62                 memcpy(user, filename, userlen);
  63                 user[userlen] = 0;
  64                 pw = getpwnam(user);
  65         }
  66 
  67         /* Use the HOME variable now. */
  68         if (pw == NULL) {
  69                 debug("User account's password entry not found, trying to use "
  70                     "the HOME variable.");
  71                 if ((pw_dir = getenv("HOME")) == NULL) {
  72                         fatal("User account's password entry not found and "
  73                             "the HOME variable not set.");
  74                 }
  75         } else {
  76                 pw_dir = pw->pw_dir;
  77         }
  78 
  79         /* If referring to someones home directory, return it now. */
  80         if (cp == NULL) {
  81                 /* Only home directory specified */
  82                 return (xstrdup(pw_dir));
  83         }
  84 
  85         /* Build a path combining the specified directory and path. */
  86         len = strlen(pw_dir) + strlen(cp + 1) + 2;
  87         if (len > MAXPATHLEN)
  88                 fatal("Home directory too long (%d > %d)", len - 1,
  89                     MAXPATHLEN - 1);
  90 
  91         expanded = xmalloc(len);
  92         snprintf(expanded, len, "%s%s%s", pw_dir,
  93             strcmp(pw_dir, "/") ? "/" : "", cp + 1);
  94         return (expanded);
  95 }