1  /* { dg-do run } */
       2  /* SEGV at comment below.  */
       3  typedef unsigned int size_t;
       4  typedef enum har {
       5    he_fatal = (-199),
       6    he_not_initialized,
       7    he_bad_input,
       8    he_memory_too_small,
       9    he_bad_action,
      10    he_duplicate,
      11    he_bad_nonce,
      12    he_stale_nonce,
      13    he_bad_credentials,
      14    he_bad_user,
      15    he_no_such_user,
      16    he_bad_passwd,
      17    he_unknown_auth_scheme,
      18    he_not_found,
      19    he_failed_digest_file_check,
      20    he_failed_digest_file_save,
      21    he_process_not_privileged,
      22    he_other,
      23    he_end_of_range,
      24    ha_no_error = 0,
      25    ha_no_value = 1
      26  } har;
      27  typedef enum realm_type
      28  {
      29    axis_realm = 0,
      30    ws_realm
      31  } realm_type;
      32  
      33  __attribute__((__noclone__, __noinline__))
      34  har has_www_auth(char *, size_t, realm_type, har);
      35  
      36  __attribute__((__noclone__, __noinline__))
      37  har has_auth_user(const char *, const char *, realm_type, char *, size_t);
      38  
      39  __attribute__((__noclone__, __noinline__))
      40  char *ha_get_string_value(void);
      41  
      42  typedef struct
      43  {
      44    unsigned int track_id;
      45    char* user;
      46    char* realm;
      47    char* authent;
      48    int internal_realm;
      49  } request;
      50  enum user_response {
      51    file_not_found_user_response = -3,
      52    access_denied_user_response = -2,
      53    no_user_response = -1,
      54    ok_user_response = 0
      55  };
      56  struct realm_group {
      57    char *name;
      58    int id;
      59    struct realm_group *next;
      60  };
      61  struct realm {
      62    char *name;
      63    char *space;
      64    struct realm_group *groups;
      65    struct realm *next;
      66  };
      67  struct user_info {
      68    char *name;
      69    int no_groups;
      70    int groups[128];
      71    struct user_info *next;
      72  };
      73  static struct user_info *find_user(const char *user_name);
      74  static int is_member_of_groups(const struct user_info *user_item,
      75                                  const struct realm_group *groups);
      76  int authent_author(request *req);
      77  struct realm *realms = ((void *)0);
      78  struct user_info *users = ((void *)0);
      79  static struct user_info*
      80  find_user(const char *user_name)
      81  {
      82    struct user_info *user_item;
      83    user_item = users;
      84    while (user_item != ((void *)0)) {
      85      /* SEGV due to NULL access here on user_name.  See also comment below.  */
      86      if ((__builtin_strcmp(user_item->name, user_name) == 0))
      87        break;
      88      user_item = user_item->next;
      89    }
      90    return user_item;
      91  }
      92  static int
      93  is_member_of_groups(const struct user_info *user_item,
      94                      const struct realm_group *groups)
      95  {
      96    const struct realm_group *group_item;
      97    int i;
      98    group_item = groups;
      99    while (group_item != ((void *)0)) {
     100      for (i = 0; i < user_item->no_groups; i++)
     101        if (user_item->groups[i] == group_item->id)
     102  	return 0;
     103      group_item = group_item->next;
     104    }
     105    return -1;
     106  }
     107  char *foo (void) __attribute__((__noclone__, __noinline__));
     108  char* g_strdup (const char *str) __attribute__((__malloc__, __noclone__, __noinline__));
     109  int g_strcmp0 (const char *str1, const char *str2);
     110  static int
     111  is_basic(char **user)
     112  {
     113    char *passwd_ptr;
     114    char *authent = foo();
     115    passwd_ptr = __builtin_strchr(authent, ':');
     116    if (passwd_ptr != ((void *)0)) {
     117      *user = g_strdup(authent);
     118      return 0;
     119    }
     120    return -1;
     121  }
     122  static int
     123  is_digest(char **user)
     124  {
     125    int ret_val = -1;
     126    char *authent;
     127    authent = ha_get_string_value();
     128    if (authent) {
     129      *user = g_strdup(authent);
     130      ret_val = 0;
     131    }
     132    return ret_val;
     133  }
     134  __attribute__((__noclone__, __noinline__))
     135  void g_free (void * mem);
     136  static enum user_response
     137  get_user_info_from_header(const realm_type type,
     138                            char **user_name,
     139                            struct user_info **user_item)
     140  {
     141    int ret_val = no_user_response;
     142    if ((type == ws_realm)) {
     143      if (is_basic(user_name) == 0)
     144        ret_val = access_denied_user_response;
     145      if (is_digest(user_name) == 0)
     146        ret_val = ok_user_response;
     147    } else {
     148      if (is_basic(user_name) < 0 &&
     149  	/* Load of *user_name here, but not after the is_digest call.  */
     150  	is_digest(user_name) < 0)
     151        ;
     152      else if ((*user_item = find_user(*user_name)) != ((void *)0))
     153        ret_val = ok_user_response;
     154      else
     155        ret_val = access_denied_user_response;
     156      if (ret_val != ok_user_response)
     157        g_free(*user_name);
     158    }
     159    return ret_val;
     160  }
     161  static enum user_response
     162  authenticate_user(request *req,
     163                    char **user_name,
     164                    struct user_info **user_item)
     165  {
     166    char *authent = ((void *)0);
     167    har resp = ha_no_value;
     168    enum user_response user_resp;
     169    int ret_val = no_user_response;
     170    if (req->authent && __builtin_strlen(req->authent)) {
     171      authent = req->authent;
     172      user_resp = get_user_info_from_header(req->internal_realm,
     173                                            user_name,
     174                                            user_item);
     175      if (user_resp == ok_user_response) {
     176        resp = has_auth_user(authent, 0, req->internal_realm, "", 1);
     177        if (resp == ha_no_error)
     178  	ret_val = ok_user_response;
     179        else if (resp != he_stale_nonce)
     180  	ret_val = access_denied_user_response;
     181      } else if (user_resp == access_denied_user_response)
     182        ret_val = access_denied_user_response;
     183    }
     184    if (resp != he_memory_too_small && resp != ha_no_error)
     185      resp = has_www_auth("", 1, req->internal_realm, resp);
     186    return ret_val;
     187  }
     188  
     189  int __attribute__ ((__noinline__, __noclone__))
     190  authent_author(request *req)
     191  {
     192    struct realm *realm;
     193    char *user_name = ((void *)0);
     194    struct user_info *user_item = ((void *)0);
     195    int res = 0;
     196    asm ("");
     197    realm = realms;
     198    if (__builtin_strcmp("Wsd", realm->name) == 0) {
     199      req->internal_realm = ws_realm;
     200      is_digest(&user_name);
     201    }
     202    if (authenticate_user(req, &user_name, &user_item) < 0) {
     203      if (user_name != ((void *)0))
     204        req->user = user_name;
     205      res = -2;
     206      goto authent_author_return;
     207    }
     208    if (is_member_of_groups(user_item, realm->groups) < 0)
     209      res = -1;
     210  authent_author_return:
     211    return res;
     212  }
     213  
     214  int good0, good1, good2;
     215  
     216  __attribute__ ((__noinline__, __noclone__))
     217  char *foo(void)
     218  {
     219    asm ("");
     220    good0++;
     221    return "";
     222  }
     223  
     224  __attribute__ ((__noinline__, __noclone__))
     225  char *ha_get_string_value(void)
     226  {
     227    asm ("");
     228    good1++;
     229    return "f";
     230  }
     231  
     232  __attribute__ ((__noinline__, __noclone__))
     233  har has_auth_user(const char *a, const char *b, realm_type c, char *d, size_t e)
     234  {
     235    asm ("");
     236    if (*a != 'z' || a[1] != 0 || b != 0 || c != axis_realm || *d != 0
     237        || e != 1)
     238      __builtin_abort ();
     239    return ha_no_error;
     240  }
     241  
     242  __attribute__ ((__noinline__, __noclone__))
     243  har has_www_auth(char *a, size_t b, realm_type c, har d)
     244  {
     245    (void)(*a+b+c+d);
     246    asm ("");
     247    __builtin_abort ();
     248  }
     249  
     250  
     251  char *strdupped_user = "me";
     252  __attribute__((__malloc__, __noclone__, __noinline__))
     253  char* g_strdup (const char *str)
     254  {
     255    asm ("");
     256    if (*str != 'f')
     257      __builtin_abort ();
     258    good2++;
     259    return strdupped_user;
     260  }
     261  
     262  __attribute__((__noclone__, __noinline__))
     263  void g_free (void * mem)
     264  {
     265    (void)mem;
     266    asm ("");
     267    __builtin_abort ();
     268  }
     269  
     270  struct user_info me = { .name = "me", .no_groups = 1, .groups = {42}, .next = 0};
     271  struct user_info you = { .name = "you", .next = &me};
     272  struct realm_group xgroups = { .name = "*", .id = 42, .next = 0};
     273  
     274  int main(void)
     275  {
     276    char *orig_user = "?";
     277    struct realm r = { .name = "x", .space = "space?", .groups = &xgroups, .next = 0};
     278    request req = { .user = orig_user, .realm = "!", .authent = "z",
     279  		  .internal_realm = axis_realm};
     280    realms = &r;
     281    users = &you;
     282    if (authent_author (&req) != 0 || good0 != 1 || good1 != 1 || good2 != 1
     283        || req.user != orig_user
     284        || req.internal_realm != axis_realm)
     285      __builtin_abort ();
     286    __builtin_exit (0);
     287  }
     288