source: web/old/remctl-2.14/util/tokens.c @ f6f3e91

web
Last change on this file since f6f3e91 was f6f3e91, checked in by Jessica B. Hamrick <jhamrick@…>, 15 years ago

Preserve directory hierarchy (not sure what happened to it)

  • Property mode set to 100644
File size: 4.8 KB
Line 
1/*
2 * Token handling routines.
3 *
4 * Low-level routines to send and receive remctl tokens.  token_send and
5 * token_recv do not do anything to their provided input or output except
6 * wrapping flags and a length around them.
7 *
8 * Originally written by Anton Ushakov
9 * Extensive modifications by Russ Allbery <rra@stanford.edu>
10 * Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008
11 *     Board of Trustees, Leland Stanford Jr. University
12 *
13 * See LICENSE for licensing terms.
14 */
15
16#include <config.h>
17#include <portable/system.h>
18#include <portable/gssapi.h>
19#include <portable/socket.h>
20
21#include <errno.h>
22
23#include <util/util.h>
24
25/*
26 * Windows requires a different function when sending to sockets, but can't
27 * return short writes on blocking sockets.
28 */
29#ifdef _WIN32
30# define socket_xwrite(fd, b, s)        send((fd), (b), (s), 0)
31#else
32# define socket_xwrite(fd, b, s)        xwrite((fd), (b), (s))
33#endif
34
35
36/*
37 * Equivalent to read, but reads all the available data up to the buffer
38 * length, using multiple reads if needed and handling EINTR and EAGAIN.
39 */
40static ssize_t
41xread(int fd, void *buffer, size_t size)
42{
43    size_t total;
44    ssize_t status;
45    int count = 0;
46
47    if (size == 0)
48        return 0;
49
50    /* Abort the read if we try 100 times with no forward progress. */
51    for (total = 0; total < size; total += status) {
52        if (++count > 100)
53            break;
54        status = socket_read(fd, (char *) buffer + total, size - total);
55        if (status > 0)
56            count = 0;
57        if (status < 0) {
58            if ((errno != EINTR) && (errno != EAGAIN))
59                break;
60            status = 0;
61        }
62    }
63    return (status < 0) ? status : (ssize_t) total;
64}
65
66
67/*
68 * Send a token to a file descriptor.  Takes the file descriptor, the token,
69 * and the flags (a single byte, even though they're passed in as an integer)
70 * and writes them to the file descriptor.  Returns TOKEN_OK on success and
71 * TOKEN_FAIL_SYSTEM or TOKEN_FAIL_SOCKET on an error (including partial
72 * writes).
73 */
74enum token_status
75token_send(int fd, int flags, gss_buffer_t tok)
76{
77    ssize_t status;
78    size_t buflen;
79    char *buffer;
80    unsigned char char_flags = (unsigned char) flags;
81    OM_uint32 len = htonl(tok->length);
82
83    /* Send out the whole message in a single write. */
84    buflen = 1 + sizeof(OM_uint32) + tok->length;
85    buffer = malloc(buflen);
86    if (buffer == NULL)
87        return TOKEN_FAIL_SYSTEM;
88    memcpy(buffer, &char_flags, 1);
89    memcpy(buffer + 1, &len, sizeof(OM_uint32));
90    memcpy(buffer + 1 + sizeof(OM_uint32), tok->value, tok->length);
91    status = socket_xwrite(fd, buffer, buflen);
92    free(buffer);
93    if (status < 0 || (size_t) status != buflen)
94        return TOKEN_FAIL_SOCKET;
95    else
96        return TOKEN_OK;
97}
98
99
100/*
101 * Receive a token from a file descriptor.  Takes the file descriptor, a
102 * buffer into which to store the token, a pointer into which to store the
103 * flags, and the maximum token length we're willing to accept.  Returns
104 * TOKEN_OK on success.  On failure, returns one of:
105 *
106 *     TOKEN_FAIL_SYSTEM       System call failed, errno set.
107 *     TOKEN_FAIL_SOCKET       Socket call failed, socket_errno set.
108 *     TOKEN_FAIL_INVALID      Invalid token format.
109 *     TOKEN_FAIL_LARGE        Token data larger than provided limit.
110 *     TOKEN_FAIL_EOF          Unexpected end of file
111 *
112 * TOKEN_FAIL_SYSTEM and TOKEN_FAIL_SOCKET are the same on UNIX but different
113 * on Windows.
114 *
115 * recv_token reads the token flags (a single byte, even though they're stored
116 * into an integer, then reads the token length (as a network long), allocates
117 * memory to hold the data, and then reads the token data from the file
118 * descriptor.  It blocks to read the length and data, if necessary.  On a
119 * successful return, the value member of the token should be freed with
120 * free().
121 */
122enum token_status
123token_recv(int fd, int *flags, gss_buffer_t tok, size_t max)
124{
125    ssize_t status;
126    OM_uint32 len;
127    unsigned char char_flags;
128
129    status = xread(fd, &char_flags, 1);
130    if (status < 0)
131        return TOKEN_FAIL_SOCKET;
132    else if (status == 0)
133        return TOKEN_FAIL_EOF;
134    *flags = char_flags;
135
136    status = xread(fd, &len, sizeof(OM_uint32));
137    if (status < 0)
138        return TOKEN_FAIL_SOCKET;
139    else if (status == 0)
140        return TOKEN_FAIL_EOF;
141    else if (status != sizeof(OM_uint32))
142        return TOKEN_FAIL_INVALID;
143    tok->length = ntohl(len);
144    if (tok->length > max)
145        return TOKEN_FAIL_LARGE;
146
147    tok->value = malloc(tok->length);
148    if (tok->value == NULL)
149        return TOKEN_FAIL_SYSTEM;
150    status = xread(fd, tok->value, tok->length);
151    if (status < 0) {
152        free(tok->value);
153        return TOKEN_FAIL_SOCKET;
154    } else if (status != (ssize_t) tok->length) {
155        free(tok->value);
156        return TOKEN_FAIL_INVALID;
157    }
158    return TOKEN_OK;
159}
Note: See TracBrowser for help on using the repository browser.