Git fork
at reftables-rust 311 lines 10 kB view raw
1#ifndef CREDENTIAL_H 2#define CREDENTIAL_H 3 4#include "string-list.h" 5#include "strvec.h" 6 7struct repository; 8 9/** 10 * The credentials API provides an abstracted way of gathering 11 * authentication credentials from the user. 12 * 13 * Typical setup 14 * ------------- 15 * 16 * ------------ 17 * +-----------------------+ 18 * | Git code (C) |--- to server requiring ---> 19 * | | authentication 20 * |.......................| 21 * | C credential API |--- prompt ---> User 22 * +-----------------------+ 23 * ^ | 24 * | pipe | 25 * | v 26 * +-----------------------+ 27 * | Git credential helper | 28 * +-----------------------+ 29 * ------------ 30 * 31 * The Git code (typically a remote-helper) will call the C API to obtain 32 * credential data like a login/password pair (credential_fill). The 33 * API will itself call a remote helper (e.g. "git credential-cache" or 34 * "git credential-store") that may retrieve credential data from a 35 * store. If the credential helper cannot find the information, the C API 36 * will prompt the user. Then, the caller of the API takes care of 37 * contacting the server, and does the actual authentication. 38 * 39 * C API 40 * ----- 41 * 42 * The credential C API is meant to be called by Git code which needs to 43 * acquire or store a credential. It is centered around an object 44 * representing a single credential and provides three basic operations: 45 * fill (acquire credentials by calling helpers and/or prompting the user), 46 * approve (mark a credential as successfully used so that it can be stored 47 * for later use), and reject (mark a credential as unsuccessful so that it 48 * can be erased from any persistent storage). 49 * 50 * Example 51 * ~~~~~~~ 52 * 53 * The example below shows how the functions of the credential API could be 54 * used to login to a fictitious "foo" service on a remote host: 55 * 56 * ----------------------------------------------------------------------- 57 * int foo_login(struct foo_connection *f) 58 * { 59 * int status; 60 * // Create a credential with some context; we don't yet know the 61 * // username or password. 62 * 63 * struct credential c = CREDENTIAL_INIT; 64 * c.protocol = xstrdup("foo"); 65 * c.host = xstrdup(f->hostname); 66 * 67 * // Fill in the username and password fields by contacting 68 * // helpers and/or asking the user. The function will die if it 69 * // fails. 70 * credential_fill(repo, &c); 71 * 72 * // Otherwise, we have a username and password. Try to use it. 73 * 74 * status = send_foo_login(f, c.username, c.password); 75 * switch (status) { 76 * case FOO_OK: 77 * // It worked. Store the credential for later use. 78 * credential_accept(&c); 79 * break; 80 * case FOO_BAD_LOGIN: 81 * // Erase the credential from storage so we don't try it again. 82 * credential_reject(&c); 83 * break; 84 * default: 85 * // Some other error occurred. We don't know if the 86 * // credential is good or bad, so report nothing to the 87 * // credential subsystem. 88 * } 89 * 90 * // Free any associated resources. 91 * credential_clear(&c); 92 * 93 * return status; 94 * } 95 * ----------------------------------------------------------------------- 96 */ 97 98/* 99 * These values define the kind of operation we're performing and the 100 * capabilities at each stage. The first is either an external request (via git 101 * credential fill) or an internal request (e.g., via the HTTP) code. The 102 * second is the call to the credential helper, and the third is the response 103 * we're providing. 104 * 105 * At each stage, we will emit the capability only if the previous stage 106 * supported it. 107 */ 108enum credential_op_type { 109 CREDENTIAL_OP_INITIAL = 1, 110 CREDENTIAL_OP_HELPER = 2, 111 CREDENTIAL_OP_RESPONSE = 3, 112}; 113 114struct credential_capability { 115 unsigned request_initial:1, 116 request_helper:1, 117 response:1; 118}; 119 120/** 121 * This struct represents a single login credential (typically a 122 * username/password combination) along with any associated 123 * context. All string fields should be heap-allocated (or NULL if 124 * they are not known or not applicable). The meaning of the 125 * individual context fields is the same as their counterparts in 126 * the helper protocol. 127 * 128 * This struct should always be initialized with `CREDENTIAL_INIT` or 129 * `credential_init`. 130 */ 131struct credential { 132 133 /** 134 * A `string_list` of helpers. Each string specifies an external 135 * helper which will be run, in order, to either acquire or store 136 * credentials. This list is filled-in by the API functions 137 * according to the corresponding configuration variables before 138 * consulting helpers, so there usually is no need for a caller to 139 * modify the helpers field at all. 140 */ 141 struct string_list helpers; 142 143 /** 144 * A `strvec` of WWW-Authenticate header values. Each string 145 * is the value of a WWW-Authenticate header in an HTTP response, 146 * in the order they were received in the response. 147 */ 148 struct strvec wwwauth_headers; 149 150 /** 151 * A `strvec` of state headers received from credential helpers. 152 */ 153 struct strvec state_headers; 154 155 /** 156 * A `strvec` of state headers to send to credential helpers. 157 */ 158 struct strvec state_headers_to_send; 159 160 /** 161 * Internal use only. Keeps track of if we previously matched against a 162 * WWW-Authenticate header line in order to re-fold future continuation 163 * lines into one value. 164 */ 165 unsigned header_is_last_match:1; 166 167 unsigned approved:1, 168 ephemeral:1, 169 configured:1, 170 multistage: 1, 171 quit:1, 172 use_http_path:1, 173 username_from_proto:1, 174 sanitize_prompt:1, 175 protect_protocol:1; 176 177 struct credential_capability capa_authtype; 178 struct credential_capability capa_state; 179 180 char *username; 181 char *password; 182 char *credential; 183 char *protocol; 184 char *host; 185 char *path; 186 char *oauth_refresh_token; 187 timestamp_t password_expiry_utc; 188 189 /** 190 * The authorization scheme to use. If this is NULL, libcurl is free to 191 * negotiate any scheme it likes. 192 */ 193 char *authtype; 194}; 195 196#define CREDENTIAL_INIT { \ 197 .helpers = STRING_LIST_INIT_DUP, \ 198 .password_expiry_utc = TIME_MAX, \ 199 .wwwauth_headers = STRVEC_INIT, \ 200 .state_headers = STRVEC_INIT, \ 201 .state_headers_to_send = STRVEC_INIT, \ 202 .sanitize_prompt = 1, \ 203 .protect_protocol = 1, \ 204} 205 206/* Initialize a credential structure, setting all fields to empty. */ 207void credential_init(struct credential *); 208 209/** 210 * Free any resources associated with the credential structure, returning 211 * it to a pristine initialized state. 212 */ 213void credential_clear(struct credential *); 214 215/** 216 * Instruct the credential subsystem to fill the username and 217 * password (or authtype and credential) fields of the passed 218 * credential struct by first consulting helpers, then asking the 219 * user. After this function returns, either the username and 220 * password fields or the credential field of the credential are 221 * guaranteed to be non-NULL. If an error occurs, the function 222 * will die(). 223 * 224 * If all_capabilities is set, this is an internal user that is prepared 225 * to deal with all known capabilities, and we should advertise that fact. 226 */ 227void credential_fill(struct repository *, struct credential *, 228 int all_capabilities); 229 230/** 231 * Inform the credential subsystem that the provided credentials 232 * were successfully used for authentication. This will cause the 233 * credential subsystem to notify any helpers of the approval, so 234 * that they may store the result to be used again. Any errors 235 * from helpers are ignored. 236 */ 237void credential_approve(struct repository *, struct credential *); 238 239/** 240 * Inform the credential subsystem that the provided credentials 241 * have been rejected. This will cause the credential subsystem to 242 * notify any helpers of the rejection (which allows them, for 243 * example, to purge the invalid credentials from storage). It 244 * will also free() the username, password, and credential fields 245 * of the credential and set them to NULL (readying the credential 246 * for another call to `credential_fill`). Any errors from helpers 247 * are ignored. 248 */ 249void credential_reject(struct repository *, struct credential *); 250 251/** 252 * Enable all of the supported credential flags in this credential. 253 */ 254void credential_set_all_capabilities(struct credential *c, 255 enum credential_op_type op_type); 256 257/** 258 * Clear the secrets in this credential, but leave other data intact. 259 * 260 * This is useful for resetting credentials in preparation for a subsequent 261 * stage of filling. 262 */ 263void credential_clear_secrets(struct credential *c); 264 265/** 266 * Print a list of supported capabilities and version numbers to standard 267 * output. 268 */ 269void credential_announce_capabilities(struct credential *c, FILE *fp); 270 271/** 272 * Prepares the credential for the next iteration of the helper protocol by 273 * updating the state headers to send with the ones read by the last iteration 274 * of the protocol. 275 * 276 * Except for internal callers, this should be called exactly once between 277 * reading credentials with `credential_fill` and writing them. 278 */ 279void credential_next_state(struct credential *c); 280 281/** 282 * Return true if the capability is enabled for an operation of op_type. 283 */ 284int credential_has_capability(const struct credential_capability *capa, 285 enum credential_op_type op_type); 286 287int credential_read(struct credential *, FILE *, 288 enum credential_op_type); 289void credential_write(const struct credential *, FILE *, 290 enum credential_op_type); 291 292/* 293 * Parse a url into a credential struct, replacing any existing contents. 294 * 295 * If the url can't be parsed (e.g., a missing "proto://" component), the 296 * resulting credential will be empty and the function will return an 297 * error (even in the "gently" form). 298 * 299 * If we encounter a component which cannot be represented as a credential 300 * value (e.g., because it contains a newline), the "gently" form will return 301 * an error but leave the broken state in the credential object for further 302 * examination. The non-gentle form will issue a warning to stderr and return 303 * an empty credential. 304 */ 305void credential_from_url(struct credential *, const char *url); 306int credential_from_url_gently(struct credential *, const char *url, int quiet); 307 308int credential_match(const struct credential *want, 309 const struct credential *have, int match_password); 310 311#endif /* CREDENTIAL_H */