Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
86879f4
cifs-utils: add documentation for acregmax and acdirmax
bharathsm-ms Aug 28, 2024
b18aaa8
Merge pull request #1 from bharathsm-ms/update_metadata_caching_docum…
smfrench Aug 29, 2024
4454465
cifs-utils: add documentation for multichannel and max_channels
bharathsm-ms Sep 3, 2024
a6966fc
Merge pull request #3 from smfrench/update_multichannel_documentations
smfrench Oct 4, 2024
03f0c2b
checkopts: update it to work with latest kernel version
hac-v Sep 16, 2024
7e73642
docs: add compress description
hac-v Sep 17, 2024
02034bf
docs: add closetimeo description
hac-v Sep 17, 2024
9cb001f
Merge pull request #3 from smfrench/update_multichannel_documentations
smfrench Oct 4, 2024
a5ed24c
cifs: update documentation for sloppy mount option
bharathsm-ms Oct 4, 2024
e44b9a9
Merge pull request #5 from smfrench/update_documentation_for_mount_op…
smfrench Oct 4, 2024
55dde41
smbinfo: add bash completion support for filestreaminfo, keys, gettco…
Oct 7, 2024
82db1d6
cifs-utils: support and document password2 mount option
meetakshi253 Oct 22, 2024
777ac65
use enums to check password or password2 in set_password, get_passwor…
meetakshi253 Nov 11, 2024
a80dac4
cifs-utils: Skip TGT check if valid service ticket is already available
bharathsm-ms Nov 26, 2024
968311d
CIFS.upcall to accomodate new namespace mount opt
ritbudhiraja Nov 19, 2024
4a2ca2b
Fix compiler warnings in mount.cifs
meetakshi253 Dec 6, 2024
b152669
Merge pull request #8 from smfrench/mount-warnings
smfrench Dec 13, 2024
d625cbb
docs: update actimeo description
hac-v Oct 5, 2024
b864bbb
docs: add max_cached_dirs description
hac-v Dec 18, 2024
bc3ea65
docs: add esize description
hac-v Dec 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions bash-completion/smbinfo
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,22 @@ smb_info()
filemodeinfo
filepositioninfo
filestandardinfo
filestreaminfo
fsctl-getobjid
getcompression
setcompression
list-snapshots
quota
secdesc"
secdesc
keys
gettconinfo"
case $prev in
'-v'|'-h')
return 0
;;
'fileaccessinfo'|'filealigninfo'|'fileallinfo'|'filebasicinfo'|'fileeainfo'|'filefsfullsizeinfo'|\
'fileinternalinfo'|'filemodeinfo'|'filepositioninfo'|'filestandardinfo'|'fsctl-getobjid'|\
'getcompression'|'setcompression'|'list-snapshots'|'quota'|'secdesc')
'fileinternalinfo'|'filemodeinfo'|'filepositioninfo'|'filestandardinfo'|'filestreaminfo'|'fsctl-getobjid'|\
'getcompression'|'setcompression'|'list-snapshots'|'quota'|'secdesc'|'keys'|'gettconinfo')
local IFS=$'\n'
compopt -o filenames
COMPREPLY=( $(compgen -f -o dirnames -- ${cur:-""}) )
Expand Down
72 changes: 29 additions & 43 deletions checkopts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import re
import subprocess
import argparse
from pprint import pprint as P
from collections import defaultdict

def extract_canonical_opts(s):
"""
Expand All @@ -38,52 +39,30 @@ def extract_canonical_opts(s):

def extract_kernel_opts(fn):
STATE_BASE = 0
STATE_DEF = 1
STATE_USE = 2
STATE_EXIT = 3
STATE_USE = 1

state = STATE_BASE
fmt2enum = {}
enum2code = {}
code = ''
current_opt = ''
name2enum = {}
enum2code = defaultdict(lambda: '')
rx = RX()

def code_add(s):
if current_opt != '':
if current_opt not in enum2code:
enum2code[current_opt] = ''
enum2code[current_opt] += s

with open(fn) as f:
for s in f.readlines():
if state == STATE_EXIT:
break

elif state == STATE_BASE:
if rx.search(r'cifs_mount_option_tokens.*\{', s):
state = STATE_DEF
elif rx.search(r'^cifs_parse_mount_options', s):
if state == STATE_BASE:
if rx.search(r'^\s*fsparam_(.*)\("([^,]+)",\s+([^,]+)(?:,\s+([^,]+))?\)', s):
fmt = rx.group(1)
name = rx.group(2)
name2enum[name] = { 'enum': rx.group(3), 'fmt': fmt }
elif rx.search(r'^\s*case (Opt_[a-zA-Z0-9_]+)', s):
current_opt = rx.group(1)
state = STATE_USE

elif state == STATE_DEF:
if rx.search(r'(Opt_[a-zA-Z0-9_]+)\s*,\s*"([^"]+)"', s):
fmt = rx.group(2)
opts = extract_canonical_opts(fmt)
assert(len(opts) == 1)
name = opts[0]
fmt2enum[name] = {'enum':rx.group(1), 'fmt':fmt}
elif rx.search(r'^};', s):
elif state == STATE_USE:
enum2code[current_opt] += s
if rx.search(r'\s*break;', s):
state = STATE_BASE

elif state == STATE_USE:
if rx.search(r'^\s*case (Opt_[a-zA-Z0-9_]+)', s):
current_opt = rx.group(1)
elif current_opt != '' and rx.search(r'^\s*default:', s):
state = STATE_EXIT
else:
code_add(s)
return fmt2enum, enum2code
return name2enum, enum2code

def chomp(s):
if s[-1] == '\n':
Expand Down Expand Up @@ -158,23 +137,23 @@ def main():
ap.add_argument("rstfile", help="path to mount.cifs.rst")
args = ap.parse_args()

fmt2enum, enum2code = extract_kernel_opts(args.cfile)
name2enum, enum2code = extract_kernel_opts(args.cfile)
manopts = extract_man_opts(args.rstfile)

kernel_opts_set = set(fmt2enum.keys())
kernel_opts_set = set(name2enum.keys())
man_opts_set = set(manopts.keys())

def opt_alias_is_doc(o):
enum = fmt2enum[o]['enum']
enum = name2enum[o]['enum']
aliases = []
for k,v in fmt2enum.items():
for k,v in name2enum.items():
if k != o and v['enum'] == enum:
if opt_is_doc(k):
return k
return None

def opt_exists(o):
return o in fmt2enum
return o in name2enum

def opt_is_doc(o):
return o in manopts
Expand All @@ -194,8 +173,8 @@ def main():
undoc_opts = kernel_opts_set - man_opts_set
# group opts and their negations together
for opt in sortedset(undoc_opts):
fmt = fmt2enum[opt]['fmt']
enum = fmt2enum[opt]['enum']
fmt = name2enum[opt]['fmt']
enum = name2enum[opt]['enum']
code = format_code(enum2code[enum])
neg = opt_neg(opt)

Expand All @@ -222,6 +201,13 @@ def main():
# group opts and their negations together
for opt in sortedset(unex_opts):
man = manopts[opt][0]

# If positive opt exists and it is used, then negative opt does
# not need to exist
if opt.startswith('no') and opt[2:] in name2enum:
print(f'# skipping {opt} ({opt[2:]} exists)')
continue

print('OPTION %s ("%s") line %d' % (opt, man['fmt'], man['ln']))


Expand Down
119 changes: 105 additions & 14 deletions cifs.upcall.c
Original file line number Diff line number Diff line change
Expand Up @@ -552,11 +552,6 @@ get_existing_cc(const char *env_cachename)
syslog(LOG_DEBUG, "%s: default ccache is %s\n", __func__, cachename);
krb5_free_string(context, cachename);
}

if (!get_tgt_time(cc)) {
krb5_cc_close(context, cc);
cc = NULL;
}
return cc;
}

Expand Down Expand Up @@ -638,6 +633,49 @@ init_cc_from_keytab(const char *keytab_name, const char *user)

#define CIFS_SERVICE_NAME "cifs"

static krb5_error_code check_service_ticket_exists(krb5_ccache ccache,
const char *hostname) {

krb5_error_code rc;
krb5_creds mcreds, out_creds;

memset(&mcreds, 0, sizeof(mcreds));

rc = krb5_cc_get_principal(context, ccache, &mcreds.client);
if (rc) {
syslog(LOG_DEBUG, "%s: unable to get client principal from cache: %s",
__func__, krb5_get_error_message(context, rc));
return rc;
}

rc = krb5_sname_to_principal(context, hostname, CIFS_SERVICE_NAME,
KRB5_NT_UNKNOWN, &mcreds.server);
if (rc) {
syslog(LOG_DEBUG, "%s: unable to convert service name (%s) to principal: %s",
__func__, hostname, krb5_get_error_message(context, rc));
krb5_free_principal(context, mcreds.client);
return rc;
}

rc = krb5_timeofday(context, &mcreds.times.endtime);
if (rc) {
syslog(LOG_DEBUG, "%s: unable to get time: %s",
__func__, krb5_get_error_message(context, rc));
goto out_free_principal;
}

rc = krb5_cc_retrieve_cred(context, ccache, KRB5_TC_MATCH_TIMES, &mcreds, &out_creds);

if (!rc)
krb5_free_cred_contents(context, &out_creds);

out_free_principal:
krb5_free_principal(context, mcreds.server);
krb5_free_principal(context, mcreds.client);

return rc;
}

static int
cifs_krb5_get_req(const char *host, krb5_ccache ccache,
DATA_BLOB * mechtoken, DATA_BLOB * sess_key)
Expand Down Expand Up @@ -954,6 +992,13 @@ struct decoded_args {
#define MAX_USERNAME_SIZE 256
char username[MAX_USERNAME_SIZE + 1];

#define MAX_UPCALL_STRING_LEN 6 /* "mount\0" */
enum upcall_target_enum {
UPTARGET_UNSPECIFIED, /* not specified, defaults to app */
UPTARGET_MOUNT, /* upcall to the mount namespace */
UPTARGET_APP, /* upcall to the application namespace which did the mount */
} upcall_target;

uid_t uid;
uid_t creduid;
pid_t pid;
Expand All @@ -970,6 +1015,7 @@ struct decoded_args {
#define DKD_HAVE_PID 0x20
#define DKD_HAVE_CREDUID 0x40
#define DKD_HAVE_USERNAME 0x80
#define DKD_HAVE_UPCALL_TARGET 0x100
#define DKD_MUSTHAVE_SET (DKD_HAVE_HOSTNAME|DKD_HAVE_VERSION|DKD_HAVE_SEC)
int have;
};
Expand All @@ -980,6 +1026,7 @@ __decode_key_description(const char *desc, struct decoded_args *arg)
size_t len;
char *pos;
const char *tkn = desc;
arg->upcall_target = UPTARGET_UNSPECIFIED;

do {
pos = index(tkn, ';');
Expand Down Expand Up @@ -1078,6 +1125,31 @@ __decode_key_description(const char *desc, struct decoded_args *arg)
}
arg->have |= DKD_HAVE_VERSION;
syslog(LOG_DEBUG, "ver=%d", arg->ver);
} else if (strncmp(tkn, "upcall_target=", 14) == 0) {
if (pos == NULL)
len = strlen(tkn);
else
len = pos - tkn;

len -= 14;
if (len > MAX_UPCALL_STRING_LEN) {
syslog(LOG_ERR, "upcall_target= value too long for buffer");
return 1;
}
if (strncmp(tkn + 14, "mount", 5) == 0) {
arg->upcall_target = UPTARGET_MOUNT;
syslog(LOG_DEBUG, "upcall_target=mount");
} else if (strncmp(tkn + 14, "app", 3) == 0) {
arg->upcall_target = UPTARGET_APP;
syslog(LOG_DEBUG, "upcall_target=app");
} else {
// Should never happen
syslog(LOG_ERR, "Invalid upcall_target value: %s, defaulting to app",
tkn + 14);
arg->upcall_target = UPTARGET_APP;
syslog(LOG_DEBUG, "upcall_target=app");
}
arg->have |= DKD_HAVE_UPCALL_TARGET;
}
if (pos == NULL)
break;
Expand Down Expand Up @@ -1441,15 +1513,20 @@ int main(const int argc, char *const argv[])
* acceptably in containers, because we'll be looking at the correct
* filesystem and have the correct network configuration.
*/
rc = switch_to_process_ns(arg->pid);
if (rc == -1) {
syslog(LOG_ERR, "unable to switch to process namespace: %s", strerror(errno));
rc = 1;
goto out;
if (arg->upcall_target == UPTARGET_APP || arg->upcall_target == UPTARGET_UNSPECIFIED) {
syslog(LOG_INFO, "upcall_target=app, switching namespaces to application thread");
rc = switch_to_process_ns(arg->pid);
if (rc == -1) {
syslog(LOG_ERR, "unable to switch to process namespace: %s", strerror(errno));
rc = 1;
goto out;
}
if (trim_capabilities(env_probe))
goto out;
} else {
syslog(LOG_INFO, "upcall_target=mount, not switching namespaces to application thread");
}

if (trim_capabilities(env_probe))
goto out;

/*
* The kernel doesn't pass down the gid, so we resort here to scraping
Expand Down Expand Up @@ -1496,7 +1573,7 @@ int main(const int argc, char *const argv[])
* look at the environ file.
*/
env_cachename =
get_cachename_from_process_env(env_probe ? arg->pid : 0);
get_cachename_from_process_env((env_probe && (arg->upcall_target == UPTARGET_APP)) ? arg->pid : 0);

rc = setuid(uid);
if (rc == -1) {
Expand All @@ -1516,12 +1593,26 @@ int main(const int argc, char *const argv[])
goto out;
}

host = arg->hostname;
ccache = get_existing_cc(env_cachename);
if (ccache != NULL) {
rc = check_service_ticket_exists(ccache, host);
if(rc == 0) {
syslog(LOG_DEBUG, "%s: valid service ticket exists in credential cache",
__func__);
} else {
if (!get_tgt_time(ccache)) {
syslog(LOG_DEBUG, "%s: valid TGT is not present in credential cache",
__func__);
krb5_cc_close(context, ccache);
ccache = NULL;
}
}
}
/* Couldn't find credcache? Try to use keytab */
if (ccache == NULL && arg->username[0] != '\0')
ccache = init_cc_from_keytab(keytab_name, arg->username);

host = arg->hostname;

// do mech specific authorization
switch (arg->sec) {
Expand Down
Loading