summaryrefslogtreecommitdiffstats
path: root/src/gss_err.c
blob: ee299184e3db18c2b6eb03b4f34e9fb9b0f2da99 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* Copyright (C) 2014 GSS-NTLMSSP contributors, see COPYING for license */

#include "config.h"

#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <gssapi/gssapi.h>
#include <gssapi/gssapi_ext.h>

#include "gss_ntlmssp.h"

/* Untl we get gettext support */
#define _(x) x

/* the order is determined by ntlm_err_code order */
static const char *err_strs[] = {
    _("Unknown Error"),
    _("Failed to decode data"), /* ERR_DECODE */
    _("Failed to encode data"), /* ERR_ENCODE */
    _("Crypto routine failure"), /* ERR_CRYPTO */
    _("A required argument is missing"), /* ERR_NOARG */
    _("Invalid value in argument"), /* ERR_BADARG */
    _("Name is empty"), /* ERR_NONAME */
    _("Not a server name"), /* ERR_NOSRVNAME */
    _("Not a user name"), /* ERR_NOUSRNAME */
    _("Bad LM compatibility Level"), /* ERR_BADLMLEVEL */
    _("An impossible error occurred"), /* ERR_IMPOSSIBLE */
    _("Invalid or incomplete context"), /* ERR_BADCTX */
    _("Wrong context type"), /* ERR_WRONGCTX */
    _("Wrong message type"), /* ERR_WRONGMSG */
    _("A required Negotiate flag was no provided"), /* ERR_REQNEGFLAG */
    _("Failed to negotiate a common set of flags"), /* ERR_FAILNEGFLAGS */
    _("Invalid combinations of negotiate flags"), /* ERR_BADNEGFLAGS */
    _("Not a server credential type"), /* ERR_NOSRVCRED */
    _("Not a user redential type"), /* ERR_NOUSRCRED */
    _("Invalid or unknown credential"), /* ERR_BADCRED */
    _("Empty or missing token"), /* ERR_NOTOKEN */
    _("Feature not supported"), /* ERR_NOTSUPPORTED */
    _("Feature not available"), /* ERR_NOTAVAIL */
    _("Name is too long"), /* ERR_NAMETOOLONG */
    _("Required channel bingings are not available"), /* ERR_NOBINDINGS */
    _("Server and client clocks are too far apart"), /* ERR_TIMESKEW */
    _("Expired"), /* ERR_EXPIRED */
    _("Invalid key length"), /* ERR_KEYLEN */
    _("NTLM version 1 not allowed"), /* ERR_NONTLMV1 */
    _("User not found"), /* ERR_NOUSRFOUND */
};

#define UNKNOWN_ERROR err_strs[0]

uint32_t gssntlm_display_status(uint32_t *minor_status,
                                uint32_t status_value,
                                int status_type,
                                gss_OID mech_type,
                                uint32_t *message_context,
                                gss_buffer_t status_string)
{
    uint32_t retmaj;
    uint32_t retmin;
    /* if you can't say it in ~6 lines of text we don't bother */
    char buf[512];
    int err;

    if (!status_string) {
        return GSSERRS(ERR_NOARG, GSS_S_CALL_INACCESSIBLE_READ);
    }

    if (status_type != GSS_C_MECH_CODE) {
        return GSSERRS(ERR_BADARG, GSS_S_BAD_STATUS);
    }

    *minor_status = 0;
    *message_context = 0;
    status_string->length = 0;
    status_string->value = NULL;

    if (!status_value) {
        /* There must have been *some* error. No point saying 'Success' */
        goto done;
    }

    if (status_value > ERR_BASE && status_value < ERR_LAST) {
        status_string->value = strdup(err_strs[status_value - ERR_BASE]);
        if (!status_string->value) {
            return GSSERRS(ENOMEM, GSS_S_FAILURE);
        }
        goto done;
    }

    /* handle both XSI and GNU specific varints of strerror_r */
    errno = 0;
#if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE)
    /* XSI version */
    err = strerror_r(status_value, buf, 400);
    /* The XSI-compliant strerror_r() function returns 0 on success.
     * On error, a (positive) error number is returned (since glibc
     * 2.13), or -1 is returned and errno is set to indicate the
     * error (glibc versions before 2.13). */
#else
    {
        char *ret;
        ret = strerror_r(status_value, buf, 400);
        if (ret == NULL) {
            err = errno;
        } else {
            if (ret != buf) {
                memmove(buf, ret, strlen(ret) + 1);
            }
            err = 0;
        }
    }
#endif
    if (err == -1) err = errno;
    switch (err) {
    case ERANGE:
        /* Screw it, they can have a truncated version */
    case 0:
        status_string->value = strdup(buf);
        break;
    default:
        break;
    }

done:
    if (!status_string->value) {
        status_string->value = strdup(UNKNOWN_ERROR);
        if (!status_string->value) {
            return GSSERRS(ENOMEM, GSS_S_FAILURE);
        }
    }
    status_string->length = strlen(status_string->value);
    return GSSERRS(0, GSS_S_COMPLETE);
}